Cool! Carry on.
Looking good, stay simple.
$ cat > myproject.vx2 << EOF Project('myproject') HaskellPackage('dependency', '0.9.1.3') EOF $ vernix $ cat > shell.nix << EOF { ghcver ? 'ghc822'}: (import ./myproject-project.nix { inherit ghcver; }).myproject.env EOF $ nix-shell nix-shell$ cabal ...
$ cat > myproject.vx2 << EOF Project('myproject') HaskellPackage('dependency', RepoIdent(team='bestcoders', reponame='deplib')) EOF $ vernix $ cat > shell.nix << EOF { ghcver ? 'ghc822'}: (import ./myproject-project.nix { inherit ghcver; }).myproject.env EOF $ nix-shell nix-shell$ cabal ...
Note that any package that you do not explicitly specify in your vx2 file will be obtained from the standard nixpkgs specification. If nixpkgs knows about the package, and if the version it supplies is fine, then you don’t need to explicitly add the package into the vx2 file.
$ cat > myproject.vx2 << EOF Project('myproject') HaskellPackage('dependency1', 'devel-branch', RepoIdent(team='bestcoders', reponame='deplib')) HaskellPackage('dependency2', '9fa3a11', RepoIdent(team='maxcoders', reponame='fancylib')) EOF $ vernix $ cat > shell.nix << EOF { ghcver ? 'ghc822'}: (import ./myproject-project.nix { inherit ghcver; }).myproject.env EOF $ nix-shell nix-shell$ cabal ...
$ cat > myproject.vx2 << EOF Project('myproject') HaskellPackage('dependency1', 'devel-branch', RepoIdent(team='bestcoders', reponame='deplib'), Local('../localdep3')) EOF $ vernix $ cat > shell.nix << EOF { ghcver ? 'ghc822'}: (import ./myproject-project.nix { inherit ghcver; }).myproject.env EOF $ nix-shell nix-shell$ cabal ...
Note that when both the RepoIdent and the Local are specified, the Local takes precedence, but is ignored when it is removed. This allows nix to provide the dependency from a local source (even if it’s normally available via a git submodule, this is an override alternative).
The Local precedence+ignore behavior can be particularly handy when the top-level project uses git submodules:
Start my dev:
$ git clone myproject... $ cd myproject $ cat > myproject.vx2 << EOF Project('myproject') HaskellPackage('dependency1', 'devel-branch', RepoIdent(team='bestcoders', reponame='deplib'), Local('./submodules/deplib')) EOF $ vernix $ cat > shell.nix << EOF { ghcver ? 'ghc822'}: (import ./myproject-project.nix { inherit ghcver; }).myproject.env EOF $ nix-shell nix-shell$ cabal ...
Decide I want to make modifications to deplib as well:
$ git submodule init submodules/deplib $ git submodule update submodules/deplib $ vernix $ nix-shell
Finished with the deplib modifications, but still working on the main project:
$ cd submodules/deplib $ git commit ... $ git push $ cd - $ git submodules deinit submodules/deplib $ rm -rf submodules/deplib $ vernix $ nix-shell
Now deplib is coming from the git repo again.
The vernix “–static” and “–dynamic” command-line flags determine when the source is fetched from remote git repos.
In static mode, the source is fetched when vernix
runs: the
result is a consistent -project.nix
file that always references
the same sources, even if new commits are pushed to the remote
repo.
In dynamic mode, the source is fetched each time nix-build
, or
nix-shell
is run. This will make these commands somewhat
slower, but will ensure that the latest remote sources are
obtained each time they are run. Note that this mode cannot be
used in “restricted” nix mode (Hydra runs in restricted mode, and
always uses --static
).
Changed to be incorporated | –static (default) | –dynamic | Re-run nix-shell |
---|---|---|---|
Modify the vx2 file | yes | yes | yes |
Get new remote (github) change | yes | yes | |
Changes in a Local dependency | yes |
Vernix will process each package, looking first for the package in the specified Local location (if any), and then from the RepoIdent location, and finally assuming that it comes from the standard package repository (e.g. Hackage).
Vernix will generate a nix build specification for each package from the specified source location, often using helpers (e.g. cabal2nix).
Vernix will write a -project.nix
file that contains all of the
build specifications as overrides/additions to the standard nixpkg
specifications, as well as some usage instructions at the end. It
will optionally generate Hydra build information.
If you are working on ProjectA, which depends on ProjectB, and you have both checked out locally and referenced by a Local specification, and you have made changes in ProjectB that you want visible in ProjectA, how do you do it?
~/dev/ProjectB $ edit [make some changes] ~/dev/ProjectB $ nix-shell [nix-shell:~/dev/ProjectB]$ cabal build [everything looks good, you now want to use these changes in ProjectA] [nix-shell:~/dev/ProjectB]$ exit ~/dev/ProjectB $ cd ../ProjectA ~/dev/ProjectB $ nix-shell [sees changes in ~/dev/ProjectB and copies them to /nix/store/...] [rebuilds a new ProjectB in /nix/store] [nix-shell:~/dev/ProjectA]$ cabal clean
This is a fairly standard process, except for a couple of notable elements:
- If you already had a nix-shell open in ProjectA, the ProjectB
dependency points to the last build in
/nix/store
, and not to thedev/ProjectB
directory where your newest changes are. You must exit any existingnix-shell
environment and re-issue thenix-shell
(ornix-build
) to get the updated ProjectB rebuild into the/nix/store
and available for ProjectA. - The cabal tool is unaware of the new ProjectB build in the
/nix/store
, so anything previously built into ProjectA’sdist
output directory will not be updated. The safest way to manage this is to usecabal clean
in ProjectA to ensure that cabal sees the new ProjectB build in the/nix/store
location.
You can use vernix for these, but there are a couple of additional steps.
- Use the ssh repo access methodology, not the https access method.
- Ensure you have an ssh-agent running and loaded with the keys you need to access the private repo.
- Always run vernix with the
--static
flag (the default). This ensures that any fetches from the private repo are performed during thevernix
run when the local ssh-agent is available to respond to permissions challenges. When running nix-shell/nix-build/nix-env, those usually run via anix-buildN
alternate process, which will not have access to your locally running ssh-agent and therefore cannot pull the sources from the remote repository. - The use of the
--fast
flag with private repositories is not recommended: the ssh-agent doesn’t seem to handle simultaneous challenge sessions well, and thevernix
run will fail with strange and non-deterministic errors. Running without the--fast
flag will take a little longer, but should be deterministically successful. - If you are using
--hydra
, then the RepoIdent for the private repository will need to use a specific name for the remote server. The hydra user on the Hydra system will need the .ssh/config file to specify that hostname with a translation to the actual remote repository and a specification of which identify file (private key) to use to allow Hydra to access the private repository. That private key should not have a passphrase to allow it to be used in batch mode.