1{lib, stdenvNoCC, git, git-lfs, cacert}: let
2 urlToName = url: rev: let
3 inherit (lib) removeSuffix splitString last;
4 base = last (splitString ":" (baseNameOf (removeSuffix "/" url)));
5
6 matched = builtins.match "(.*)\\.git" base;
7
8 short = builtins.substring 0 7 rev;
9
10 appendShort = lib.optionalString ((builtins.match "[a-f0-9]*" rev) != null) "-${short}";
11 in "${if matched == null then base else builtins.head matched}${appendShort}";
12in
13lib.makeOverridable (
14{ url, rev ? "HEAD", sha256 ? "", hash ? "", leaveDotGit ? deepClone
15, fetchSubmodules ? true, deepClone ? false
16, branchName ? null
17, sparseCheckout ? []
18, nonConeMode ? false
19, name ? urlToName url rev
20, # Shell code executed after the file has been fetched
21 # successfully. This can do things like check or transform the file.
22 postFetch ? ""
23, preferLocalBuild ? true
24, fetchLFS ? false
25, # Shell code to build a netrc file for BASIC auth
26 netrcPhase ? null
27, # Impure env vars (https://nixos.org/nix/manual/#sec-advanced-attributes)
28 # needed for netrcPhase
29 netrcImpureEnvVars ? []
30, meta ? {}
31, allowedRequisites ? null
32}:
33
34/* NOTE:
35 fetchgit has one problem: git fetch only works for refs.
36 This is because fetching arbitrary (maybe dangling) commits creates garbage collection risks
37 and checking whether a commit belongs to a ref is expensive. This may
38 change in the future when some caching is added to git (?)
39 Usually refs are either tags (refs/tags/*) or branches (refs/heads/*)
40 Cloning branches will make the hash check fail when there is an update.
41 But not all patches we want can be accessed by tags.
42
43 The workaround is getting the last n commits so that it's likely that they
44 still contain the hash we want.
45
46 for now : increase depth iteratively (TODO)
47
48 real fix: ask git folks to add a
49 git fetch $HASH contained in $BRANCH
50 facility because checking that $HASH is contained in $BRANCH is less
51 expensive than fetching --depth $N.
52 Even if git folks implemented this feature soon it may take years until
53 server admins start using the new version?
54*/
55
56assert deepClone -> leaveDotGit;
57assert nonConeMode -> (sparseCheckout != []);
58
59if hash != "" && sha256 != "" then
60 throw "Only one of sha256 or hash can be set"
61else if builtins.isString sparseCheckout then
62 # Changed to throw on 2023-06-04
63 throw "Please provide directories/patterns for sparse checkout as a list of strings. Passing a (multi-line) string is not supported any more."
64else
65stdenvNoCC.mkDerivation {
66 inherit name;
67 builder = ./builder.sh;
68 fetcher = ./nix-prefetch-git;
69
70 nativeBuildInputs = [ git ]
71 ++ lib.optionals fetchLFS [ git-lfs ];
72
73 outputHashAlgo = if hash != "" then null else "sha256";
74 outputHashMode = "recursive";
75 outputHash = if hash != "" then
76 hash
77 else if sha256 != "" then
78 sha256
79 else
80 lib.fakeSha256;
81
82 # git-sparse-checkout(1) says:
83 # > When the --stdin option is provided, the directories or patterns are read
84 # > from standard in as a newline-delimited list instead of from the arguments.
85 sparseCheckout = builtins.concatStringsSep "\n" sparseCheckout;
86
87 inherit url rev leaveDotGit fetchLFS fetchSubmodules deepClone branchName nonConeMode postFetch;
88
89 postHook = if netrcPhase == null then null else ''
90 ${netrcPhase}
91 # required that git uses the netrc file
92 mv {,.}netrc
93 export NETRC=$PWD/.netrc
94 export HOME=$PWD
95 '';
96
97 GIT_SSL_CAINFO = "${cacert}/etc/ssl/certs/ca-bundle.crt";
98
99 impureEnvVars = lib.fetchers.proxyImpureEnvVars ++ netrcImpureEnvVars ++ [
100 "GIT_PROXY_COMMAND" "NIX_GIT_SSL_CAINFO" "SOCKS_SERVER"
101 ];
102
103
104 inherit preferLocalBuild meta allowedRequisites;
105
106 passthru = {
107 gitRepoUrl = url;
108 };
109}
110)