From d5334c466b9ee237a1cce4fd005d790e67d74822 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Sun, 2 Feb 2020 16:32:46 +0100 Subject: [PATCH] Automatically do git/hg add on flake.lock --- src/libexpr/flake/flake.cc | 25 +++++++++++++------------ src/libstore/fetchers/fetchers.hh | 3 +++ src/libstore/fetchers/git.cc | 12 ++++++++++++ src/libstore/fetchers/mercurial.cc | 11 +++++++++++ tests/flakes.sh | 19 ++++++++----------- 5 files changed, 47 insertions(+), 23 deletions(-) diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index 39fdc776c..5018b460b 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -579,22 +579,23 @@ LockedFlake lockFlake( newLockFile.write(path); - // Rewriting the lockfile changed the top-level - // repo, so we should re-read it. + topRef.input->markChangedFile( + (topRef.subdir == "" ? "" : topRef.subdir + "/") + "flake.lock"); + + /* Rewriting the lockfile changed the top-level + repo, so we should re-read it. FIXME: we could + also just clear the 'rev' field... */ + auto prevLockedRef = flake.lockedRef; FlakeCache dummyCache; flake = getFlake(state, topRef, {}, lockFlags.useRegistries, dummyCache); - if (flake.lockedRef.input->isImmutable()) + /* Make sure that we picked up the change, + i.e. the tree should usually be dirty + now. Corner case: we could have reverted from a + dirty to a clean tree! */ + if (flake.lockedRef.input == prevLockedRef.input + && !flake.lockedRef.input->isImmutable()) throw Error("'%s' did not change after I updated its 'flake.lock' file; is 'flake.lock' under version control?", flake.originalRef); - - #if 0 - // Hack: Make sure that flake.lock is visible to Git, so it ends up in the Nix store. - runProgram("git", true, - { "-C", *sourcePath, "add", - "--force", - "--intent-to-add", - (topRef.subdir == "" ? "" : topRef.subdir + "/") + "flake.lock" }); - #endif } } else throw Error("cannot write modified lock file of flake '%s' (use '--no-write-lock-file' to ignore)", topRef); diff --git a/src/libstore/fetchers/fetchers.hh b/src/libstore/fetchers/fetchers.hh index 0ef79bc45..64628d1bb 100644 --- a/src/libstore/fetchers/fetchers.hh +++ b/src/libstore/fetchers/fetchers.hh @@ -62,6 +62,9 @@ struct Input : std::enable_shared_from_this virtual std::optional getSourcePath() const { return {}; } + // FIXME: should merge with getSourcePath(). + virtual void markChangedFile(std::string_view file) const { assert(false); } + virtual void clone(const Path & destDir) const { throw Error("do not know how to clone input '%s'", to_string()); diff --git a/src/libstore/fetchers/git.cc b/src/libstore/fetchers/git.cc index 0101744bd..1c74d92a4 100644 --- a/src/libstore/fetchers/git.cc +++ b/src/libstore/fetchers/git.cc @@ -165,6 +165,18 @@ struct GitInput : Input return {}; } + void markChangedFile(std::string_view file) const override + { + auto sourcePath = getSourcePath(); + assert(sourcePath); + runProgram("git", true, + { "-C", *sourcePath, "add", + "--force", + "--intent-to-add", + std::string(file) + }); + } + std::pair getActualUrl() const { // Don't clone file:// URIs (but otherwise treat them the diff --git a/src/libstore/fetchers/mercurial.cc b/src/libstore/fetchers/mercurial.cc index 9b8c2132c..0825f6b23 100644 --- a/src/libstore/fetchers/mercurial.cc +++ b/src/libstore/fetchers/mercurial.cc @@ -84,6 +84,17 @@ struct MercurialInput : Input return {}; } + void markChangedFile(std::string_view file) const override + { + auto sourcePath = getSourcePath(); + assert(sourcePath); + // FIXME: shut up if file is already tracked. + runProgram("hg", true, + { "add", + *sourcePath + "/" + std::string(file) + }); + } + std::pair getActualUrl() const { bool isLocal = url.scheme == "file"; diff --git a/tests/flakes.sh b/tests/flakes.sh index 5a00d8671..63e7f8e87 100644 --- a/tests/flakes.sh +++ b/tests/flakes.sh @@ -5,6 +5,11 @@ if [[ -z $(type -p git) ]]; then exit 99 fi +if [[ -z $(type -p hg) ]]; then + echo "Mercurial not installed; skipping flake tests" + exit 99 +fi + clearStore rm -rf $TEST_HOME/.cache $TEST_HOME/.config @@ -372,7 +377,7 @@ nix flake remove flake1 (cd $flake7Dir && nix flake init) git -C $flake7Dir add flake.nix nix flake check $flake7Dir -git -C $flake7Dir commit -m 'Initial' +git -C $flake7Dir commit -a -m 'Initial' # Test 'nix flake clone'. rm -rf $TEST_ROOT/flake1-v2 @@ -545,11 +550,6 @@ nix flake update $flake3Dir --recreate-lock-file [[ $(jq .inputs.flake2.inputs.flake1.locked.url $flake3Dir/flake.lock) =~ flake7 ]] # Test Mercurial flakes. -if [[ -z $(type -p hg) ]]; then - echo "Git not installed; skipping Mercurial flake tests" - exit 99 -fi - rm -rf $flake5Dir hg init $flake5Dir @@ -571,12 +571,9 @@ hg commit --config ui.username=foobar@example.org $flake5Dir -m 'Initial commit' nix build -o $TEST_ROOT/result hg+file://$flake5Dir [[ -e $TEST_ROOT/result/hello ]] -nix flake info --json hg+file://$flake5Dir | jq -e -r .revision +(! nix flake info --json hg+file://$flake5Dir | jq -e -r .revision) -# This will fail because flake.lock is not tracked by Mercurial. -(! nix eval hg+file://$flake5Dir#expr) - -hg add $flake5Dir/flake.lock +nix eval hg+file://$flake5Dir#expr nix eval hg+file://$flake5Dir#expr