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