Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: NixOS/nix
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: e53c89a64388
Choose a base ref
...
head repository: NixOS/nix
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: f68bed7f67d9
Choose a head ref
  • 1 commit
  • 8 files changed
  • 1 contributor

Commits on Jan 29, 2020

  1. Add flag --override-input to override specific lock file entries

    E.g.
    
      $ nix flake update ~/Misc/eelco-configurations/hagbard \
        --override-input 'dwarffs/nixpkgs' ../my-nixpkgs
    
    overrides the 'nixpkgs' input of the 'dwarffs' input of the top-level
    flake.
    
    Fixes #2837.
    edolstra committed Jan 29, 2020
    Copy the full SHA
    f68bed7 View commit details
Showing with 75 additions and 26 deletions.
  1. +12 −20 src/libexpr/flake/flake.cc
  2. +10 −1 src/libexpr/flake/flake.hh
  3. +17 −0 src/libexpr/flake/lockfile.cc
  4. +2 −0 src/libexpr/flake/lockfile.hh
  5. +3 −2 src/nix/command.hh
  6. +1 −1 src/nix/flake.cc
  7. +13 −2 src/nix/installables.cc
  8. +17 −0 tests/flakes.sh
32 changes: 12 additions & 20 deletions src/libexpr/flake/flake.cc
Original file line number Diff line number Diff line change
@@ -4,7 +4,6 @@
#include "eval-inline.hh"
#include "store-api.hh"
#include "fetchers/fetchers.hh"
#include "fetchers/regex.hh"

#include <iostream>
#include <ctime>
@@ -62,22 +61,6 @@ static void expectType(EvalState & state, ValueType type,
showType(type), showType(value.type), pos);
}

static InputPath parseInputPath(std::string_view s, const Pos & pos)
{
InputPath path;

for (auto & elem : tokenizeString<std::vector<std::string>>(s, "/")) {
if (!std::regex_match(elem, fetchers::flakeIdRegex))
throw Error("invalid flake input path element '%s' at %s", elem, pos);
path.push_back(elem);
}

if (path.empty())
throw Error("flake input path is empty at %s", pos);

return path;
}

static std::map<FlakeId, FlakeInput> parseFlakeInputs(
EvalState & state, Value * value, const Pos & pos);

@@ -107,7 +90,11 @@ static FlakeInput parseFlakeInput(EvalState & state,
input.overrides = parseFlakeInputs(state, attr.value, *attr.pos);
} else if (attr.name == sFollows) {
expectType(state, tString, *attr.value, *attr.pos);
input.follows = parseInputPath(attr.value->string.s, *attr.pos);
try {
input.follows = parseInputPath(attr.value->string.s);
} catch (Error & e) {
e.addPrefix("in flake attribute at '%s':\n");
}
} else
throw Error("flake input '%s' has an unsupported attribute '%s', at %s",
inputName, attr.name, *attr.pos);
@@ -324,7 +311,8 @@ static std::string diffLockFiles(const LockedInputs & oldLocks, const LockedInpu
LockedFlake lockFlake(
EvalState & state,
const FlakeRef & topRef,
LockFileMode lockFileMode)
LockFileMode lockFileMode,
const LockFlags & lockFlags)
{
settings.requireExperimentalFeature("flakes");

@@ -350,6 +338,9 @@ LockedFlake lockFlake(
// FIXME: check whether all overrides are used.
std::map<InputPath, FlakeInput> overrides;

for (auto & i : lockFlags.inputOverrides)
overrides.insert_or_assign(i.first, FlakeInput { .ref = i.second });

/* Compute the new lock file. This is dones as a fixpoint
iteration: we repeat until the new lock file no longer changes
and there are no unresolved "follows" inputs. */
@@ -664,8 +655,9 @@ void callFlake(EvalState & state,
// This function is exposed to be used in nix files.
static void prim_getFlake(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
LockFlags lockFlags;
callFlake(state, lockFlake(state, parseFlakeRef(state.forceStringNoCtx(*args[0], pos)),
evalSettings.pureEval ? AllPure : UseUpdatedLockFile), v);
evalSettings.pureEval ? AllPure : UseUpdatedLockFile, lockFlags), v);
}

static RegisterPrimOp r2("getFlake", 1, prim_getFlake);
11 changes: 10 additions & 1 deletion src/libexpr/flake/flake.hh
Original file line number Diff line number Diff line change
@@ -59,7 +59,16 @@ struct LockedFlake
Fingerprint getFingerprint() const;
};

LockedFlake lockFlake(EvalState &, const FlakeRef &, LockFileMode);
struct LockFlags
{
std::map<InputPath, FlakeRef> inputOverrides;
};

LockedFlake lockFlake(
EvalState &,
const FlakeRef &,
LockFileMode,
const LockFlags &);

void callFlake(EvalState & state,
const Flake & flake,
17 changes: 17 additions & 0 deletions src/libexpr/flake/lockfile.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "lockfile.hh"
#include "store-api.hh"
#include "fetchers/regex.hh"

#include <nlohmann/json.hpp>

@@ -104,4 +105,20 @@ void LockFile::write(const Path & path) const
writeFile(path, fmt("%s\n", *this));
}

InputPath parseInputPath(std::string_view s)
{
InputPath path;

for (auto & elem : tokenizeString<std::vector<std::string>>(s, "/")) {
if (!std::regex_match(elem, fetchers::flakeIdRegex))
throw Error("invalid flake input path element '%s'", elem);
path.push_back(elem);
}

if (path.empty())
throw Error("flake input path is empty");

return path;
}

}
2 changes: 2 additions & 0 deletions src/libexpr/flake/lockfile.hh
Original file line number Diff line number Diff line change
@@ -81,5 +81,7 @@ struct LockFile : LockedInputs

std::ostream & operator <<(std::ostream & stream, const LockFile & lockFile);

InputPath parseInputPath(std::string_view s);

}

5 changes: 3 additions & 2 deletions src/nix/command.hh
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@
#include "args.hh"
#include "common-eval-args.hh"
#include "path.hh"
#include "flake/lockfile.hh"

#include <optional>

@@ -42,11 +43,11 @@ struct EvalCommand : virtual StoreCommand, MixEvalArgs
struct MixFlakeOptions : virtual Args
{
bool recreateLockFile = false;

bool saveLockFile = true;

bool useRegistries = true;

flake::LockFlags lockFlags;

MixFlakeOptions();

flake::LockFileMode getLockFileMode();
2 changes: 1 addition & 1 deletion src/nix/flake.cc
Original file line number Diff line number Diff line change
@@ -43,7 +43,7 @@ class FlakeCommand : virtual Args, public EvalCommand, public MixFlakeOptions

LockedFlake lockFlake()
{
return flake::lockFlake(*getEvalState(), getFlakeRef(), getLockFileMode());
return flake::lockFlake(*getEvalState(), getFlakeRef(), getLockFileMode(), lockFlags);
}
};

15 changes: 13 additions & 2 deletions src/nix/installables.cc
Original file line number Diff line number Diff line change
@@ -33,6 +33,17 @@ MixFlakeOptions::MixFlakeOptions()
.longName("no-registries")
.description("don't use flake registries")
.set(&useRegistries, false);

mkFlag()
.longName("override-input")
.description("override a specific flake input (e.g. 'dwarffs/nixpkgs')")
.arity(2)
.labels({"input-path", "flake-url"})
.handler([&](std::vector<std::string> ss) {
lockFlags.inputOverrides.insert_or_assign(
flake::parseInputPath(ss[0]),
parseFlakeRef(ss[1], absPath(".")));
});
}

flake::LockFileMode MixFlakeOptions::getLockFileMode()
@@ -321,7 +332,7 @@ std::tuple<std::string, FlakeRef, flake::EvalCache::Derivation> InstallableFlake
{
auto state = cmd.getEvalState();

auto lockedFlake = lockFlake(*state, flakeRef, cmd.getLockFileMode());
auto lockedFlake = lockFlake(*state, flakeRef, cmd.getLockFileMode(), cmd.lockFlags);

Value * vOutputs = nullptr;

@@ -375,7 +386,7 @@ std::vector<flake::EvalCache::Derivation> InstallableFlake::toDerivations()

Value * InstallableFlake::toValue(EvalState & state)
{
auto lockedFlake = lockFlake(state, flakeRef, cmd.getLockFileMode());
auto lockedFlake = lockFlake(state, flakeRef, cmd.getLockFileMode(), cmd.lockFlags);

auto vOutputs = getFlakeOutputs(state, lockedFlake);

17 changes: 17 additions & 0 deletions tests/flakes.sh
Original file line number Diff line number Diff line change
@@ -129,6 +129,12 @@ json=$(nix flake info flake1 --json | jq .)
[[ $(echo "$json" | jq -r .description) = 'Bla bla' ]]
[[ -d $(echo "$json" | jq -r .path) ]]
[[ $(echo "$json" | jq -r .lastModified) = $(git -C $flake1Dir log -n1 --format=%ct) ]]
hash1=$(echo "$json" | jq -r .revision)

echo -n '# foo' >> $flake1Dir/flake.nix
git -C $flake1Dir commit -a -m 'Foo'
hash2=$(nix flake info flake1 --json --refresh | jq -r .revision)
[[ $hash1 != $hash2 ]]

# Test 'nix build' on a flake.
nix build -o $TEST_ROOT/result flake1#foo
@@ -587,3 +593,14 @@ nix build -o $TEST_ROOT/result $url

# Building with an incorrect SRI hash should fail.
nix build -o $TEST_ROOT/result "file://$TEST_ROOT/flake.tar.gz?narHash=sha256-qQ2Zz4DNHViCUrp6gTS7EE4+RMqFQtUfWF2UNUtJKS0=" 2>&1 | grep 'NAR hash mismatch'

# Test --override-input.
git -C $flake3Dir reset --hard
nix flake update $flake3Dir --override-input flake2/flake1 flake5
[[ $(jq .inputs.flake2.inputs.flake1.url $flake3Dir/flake.lock) =~ flake5 ]]

nix flake update $flake3Dir --override-input flake2/flake1 flake1
[[ $(jq .inputs.flake2.inputs.flake1.url $flake3Dir/flake.lock) =~ flake1.*rev=$hash2 ]]

nix flake update $flake3Dir --override-input flake2/flake1 flake1/master/$hash1
[[ $(jq .inputs.flake2.inputs.flake1.url $flake3Dir/flake.lock) =~ flake1.*rev=$hash1 ]]