on iko/ghcjs-patch-master help sign in
[ifd] cabalProjectToNix (#122)
commit52280f23245635db051acb737c6c293df10a57a2 authorMoritz Angermann <moritz.angermann@gmail.com> dateSat 18 May 2019, 22:00 (7 years ago) parent66bf69e
5 files changed+131
default.nix+19 lib/cabalProjectToNix.nix+62 lib/hackageIndex.nix+16 test/call-cabal-project-to-nix/default.nix+33 test/default.nix+1
default.nix+19
@@ -38,6 +38,11 @@ let
3838 # overridden with NIX_PATH.
3939 fetchExternal = import ./lib/fetch-external.nix;
4040
41+ mkHackageIndex = indexState: import ./lib/hackageIndex.nix {
42+ inherit (pkgs) runCommand cabal-install;
43+ inherit indexState;
44+ };
45+
4146 # All packages from Hackage as Nix expressions
4247 hackage = import (fetchExternal {
4348 name = "hackage-exprs-source";
@@ -123,6 +128,20 @@ let
123128 update-stackage = self.callPackage ./scripts/update-stackage.nix {};
124129 update-pins = self.callPackage ./scripts/update-pins.nix {};
125130 };
131+
132+ # Make this handy overridable fetch function available.
133+ inherit fetchExternal;
134+
135+ # Takes a haskell src directory runs cabal new-configure and plan-to-nix.
136+ # Resulting nix files are added to nix-plan subdirectory.
137+ callCabalProjectToNix = import ./lib/cabalProjectToNix.nix {
138+ inherit mkHackageIndex;
139+ inherit pkgs;
140+ inherit (pkgs) runCommand cabal-install ghc;
141+ inherit (pkgs.haskellPackages) hpack;
142+ inherit (self) nix-tools;
143+ inherit (pkgs) symlinkJoin;
144+ };
126145 });
127146
128147in
lib/cabalProjectToNix.nixnew file+62
@@ -0,0 +1,62 @@
1+{ mkHackageIndex, pkgs, runCommand, nix-tools, cabal-install, ghc, hpack, symlinkJoin }:
2+let defaultGhc = ghc;
3+ defaultCabalInstall = cabal-install;
4+in { hackageIndexState, src, ghc ? defaultGhc, cabal-install ? defaultCabalInstall }:
5+let
6+ cabalFiles =
7+ pkgs.lib.cleanSourceWith {
8+ inherit src;
9+ filter = path: type:
10+ type == "directory" ||
11+ pkgs.lib.any (i: (pkgs.lib.hasSuffix i path)) [ ".project" ".cabal" "package.yaml" ];
12+ };
13+ plan = if (builtins.compareVersions cabal-install.version "2.4.0.0") < 0
14+ # cabal-install versions before 2.4 will generate insufficient plan information.
15+ then throw "cabal-install (current version: ${cabal-install.version}) needs to be at least 2.4 for plan-to-nix to work without cabal-to-nix"
16+ else runCommand "plan" {
17+ nativeBuildInputs = [ nix-tools ghc hpack cabal-install pkgs.rsync ];
18+ } ''
19+ tmp=$(mktemp -d)
20+ cd $tmp
21+ cp -r ${cabalFiles}/* .
22+ chmod +w -R .
23+ # warning: this may not generate the proper cabal file.
24+ # hpack allows globbing, and turns that into module lists
25+ # without the source available (we cleaneSourceWith'd it),
26+ # this may not produce the right result.
27+ find . -name package.yaml -exec hpack "{}" \;
28+ HOME=${mkHackageIndex hackageIndexState} cabal new-configure
29+
30+ export LANG=C.utf8 # Needed or stack-to-nix will die on unicode inputs
31+ mkdir -p $out
32+
33+ # ensure we have all our .cabal files (also those generated from package.yaml) files.
34+ # otherwise we'd need to be careful about putting the `cabal-generator = hpack` into
35+ # the nix expression. As we already called `hpack` on all `package.yaml` files we can
36+ # skip that step and just package the .cabal files up as well.
37+ #
38+ # This is also important as `plan-to-nix` will look for the .cabal files when generating
39+ # the relevant `pkgs.nix` file with the local .cabal expressions.
40+ rsync -a --prune-empty-dirs \
41+ --include '*/' --include '*.cabal' --include 'package.yaml' \
42+ --exclude '*' \
43+ $tmp/ $out/
44+
45+ # make sure the path's in the plan.json are relative to $out instead of $tmp
46+ # this is necessary so that plan-to-nix relative path logic can work.
47+ substituteInPlace $tmp/dist-newstyle/cache/plan.json --replace "$tmp" "$out"
48+
49+ # run `plan-to-nix` in $out. This should produce files right there with the
50+ # proper relative paths.
51+ (cd $out && plan-to-nix --plan-json $tmp/dist-newstyle/cache/plan.json -o .)
52+
53+ # move pkgs.nix to default.nix ensure we can just nix `import` the result.
54+ mv $out/pkgs.nix $out/default.nix
55+ '';
56+in
57+ runCommand "plan-and-src" { nativeBuildInputs = [ pkgs.xorg.lndir pkgs.rsync ]; } ''
58+ mkdir $out
59+ # todo: should we clean `src` to drop any .git, .nix, ... other irelevant files?
60+ lndir -silent "${src}" "$out"
61+ rsync -a ${plan}/ $out/
62+ ''
lib/hackageIndex.nixnew file+16
@@ -0,0 +1,16 @@
1+{ runCommand, cabal-install
2+, indexState ? "2019-04-24T21:34:04Z"
3+} :
4+let
5+ # To avoid downloading more data than necessary this will provide a base.
6+ cachedState = runCommand "hackage-${builtins.substring 0 4 indexState}" {} ''
7+ mkdir -p $out
8+ HOME=$out ${cabal-install}/bin/cabal update --index-state='${builtins.substring 0 4 indexState}-01-01T00:00:00Z'
9+ '';
10+in runCommand "hackage-${builtins.replaceStrings [":"] [""] indexState}" {} ''
11+ mkdir -p $out
12+ cp -r ${cachedState}/.cabal $out
13+ chmod +w -R $out/.cabal
14+ sed -i.back -e "s|${cachedState}|$out|g" $out/.cabal/config
15+ HOME=$out ${cabal-install}/bin/cabal update --index-state='${indexState}'
16+ ''
test/call-cabal-project-to-nix/default.nixnew file+33
@@ -0,0 +1,33 @@
1+{ stdenv, mkCabalProjectPkgSet, callCabalProjectToNix }:
2+
3+with stdenv.lib;
4+
5+let
6+ pkgSet = mkCabalProjectPkgSet {
7+ plan-pkgs = import (callCabalProjectToNix {
8+ hackageIndexState = "2019-04-24T21:34:04Z";
9+ # reuse the cabal-simple test project
10+ src = ../cabal-simple;
11+ });
12+ };
13+ packages = pkgSet.config.hsPkgs;
14+in
15+ stdenv.mkDerivation {
16+ name = "callStackToNix-test";
17+
18+ buildCommand = ''
19+ exe="${packages.cabal-simple.components.exes.cabal-simple}/bin/cabal-simple"
20+
21+ printf "checking whether executable runs... " >& 2
22+ $exe
23+
24+ touch $out
25+ '';
26+
27+ meta.platforms = platforms.all;
28+
29+ passthru = {
30+ # Attributes used for debugging with nix repl
31+ inherit pkgSet packages;
32+ };
33+ }
test/default.nix+1
@@ -16,6 +16,7 @@ in {
1616 builder-haddock = haskell.callPackage ./builder-haddock {};
1717 stack-simple = haskell.callPackage ./stack-simple {};
1818 callStackToNix = haskell.callPackage ./callStackToNix {};
19+ callCabalProjectToNix = haskell.callPackage ./call-cabal-project-to-nix {};
1920
2021 # Run unit tests with: nix-instantiate --eval --strict -A unit
2122 # An empty list means success.