tinc in Nix mode
January 23, 2017 ยท View on GitHub
When tinc is installed under /nix or the environment variable TINC_USE_NIX is set to yes, it operates in Nix mode. Everything is installed under /nix including:
- System dependencies for GHC
- GHC
- System and Haskell dependencies for your project (cabal packages)
- Your project
Essentially, tinc does the following:
- Use
cabalto generate an install plan from your.cabalfile. - Use
cabal2nixto generate Nix derivations for all dependencies in the install plan. These Nix derivations are stored in$HOME/.tinc/cache/nix. - Use
cabal2nixto generate Nix derivation from the project.cabal. - Incorporate the previous Nix derivations and create the final project Nix files, including
default.nixandshell.nix. These files can be used as-is withouttincinstalled.
With the Nix files, you can:
- Run
nix-shellto enter an environment with all the dependencies in scope, which allows you to runghci,cabal configure,cabal build,cabal test, etc. - Run
nix-buildto build your project in/nix.
Walkthrough
It is probably not feasible to follow these steps perfectly because your cabal package index or nixpkgs will not be exactly the same, but the following describes the general steps for using tinc to build a sample project:
- Imagine it is the end of May 2016. The latest version of QuickCheck is 2.8.2 when we update our cabal package index.
cabal update
- We checkout the state of our sample project at this time (any Haskell project should work):
git clone https://github.com/robbinch/tinc
cd tinc
git reset --hard 405af997c182b89edfc9656612c32616e98c7862
- We pretend we do not have any
.nixortinc.freezefiles:
rm -f *.nix tinc.freeze
- Let
tincgenerate the Nix files:
export TINC_USE_NIX=yes
tinc
- We can now use
nix-shellto configure, build or test the project:
nix-shell
cabal configure --enable-tests
cabal build
cabal test
exit
-
As it is common to run
nix-shellright aftertinc, the plugintinc shellcan be used to do this in one step. -
We can also use
nix-buildornix-env:
nix-build # will build project in /nix
nix-env -i tinc -f default.nix # will build and install project in profile
-
Instead of directly installing using
nix-env, the plugintinc installcan and should be used. It does the extra steps of packaging usingcabal sdist, extracting the tarball and resetting the file modification times before runningnix-env. This creates a consistent derivation (Nix checksum) untainted by extraneous files in the development directory. -
It is recommended to keep all
.nixfiles andtinc.freezeunder version control. That way, distributing them with your project gives users the best chance of building your Haskell project with Nix. They can simply donix-buildornix-envwithout havingtincinstalled. They can even use the same commit ofnixpkgsfor better reproducibility. -
When you wish to update your project to use the latest cabal packages:
cabal update
rm *.nix tinc.freeze
tinc shell
- If anything goes wrong, you can revert back to the old
.nixfiles to build your project again.
Missing dependencies
Sometimes, we get missing dependencies. Let's see the problem:
- Update to a more recent cabal package index (it's early November 2016 now). The latest version of QuickCheck at this time is 2.9.2.
cabal update
- Checkout a more recent project:
git clone https://github.com/robbinch/tinc
cd tinc
git reset --hard 411d0f319717d01dc71bd5c1faef8035656eaf3d
- Again, we pretend we do not have any
.nixortinc.freezefiles:
rm -f *.nix tinc.freeze
- Run
tinc shellto generate Nix files and enter the build environment:
tinc shell
- We get a build error for QuickCheck. It needs the
semigroupspackage but our Nix derivation$HOME/.tinc/cache/nix/QuickCheck-2.9.2.nixdoes not have it. This is probably due tocabal2nixnot working properly with QuickCheck-2.9.2. Addsemigroupsto the list of dependencies:
{ mkDerivation, base, containers, random, stdenv, template-haskell
, test-framework, tf-random, transformers
, semigroups # <-- add here
}:
mkDerivation {
pname = "QuickCheck";
version = "2.9.2";
sha256 = "119np67qvx8hyp9vkg4gr2wv3lj3j6ay2vl4hxspkg43ymb1cp0m";
libraryHaskellDepends = [
base containers random template-haskell tf-random transformers
semigroups # <-- add here
];
testHaskellDepends = [
base containers template-haskell test-framework
semigroups # <-- add here
];
homepage = "https://github.com/nick8325/quickcheck";
description = "Automatic testing of Haskell programs";
license = stdenv.lib.licenses.bsd3;
doCheck = false;
doHaddock = false;
}
-
Run
tinc shellagain. This time, we encounter similar problems withattoparsec, among others. Fix them the same way in$HOME/.tinc/cache/nix. -
After all the missing dependencies are added,
tinc shellwill hopefully be successful and we get working Nix derivations again. Put the.nixfiles under version control so we do not need to repeat this in future.
Plugins
Plugins are simply shell scripts named like tinc-shell or tinc-install in $HOME/.tinc/plugins. They are executed with commands like tinc shell or tinc install. The standard plugins are provided in the plugins directory of the source code and can be copied or symlink-ed to $HOME/.tinc/plugins.
Overriding attributes in default.nix
To override attributes (like doCheck, configureFlags, postInstall, etc) in the generated default.nix, create the file default-override.nix. tinc will never overwrite this file but default.nix will use it if it exists. See example in tinc repository.
Using curated packages from Stack
Instead of using cabal's solver to generate the install plan, you can opt for curated packages from Stack. Just download cabal.config from one of the LTS resolvers and place it beside your project .cabal.
wget https://www.stackage.org/lts-7.16/cabal.config
tinc shell