|
1 | 1 | { dotCabal, pkgs, runCommand, nix-tools, cabal-install, ghc, hpack, symlinkJoin, cacert, index-state-hashes }: |
2 | 2 | let defaultGhc = ghc; |
3 | 3 | defaultCabalInstall = cabal-install; |
4 | | -in { index-state, index-sha256 ? index-state-hashes.${index-state} or null, src, ghc ? defaultGhc, cabal-install ? defaultCabalInstall }: |
| 4 | +in { index-state, index-sha256 ? index-state-hashes.${index-state} or null, src, ghc ? defaultGhc, |
| 5 | + cabal-install ? defaultCabalInstall, cabalProject ? null }: |
5 | 6 |
|
6 | 7 | # better error message than just assert failed. |
7 | 8 | assert (if index-sha256 == null then throw "provided sha256 for index-state ${index-state} is null!" else true); |
|
13 | 14 | maybeCleanedSource = |
14 | 15 | if pkgs.lib.canCleanSource src |
15 | 16 | then pkgs.lib.cleanSourceWith { |
16 | | - src = builtins.trace "src = ${src};" src; |
| 17 | + inherit src; |
17 | 18 | filter = path: type: |
18 | 19 | type == "directory" || |
19 | 20 | pkgs.lib.any (i: (pkgs.lib.hasSuffix i path)) [ ".project" ".cabal" "package.yaml" ]; } |
20 | | - else src; |
| 21 | + else src; |
| 22 | + |
| 23 | + # Using origSrc bypasses any cleanSourceWith so that it will work when |
| 24 | + # access to the store is restricted. If origSrc was already in the store |
| 25 | + # you can pass the project in as a string. |
| 26 | + rawCabalProject = |
| 27 | + let origSrcDir = maybeCleanedSource.origSrc or maybeCleanedSource; |
| 28 | + in if cabalProject != null |
| 29 | + then cabalProject |
| 30 | + else |
| 31 | + if ((builtins.readDir origSrcDir)."cabal.project" or "") == "regular" |
| 32 | + then builtins.readFile (origSrcDir + "/cabal.project") |
| 33 | + else null; |
| 34 | + |
| 35 | + span = pred: list: |
| 36 | + let n = pkgs.lib.lists.foldr (x: acc: if pred x then acc + 1 else 0) 0 list; |
| 37 | + in { fst = pkgs.lib.lists.take n list; snd = pkgs.lib.lists.drop n list; }; |
| 38 | + |
| 39 | + # Parse lines of a source-repository-package block |
| 40 | + parseBlockLines = blockLines: builtins.listToAttrs (builtins.concatMap (s: |
| 41 | + let pair = builtins.match " *([^:]*): *(.*)" s; |
| 42 | + in pkgs.lib.optional (pair != null) (pkgs.lib.attrsets.nameValuePair |
| 43 | + (builtins.head pair) |
| 44 | + (builtins.elemAt pair 1))) blockLines); |
| 45 | + |
| 46 | + fetchRepo = repo: (pkgs.fetchgit { |
| 47 | + url = repo.location; |
| 48 | + rev = repo.tag; |
| 49 | + sha256 = repo."--sha256"; |
| 50 | + }) + (if repo.subdir or "" == "" then "" else "/" + repo.subdir); |
| 51 | + |
| 52 | + # Parse a source-repository-package and fetch it if it containts |
| 53 | + # a line of the form |
| 54 | + # --shar256: <<SHA256>> |
| 55 | + parseBlock = block: |
| 56 | + let |
| 57 | + x = span (pkgs.lib.strings.hasPrefix " ") (pkgs.lib.splitString "\n" block); |
| 58 | + attrs = parseBlockLines x.fst; |
| 59 | + in |
| 60 | + if attrs."--sha256" or "" == "" |
| 61 | + then { |
| 62 | + sourceRepo = []; |
| 63 | + otherText = "\nsource-repository-package\n" + block; |
| 64 | + } |
| 65 | + else { |
| 66 | + sourceRepo = [ (fetchRepo attrs) ]; |
| 67 | + otherText = pkgs.lib.strings.concatStringsSep "\n" x.snd; |
| 68 | + }; |
| 69 | + |
| 70 | + # Deal with source-repository-packages in a way that will work on |
| 71 | + # hydra build agents (as long as a sha256 is included). |
| 72 | + # Replace source-repository-package blocks that have a sha256 with |
| 73 | + # packages: block containing nix sotre paths of the fetched repos. |
| 74 | + replaceSoureRepos = projectFile: |
| 75 | + let |
| 76 | + blocks = pkgs.lib.splitString "\nsource-repository-package\n" projectFile; |
| 77 | + initialText = pkgs.lib.lists.take 1 blocks; |
| 78 | + repoBlocks = builtins.map parseBlock (pkgs.lib.lists.drop 1 blocks); |
| 79 | + sourceRepos = pkgs.lib.lists.concatMap (x: x.sourceRepo) repoBlocks; |
| 80 | + otherText = pkgs.writeText "cabal.project" (pkgs.lib.strings.concatStringsSep "\n" ( |
| 81 | + initialText |
| 82 | + ++ (builtins.map (x: x.otherText) repoBlocks))); |
| 83 | + in { |
| 84 | + inherit sourceRepos; |
| 85 | + makeFixedProjectFile = '' |
| 86 | + cp -f ${otherText} ./cabal.project |
| 87 | + chmod +w -R ./cabal.project |
| 88 | + echo "packages:" >> ./cabal.project |
| 89 | + mkdir -p ./.source-repository-packages |
| 90 | + '' + |
| 91 | + ( pkgs.lib.strings.concatStrings ( |
| 92 | + pkgs.lib.lists.zipListsWith (n: f: '' |
| 93 | + mkdir -p ./.source-repository-packages/${builtins.toString n} |
| 94 | + rsync -a --prune-empty-dirs \ |
| 95 | + --include '*/' --include '*.cabal' --include 'package.yaml' \ |
| 96 | + --exclude '*' \ |
| 97 | + "${f}/" "./.source-repository-packages/${builtins.toString n}/" |
| 98 | + echo " ./.source-repository-packages/${builtins.toString n}" >> ./cabal.project |
| 99 | + '') |
| 100 | + (pkgs.lib.lists.range 0 ((builtins.length fixedProject.sourceRepos) - 1)) |
| 101 | + sourceRepos |
| 102 | + ) |
| 103 | + ); |
| 104 | + }; |
| 105 | + |
| 106 | + fixedProject = |
| 107 | + if rawCabalProject == null |
| 108 | + then { |
| 109 | + sourceRepos = []; |
| 110 | + makeFixedProjectFile = ""; |
| 111 | + } |
| 112 | + else replaceSoureRepos rawCabalProject; |
| 113 | + |
21 | 114 | plan = runCommand "plan-to-nix-pkgs" { |
22 | 115 | nativeBuildInputs = [ nix-tools ghc hpack cabal-install pkgs.rsync pkgs.git ]; |
23 | | - } '' |
| 116 | + } ('' |
24 | 117 | tmp=$(mktemp -d) |
25 | 118 | cd $tmp |
26 | 119 | cp -r ${maybeCleanedSource}/* . |
27 | 120 | chmod +w -R . |
| 121 | + ${fixedProject.makeFixedProjectFile} |
28 | 122 | # warning: this may not generate the proper cabal file. |
29 | 123 | # hpack allows globbing, and turns that into module lists |
30 | 124 | # without the source available (we cleaneSourceWith'd it), |
|
61 | 155 |
|
62 | 156 | # move pkgs.nix to default.nix ensure we can just nix `import` the result. |
63 | 157 | mv $out/pkgs.nix $out/default.nix |
64 | | - ''; |
| 158 | + ''); |
65 | 159 | in |
66 | 160 | # TODO: We really want this (symlinks) instead of copying the source over each and |
67 | 161 | # every time. However this will not work with sandboxed builds. They won't |
|
79 | 173 | # # todo: should we clean `src` to drop any .git, .nix, ... other irelevant files? |
80 | 174 | # buildInputs = [ plan src ]; |
81 | 175 | # } |
82 | | - runCommand "plan-to-nix-pkgs-with-src" { nativeBuildInputs = [ pkgs.rsync ]; } '' |
| 176 | + runCommand "plan-to-nix-pkgs-with-src" { nativeBuildInputs = [ pkgs.rsync ]; } ('' |
83 | 177 | mkdir $out |
84 | 178 | # todo: should we clean `src` to drop any .git, .nix, ... other irelevant files? |
85 | 179 | rsync -a "${src}/" "$out/" |
86 | 180 | rsync -a ${plan}/ $out/ |
| 181 | + '' + |
| 182 | + ( pkgs.lib.strings.concatStrings ( |
| 183 | + pkgs.lib.lists.zipListsWith (n: f: '' |
| 184 | + mkdir -p $out/.source-repository-packages/${builtins.toString n} |
| 185 | + rsync -a "${f}/" "$out/.source-repository-packages/${builtins.toString n}/" |
| 186 | + '') |
| 187 | + (pkgs.lib.lists.range 0 ((builtins.length fixedProject.sourceRepos) - 1)) |
| 188 | + fixedProject.sourceRepos |
| 189 | + ) |
| 190 | + ) + '' |
87 | 191 | # Rsync will have made $out read only and that can cause problems when |
88 | 192 | # nix sandboxing is enabled (since it can prevent nix from moving the directory |
89 | 193 | # out of the chroot sandbox). |
90 | 194 | chmod +w $out |
91 | | - '' |
| 195 | + '') |
0 commit comments