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: 65e88694c27a
Choose a base ref
...
head repository: NixOS/nix
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 134942f56a7a
Choose a head ref
  • 2 commits
  • 8 files changed
  • 1 contributor

Commits on May 31, 2019

  1. Verified

    This commit was signed with the committer’s verified signature.
    edolstra Eelco Dolstra
    Copy the full SHA
    094539e View commit details
  2. Merge pull request #2904 from NixOS/flake-terminology

    Rename requires -> inputs, provides -> outputs
    edolstra authored May 31, 2019

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    134942f View commit details
Showing with 112 additions and 111 deletions.
  1. +19 −18 doc/flakes/design.md
  2. +4 −4 flake.lock
  3. +5 −5 flake.nix
  4. +45 −45 src/libexpr/primops/flake.cc
  5. +3 −3 src/libexpr/primops/flake.hh
  6. +10 −10 src/nix/flake.cc
  7. +7 −7 src/nix/installables.cc
  8. +19 −19 tests/flakes.sh
37 changes: 19 additions & 18 deletions doc/flakes/design.md
Original file line number Diff line number Diff line change
@@ -103,12 +103,12 @@ module.
# A list of flake references denoting the flakes that this flake
# depends on. Nix will resolve and fetch these flakes and pass them
# as a function argument to `provides` below.
# as a function argument to `outputs` below.
#
# `flake:nixpkgs` denotes a flake named `nixpkgs` which is looked up
# in the flake registry, or in `flake.lock` inside this flake, if it
# exists.
requires = [ flake:nixpkgs ];
inputs = [ flake:nixpkgs ];
# The stuff provided by this flake. Flakes can provide whatever they
# want (convention over configuration), but some attributes have
@@ -117,9 +117,9 @@ module.
# `nixosModules` is used by NixOS to automatically pull in the
# modules provided by a flake.
#
# `provides` takes a single argument named `deps` that contains
# `outputs` takes a single argument named `deps` that contains
# the resolved set of flakes. (See below.)
provides = deps: {
outputs = deps: {
# This is searched by `nix`, so something like `nix install
# dwarffs.dwarffs` resolves to this `packages.dwarffs`.
@@ -168,7 +168,7 @@ Similarly, a minimal `flake.nix` for Nixpkgs:
description = "A collection of packages for the Nix package manager";
provides = deps:
outputs = deps:
let pkgs = import ./. {}; in
{
lib = import ./lib;
@@ -310,9 +310,9 @@ Example:
```


## `provides`
## `outputs`

The flake attribute `provides` is a function that takes an argument
The flake attribute `outputs` is a function that takes an argument
named `deps` and returns a (mostly) arbitrary attrset of values. Some
of the standard result attributes:

@@ -329,13 +329,13 @@ of the standard result attributes:
we need to avoid a situation where `nixos-rebuild` needs to fetch
its own `nixpkgs` just to do `evalModules`.)

* `shell`: A specification of a development environment in some TBD
* `devShell`: A specification of a development environment in some TBD
format.

The function argument `flakes` is an attrset that contains an
attribute for each dependency specified in `requires`. (Should it
attribute for each dependency specified in `inputs`. (Should it
contain transitive dependencies? Probably not.) Each attribute is an
attrset containing the `provides` of the dependency, in addition to
attrset containing the `outputs` of the dependency, in addition to
the following attributes:

* `path`: The path to the flake's source code. Useful when you want to
@@ -366,13 +366,13 @@ It may be useful to pull in repositories that are not flakes
(i.e. don't contain a `flake.nix`). This could be done in two ways:

* Allow flakes not to have a `flake.nix` file, in which case it's a
flake with no requires and no provides. The downside of this
flake with no inputs and no outputs. The downside of this
approach is that we can't detect accidental use of a non-flake
repository. (Also, we need to conjure up an identifier somehow.)

* Add a flake attribute to specifiy non-flake dependencies, e.g.

> nonFlakeRequires.foobar = github:foo/bar;
> nonFlakeInputs.foobar = github:foo/bar;

## Flake registry
@@ -454,7 +454,7 @@ The default installation source in `nix` is the `packages` from all
flakes in the registry, that is:
```
builtins.mapAttrs (flakeName: flakeInfo:
(getFlake flakeInfo.uri).${flakeName}.provides.packages or {})
(getFlake flakeInfo.uri).${flakeName}.outputs.packages or {})
builtins.flakeRegistry
```
(where `builtins.flakeRegistry` is the global registry with user
@@ -476,10 +476,11 @@ in the registry named `hello`.

Maybe the command

> nix shell
> nix dev-shell
should do something like use `provides.shell` to initialize the shell,
but probably we should ditch `nix shell` / `nix-shell` for direnv.
should do something like use `outputs.devShell` to initialize the
shell, but probably we should ditch `nix shell` / `nix-shell` for
direnv.


## Pure evaluation and caching
@@ -535,7 +536,7 @@ repositories.

```nix
{
provides = flakes: {
outputs = flakes: {
nixosSystems.default =
flakes.nixpkgs.lib.evalModules {
modules =
@@ -549,7 +550,7 @@ repositories.
};
};
requires =
inputs =
[ "nixpkgs/nixos-18.09"
"dwarffs"
"hydra"
8 changes: 4 additions & 4 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -5,13 +5,13 @@

epoch = 2019;

requires = [ "nixpkgs" ];
inputs = [ "nixpkgs" ];

provides = deps: rec {
outputs = inputs: rec {

hydraJobs = import ./release.nix {
nix = deps.self;
nixpkgs = deps.nixpkgs;
nix = inputs.self;
nixpkgs = inputs.nixpkgs;
};

checks = {
@@ -29,7 +29,7 @@
defaultPackage = packages.nix;

devShell = import ./shell.nix {
nixpkgs = deps.nixpkgs;
nixpkgs = inputs.nixpkgs;
};
};
}
90 changes: 45 additions & 45 deletions src/libexpr/primops/flake.cc
Original file line number Diff line number Diff line change
@@ -56,21 +56,21 @@ LockFile::FlakeEntry readFlakeEntry(nlohmann::json json)
if (!flakeRef.isImmutable())
throw Error("cannot use mutable flake '%s' in pure mode", flakeRef);

LockFile::FlakeEntry entry(flakeRef, Hash((std::string) json["contentHash"]));
LockFile::FlakeEntry entry(flakeRef, Hash((std::string) json["narHash"]));

auto nonFlakeRequires = json["nonFlakeRequires"];
auto nonFlakeInputs = json["nonFlakeInputs"];

for (auto i = nonFlakeRequires.begin(); i != nonFlakeRequires.end(); ++i) {
for (auto i = nonFlakeInputs.begin(); i != nonFlakeInputs.end(); ++i) {
FlakeRef flakeRef(i->value("uri", ""));
if (!flakeRef.isImmutable())
throw Error("requested to fetch FlakeRef '%s' purely, which is mutable", flakeRef);
LockFile::NonFlakeEntry nonEntry(flakeRef, Hash(i->value("contentHash", "")));
LockFile::NonFlakeEntry nonEntry(flakeRef, Hash(i->value("narHash", "")));
entry.nonFlakeEntries.insert_or_assign(i.key(), nonEntry);
}

auto requires = json["requires"];
auto inputs = json["inputs"];

for (auto i = requires.begin(); i != requires.end(); ++i)
for (auto i = inputs.begin(); i != inputs.end(); ++i)
entry.flakeEntries.insert_or_assign(i.key(), readFlakeEntry(*i));

return entry;
@@ -89,19 +89,19 @@ LockFile readLockFile(const Path & path)
if (version != 1)
throw Error("lock file '%s' has unsupported version %d", path, version);

auto nonFlakeRequires = json["nonFlakeRequires"];
auto nonFlakeInputs = json["nonFlakeInputs"];

for (auto i = nonFlakeRequires.begin(); i != nonFlakeRequires.end(); ++i) {
for (auto i = nonFlakeInputs.begin(); i != nonFlakeInputs.end(); ++i) {
FlakeRef flakeRef(i->value("uri", ""));
LockFile::NonFlakeEntry nonEntry(flakeRef, Hash(i->value("contentHash", "")));
LockFile::NonFlakeEntry nonEntry(flakeRef, Hash(i->value("narHash", "")));
if (!flakeRef.isImmutable())
throw Error("found mutable FlakeRef '%s' in lockfile at path %s", flakeRef, path);
lockFile.nonFlakeEntries.insert_or_assign(i.key(), nonEntry);
}

auto requires = json["requires"];
auto inputs = json["inputs"];

for (auto i = requires.begin(); i != requires.end(); ++i)
for (auto i = inputs.begin(); i != inputs.end(); ++i)
lockFile.flakeEntries.insert_or_assign(i.key(), readFlakeEntry(*i));

return lockFile;
@@ -111,28 +111,28 @@ nlohmann::json flakeEntryToJson(const LockFile::FlakeEntry & entry)
{
nlohmann::json json;
json["uri"] = entry.ref.to_string();
json["contentHash"] = entry.narHash.to_string(SRI);
json["narHash"] = entry.narHash.to_string(SRI);
for (auto & x : entry.nonFlakeEntries) {
json["nonFlakeRequires"][x.first]["uri"] = x.second.ref.to_string();
json["nonFlakeRequires"][x.first]["contentHash"] = x.second.narHash.to_string(SRI);
json["nonFlakeInputs"][x.first]["uri"] = x.second.ref.to_string();
json["nonFlakeInputs"][x.first]["narHash"] = x.second.narHash.to_string(SRI);
}
for (auto & x : entry.flakeEntries)
json["requires"][x.first.to_string()] = flakeEntryToJson(x.second);
json["inputs"][x.first.to_string()] = flakeEntryToJson(x.second);
return json;
}

void writeLockFile(const LockFile & lockFile, const Path & path)
{
nlohmann::json json;
json["version"] = 1;
json["nonFlakeRequires"] = nlohmann::json::object();
json["nonFlakeInputs"] = nlohmann::json::object();
for (auto & x : lockFile.nonFlakeEntries) {
json["nonFlakeRequires"][x.first]["uri"] = x.second.ref.to_string();
json["nonFlakeRequires"][x.first]["contentHash"] = x.second.narHash.to_string(SRI);
json["nonFlakeInputs"][x.first]["uri"] = x.second.ref.to_string();
json["nonFlakeInputs"][x.first]["narHash"] = x.second.narHash.to_string(SRI);
}
json["requires"] = nlohmann::json::object();
json["inputs"] = nlohmann::json::object();
for (auto & x : lockFile.flakeEntries)
json["requires"][x.first.to_string()] = flakeEntryToJson(x.second);
json["inputs"][x.first.to_string()] = flakeEntryToJson(x.second);
createDirs(dirOf(path));
writeFile(path, json.dump(4) + "\n"); // '4' = indentation in json file
}
@@ -319,41 +319,41 @@ Flake getFlake(EvalState & state, const FlakeRef & flakeRef, bool impureIsAllowe
if (auto description = vInfo.attrs->get(state.sDescription))
flake.description = state.forceStringNoCtx(*(**description).value, *(**description).pos);

auto sRequires = state.symbols.create("requires");
auto sInputs = state.symbols.create("inputs");

if (auto requires = vInfo.attrs->get(sRequires)) {
state.forceList(*(**requires).value, *(**requires).pos);
for (unsigned int n = 0; n < (**requires).value->listSize(); ++n)
flake.requires.push_back(FlakeRef(state.forceStringNoCtx(
*(**requires).value->listElems()[n], *(**requires).pos)));
if (auto inputs = vInfo.attrs->get(sInputs)) {
state.forceList(*(**inputs).value, *(**inputs).pos);
for (unsigned int n = 0; n < (**inputs).value->listSize(); ++n)
flake.inputs.push_back(FlakeRef(state.forceStringNoCtx(
*(**inputs).value->listElems()[n], *(**inputs).pos)));
}

auto sNonFlakeRequires = state.symbols.create("nonFlakeRequires");
auto sNonFlakeInputs = state.symbols.create("nonFlakeInputs");

if (std::optional<Attr *> nonFlakeRequires = vInfo.attrs->get(sNonFlakeRequires)) {
state.forceAttrs(*(**nonFlakeRequires).value, *(**nonFlakeRequires).pos);
for (Attr attr : *(*(**nonFlakeRequires).value).attrs) {
if (std::optional<Attr *> nonFlakeInputs = vInfo.attrs->get(sNonFlakeInputs)) {
state.forceAttrs(*(**nonFlakeInputs).value, *(**nonFlakeInputs).pos);
for (Attr attr : *(*(**nonFlakeInputs).value).attrs) {
std::string myNonFlakeUri = state.forceStringNoCtx(*attr.value, *attr.pos);
FlakeRef nonFlakeRef = FlakeRef(myNonFlakeUri);
flake.nonFlakeRequires.insert_or_assign(attr.name, nonFlakeRef);
flake.nonFlakeInputs.insert_or_assign(attr.name, nonFlakeRef);
}
}

auto sProvides = state.symbols.create("provides");
auto sOutputs = state.symbols.create("outputs");

if (auto provides = vInfo.attrs->get(sProvides)) {
state.forceFunction(*(**provides).value, *(**provides).pos);
flake.vProvides = (**provides).value;
if (auto outputs = vInfo.attrs->get(sOutputs)) {
state.forceFunction(*(**outputs).value, *(**outputs).pos);
flake.vOutputs = (**outputs).value;
} else
throw Error("flake '%s' lacks attribute 'provides'", flakeRef);
throw Error("flake '%s' lacks attribute 'outputs'", flakeRef);

for (auto & attr : *vInfo.attrs) {
if (attr.name != sEpoch &&
attr.name != state.sName &&
attr.name != state.sDescription &&
attr.name != sRequires &&
attr.name != sNonFlakeRequires &&
attr.name != sProvides)
attr.name != sInputs &&
attr.name != sNonFlakeInputs &&
attr.name != sOutputs)
throw Error("flake '%s' has an unsupported attribute '%s', at %s",
flakeRef, attr.name, *attr.pos);
}
@@ -436,7 +436,7 @@ ResolvedFlake resolveFlakeFromLockFile(EvalState & state, const FlakeRef & flake

ResolvedFlake deps(flake);

for (auto & nonFlakeInfo : flake.nonFlakeRequires) {
for (auto & nonFlakeInfo : flake.nonFlakeInputs) {
FlakeRef ref = nonFlakeInfo.second;
auto i = lockFile.nonFlakeEntries.find(nonFlakeInfo.first);
if (i != lockFile.nonFlakeEntries.end()) {
@@ -451,7 +451,7 @@ ResolvedFlake resolveFlakeFromLockFile(EvalState & state, const FlakeRef & flake
}
}

for (auto newFlakeRef : flake.requires) {
for (auto newFlakeRef : flake.inputs) {
auto i = lockFile.flakeEntries.find(newFlakeRef);
if (i != lockFile.flakeEntries.end()) { // Propagate lockFile downwards if possible
ResolvedFlake newResFlake = resolveFlakeFromLockFile(state, i->second.ref, handleLockFile, entryToLockFile(i->second));
@@ -532,8 +532,8 @@ static void emitSourceInfoAttrs(EvalState & state, const SourceInfo & sourceInfo

void callFlake(EvalState & state, const ResolvedFlake & resFlake, Value & v)
{
// Construct the resulting attrset '{description, provides,
// ...}'. This attrset is passed lazily as an argument to 'provides'.
// Construct the resulting attrset '{description, outputs,
// ...}'. This attrset is passed lazily as an argument to 'outputs'.

state.mkAttrs(v, resFlake.flakeDeps.size() + resFlake.nonFlakeDeps.size() + 8);

@@ -558,8 +558,8 @@ void callFlake(EvalState & state, const ResolvedFlake & resFlake, Value & v)

emitSourceInfoAttrs(state, resFlake.flake.sourceInfo, v);

auto vProvides = state.allocAttr(v, state.symbols.create("provides"));
mkApp(*vProvides, *resFlake.flake.vProvides, v);
auto vOutputs = state.allocAttr(v, state.symbols.create("outputs"));
mkApp(*vOutputs, *resFlake.flake.vOutputs, v);

v.attrs->push_back(Attr(state.symbols.create("self"), &v));

6 changes: 3 additions & 3 deletions src/libexpr/primops/flake.hh
Original file line number Diff line number Diff line change
@@ -106,9 +106,9 @@ struct Flake
FlakeRef originalRef;
std::string description;
SourceInfo sourceInfo;
std::vector<FlakeRef> requires;
std::map<FlakeAlias, FlakeRef> nonFlakeRequires;
Value * vProvides; // FIXME: gc
std::vector<FlakeRef> inputs;
std::map<FlakeAlias, FlakeRef> nonFlakeInputs;
Value * vOutputs; // FIXME: gc
unsigned int epoch;

Flake(const FlakeRef & origRef, const SourceInfo & sourceInfo)
20 changes: 10 additions & 10 deletions src/nix/flake.cc
Original file line number Diff line number Diff line change
@@ -199,16 +199,16 @@ struct CmdFlakeUpdate : FlakeCommand
}
};

static void enumerateProvides(EvalState & state, Value & vFlake,
static void enumerateOutputs(EvalState & state, Value & vFlake,
std::function<void(const std::string & name, Value & vProvide)> callback)
{
state.forceAttrs(vFlake);

auto vProvides = (*vFlake.attrs->get(state.symbols.create("provides")))->value;
auto vOutputs = (*vFlake.attrs->get(state.symbols.create("outputs")))->value;

state.forceAttrs(*vProvides);
state.forceAttrs(*vOutputs);

for (auto & attr : *vProvides->attrs)
for (auto & attr : *vOutputs->attrs)
callback(attr.name, *attr.value);
}

@@ -237,9 +237,9 @@ struct CmdFlakeInfo : FlakeCommand, MixJSON
auto vFlake = state->allocValue();
flake::callFlake(*state, flake, *vFlake);

auto provides = nlohmann::json::object();
auto outputs = nlohmann::json::object();

enumerateProvides(*state,
enumerateOutputs(*state,
*vFlake,
[&](const std::string & name, Value & vProvide) {
auto provide = nlohmann::json::object();
@@ -250,10 +250,10 @@ struct CmdFlakeInfo : FlakeCommand, MixJSON
provide[aCheck.name] = nlohmann::json::object();
}

provides[name] = provide;
outputs[name] = provide;
});

json["provides"] = std::move(provides);
json["outputs"] = std::move(outputs);

std::cout << json.dump() << std::endl;
} else
@@ -298,7 +298,7 @@ struct CmdFlakeCheck : FlakeCommand, MixJSON
// FIXME: check meta attributes
return drvInfo->queryDrvPath();
} catch (Error & e) {
e.addPrefix(fmt("while checking flake attribute '" ANSI_BOLD "%s" ANSI_NORMAL "':\n", attrPath));
e.addPrefix(fmt("while checking flake output attribute '" ANSI_BOLD "%s" ANSI_NORMAL "':\n", attrPath));
throw;
}
};
@@ -311,7 +311,7 @@ struct CmdFlakeCheck : FlakeCommand, MixJSON
auto vFlake = state->allocValue();
flake::callFlake(*state, flake, *vFlake);

enumerateProvides(*state,
enumerateOutputs(*state,
*vFlake,
[&](const std::string & name, Value & vProvide) {
Activity act(*logger, lvlChatty, actUnknown,
14 changes: 7 additions & 7 deletions src/nix/installables.cc
Original file line number Diff line number Diff line change
@@ -230,16 +230,16 @@ struct InstallableFlake : InstallableValue

makeFlakeClosureGCRoot(*state.store, flakeRef, resFlake);

auto vProvides = (*vFlake->attrs->get(state.symbols.create("provides")))->value;
auto vOutputs = (*vFlake->attrs->get(state.symbols.create("outputs")))->value;

state.forceValue(*vProvides);
state.forceValue(*vOutputs);

auto emptyArgs = state.allocBindings(0);

if (searchPackages) {
// As a convenience, look for the attribute in
// 'provides.packages'.
if (auto aPackages = *vProvides->attrs->get(state.symbols.create("packages"))) {
// 'outputs.packages'.
if (auto aPackages = *vOutputs->attrs->get(state.symbols.create("packages"))) {
try {
auto * v = findAlongAttrPath(state, *attrPaths.begin(), *emptyArgs, *aPackages->value);
state.forceValue(*v);
@@ -250,7 +250,7 @@ struct InstallableFlake : InstallableValue

// As a temporary hack until Nixpkgs is properly converted
// to provide a clean 'packages' set, look in 'legacyPackages'.
if (auto aPackages = *vProvides->attrs->get(state.symbols.create("legacyPackages"))) {
if (auto aPackages = *vOutputs->attrs->get(state.symbols.create("legacyPackages"))) {
try {
auto * v = findAlongAttrPath(state, *attrPaths.begin(), *emptyArgs, *aPackages->value);
state.forceValue(*v);
@@ -260,10 +260,10 @@ struct InstallableFlake : InstallableValue
}
}

// Otherwise, look for it in 'provides'.
// Otherwise, look for it in 'outputs'.
for (auto & attrPath : attrPaths) {
try {
auto * v = findAlongAttrPath(state, attrPath, *emptyArgs, *vProvides);
auto * v = findAlongAttrPath(state, attrPath, *emptyArgs, *vOutputs);
state.forceValue(*v);
return v;
} catch (AttrPathNotFound & e) {
38 changes: 19 additions & 19 deletions tests/flakes.sh
Original file line number Diff line number Diff line change
@@ -33,7 +33,7 @@ cat > $flake1Dir/flake.nix <<EOF
description = "Bla bla";
provides = deps: rec {
outputs = inputs: rec {
packages.foo = import ./simple.nix;
defaultPackage = packages.foo;
};
@@ -50,12 +50,12 @@ cat > $flake2Dir/flake.nix <<EOF
epoch = 2019;
requires = [ "flake1" ];
inputs = [ "flake1" ];
description = "Fnord";
provides = deps: rec {
packages.bar = deps.flake1.provides.packages.foo;
outputs = inputs: rec {
packages.bar = inputs.flake1.outputs.packages.foo;
};
}
EOF
@@ -69,12 +69,12 @@ cat > $flake3Dir/flake.nix <<EOF
epoch = 2019;
requires = [ "flake2" ];
inputs = [ "flake2" ];
description = "Fnord";
provides = deps: rec {
packages.xyzzy = deps.flake2.provides.packages.bar;
outputs = inputs: rec {
packages.xyzzy = inputs.flake2.outputs.packages.bar;
};
}
EOF
@@ -168,13 +168,13 @@ cat > $flake3Dir/flake.nix <<EOF
epoch = 2019;
requires = [ "flake1" "flake2" ];
inputs = [ "flake1" "flake2" ];
description = "Fnord";
provides = deps: rec {
packages.xyzzy = deps.flake2.provides.packages.bar;
packages.sth = deps.flake1.provides.packages.foo;
outputs = inputs: rec {
packages.xyzzy = inputs.flake2.outputs.packages.bar;
packages.sth = inputs.flake1.outputs.packages.foo;
};
}
EOF
@@ -209,7 +209,7 @@ nix build -o $TEST_ROOT/result --flake-registry file://$registry file://$flake2D
mv $flake1Dir.tmp $flake1Dir
mv $flake2Dir.tmp $flake2Dir

# Add nonFlakeRequires to flake3.
# Add nonFlakeInputs to flake3.
rm $flake3Dir/flake.nix

cat > $flake3Dir/flake.nix <<EOF
@@ -218,23 +218,23 @@ cat > $flake3Dir/flake.nix <<EOF
epoch = 2019;
requires = [ "flake1" "flake2" ];
inputs = [ "flake1" "flake2" ];
nonFlakeRequires = {
nonFlakeInputs = {
nonFlake = "$nonFlakeDir";
};
description = "Fnord";
provides = deps: rec {
packages.xyzzy = deps.flake2.provides.packages.bar;
packages.sth = deps.flake1.provides.packages.foo;
outputs = inputs: rec {
packages.xyzzy = inputs.flake2.outputs.packages.bar;
packages.sth = inputs.flake1.outputs.packages.foo;
};
}
EOF

git -C $flake3Dir add flake.nix
git -C $flake3Dir commit -m 'Add nonFlakeRequires'
git -C $flake3Dir commit -m 'Add nonFlakeInputs'

# Check whether `nix build` works with a lockfile which is missing a nonFlakeRequires
# Check whether `nix build` works with a lockfile which is missing a nonFlakeInputs
nix build -o $TEST_ROOT/result --flake-registry $registry $flake3Dir:sth