Reflex Package Versions
I was hesitant to write the Nix Reproducibility blog
entry yesterday, but I am glad that I did. Thanks to writing that blog
entry, I noticed that the version of reflex-dom-core
used was quite old. It makes sense that a project developed with Nix uses versions of packages that are
determined by a fixed nixpkgs (or other)
repository revision, and an old project likely uses old revisions. Obelisk is
installed from the master
branch, however. In this blog
entry, I investigate which package versions are used when using Reflex FRP.
First, I prepared a clean Nix environment. See the Nix Cleanup Everything blog entry for details.
$ nix-env --query
nix-2.7.0
$ du -sh /nix/
434M /nix/
For my first test, I experimented with the tutorial on the Reflex homepage. I installed Obelisk by following the Installing Obelisk instructions in the project README. With Nix already installed and caches configured, I just needed to run the following command.
$ nix-env -f https://github.com/obsidiansystems/obelisk/archive/master.tar.gz -iA command
It does not take too long to install.
$ nix-env --query
nix-2.7.0
obelisk-command-0.9.0.1
$ du -sh /nix/
1.8G /nix/
Yesterday, I noticed that I had many versions of Obelisk packages in
my Nix store and wondered which version I was using. My profile pointed
to version 0.9.0.1
like above, but I assume that the older
versions were installed and used by the project repositories that I was
experimenting with. The changelog
and releases
indicate that the latest version of Obelisk is 1.0.0.0
, but
I did not see that version. The ob
command unfortunately
does not provide a --version
option or version
command, so commands like ls -l $(which ob)
need to be used
to investigate which version is actually being used.
I now realize that the 1.0.0.0
version is for the
master
branch as a whole and is unrelated to the version of
the packages. Indeed, lib/command/obelisk-command.cabal
specifies version 0.9.0.1
.
At this point, even running ob --help
causes Nix to
build the command. This downloads lots of stuff, including many obsolete
Python 2.7 libraries, which is puzzling. (Why is Python 2.7 still being
used!?!?) Nix 2.2.2 is also downloaded! I guess this explains why I saw
old versions of Nix in my store. I found that running
ob --help
increased the size of my store by a gigabyte!
$ du -sh /nix/
2.8G /nix/
The tutorial
repository includes an .obelisk/impl
directory that
points to a specific commit in the Obelisk repository. The specified
branch is a few years old, and the specified revision is not even the
latest on that branch.
{
"owner": "obsidiansystems",
"repo": "obelisk",
"branch": "ls-reflex-frp",
"rev": "50a5b9e0da7986de0f885575ab302ca05dc793ac",
"sha256": "0qx74sl710zd50zgccyn8y4c37d5lj3xhh7ckicjvhy5kbk12bps"
}
Checking Obelisk revision 50a5b9e0da,
I found that obelisk-command
is at version
0.1
, which is something that had puzzled me yesterday. I
guess that this revision is also what determines the versions of the
libraries used to build the project. Indeed,
dep/reflex-platform
points to a specific commit in the Reflex Platform
repository.
{
"owner": "reflex-frp",
"repo": "reflex-platform",
"branch": "je-reflex-frp-website-temp",
"rev": "a3acd23d3242f7cd80baff38b44d73c41d527c5f",
"sha256": "1cv4i0wxgyhalx04vqilrw8ybni0ka51zgx4g9yx4vljk82qdbjd"
}
Checking Reflex Platform revision a3acd23d32,
I found that nixpkgs
points to a specific commit in the nixpkgs repository. The
specified revision is a pretty old revision in the
nixos-19.03
branch.
{
"owner": "nixos",
"repo": "nixpkgs-channels",
"branch": "nixos-19.03",
"rev": "9d55c1430af72ace3a479d5e0a90451108e774b4",
"sha256": "05625fwgsa15i2jlsf2ymv3jx68362nf3zqbpnrwq6d3sn89liny"
}
Checking nixpkgs
revision 9d55c1430a,
I found that reflex-dom-core
is set at version 0.4
in
pkgs/development/haskell-modules/hackage-packages.nix
.
Fixing the revisions/versions of the whole development ecosystem is important for providing reproducibility. When experimenting with numerous Reflex projects, however, I ended up building many similar yet slightly different development ecosystems. This consumes a lot of storage space, takes a lot of time, and uses a lot of bandwidth. I imagine/hope that this is not an issue when focusing on a single project.
I am curious if the tutorial works with the
latest release of Obelisk. It should not take too long to try! I first
created a new directory and ran ob init
to initialize a new
project. The new .obelisk/impl
directory points to the
latest revision on the master
branch! Wow!
{
"owner": "obsidiansystems",
"repo": "obelisk",
"branch": "master",
"private": false,
"rev": "e3ec75f6988eed47189dd20f8c8514748b33ea81",
"sha256": "0sdlcyzdx9nyql5vmpjydhzsakixc8y050v8m2rz87l2rmhkqnw9"
}
Obelisk revision e3ec75f698
uses Reflex Platform revision 123a6f487c,
the latest revision of the release/0.9.2.0
branch.
Interestingly, a fork of nixpkgs
is used! Revision a78062dc78
on this fork is the second newest revision of the
reflex-platform-20.09
branch. GitHub reports that the
branch is 4,444 commits ahead and 122,868 commits behind the nixpkgs master
branch. There are newer reflex-platform-*
branches, but
perhaps they are not stable yet. I found that reflex-dom-core
version 0.6.0.0
is used in this revision.
{
"owner": "obsidiansystems",
"repo": "nixpkgs",
"branch": "reflex-platform-20.09",
"private": false,
"rev": "a78062dc78a85f5d553443ea636a3242c0e6de04",
"sha256": "1kda0hdmvscma86c13z01mm29ka43djd9fskfa9g6f170sd9f4qc"
}
I manually merged the tutorial with the new project template.
The cabal.project
configuration now configures write-ghc-environment-files
to never
, which is the default anyway. I kept this
setting.
There are a few changes to the default.nix
file. A
system
parameter is added so that
builtins.currentSystem
can be overridden. A newer iOS SDK
version is used. There is new
terms.security.acme.acceptTerms
configuration that is
required to use Let’s Encrypt. I
merged in all of these new changes.
The new .cabal
files have updated ghc-options.
Libraries use the following options, while executables use the same
options with the additions of -threaded
.
-O
-Wall
-Wincomplete-record-updates
-Wincomplete-uni-patterns
-Wredundant-constraints
-fno-show-valid-hole-fits
The .gitignore
file is significantly updated. I kept the
new version. I also kept the new .obelisk
directory, of
course.
The ob run
command takes a long time to run. A log is
displayed indicating that the command is built, and then there is
long time without any output at all! Perhaps I should run the
command using the --verbose
flag… In this case, I monitored
the system using htop (sorting by CPU
percentage and using the full width of my monitor in order to see the
full paths of programs under /nix/store
) and Nethogs.
I of course did something else while waiting for the build. After returning from lunch, I found that the build had failed. The following error was displayed, reformatted to multiple lines.
Process exited with code 100;
/nix/store/4z4336r8yhyznz3fiscvz53wgdj43kjb-nix-2.3.11/bin/nix-shell -E
$'{root, pkgs, shell}: ((import root {}).passthru.__unstable__.self.extend
(_: _: {shellPackages = builtins.fromJSON pkgs;})).project.shells.${shell}'
--arg root ./. --argstr pkgs $'{"backend":"/tmp/calculator-tutorial/backend",
"common":"/tmp/calculator-tutorial/common",
"frontend":"/tmp/calculator-tutorial/frontend",
"obelisk-generated-static":
"/nix/store/lsaqdxf2vhw6ipnj5jb1d9ylfw0aisr0-asset-manifest-haskellManifest"}'
--argstr shell ghc --run $'export
$\'NIX_PATH=nixpkgs=/nix/store/yxa12wh8fc6j8w61y3jn27vw8dhydby7-source\' ;
bash -c \'type -p ghc\''
I ran ob run
again, and (after more waiting and near
100% CPU usage) it failed with the same error, with no additional
output. I tried again with the --verbose
option and got
different output.
$ ob run --verbose
Starting Obelisk </nix/store/ndgqr350z5rnr58wd70nwkzjg9847nxq-obelisk-command-0.9.0.1/bin/.ob-wrapped> args=["run","--verbose"] logging-level=Debug
Thunk specification git-v5 did not match "./.obelisk/impl": ReadThunkError_UnrecognizedPaths ("./.obelisk/impl/github.json" :| [])
Thunk specification github-v5 matched "./.obelisk/impl"
./.obelisk/impl: command not cached, building ...
Creating process: nix-build ./.obelisk/impl -A command --out-link ./.obelisk/impl/.attr-cache/command.out
DONE Built on ./.obelisk/impl [command]
Handing off to ./.obelisk/impl/.attr-cache/command.out/bin/ob
Starting Obelisk </nix/store/ndgqr350z5rnr58wd70nwkzjg9847nxq-obelisk-command-0.9.0.1/bin/.ob-wrapped> args=["--no-handoff","run","--verbose"] logging-level=Debug
Finding packages with root "." and interpret paths:
ob: <stdout>: commitAndReleaseBuffer: invalid argument (invalid character)
The thunk error is intriguing. After researching it a bit, I found a thread on /r/haskell that indicates that the error is not an issue.
That final error is strange. It is an error that is commonly seen when a Haskell program is run in a non-UTF-8 locale. My shell of course has the locale configured correctly, but perhaps something is wrong within the Nix environment…
I tried building a few more times, and I discovered that the “invalid
character” error now occurs very quickly as soon as I run
ob run --verbose
, while running just ob run
takes a lot longer and uses a lot of CPU before eventually
failing with the above “Process exited with code 100” error message.
This leads me to believe that the “invalid character” error is an issue
with the Obelisk command, not the tutorial project. Unfortunately, it
keeps me from seeing what is really making the build fail.
I tried running ob --verbose run
, on the off chance that
the option order is significant, but I get the same “invalid character”
error.
I created a new project, initialized using ob init
, and
tried running ob --verbose run
in that project without any
changes. It fails with the same “invalid character” error.
I tried searching the Obelisk issues and
found an old/closed issue about a similar problem that used to happen
with ob init
(issue
335). I once again confirmed that my LANG
environment
variable is set. I also searched the currently open pull requests but
did not see anything relevant. I went ahead and submitted a new
issue.
This is an unsatisfactory way to fail at making the tutorial use the latest release of Obelisk. I do not even know the real error! Alas, at least I am getting more familiar with Obelisk projects.