summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Taron <philip.taron@gmail.com>2025-08-10 17:38:43 -0700
committerGitHub <noreply@github.com>2025-08-10 17:38:43 -0700
commit754ee2fc40577285d31fa14b895a3cf55103a925 (patch)
tree2f9f24272eef0b531193eab2677c2e590a8ad65b
parentsydbox: 3.37.2 -> 3.37.6 (#432577) (diff)
parentfetchgit: Add rootDir argument (diff)
downloadnixpkgs-754ee2fc40577285d31fa14b895a3cf55103a925.tar.gz
fetchgit: Add rootDir argument (#427165)
-rw-r--r--doc/build-helpers/fetchers.chapter.md4
-rw-r--r--doc/release-notes/rl-2511.section.md1
-rw-r--r--pkgs/build-support/fetchgit/builder.sh3
-rw-r--r--pkgs/build-support/fetchgit/default.nix23
-rwxr-xr-xpkgs/build-support/fetchgit/nix-prefetch-git62
-rw-r--r--pkgs/build-support/fetchgit/tests.nix8
6 files changed, 78 insertions, 23 deletions
diff --git a/doc/build-helpers/fetchers.chapter.md b/doc/build-helpers/fetchers.chapter.md
index 5ee1d78501ca..6a6ebe9013c2 100644
--- a/doc/build-helpers/fetchers.chapter.md
+++ b/doc/build-helpers/fetchers.chapter.md
@@ -829,6 +829,10 @@ Additionally, the following optional arguments can be given:
See [git sparse-checkout](https://git-scm.com/docs/git-sparse-checkout) for more information.
+*`rootDir`* (String)
+
+: When not empty, copy only contents of the subdirectory of the repository to the result. Automatically sets `sparseCheckout` and `nonConeMode` to avoid checking out any extra pieces. Incompatible with `leaveDotGit`.
+
Some additional parameters for niche use-cases can be found listed in the function parameters in the declaration of `fetchgit`: `pkgs/build-support/fetchgit/default.nix`.
Future parameters additions might also happen without immediately being documented here.
diff --git a/doc/release-notes/rl-2511.section.md b/doc/release-notes/rl-2511.section.md
index 68f68cb4e64f..6cd94f483531 100644
--- a/doc/release-notes/rl-2511.section.md
+++ b/doc/release-notes/rl-2511.section.md
@@ -103,6 +103,7 @@
* `$debug/lib/debug/.build-id/48/3bd7f7229bdb06462222e1e353e4f37e15c293.sourceoverlay` is a symlink to a directory with the same structure as the expanded `$sourceRoot` but containing only a copy of files which were patched during the build
* `$debug/lib/debug/.build-id/48/3bd7f7229bdb06462222e1e353e4f37e15c293.debug` is the file containing debug symbols (like before).
+- `fetchgit`: Add `rootDir` argument to limit the resulting source to one subdirectory of the whole Git repository. Corresponding `--root-dir` option added to `nix-prefetch-git`.
## Nixpkgs Library {#sec-nixpkgs-release-25.11-lib}
diff --git a/pkgs/build-support/fetchgit/builder.sh b/pkgs/build-support/fetchgit/builder.sh
index 819b0127a852..393d0a57d163 100644
--- a/pkgs/build-support/fetchgit/builder.sh
+++ b/pkgs/build-support/fetchgit/builder.sh
@@ -16,6 +16,7 @@ $SHELL $fetcher --builder --url "$url" --out "$out" --rev "$rev" --name "$name"
${fetchTags:+--fetch-tags} \
${sparseCheckout:+--sparse-checkout "$sparseCheckout"} \
${nonConeMode:+--non-cone-mode} \
- ${branchName:+--branch-name "$branchName"}
+ ${branchName:+--branch-name "$branchName"} \
+ ${rootDir:+--root-dir "$rootDir"}
runHook postFetch
diff --git a/pkgs/build-support/fetchgit/default.nix b/pkgs/build-support/fetchgit/default.nix
index d364c8ebf708..b2f5f15a309d 100644
--- a/pkgs/build-support/fetchgit/default.nix
+++ b/pkgs/build-support/fetchgit/default.nix
@@ -8,12 +8,16 @@
let
urlToName =
- url: rev:
+ {
+ 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}${appendShort}";
+ "${lib.sources.urlToName url}${if append == "" then appendShort else append}";
in
lib.makeOverridable (
@@ -24,15 +28,20 @@ lib.makeOverridable (
url,
tag ? null,
rev ? null,
- name ? urlToName url (lib.revOrTag rev tag),
+ 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 ? [ ],
- nonConeMode ? false,
+ 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
@@ -53,6 +62,8 @@ lib.makeOverridable (
allowedRequisites ? null,
# fetch all tags after tree (useful for git describe)
fetchTags ? false,
+ # make this subdirectory the root of the result
+ rootDir ? "",
}:
/*
@@ -80,6 +91,7 @@ lib.makeOverridable (
assert nonConeMode -> (sparseCheckout != [ ]);
assert fetchTags -> leaveDotGit;
+ assert rootDir != "" -> !leaveDotGit;
let
revWithTag =
@@ -135,6 +147,7 @@ lib.makeOverridable (
preFetch
postFetch
fetchTags
+ rootDir
;
rev = revWithTag;
diff --git a/pkgs/build-support/fetchgit/nix-prefetch-git b/pkgs/build-support/fetchgit/nix-prefetch-git
index 259138641ea9..7f3616af92fc 100755
--- a/pkgs/build-support/fetchgit/nix-prefetch-git
+++ b/pkgs/build-support/fetchgit/nix-prefetch-git
@@ -59,6 +59,7 @@ Options:
--fetch-submodules Fetch submodules.
--fetch-tags Fetch all tags (useful for git describe).
--builder Clone as fetchgit does, but url, rev, and out option are mandatory.
+ --root-dir dir Directory in the repository that will be copied to the output instead of the full repository.
--quiet Only print the final json summary.
"
exit 1
@@ -90,6 +91,7 @@ for arg; do
--fetch-submodules) fetchSubmodules=true;;
--fetch-tags) fetchTags=true;;
--builder) builder=true;;
+ --root-dir) argfun=set_rootDir;;
-h|--help) usage; exit;;
*)
: $((++argi))
@@ -155,10 +157,16 @@ url_to_name(){
local base
base=$(basename "$url" .git | cut -d: -f2)
- if [[ $ref =~ ^[a-z0-9]+$ ]]; then
- echo "$base-${ref:0:7}"
+ if test -n "$rootDir"; then
+ # Sanitize by removing leading dots and replacing all invalid character sequences with dashes.
+ # See sanitizeDerivationName in ../../../lib/strings.nix for reference.
+ echo "$base-$(sed -E 's/^\.+//;s/[^[:alnum:]+._?=-]+/-/g' <<< $rootDir)"
else
- echo "$base"
+ if [[ $ref =~ ^[a-z0-9]+$ ]]; then
+ echo "$base-${ref:0:7}"
+ else
+ echo "$base"
+ fi
fi
}
@@ -353,6 +361,23 @@ clone_user_rev() {
fi
}
+clone_user_rev_to_tmpfile(){
+ local url="$1"
+ local rev="${2:-HEAD}"
+
+ # nix>=2.20 rejects adding symlinked paths to the store, so use realpath
+ # to resolve to a physical path. https://github.com/NixOS/nix/issues/11941
+ tmpPath="$(realpath "$(mktemp -d --tmpdir git-checkout-tmp-XXXXXXXX)")"
+ exit_handlers+=(remove_tmpPath)
+
+ tmpOut="$tmpPath/out/$storePathName"
+ tmpClone="$tmpPath/clone"
+ mkdir -p "$tmpPath/out" "$tmpClone"
+
+ # Perform the checkout.
+ clone_user_rev "$tmpClone" "$url" "$rev"
+}
+
exit_handlers=()
run_exit_handlers() {
@@ -418,7 +443,8 @@ print_results() {
"fetchSubmodules": $([[ -n "$fetchSubmodules" ]] && echo true || echo false),
"deepClone": $([[ -n "$deepClone" ]] && echo true || echo false),
"fetchTags": $([[ -n "$fetchTags" ]] && echo true || echo false),
- "leaveDotGit": $([[ -n "$leaveDotGit" ]] && echo true || echo false)
+ "leaveDotGit": $([[ -n "$leaveDotGit" ]] && echo true || echo false),
+ "rootDir": "$(json_escape "$rootDir")"
}
EOF
fi
@@ -456,8 +482,13 @@ export GIT_CONFIG_NOSYSTEM=1
if test -n "$builder"; then
test -n "$out" -a -n "$url" -a -n "$rev" || usage
- mkdir -p "$out"
- clone_user_rev "$out" "$url" "$rev"
+ if test -n "$rootDir"; then
+ clone_user_rev_to_tmpfile "$url" "$rev"
+ mv "$tmpClone/$rootDir" "$out"
+ else
+ mkdir -p "$out"
+ clone_user_rev "$out" "$url" "$rev"
+ fi
else
if test -z "$hashType"; then
hashType=sha256
@@ -476,22 +507,19 @@ else
# If we don't know the hash or a path with that hash doesn't exist,
# download the file and add it to the store.
if test -z "$finalPath"; then
- # nix>=2.20 rejects adding symlinked paths to the store, so use realpath
- # to resolve to a physical path. https://github.com/NixOS/nix/issues/11941
- tmpPath="$(realpath "$(mktemp -d --tmpdir git-checkout-tmp-XXXXXXXX)")"
- exit_handlers+=(remove_tmpPath)
+ clone_user_rev_to_tmpfile "$url" "$rev"
- tmpFile="$tmpPath/$storePathName"
- mkdir -p "$tmpFile"
-
- # Perform the checkout.
- clone_user_rev "$tmpFile" "$url" "$rev"
+ if test -z "$rootDir"; then
+ mv "$tmpClone" "$tmpOut"
+ else
+ mv "$tmpClone/$rootDir" "$tmpOut"
+ fi
# Compute the hash.
- hash=$(nix-hash --type $hashType --base32 "$tmpFile")
+ hash=$(nix-hash --type $hashType --base32 "$tmpOut")
# Add the downloaded file to the Nix store.
- finalPath=$(nix-store --add-fixed --recursive "$hashType" "$tmpFile")
+ finalPath=$(nix-store --add-fixed --recursive "$hashType" "$tmpOut")
if test -n "$expHash" -a "$expHash" != "$hash"; then
echo "hash mismatch for URL \`$url'. Got \`$hash'; expected \`$expHash'." >&2
diff --git a/pkgs/build-support/fetchgit/tests.nix b/pkgs/build-support/fetchgit/tests.nix
index fd6aebc335f7..e3fdd5fb8672 100644
--- a/pkgs/build-support/fetchgit/tests.nix
+++ b/pkgs/build-support/fetchgit/tests.nix
@@ -97,4 +97,12 @@
rm -rf .git
'';
};
+
+ rootDir = testers.invalidateFetcherByDrvHash fetchgit {
+ name = "fetchgit-with-rootdir";
+ url = "https://github.com/NixOS/nix";
+ rev = "9d9dbe6ed05854e03811c361a3380e09183f4f4a";
+ rootDir = "misc/systemd";
+ sha256 = "sha256-UhxHk4SrXYq7ZDMtXLig5SigpbITrVgkpFTmryuvpcM=";
+ };
}