diff options
| author | tv <tv@krebsco.de> | 2026-11-13 20:28:00 +0000 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-11-13 21:59:13 +0100 |
| commit | 24fd14b1e6de45def6a59b65486f5035ac486ee3 (patch) | |
| tree | ff9928227578c3befa83bfcdee41548aa978efe8 | |
| parent | b34f53d538c5afa95fd0dc6dd81b56e4995b80c2 (diff) | |
populate: refer to flakes as git+file: only with a usable .git
Writing the lock file of a git+file: flake, Nix runs Git, with the
repository's configuration and hooks, which may run commands. A .git
in a source's directory can come from anywhere, e.g. one planted in a
materialized flake, or one a file source keeps. So drawing inputs
refers to a flake as git+file: only if git_problems finds nothing wrong
with its .git directory, the way git sources check their work trees,
and else as path:.
lock-foreign-git plants a .git in a materialized flake and in a file
source that keeps it, whose configuration names an fsmonitor command.
| -rw-r--r-- | CHANGELOG.md | 2 | ||||
| -rw-r--r-- | README.md | 5 | ||||
| -rw-r--r-- | pkgs/populate/src/flake.rs | 6 | ||||
| -rw-r--r-- | pkgs/populate/src/sh.rs | 11 | ||||
| -rw-r--r-- | tests/scenarios.nix | 45 |
5 files changed, 63 insertions, 6 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index e19decc..242bca3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ - `git` sources also refuse work trees whose `.git` directory contains hooks, or in which a submodule's `.git` isn't a file naming a repository in `.git/modules`, unless `reclone` is set. +- Drawing inputs refers to a source in a Git work tree as `git+file:` only + if a `git` source would use its `.git` directory, and else as `path:`. - `git` sources with a branch or tag as `ref` follow it: populate fetches the branch or tag on every run, and resets the work tree to what it fetched. @@ -724,7 +724,10 @@ drawing an input from a source with a generated flake uses that flake. automatically. Sources in a Git work tree are referred to as `git+file:` (with submodules if -there are any), all other sources as `path:`, with symlinks resolved. Lock +there are any), all other sources as `path:`, with symlinks resolved. Nix +runs Git in a `git+file:` flake, so that's only for work trees whose `.git` +directory a `git` source would use, see +[The target directory](#the-target-directory). Lock files get rewritten or generated on every run, so they match the sources. Copies of `flake` and `flake-input` sources get made again only if the delivered store path, the patches, or the sources they draw inputs from diff --git a/pkgs/populate/src/flake.rs b/pkgs/populate/src/flake.rs index 26373d4..ded7692 100644 --- a/pkgs/populate/src/flake.rs +++ b/pkgs/populate/src/flake.rs @@ -228,8 +228,9 @@ impl<'a> Flakes<'a> { String::new() }; format!( - "{}{}{require}{snippet}", + "{}{}{}{require}{snippet}", sh::prelude(), + sh::GIT_PROBLEMS, sh::draw::DEFINITIONS ) } @@ -270,7 +271,8 @@ impl<'a> Flakes<'a> { .collect()) } - /// The flake URL of the source named name, at resolved. + /// The flake URL of the source named name, at resolved: git+file: if + /// it has a .git directory populate can use, else path:. fn flake_url(name: &str, resolved: &Resolved) -> Result<String> { if !resolved.dir { return Err(Failure::Message(format!( diff --git a/pkgs/populate/src/sh.rs b/pkgs/populate/src/sh.rs index f76a0f7..15da78c 100644 --- a/pkgs/populate/src/sh.rs +++ b/pkgs/populate/src/sh.rs @@ -812,14 +812,19 @@ use_state "$@" /// resolve PATH...: prints, for each PATH, what's there and where it /// resolves to, as two fields, each ending in a null byte. The first - /// holds d if PATH is a directory, g if it has .git, s if it has - /// .gitmodules, and f if it has flake.nix. + /// holds d if PATH is a directory, g if it has a .git directory that + /// git_problems finds nothing wrong with, s if it has .gitmodules, and + /// f if it has flake.nix. Nix runs Git in a git+file: flake, with the + /// repository's configuration and hooks, so it only gets such ones. pub const RESOLVE: &str = r#" for path; do resolved=$(readlink -f "$path") || resolved= flags= if test -d "$path"; then flags=${flags}d; fi - if test -e "$path"/.git; then flags=${flags}g; fi + if ! test -L "$path"/.git && test -d "$path"/.git; then + problems=$(git_problems "$path" 2>/dev/null) || problems=failed + if test -z "$problems"; then flags=${flags}g; fi + fi if test -e "$path"/.gitmodules; then flags=${flags}s; fi if test -e "$path"/flake.nix; then flags=${flags}f; fi printf '%s\0%s\0' "$flags" "$resolved" diff --git a/tests/scenarios.nix b/tests/scenarios.nix index d12dcd1..15d0a53 100644 --- a/tests/scenarios.nix +++ b/tests/scenarios.nix @@ -2188,6 +2188,51 @@ assert !(krops.isLocalTarget (targets.remote "/")); } ]; })) + # A .git that a materialized flake got, and one that a file source + # keeps, which Nix uses for the git+file: URL of the flake there: writing + # its lock file, Nix runs Git, with that repository's configuration. + (s "lock-foreign-git" (let + elsewhere = "/var/krops-elsewhere"; + sources = alt // { + x.flake-input = { + url = "/fixtures/top"; name = "dep"; inherit fetchOnTarget; + materialize = true; + inputs.inner.follows = "alt"; + }; + y.file = { + path = "/fixtures/filesrc"; + deleteExcluded = false; + filters = [ { type = "exclude"; pattern = "/.git"; } ]; + inputs.dep.follows = "alt"; + }; + }; + in { + isolate = true; + prepare = '' + rm -fR ${elsewhere} + mkdir -p ${elsewhere} + ''; + phases = [ + { + inherit sources; + # Repositories tracking only flake.nix, so the lock file changes. + mutate = '' + for name in x y; do + git -C "$T"/$name init -q + git -C "$T"/$name add flake.nix + git -C "$T"/$name -c user.name=x -c user.email=x@x commit -q -m x + git -C "$T"/$name config core.fsmonitor "touch ${elsewhere}/ran; false" + done + ''; + } + { + inherit sources; + check = '' + test ! -e ${elsewhere}/ran || fail "a command in a .git directory ran" + ''; + } + ]; + })) # A file in populate's state replaced by a symlink to a file outside. (s "state-key" (let sources.x.flake-input = { |
