|
12 | 12 | maybeCleanedSource = |
13 | 13 | if pkgs.lib.canCleanSource src |
14 | 14 | then pkgs.lib.cleanSourceWith { |
15 | | - src = builtins.trace "src = ${src};" src; |
| 15 | + inherit src; |
16 | 16 | filter = path: type: |
17 | 17 | type == "directory" || |
18 | 18 | pkgs.lib.any (i: (pkgs.lib.hasSuffix i path)) [ ".project" ".cabal" "package.yaml" ]; } |
|
21 | 21 | # Using origSrc bypasses any cleanSourceWith so that it will work when |
22 | 22 | # access to the store is restricted. If origSrc was already in the store |
23 | 23 | # you can pass the project in as a string. |
24 | | - rawCabalProject = if cabalProject != null |
| 24 | + rawCabalProject = |
| 25 | + let origSrcDir = maybeCleanedSource.origSrc or maybeCleanedSource; |
| 26 | + in if cabalProject != null |
25 | 27 | then cabalProject |
26 | | - else builtins.readFile ((maybeCleanedSource.origSrc or maybeCleanedSource) + "/cabal.project"); |
| 28 | + else |
| 29 | + if ((builtins.readDir origSrcDir)."cabal.project" or "") == "regular" |
| 30 | + then builtins.readFile (origSrcDir + "/cabal.project") |
| 31 | + else null; |
27 | 32 |
|
28 | 33 | # Look for a index-state: field in the cabal.project file |
29 | 34 | parseIndexState = rawCabalProject: |
|
37 | 42 |
|
38 | 43 | index-state-found = if index-state != null |
39 | 44 | then index-state |
40 | | - else parseIndexState rawCabalProject; |
| 45 | + else if rawCabalProject != null |
| 46 | + then parseIndexState rawCabalProject |
| 47 | + else null; |
41 | 48 |
|
42 | 49 | # Lookup hash for the index state we found |
43 | 50 | index-sha256-found = if index-sha256 != null |
|
51 | 58 | then throw "provided sha256 for index-state ${index-state-found} is null!" else true); |
52 | 59 |
|
53 | 60 | let |
| 61 | + span = pred: list: |
| 62 | + let n = pkgs.lib.lists.foldr (x: acc: if pred x then acc + 1 else 0) 0 list; |
| 63 | + in { fst = pkgs.lib.lists.take n list; snd = pkgs.lib.lists.drop n list; }; |
| 64 | + |
| 65 | + # Parse lines of a source-repository-package block |
| 66 | + parseBlockLines = blockLines: builtins.listToAttrs (builtins.concatMap (s: |
| 67 | + let pair = builtins.match " *([^:]*): *(.*)" s; |
| 68 | + in pkgs.lib.optional (pair != null) (pkgs.lib.attrsets.nameValuePair |
| 69 | + (builtins.head pair) |
| 70 | + (builtins.elemAt pair 1))) blockLines); |
| 71 | + |
| 72 | + fetchRepo = repo: (pkgs.fetchgit { |
| 73 | + url = repo.location; |
| 74 | + rev = repo.tag; |
| 75 | + sha256 = repo."--sha256"; |
| 76 | + }) + (if repo.subdir or "" == "" then "" else "/" + repo.subdir); |
| 77 | + |
| 78 | + # Parse a source-repository-package and fetch it if it containts |
| 79 | + # a line of the form |
| 80 | + # --shar256: <<SHA256>> |
| 81 | + parseBlock = block: |
| 82 | + let |
| 83 | + x = span (pkgs.lib.strings.hasPrefix " ") (pkgs.lib.splitString "\n" block); |
| 84 | + attrs = parseBlockLines x.fst; |
| 85 | + in |
| 86 | + if attrs."--sha256" or "" == "" |
| 87 | + then { |
| 88 | + sourceRepo = []; |
| 89 | + otherText = "\nsource-repository-package\n" + block; |
| 90 | + } |
| 91 | + else { |
| 92 | + sourceRepo = [ (fetchRepo attrs) ]; |
| 93 | + otherText = pkgs.lib.strings.concatStringsSep "\n" x.snd; |
| 94 | + }; |
| 95 | + |
| 96 | + # Deal with source-repository-packages in a way that will work in |
| 97 | + # restricted-eval mode (as long as a sha256 is included). |
| 98 | + # Replace source-repository-package blocks that have a sha256 with |
| 99 | + # packages: block containing nix sotre paths of the fetched repos. |
| 100 | + replaceSoureRepos = projectFile: |
| 101 | + let |
| 102 | + blocks = pkgs.lib.splitString "\nsource-repository-package\n" projectFile; |
| 103 | + initialText = pkgs.lib.lists.take 1 blocks; |
| 104 | + repoBlocks = builtins.map parseBlock (pkgs.lib.lists.drop 1 blocks); |
| 105 | + sourceRepos = pkgs.lib.lists.concatMap (x: x.sourceRepo) repoBlocks; |
| 106 | + otherText = pkgs.writeText "cabal.project" (pkgs.lib.strings.concatStringsSep "\n" ( |
| 107 | + initialText |
| 108 | + ++ (builtins.map (x: x.otherText) repoBlocks))); |
| 109 | + in { |
| 110 | + inherit sourceRepos; |
| 111 | + makeFixedProjectFile = '' |
| 112 | + cp -f ${otherText} ./cabal.project |
| 113 | + chmod +w -R ./cabal.project |
| 114 | + echo "packages:" >> ./cabal.project |
| 115 | + mkdir -p ./.source-repository-packages |
| 116 | + '' + |
| 117 | + ( pkgs.lib.strings.concatStrings ( |
| 118 | + pkgs.lib.lists.zipListsWith (n: f: '' |
| 119 | + mkdir -p ./.source-repository-packages/${builtins.toString n} |
| 120 | + rsync -a --prune-empty-dirs \ |
| 121 | + --include '*/' --include '*.cabal' --include 'package.yaml' \ |
| 122 | + --exclude '*' \ |
| 123 | + "${f}/" "./.source-repository-packages/${builtins.toString n}/" |
| 124 | + echo " ./.source-repository-packages/${builtins.toString n}" >> ./cabal.project |
| 125 | + '') |
| 126 | + (pkgs.lib.lists.range 0 ((builtins.length fixedProject.sourceRepos) - 1)) |
| 127 | + sourceRepos |
| 128 | + ) |
| 129 | + ); |
| 130 | + }; |
| 131 | + |
| 132 | + fixedProject = |
| 133 | + if rawCabalProject == null |
| 134 | + then { |
| 135 | + sourceRepos = []; |
| 136 | + makeFixedProjectFile = ""; |
| 137 | + } |
| 138 | + else replaceSoureRepos rawCabalProject; |
| 139 | + |
54 | 140 | plan = runCommand "plan-to-nix-pkgs" { |
55 | 141 | nativeBuildInputs = [ nix-tools ghc hpack cabal-install pkgs.rsync pkgs.git ]; |
56 | | - } '' |
| 142 | + } ('' |
57 | 143 | tmp=$(mktemp -d) |
58 | 144 | cd $tmp |
59 | 145 | cp -r ${maybeCleanedSource}/* . |
60 | 146 | chmod +w -R . |
| 147 | + ${fixedProject.makeFixedProjectFile} |
61 | 148 | # warning: this may not generate the proper cabal file. |
62 | 149 | # hpack allows globbing, and turns that into module lists |
63 | 150 | # without the source available (we cleaneSourceWith'd it), |
|
96 | 183 |
|
97 | 184 | # move pkgs.nix to default.nix ensure we can just nix `import` the result. |
98 | 185 | mv $out/pkgs.nix $out/default.nix |
99 | | - ''; |
| 186 | + ''); |
100 | 187 | in |
101 | 188 | # TODO: We really want this (symlinks) instead of copying the source over each and |
102 | 189 | # every time. However this will not work with sandboxed builds. They won't |
|
114 | 201 | # # todo: should we clean `src` to drop any .git, .nix, ... other irelevant files? |
115 | 202 | # buildInputs = [ plan src ]; |
116 | 203 | # } |
117 | | - runCommand "plan-to-nix-pkgs-with-src" { nativeBuildInputs = [ pkgs.rsync ]; } '' |
| 204 | + runCommand "plan-to-nix-pkgs-with-src" { nativeBuildInputs = [ pkgs.rsync ]; } ('' |
118 | 205 | mkdir $out |
119 | 206 | # todo: should we clean `src` to drop any .git, .nix, ... other irelevant files? |
120 | 207 | rsync -a "${src}/" "$out/" |
121 | 208 | rsync -a ${plan}/ $out/ |
| 209 | + '' + |
| 210 | + ( pkgs.lib.strings.concatStrings ( |
| 211 | + pkgs.lib.lists.zipListsWith (n: f: '' |
| 212 | + mkdir -p $out/.source-repository-packages/${builtins.toString n} |
| 213 | + rsync -a "${f}/" "$out/.source-repository-packages/${builtins.toString n}/" |
| 214 | + '') |
| 215 | + (pkgs.lib.lists.range 0 ((builtins.length fixedProject.sourceRepos) - 1)) |
| 216 | + fixedProject.sourceRepos |
| 217 | + ) |
| 218 | + ) + '' |
122 | 219 | # Rsync will have made $out read only and that can cause problems when |
123 | 220 | # nix sandboxing is enabled (since it can prevent nix from moving the directory |
124 | 221 | # out of the chroot sandbox). |
125 | 222 | chmod +w $out |
126 | | - '' |
| 223 | + '') |
0 commit comments