nixpkgs mirror (for testing)
github.com/NixOS/nixpkgs
nix
1{
2 config,
3 lib,
4 stdenvNoCC,
5 git,
6 git-lfs,
7 cacert,
8}:
9
10let
11 urlToName =
12 {
13 url,
14 rev,
15 append,
16 }:
17 let
18 shortRev = lib.sources.shortRev rev;
19 appendShort = lib.optionalString ((builtins.match "[a-f0-9]*" rev) != null) "-${shortRev}";
20 in
21 "${lib.sources.urlToName url}${if append == "" then appendShort else append}";
22
23 getRevWithTag =
24 {
25 rev ? null,
26 tag ? null,
27 }:
28 if tag != null && rev != null then
29 throw "fetchgit requires one of either `rev` or `tag` to be provided (not both)."
30 else if tag != null then
31 "refs/tags/${tag}"
32 else if rev != null then
33 rev
34 else
35 # FIXME fetching HEAD if no rev or tag is provided is problematic at best
36 "HEAD";
37in
38
39lib.makeOverridable (
40 lib.extendMkDerivation {
41 constructDrv = stdenvNoCC.mkDerivation;
42
43 excludeDrvArgNames = [
44 # Additional stdenv.mkDerivation arguments from derived fetchers.
45 "derivationArgs"
46
47 # Hashes, handled by `lib.fetchers.withNormalizedHash`
48 # whose outputs contain outputHash* attributes.
49 # Use `hash` when overriding with `<pkg>.overrideAttrs`.
50 "sha256"
51 ];
52
53 extendDrvArgs =
54 finalAttrs:
55 lib.fetchers.withNormalizedHash { } (
56 # NOTE Please document parameter additions or changes in
57 # ../../../doc/build-helpers/fetchers.chapter.md
58 {
59 url,
60 tag ? null,
61 rev ? null,
62 name ? urlToName {
63 inherit url;
64 rev = lib.revOrTag finalAttrs.revCustom finalAttrs.tag;
65 # when rootDir is specified, avoid invalidating the result when rev changes
66 append = if rootDir != "" then "-${lib.strings.sanitizeDerivationName rootDir}" else "";
67 },
68 # When null, will default to: `deepClone || fetchTags`
69 leaveDotGit ? null,
70 outputHash ? lib.fakeHash,
71 outputHashAlgo ? null,
72 fetchSubmodules ? true,
73 deepClone ? false,
74 branchName ? null,
75 # When null, will default to: `lib.optional (rootdir != "") rootdir`
76 sparseCheckout ? null,
77 # When null, will default to: `rootDir != ""`
78 nonConeMode ? null,
79 nativeBuildInputs ? [ ],
80 # Shell code executed before the file has been fetched. This, in
81 # particular, can do things like set NIX_PREFETCH_GIT_CHECKOUT_HOOK to
82 # run operations between the checkout completing and deleting the .git
83 # directory.
84 preFetch ? "",
85 # Shell code executed after `git checkout` and before .git directory removal/sanitization.
86 postCheckout ? "",
87 # Shell code executed after the file has been fetched
88 # successfully. This can do things like check or transform the file.
89 postFetch ? "",
90 preferLocalBuild ? true,
91 fetchLFS ? false,
92 # Shell code to build a netrc file for BASIC auth
93 netrcPhase ? null,
94 # Impure env vars (https://nixos.org/nix/manual/#sec-advanced-attributes)
95 # needed for netrcPhase
96 netrcImpureEnvVars ? [ ],
97 passthru ? { },
98 meta ? { },
99 allowedRequisites ? null,
100 # fetch all tags after tree (useful for git describe)
101 fetchTags ? false,
102 # make this subdirectory the root of the result
103 rootDir ? "",
104 # GIT_CONFIG_GLOBAL (as a file)
105 gitConfigFile ? config.gitConfigFile,
106 # Additional stdenvNoCC.mkDerivation arguments.
107 # It is typically for derived fetchers to pass down additional arguments,
108 # and the specified arguments have lower precedence than other mkDerivation arguments.
109 derivationArgs ? { },
110 }:
111
112 /*
113 NOTE:
114 fetchgit has one problem: git fetch only works for refs.
115 This is because fetching arbitrary (maybe dangling) commits creates garbage collection risks
116 and checking whether a commit belongs to a ref is expensive. This may
117 change in the future when some caching is added to git (?)
118 Usually refs are either tags (refs/tags/*) or branches (refs/heads/*)
119 Cloning branches will make the hash check fail when there is an update.
120 But not all patches we want can be accessed by tags.
121
122 The workaround is getting the last n commits so that it's likely that they
123 still contain the hash we want.
124
125 for now : increase depth iteratively (TODO)
126
127 real fix: ask git folks to add a
128 git fetch $HASH contained in $BRANCH
129 facility because checking that $HASH is contained in $BRANCH is less
130 expensive than fetching --depth $N.
131 Even if git folks implemented this feature soon it may take years until
132 server admins start using the new version?
133 */
134
135 let
136 finalHashHasColon = lib.hasInfix ":" finalAttrs.hash;
137 finalHashColonMatch = lib.match "([^:]+)[:](.*)" finalAttrs.hash;
138 in
139
140 derivationArgs
141 // {
142 __structuredAttrs = true;
143
144 inherit name;
145
146 builder = ./builder.sh;
147 fetcher = ./nix-prefetch-git;
148
149 nativeBuildInputs = [
150 git
151 cacert
152 ]
153 ++ lib.optionals fetchLFS [ git-lfs ]
154 ++ nativeBuildInputs;
155
156 hash =
157 if outputHashAlgo == null || outputHash == "" || lib.hasPrefix outputHashAlgo outputHash then
158 outputHash
159 else
160 "${outputHashAlgo}:${outputHash}";
161
162 outputHash =
163 if finalAttrs.hash == "" then
164 lib.fakeHash
165 else if finalHashHasColon then
166 lib.elemAt finalHashColonMatch 1
167 else
168 finalAttrs.hash;
169 outputHashAlgo = if finalHashHasColon then lib.head finalHashColonMatch else null;
170 outputHashMode = "recursive";
171
172 sparseCheckout =
173 let
174 default = lib.optional (finalAttrs.rootDir != "") finalAttrs.rootDir;
175 in
176 lib.defaultTo default sparseCheckout;
177 sparseCheckoutText =
178 # Changed to throw on 2023-06-04
179 assert (
180 lib.assertMsg (lib.isList finalAttrs.sparseCheckout) "Please provide directories/patterns for sparse checkout as a list of strings. Passing a (multi-line) string is not supported any more."
181 );
182 assert finalAttrs.nonConeMode -> (finalAttrs.sparseCheckout != [ ]);
183 # git-sparse-checkout(1) says:
184 # > When the --stdin option is provided, the directories or patterns are read
185 # > from standard in as a newline-delimited list instead of from the arguments.
186 builtins.concatStringsSep "\n" finalAttrs.sparseCheckout;
187
188 inherit
189 url
190 fetchLFS
191 fetchSubmodules
192 deepClone
193 branchName
194 preFetch
195 postCheckout
196 postFetch
197 fetchTags
198 rootDir
199 gitConfigFile
200 ;
201 leaveDotGit =
202 if leaveDotGit != null then
203 assert fetchTags -> leaveDotGit;
204 assert rootDir != "" -> !leaveDotGit;
205 leaveDotGit
206 else
207 deepClone || fetchTags;
208 nonConeMode = lib.defaultTo (finalAttrs.rootDir != "") nonConeMode;
209 inherit tag;
210 revCustom = rev;
211 rev = getRevWithTag {
212 inherit (finalAttrs) tag;
213 rev = finalAttrs.revCustom;
214 };
215
216 postHook =
217 if netrcPhase == null then
218 null
219 else
220 ''
221 ${netrcPhase}
222 # required that git uses the netrc file
223 mv {,.}netrc
224 export NETRC=$PWD/.netrc
225 export HOME=$PWD
226 '';
227
228 impureEnvVars =
229 lib.fetchers.proxyImpureEnvVars
230 ++ netrcImpureEnvVars
231 ++ [
232 "GIT_PROXY_COMMAND"
233 "NIX_GIT_SSL_CAINFO"
234 "SOCKS_SERVER"
235
236 # This is a parameter intended to be set by setup hooks or preFetch
237 # scripts that want per-URL control over HTTP proxies used by Git
238 # (if per-URL control isn't needed, `http_proxy` etc. will
239 # suffice). It must be a whitespace-separated (with backslash as an
240 # escape character) list of pairs like this:
241 #
242 # http://domain1/path1 proxy1 https://domain2/path2 proxy2
243 #
244 # where the URLs are as documented in the `git-config` manual page
245 # under `http.<url>.*`, and the proxies are as documented on the
246 # same page under `http.proxy`.
247 "FETCHGIT_HTTP_PROXIES"
248 ];
249
250 outputChecks.out = {
251 ${if allowedRequisites != null then "allowedRequisites" else null} = allowedRequisites;
252 };
253
254 inherit preferLocalBuild meta;
255
256 env = {
257 NIX_PREFETCH_GIT_CHECKOUT_HOOK = finalAttrs.postCheckout;
258 };
259
260 passthru = {
261 gitRepoUrl = url;
262 }
263 // passthru;
264 }
265 );
266
267 # No ellipsis.
268 inheritFunctionArgs = false;
269 }
270)
271// {
272 inherit getRevWithTag;
273}