Announcing Dyre 0.9 release candidate
Dyre is a tool for Haskell program configuration by (re)compilation. The last release was 0.8.12, way back in 2014. Since then, the project has been dormant… until now. I am pleased to announce a Dyre 0.9 release candidate. In this post I outline what’s changed and put out a call for testing ahead of the official release.
Dyre overview §
Dyre implements program configuration in the style of xmonad. Configurations are Haskell programs using native types and functions. When a Dyre-enabled program starts up, it detects whether the configuration has changed. If so, it (re)compiles and caches a custom executable. Then it executes the custom executable and enters the “main program”.
Being able to configure a program using data types that are “native” to the program is both pleasant and powerful. Subtle user configuration errors that may go unnoticed, or lie dormant until they crash your program, instead become type errors. The program author has much less verification to perform compared to a configuration written in text formats such as YAML or JSON.
This post is not intended to be a Dyre tutorial. Refer to the
Config.Dyre
module documentation to see what Dyre
looks like in practice.
Becoming Dyre’s maintainer §
Will Donnelly is Dyre’s original author and maintainer. Credit and thanks to him for writing a very useful tool and actively maintaining it over several years.
The most recent release of Dyre on Hackage was 0.8.12 in 2014. There was activity on GitHub after that release, until early 2017. After that, Dyre was dormant.
Meanwhile my major project Purebred uses Dyre for configuration. We encountered some dependency issues and behaviour in Dyre that caused problems with newer versions of GHC. We also noticed some things that could be improved.
I decided to offer to take maintainership of Dyre. I emailed Will Donnelly but did not receive a response. Following the Taking over a package guide, I emailed the Haskell-cafe mailing list to announce my intent to take over the package. This email did get noticed. Will graciously agreed that I should assume maintainership. He added me as a maintainer on Hackage and a collaborator on GitHub.
I put my shiny new commit bit to use and soon pushed several changes to GitHub, before… not cutting a release, then doing nothing for another two years. But now—at last—I am putting the finishing touches on a new release for Dyre. So…
What’s changed in version 0.9? §
Major changes since 0.8.12 include:
realMain
can now return arbitrary types. To support this change,Params
got a new type variable.-- before data Params cfgType wrapMain :: Params cfgType -> cfgType -> IO () -- after data Params cfgType a wrapMain :: Params cfgType a -> cfgType -> IO a
defaultParams
, which containsundefined
fields, has been deprecated in favour of the new functionnewParams
:-- here be bottoms defaultParams :: Params cfg a -- celestial music playing newParams :: String -- ^ 'projectName' -> (cfg -> IO a) -- ^ 'realMain' function -> (cfg -> String -> cfg) -- ^ 'showError' function -> Params cfg a
newParams
takes values for the three required fields, so program authors can clearly see what they have to do and are less likely to make a mistake.Cabal store support: Users can add extra include dirs via the
includeDirs
field ofParams
. The program author just has to put the package’s library directory in the newincludeDirs
field:import Config.Dyre import Paths_myapp (getLibDir) = … realMain = … showError = do myapp cfg <- getLibDir libdir let params = (newParams "myapp" realMain showError) = [libdir] } { includeDirs wrapMain params cfg
If an include dir appears to be in a Cabal store and matches the
projectName
, Dyre adds the corresponding-package-id
option. As a result, recompilation works for programs installed viacabal install
.Stack support: if Dyre detects a
stack.yaml
alongside the custom configuration, it will use Stack to compile the program. Credit to Jaro Reinders for this feature.Dyre compiles the custom executable with
-threaded
when the main executable uses the threaded RTS. This means one less thing for program authors to remember (or forget) to do.Dyre now requires GHC >= 7.10.
Improved documentation.
The test suite was expanded, and can now be executed via
cabal test
.Dyre cleans up better after compilation (successful or unsuccesful), and behaves better when the custom configuration is removed.
Some versions of GHC write to standard error, even during a successful compilation. Dyre no longer treats this as a compilation failure, instead relying solely on GHC’s exit status.
Dyre recognises the
HC
environment variable. If set, it will compile the program using the specified compiler.Fixes for Windows, including working with recent versions of the process package.
Additionally, I set up continuous integration for the Dyre codebase. Initially it used Travis-CI but I recently migrated to GitHub Actions. It includes jobs for testing Dyre on MacOS and Windows.
Call for testing §
I would like testing and feedback on the release candidate before I cut the final release of Dyre 0.9. In particular, I would welcome more testing on Windows, as well as the Stack support. I also need to test with GHC 7.10, which for technical reasons is not covered by the CI matrix.
You can help by testing Dyre in any environments, but
especially those ones. Even if you only run cabal test
, or
implement the example from the Config.Dyre
module
documentation, it will help. Please report testing outcomes in the
testing checklist issue. Failures and successes should be
reported there.
For testing on Windows, you can install the cabal
and ghc
packages from Chocolatey. To run the cabal test
suite you’ll
also need a POSIX shell installed as sh.exe
. The one provided by
the gitsh
package worked for me.
I hope to make the final release in a couple of weeks.
Future work §
One area I have identified for future development is recording file hashes to detect changes. This is important to support the Nix packaging system, which sets all files’ creation and modification times to the epoch. It will also help with downgrades, where the main executable’s modification time decreases.
This known gap is the reason I didn’t release a new version in the almost two years since I became the maintainer. I kept thinking, “I should really fix that first”. But I still haven’t implemented file hashing, and don’t have immediate plans to. So I decided not to delay any longer the release of the improvements I have made.
If Nix support or other features are particularly important to you, please consider contributing to Dyre. You can create issues and pull requests on GitHub, or reach out to me directly.