1{
2 lib,
3 repoRevToNameMaybe,
4 fetchgit,
5 fetchzip,
6}:
7
8lib.makeOverridable (
9 {
10 owner,
11 repo,
12 tag ? null,
13 rev ? null,
14 name ? repoRevToNameMaybe repo (lib.revOrTag rev tag) "github",
15 fetchSubmodules ? false,
16 leaveDotGit ? null,
17 deepClone ? false,
18 private ? false,
19 forceFetchGit ? false,
20 fetchLFS ? false,
21 rootDir ? "",
22 sparseCheckout ? lib.optional (rootDir != "") rootDir,
23 githubBase ? "github.com",
24 varPrefix ? null,
25 meta ? { },
26 ... # For hash agility
27 }@args:
28
29 assert (
30 lib.assertMsg (lib.xor (tag == null) (
31 rev == null
32 )) "fetchFromGitHub requires one of either `rev` or `tag` to be provided (not both)."
33 );
34
35 let
36
37 position = (
38 if args.meta.description or null != null then
39 builtins.unsafeGetAttrPos "description" args.meta
40 else if tag != null then
41 builtins.unsafeGetAttrPos "tag" args
42 else
43 builtins.unsafeGetAttrPos "rev" args
44 );
45 baseUrl = "https://${githubBase}/${owner}/${repo}";
46 newMeta =
47 meta
48 // {
49 homepage = meta.homepage or baseUrl;
50 }
51 // lib.optionalAttrs (position != null) {
52 # to indicate where derivation originates, similar to make-derivation.nix's mkDerivation
53 position = "${position.file}:${toString position.line}";
54 };
55 passthruAttrs = removeAttrs args [
56 "owner"
57 "repo"
58 "tag"
59 "rev"
60 "fetchSubmodules"
61 "forceFetchGit"
62 "private"
63 "githubBase"
64 "varPrefix"
65 ];
66 varBase = "NIX${lib.optionalString (varPrefix != null) "_${varPrefix}"}_GITHUB_PRIVATE_";
67 useFetchGit =
68 fetchSubmodules
69 || (leaveDotGit == true)
70 || deepClone
71 || forceFetchGit
72 || fetchLFS
73 || (rootDir != "")
74 || (sparseCheckout != [ ]);
75 # We prefer fetchzip in cases we don't need submodules as the hash
76 # is more stable in that case.
77 fetcher =
78 if useFetchGit then
79 fetchgit
80 # fetchzip may not be overridable when using external tools, for example nix-prefetch
81 else if fetchzip ? override then
82 fetchzip.override { withUnzip = false; }
83 else
84 fetchzip;
85 privateAttrs = lib.optionalAttrs private {
86 netrcPhase =
87 # When using private repos:
88 # - Fetching with git works using https://github.com but not with the GitHub API endpoint
89 # - Fetching a tarball from a private repo requires to use the GitHub API endpoint
90 let
91 machineName = if githubBase == "github.com" && !useFetchGit then "api.github.com" else githubBase;
92 in
93 ''
94 if [ -z "''$${varBase}USERNAME" -o -z "''$${varBase}PASSWORD" ]; then
95 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
96 exit 1
97 fi
98 cat > netrc <<EOF
99 machine ${machineName}
100 login ''$${varBase}USERNAME
101 password ''$${varBase}PASSWORD
102 EOF
103 '';
104 netrcImpureEnvVars = [
105 "${varBase}USERNAME"
106 "${varBase}PASSWORD"
107 ];
108 };
109
110 gitRepoUrl = "${baseUrl}.git";
111
112 revWithTag = if tag != null then "refs/tags/${tag}" else rev;
113
114 fetcherArgs =
115 (
116 if useFetchGit then
117 {
118 inherit
119 tag
120 rev
121 deepClone
122 fetchSubmodules
123 sparseCheckout
124 fetchLFS
125 ;
126 url = gitRepoUrl;
127 }
128 // lib.optionalAttrs (leaveDotGit != null) { inherit leaveDotGit; }
129 else
130 {
131 # Use the API endpoint for private repos, as the archive URI doesn't
132 # support access with GitHub's fine-grained access tokens.
133 #
134 # Use the archive URI for non-private repos, as the API endpoint has
135 # relatively restrictive rate limits for unauthenticated users.
136 url =
137 if private then
138 let
139 endpoint = "/repos/${owner}/${repo}/tarball/${revWithTag}";
140 in
141 if githubBase == "github.com" then
142 "https://api.github.com${endpoint}"
143 else
144 "https://${githubBase}/api/v3${endpoint}"
145 else
146 "${baseUrl}/archive/${revWithTag}.tar.gz";
147 extension = "tar.gz";
148
149 passthru = {
150 inherit gitRepoUrl;
151 };
152 }
153 )
154 // privateAttrs
155 // passthruAttrs
156 // {
157 inherit name;
158 };
159 in
160
161 fetcher fetcherArgs
162 // {
163 meta = newMeta;
164 inherit owner repo tag;
165 rev = revWithTag;
166 }
167)