on iko/ghcjs-patch-master help sign in
Use suitable hackage state for index-state (#673)
dcadfa8Hamish Mackenzie
lib/call-cabal-project-to-nix.nix+51−10
@@ -122,14 +122,39 @@ let
122 else builtins.trace ("Using latest index state" + (if name == null then "" else " for " + name) + "!")
122 else builtins.trace ("Using latest index state" + (if name == null then "" else " for " + name) + "!")
123 (pkgs.lib.last (builtins.attrNames index-state-hashes));
123 (pkgs.lib.last (builtins.attrNames index-state-hashes));
124
124
125+in
126+ assert (if index-state-found == null
127+ then throw "No index state passed and none found in ${cabalProjectFileName}" else true);
128+
129+ assert (if index-sha256 == null && !(pkgs.lib.hasSuffix "Z" index-state-found)
130+ then throw "Index state found was ${index-state-found} and no `index-sha256` was provided. "
131+ "The index hash lookup code requires zulu time zone (ends in a Z)" else true);
132+
133+let
134+ # If a hash was not specified find a suitable cached index state to
135+ # use that will contain all the packages we need. By using the
136+ # first one after the desired index-state we can avoid recalculating
137+ # when new index-state-hashes are added.
138+ # See https://github.com/input-output-hk/haskell.nix/issues/672
139+ cached-index-state = if index-sha256 != null
140+ then index-state-found
141+ else
142+ let
143+ suitable-index-states =
144+ builtins.filter
145+ (s: s >= index-state-found) # This compare is why we need zulu time
146+ (builtins.attrNames index-state-hashes);
147+ in
148+ if builtins.length suitable-index-states == 0
149+ then index-state-found
150+ else pkgs.lib.head suitable-index-states;
151+
125 # Lookup hash for the index state we found
152 # Lookup hash for the index state we found
126 index-sha256-found = if index-sha256 != null
153 index-sha256-found = if index-sha256 != null
127 then index-sha256
154 then index-sha256
128− else index-state-hashes.${index-state-found} or null;
155+ else index-state-hashes.${cached-index-state} or null;
129
156
130in
157in
131− assert (if index-state-found == null
132− then throw "No index state passed and none found in ${cabalProjectFileName}" else true);
133 assert (if index-sha256-found == null
158 assert (if index-sha256-found == null
134 then throw "Unknown index-state ${index-state-found}, the latest index-state I know about is ${pkgs.lib.last (builtins.attrNames index-state-hashes)}. You may need to update to a newer hackage.nix." else true);
159 then throw "Unknown index-state ${index-state-found}, the latest index-state I know about is ${pkgs.lib.last (builtins.attrNames index-state-hashes)}. You may need to update to a newer hackage.nix." else true);
135
160
@@ -389,12 +414,23 @@ let
389 ''}
414 ''}
390 export SSL_CERT_FILE=${cacert}/etc/ssl/certs/ca-bundle.crt
415 export SSL_CERT_FILE=${cacert}/etc/ssl/certs/ca-bundle.crt
391 export GIT_SSL_CAINFO=${cacert}/etc/ssl/certs/ca-bundle.crt
416 export GIT_SSL_CAINFO=${cacert}/etc/ssl/certs/ca-bundle.crt
417+ HOME=${
418+ # This creates `.cabal` directory that is as it would have
419+ # been at the time `cached-index-state`. We may include
420+ # some packages that will be excluded by `index-state-found`
421+ # which is used by cabal (cached-index-state >= index-state-found).
392− HOME=${dotCabal {
422+ dotCabal {
393− inherit cabal-install nix-tools extra-hackage-tarballs;
423+ inherit cabal-install nix-tools extra-hackage-tarballs;
394− index-state =
424+ index-state = cached-index-state;
425+ sha256 = index-sha256-found;
426+ }
427+ } cabal v2-configure \
428+ --index-state=${
429+ # Setting the desired `index-state` here in case it was not
430+ # from the cabal.project file. This will further restrict the
431+ # packages used by the solver (cached-index-state >= index-state-found).
395− builtins.trace ("Using index-state: ${index-state-found}" + (if name == null then "" else " for " + name))
432+ builtins.trace ("Using index-state: ${index-state-found}" + (if name == null then "" else " for " + name))
396− index-state-found;
433+ index-state-found} \
397− sha256 = index-sha256-found; }} cabal v2-configure \
398 --with-ghc=${ghc.targetPrefix}ghc \
434 --with-ghc=${ghc.targetPrefix}ghc \
399 --with-ghc-pkg=${ghc.targetPrefix}ghc-pkg \
435 --with-ghc-pkg=${ghc.targetPrefix}ghc-pkg \
400 --enable-tests \
436 --enable-tests \
@@ -437,4 +473,9 @@ let
437 # move pkgs.nix to default.nix ensure we can just nix `import` the result.
473 # move pkgs.nix to default.nix ensure we can just nix `import` the result.
438 mv $out${subDir'}/pkgs.nix $out${subDir'}/default.nix
474 mv $out${subDir'}/pkgs.nix $out${subDir'}/default.nix
439 '');
475 '');
476+in {
477+ projectNix = plan-nix;
478+ index-state = index-state-found;
479+ inherit src;
440−in { projectNix = plan-nix; inherit src; inherit (fixedProject) sourceRepos; }
480+ inherit (fixedProject) sourceRepos;
481+}
lib/import-and-filter-project.nix+2−5
@@ -19,9 +19,7 @@ let
19 projectSubDir = pkgs.lib.strings.removePrefix "/" projectSubDir'; # Without /
19 projectSubDir = pkgs.lib.strings.removePrefix "/" projectSubDir'; # Without /
20 projectSubDir'' = if projectSubDir == "" then "" else projectSubDir + "/"; # With trailing /
20 projectSubDir'' = if projectSubDir == "" then "" else projectSubDir + "/"; # With trailing /
21 project = import "${projectNix}${projectSubDir'}";
21 project = import "${projectNix}${projectSubDir'}";
22−in {
23− nix = projectNix;
24− pkgs = project // {
22+in project // {
25 extras = hackage: let old = (project.extras hackage).packages; in {
23 extras = hackage: let old = (project.extras hackage).packages; in {
26 packages = pkgs.lib.attrsets.mapAttrs (name: value:
24 packages = pkgs.lib.attrsets.mapAttrs (name: value:
27 if builtins.isFunction value
25 if builtins.isFunction value
@@ -46,5 +44,4 @@ in {
46 src = (pkgs.lib).mkDefault packageSrc;
44 src = (pkgs.lib).mkDefault packageSrc;
47 }) old;
45 }) old;
48 };
46 };
49− };
47+ }
50−}
overlays/haskell.nix+18−6
@@ -459,9 +459,12 @@ final: prev: {
459 # plan-nix without building the project.
459 # plan-nix without building the project.
460 cabalProject' =
460 cabalProject' =
461 { ... }@args:
461 { ... }@args:
462+ let
462− let plan = importAndFilterProject (callCabalProjectToNix args);
463+ callProjectResults = callCabalProjectToNix args;
463 in let pkg-set = mkCabalProjectPkgSet
464 in let pkg-set = mkCabalProjectPkgSet
464− { plan-pkgs = plan.pkgs;
465+ { plan-pkgs = importAndFilterProject {
466+ inherit (callProjectResults) projectNix sourceRepos src;
467+ };
465 pkg-def-extras = args.pkg-def-extras or [];
468 pkg-def-extras = args.pkg-def-extras or [];
466 modules = (args.modules or [])
469 modules = (args.modules or [])
467 ++ final.lib.optional (args ? ghcOverride || args ? ghc)
470 ++ final.lib.optional (args ? ghcOverride || args ? ghc)
@@ -470,7 +473,12 @@ final: prev: {
470 { compiler.nix-name = args.compiler-nix-name; };
473 { compiler.nix-name = args.compiler-nix-name; };
471 extra-hackages = args.extra-hackages or [];
474 extra-hackages = args.extra-hackages or [];
472 };
475 };
473− in addProjectAndPackageAttrs { inherit (pkg-set.config) hsPkgs; inherit pkg-set; plan-nix = plan.nix; };
476+ in addProjectAndPackageAttrs {
477+ inherit (pkg-set.config) hsPkgs;
478+ inherit pkg-set;
479+ plan-nix = callProjectResults.projectNix;
480+ inherit (callProjectResults) index-state;
481+ };
474
482
475 # Take `hsPkgs` from the `rawProject` and update all the packages and
483 # Take `hsPkgs` from the `rawProject` and update all the packages and
476 # components so they have a `.project` attribute and as well as
484 # components so they have a `.project` attribute and as well as
@@ -509,20 +517,24 @@ final: prev: {
509
517
510 stackProject' =
518 stackProject' =
511 { ... }@args:
519 { ... }@args:
512− let stack = importAndFilterProject (callStackToNix ({ inherit cache; } // args));
520+ let callProjectResults = callStackToNix ({ inherit cache; } // args);
513 generatedCache = genStackCache {
521 generatedCache = genStackCache {
514 inherit (args) src;
522 inherit (args) src;
515 stackYaml = args.stackYaml or "stack.yaml";
523 stackYaml = args.stackYaml or "stack.yaml";
516 };
524 };
517 cache = args.cache or generatedCache;
525 cache = args.cache or generatedCache;
518 in let pkg-set = mkStackPkgSet
526 in let pkg-set = mkStackPkgSet
519− { stack-pkgs = stack.pkgs;
527+ { stack-pkgs = importAndFilterProject callProjectResults;
520 pkg-def-extras = (args.pkg-def-extras or []);
528 pkg-def-extras = (args.pkg-def-extras or []);
521 modules = final.lib.singleton (mkCacheModule cache)
529 modules = final.lib.singleton (mkCacheModule cache)
522 ++ (args.modules or [])
530 ++ (args.modules or [])
523 ++ final.lib.optional (args ? ghc) { ghc.package = args.ghc; };
531 ++ final.lib.optional (args ? ghc) { ghc.package = args.ghc; };
524 };
532 };
525− in addProjectAndPackageAttrs { inherit (pkg-set.config) hsPkgs; inherit pkg-set; stack-nix = stack.nix; };
533+ in addProjectAndPackageAttrs {
534+ inherit (pkg-set.config) hsPkgs;
535+ inherit pkg-set;
536+ stack-nix = callProjectResults.projectNix;
537+ };
526
538
527 stackProject = args: let p = stackProject' args;
539 stackProject = args: let p = stackProject' args;
528 in p.hsPkgs // {
540 in p.hsPkgs // {
test/call-cabal-project-to-nix/default.nix+6−4
@@ -5,19 +5,21 @@ with stdenv.lib;
5let
5let
6 # This test could use cabalProject', but it does so that it
6 # This test could use cabalProject', but it does so that it
7 # tests using callCabalProjectToNix and importAndFilterProject
7 # tests using callCabalProjectToNix and importAndFilterProject
8− plan = (importAndFilterProject (callCabalProjectToNix {
8+ callProjectResults = callCabalProjectToNix {
9 index-state = "2020-05-25T00:00:00Z";
9 index-state = "2020-05-25T00:00:00Z";
10 # reuse the cabal-simple test project
10 # reuse the cabal-simple test project
11 src = testSrc "cabal-simple";
11 src = testSrc "cabal-simple";
12− }));
12+ };
13 pkgSet = mkCabalProjectPkgSet {
13 pkgSet = mkCabalProjectPkgSet {
14− plan-pkgs = plan.pkgs;
14+ plan-pkgs = importAndFilterProject {
15+ inherit (callProjectResults) projectNix sourceRepos src;
16+ };
15 };
17 };
16 packages = pkgSet.config.hsPkgs;
18 packages = pkgSet.config.hsPkgs;
17
19
18in recurseIntoAttrs {
20in recurseIntoAttrs {
19 ifdInputs = {
21 ifdInputs = {
20− plan-nix = plan.nix;
22+ plan-nix = callProjectResults.projectNix;
21 };
23 };
22 run = stdenv.mkDerivation {
24 run = stdenv.mkDerivation {
23 name = "call-cabal-project-to-nix-test";
25 name = "call-cabal-project-to-nix-test";
test/call-stack-to-nix/default.nix+4−4
@@ -3,11 +3,11 @@
3with stdenv.lib;
3with stdenv.lib;
4
4
5let
5let
6− stack = importAndFilterProject (callStackToNix {
6+ callProjectResults = callStackToNix {
7 src = testSrc "stack-simple";
7 src = testSrc "stack-simple";
8− });
8+ };
9 pkgSet = mkStackPkgSet {
9 pkgSet = mkStackPkgSet {
10− stack-pkgs = stack.pkgs;
10+ stack-pkgs = importAndFilterProject callProjectResults;
11 pkg-def-extras = [];
11 pkg-def-extras = [];
12 modules = [];
12 modules = [];
13 };
13 };
@@ -15,7 +15,7 @@ let
15
15
16in recurseIntoAttrs {
16in recurseIntoAttrs {
17 ifdInputs = {
17 ifdInputs = {
18− stack-nix = stack.nix;
18+ stack-nix = callProjectResults.projectNix;
19 };
19 };
20 run = stdenv.mkDerivation {
20 run = stdenv.mkDerivation {
21 name = "callStackToNix-test";
21 name = "callStackToNix-test";
test/default.nix+4
@@ -181,6 +181,10 @@ let
181 # Pandoc does not build with ghcjs or ghc 8.10.1 yet (lookup-sha256 and fully-static build pandoc)
181 # Pandoc does not build with ghcjs or ghc 8.10.1 yet (lookup-sha256 and fully-static build pandoc)
182 lookup-sha256 = callTest ./lookup-sha256 {};
182 lookup-sha256 = callTest ./lookup-sha256 {};
183 fully-static = callTest ./fully-static { inherit (pkgs) buildPackages; };
183 fully-static = callTest ./fully-static { inherit (pkgs) buildPackages; };
184+ } // lib.optionalAttrs (pkgs.haskell-nix.defaultCompilerNixName != "ghc8101") {
185+ # This test makes a plan for building cabal 3.2 using index-states that will
186+ # never work with ghc 8.10.1
187+ index-state = callTest ./index-state {};
184 };
188 };
185
189
186 # This is the same as allTests, but filter out all the key/vaules from the
190 # This is the same as allTests, but filter out all the key/vaules from the
test/index-state/default.nixnew file+39
@@ -0,0 +1,39 @@
1+# Test a package set
2+{ stdenv, testSrc, tool }:
3+
4+with stdenv.lib;
5+
6+let
7+ # The hackage-security 0.6.0.1 was uploaded at 2020-04-06T20:54:35Z
8+ # See https://hackage.haskell.org/package/hackage-security-0.6.0.1
9+ version-used-at = index-state: (tool "cabal" {
10+ version = "3.2.0.0";
11+ inherit index-state;
12+ }).project.hsPkgs.hackage-security.components.library.version;
13+ version-before = version-used-at "2020-04-06T20:54:34Z";
14+ version-after = version-used-at "2020-04-06T20:54:35Z";
15+
16+in
17+ stdenv.mkDerivation {
18+ name = "index-state-test";
19+
20+ buildCommand = ''
21+ if [[ "${version-before}" != "0.6.0.0" ]]; then
22+ echo 'Unexpected version ${version-before} (expected "0.6.0.0")'
23+ exit 0
24+ fi
25+ if [[ "${version-after}" != "0.6.0.1" ]]; then
26+ echo 'Unexpected version ${version-after} (expected "0.6.0.1")'
27+ exit 0
28+ fi
29+
30+ touch $out
31+ '';
32+
33+ meta.platforms = platforms.all;
34+
35+ passthru = {
36+ # Used for debugging with nix repl
37+ inherit project packages;
38+ };
39+ }