1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
|
{
lib,
stdenvNoCC,
git,
git-lfs,
cacert,
}:
let
urlToName =
{
url,
rev,
append,
}:
let
shortRev = lib.sources.shortRev rev;
appendShort = lib.optionalString ((builtins.match "[a-f0-9]*" rev) != null) "-${shortRev}";
in
"${lib.sources.urlToName url}${if append == "" then appendShort else append}";
in
lib.makeOverridable (
lib.fetchers.withNormalizedHash { } (
# NOTE Please document parameter additions or changes in
# ../../../doc/build-helpers/fetchers.chapter.md
{
url,
tag ? null,
rev ? null,
name ? urlToName {
inherit url;
rev = lib.revOrTag rev tag;
# when rootDir is specified, avoid invalidating the result when rev changes
append = if rootDir != "" then "-${lib.strings.sanitizeDerivationName rootDir}" else "";
},
leaveDotGit ? deepClone || fetchTags,
outputHash ? lib.fakeHash,
outputHashAlgo ? null,
fetchSubmodules ? true,
deepClone ? false,
branchName ? null,
sparseCheckout ? lib.optional (rootDir != "") rootDir,
nonConeMode ? rootDir != "",
nativeBuildInputs ? [ ],
# Shell code executed before the file has been fetched. This, in
# particular, can do things like set NIX_PREFETCH_GIT_CHECKOUT_HOOK to
# run operations between the checkout completing and deleting the .git
# directory.
preFetch ? "",
# Shell code executed after the file has been fetched
# successfully. This can do things like check or transform the file.
postFetch ? "",
preferLocalBuild ? true,
fetchLFS ? false,
# Shell code to build a netrc file for BASIC auth
netrcPhase ? null,
# Impure env vars (https://nixos.org/nix/manual/#sec-advanced-attributes)
# needed for netrcPhase
netrcImpureEnvVars ? [ ],
meta ? { },
allowedRequisites ? null,
# fetch all tags after tree (useful for git describe)
fetchTags ? false,
# make this subdirectory the root of the result
rootDir ? "",
}:
/*
NOTE:
fetchgit has one problem: git fetch only works for refs.
This is because fetching arbitrary (maybe dangling) commits creates garbage collection risks
and checking whether a commit belongs to a ref is expensive. This may
change in the future when some caching is added to git (?)
Usually refs are either tags (refs/tags/*) or branches (refs/heads/*)
Cloning branches will make the hash check fail when there is an update.
But not all patches we want can be accessed by tags.
The workaround is getting the last n commits so that it's likely that they
still contain the hash we want.
for now : increase depth iteratively (TODO)
real fix: ask git folks to add a
git fetch $HASH contained in $BRANCH
facility because checking that $HASH is contained in $BRANCH is less
expensive than fetching --depth $N.
Even if git folks implemented this feature soon it may take years until
server admins start using the new version?
*/
assert nonConeMode -> (sparseCheckout != [ ]);
assert fetchTags -> leaveDotGit;
assert rootDir != "" -> !leaveDotGit;
let
revWithTag =
let
warningMsg = "fetchgit requires one of either `rev` or `tag` to be provided (not both).";
otherIsNull = other: lib.assertMsg (other == null) warningMsg;
in
if tag != null then
assert (otherIsNull rev);
"refs/tags/${tag}"
else if rev != null then
assert (otherIsNull tag);
rev
else
# FIXME fetching HEAD if no rev or tag is provided is problematic at best
"HEAD";
in
if builtins.isString sparseCheckout then
# Changed to throw on 2023-06-04
throw
"Please provide directories/patterns for sparse checkout as a list of strings. Passing a (multi-line) string is not supported any more."
else
stdenvNoCC.mkDerivation {
inherit name;
builder = ./builder.sh;
fetcher = ./nix-prefetch-git;
nativeBuildInputs = [
git
cacert
]
++ lib.optionals fetchLFS [ git-lfs ]
++ nativeBuildInputs;
inherit outputHash outputHashAlgo;
outputHashMode = "recursive";
# git-sparse-checkout(1) says:
# > When the --stdin option is provided, the directories or patterns are read
# > from standard in as a newline-delimited list instead of from the arguments.
sparseCheckout = builtins.concatStringsSep "\n" sparseCheckout;
inherit
url
leaveDotGit
fetchLFS
fetchSubmodules
deepClone
branchName
nonConeMode
preFetch
postFetch
fetchTags
rootDir
;
rev = revWithTag;
postHook =
if netrcPhase == null then
null
else
''
${netrcPhase}
# required that git uses the netrc file
mv {,.}netrc
export NETRC=$PWD/.netrc
export HOME=$PWD
'';
impureEnvVars =
lib.fetchers.proxyImpureEnvVars
++ netrcImpureEnvVars
++ [
"GIT_PROXY_COMMAND"
"NIX_GIT_SSL_CAINFO"
"SOCKS_SERVER"
# This is a parameter intended to be set by setup hooks or preFetch
# scripts that want per-URL control over HTTP proxies used by Git
# (if per-URL control isn't needed, `http_proxy` etc. will
# suffice). It must be a whitespace-separated (with backslash as an
# escape character) list of pairs like this:
#
# http://domain1/path1 proxy1 https://domain2/path2 proxy2
#
# where the URLs are as documented in the `git-config` manual page
# under `http.<url>.*`, and the proxies are as documented on the
# same page under `http.proxy`.
"FETCHGIT_HTTP_PROXIES"
];
inherit preferLocalBuild meta allowedRequisites;
passthru = {
gitRepoUrl = url;
inherit tag;
};
}
)
)
|