nixpkgs mirror (for testing)
github.com/NixOS/nixpkgs
nix
1{
2 lib,
3 repoRevToNameMaybe,
4 fetchgit,
5 fetchzip,
6}:
7let
8 # Here defines fetchFromGitHub arguments that determines useFetchGit,
9 # The attribute value is their default values.
10 # As fetchFromGitHub prefers fetchzip for hash stability,
11 # `defaultFetchGitArgs` attributes should lead to `useFetchGit = false`.
12 useFetchGitArgsDefault = {
13 deepClone = false;
14 fetchSubmodules = false; # This differs from fetchgit's default
15 fetchLFS = false;
16 forceFetchGit = false;
17 leaveDotGit = null;
18 postCheckout = "";
19 rootDir = "";
20 sparseCheckout = null;
21 };
22 useFetchGitArgsDefaultNullable = {
23 leaveDotGit = false;
24 sparseCheckout = [ ];
25 };
26
27 useFetchGitargsDefaultNonNull = useFetchGitArgsDefault // useFetchGitArgsDefaultNullable;
28
29 # useFetchGitArgsWD to exclude from automatic passing.
30 # Other useFetchGitArgsWD will pass down to fetchgit.
31 excludeUseFetchGitArgNames = [
32 "forceFetchGit"
33 ];
34
35 faUseFetchGit = lib.mapAttrs (_: _: true) useFetchGitArgsDefault;
36
37 adjustFunctionArgs = f: lib.setFunctionArgs f (faUseFetchGit // lib.functionArgs f);
38
39 decorate = f: lib.makeOverridable (adjustFunctionArgs f);
40in
41decorate (
42 {
43 owner,
44 repo,
45 tag ? null,
46 rev ? null,
47 # TODO(@ShamrockLee): Add back after reconstruction with lib.extendMkDerivation
48 # name ? repoRevToNameMaybe finalAttrs.repo (lib.revOrTag finalAttrs.revCustom finalAttrs.tag) "github",
49 private ? false,
50 githubBase ? "github.com",
51 varPrefix ? null,
52 passthru ? { },
53 meta ? { },
54 ... # For hash agility and additional fetchgit arguments
55 }@args:
56
57 assert (
58 lib.assertMsg (lib.xor (tag == null) (
59 rev == null
60 )) "fetchFromGitHub requires one of either `rev` or `tag` to be provided (not both)."
61 );
62
63 let
64 useFetchGit =
65 lib.mapAttrs (
66 name: nonNullDefault:
67 if args ? ${name} && (useFetchGitArgsDefaultNullable ? ${name} -> args.${name} != null) then
68 args.${name}
69 else
70 nonNullDefault
71 ) useFetchGitargsDefaultNonNull != useFetchGitargsDefaultNonNull;
72
73 useFetchGitArgsWDPassing = lib.overrideExisting (removeAttrs useFetchGitArgsDefault excludeUseFetchGitArgNames) args;
74
75 position = (
76 if args.meta.description or null != null then
77 builtins.unsafeGetAttrPos "description" args.meta
78 else if tag != null then
79 builtins.unsafeGetAttrPos "tag" args
80 else
81 builtins.unsafeGetAttrPos "rev" args
82 );
83 baseUrl = "https://${githubBase}/${owner}/${repo}";
84 newMeta =
85 meta
86 // {
87 homepage = meta.homepage or baseUrl;
88 }
89 // lib.optionalAttrs (position != null) {
90 # to indicate where derivation originates, similar to make-derivation.nix's mkDerivation
91 position = "${position.file}:${toString position.line}";
92 };
93 passthruAttrs = removeAttrs args (
94 [
95 "owner"
96 "repo"
97 "tag"
98 "rev"
99 "private"
100 "githubBase"
101 "varPrefix"
102 ]
103 ++ (if useFetchGit then excludeUseFetchGitArgNames else lib.attrNames faUseFetchGit)
104 );
105 varBase = "NIX${lib.optionalString (varPrefix != null) "_${varPrefix}"}_GITHUB_PRIVATE_";
106 # We prefer fetchzip in cases we don't need submodules as the hash
107 # is more stable in that case.
108 fetcher =
109 if useFetchGit then
110 fetchgit
111 # fetchzip may not be overridable when using external tools, for example nix-prefetch
112 else if fetchzip ? override then
113 fetchzip.override { withUnzip = false; }
114 else
115 fetchzip;
116 privateAttrs = lib.optionalAttrs private {
117 netrcPhase =
118 # When using private repos:
119 # - Fetching with git works using https://github.com but not with the GitHub API endpoint
120 # - Fetching a tarball from a private repo requires to use the GitHub API endpoint
121 let
122 machineName = if githubBase == "github.com" && !useFetchGit then "api.github.com" else githubBase;
123 in
124 ''
125 if [ -z "''$${varBase}USERNAME" -o -z "''$${varBase}PASSWORD" ]; then
126 echo "Error: Private fetchFromGitHub requires the nix building process (nix-daemon in multi user mode) to have the ${varBase}USERNAME and ${varBase}PASSWORD env vars set." >&2
127 exit 1
128 fi
129 cat > netrc <<EOF
130 machine ${machineName}
131 login ''$${varBase}USERNAME
132 password ''$${varBase}PASSWORD
133 EOF
134 '';
135 netrcImpureEnvVars = [
136 "${varBase}USERNAME"
137 "${varBase}PASSWORD"
138 ];
139 };
140
141 gitRepoUrl = "${baseUrl}.git";
142
143 fetcherArgs =
144 finalAttrs:
145 passthruAttrs
146 // (
147 if useFetchGit then
148 useFetchGitArgsWDPassing
149 // {
150 inherit tag rev;
151 url = gitRepoUrl;
152 inherit passthru;
153 derivationArgs = {
154 inherit
155 githubBase
156 owner
157 repo
158 ;
159 };
160 }
161 else
162 let
163 revWithTag = finalAttrs.rev;
164 in
165 {
166 # Use the API endpoint for private repos, as the archive URI doesn't
167 # support access with GitHub's fine-grained access tokens.
168 #
169 # Use the archive URI for non-private repos, as the API endpoint has
170 # relatively restrictive rate limits for unauthenticated users.
171 url =
172 if private then
173 let
174 endpoint = "/repos/${finalAttrs.owner}/${finalAttrs.repo}/tarball/${revWithTag}";
175 in
176 if githubBase == "github.com" then
177 "https://api.github.com${endpoint}"
178 else
179 "https://${githubBase}/api/v3${endpoint}"
180 else
181 "${baseUrl}/archive/${revWithTag}.tar.gz";
182 extension = "tar.gz";
183 derivationArgs = {
184 inherit
185 githubBase
186 owner
187 repo
188 tag
189 ;
190 rev = fetchgit.getRevWithTag {
191 inherit (finalAttrs) tag;
192 rev = finalAttrs.revCustom;
193 };
194 revCustom = rev;
195 };
196 passthru = {
197 inherit gitRepoUrl;
198 }
199 // passthru;
200 }
201 )
202 // privateAttrs
203 // {
204 # TODO(@ShamrockLee): Change back to `inherit name;` after reconstruction with lib.extendMkDerivation
205 name =
206 args.name
207 or (repoRevToNameMaybe finalAttrs.repo (lib.revOrTag finalAttrs.revCustom finalAttrs.tag) "github");
208 meta = newMeta;
209 };
210 in
211
212 fetcher fetcherArgs
213)