Skip to content

Commit

Permalink
Overhaul nix flake update and lock commands
Browse files Browse the repository at this point in the history
Closes #5110
  • Loading branch information
iFreilicht committed Aug 12, 2023
1 parent 4c07321 commit 944f6ab
Show file tree
Hide file tree
Showing 10 changed files with 113 additions and 75 deletions.
14 changes: 14 additions & 0 deletions doc/manual/src/release-notes/rl-next.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,17 @@

- The JSON output for derived paths with are store paths is now a string, not an object with a single `path` field.
This only affects `nix-build --json` when "building" non-derivation things like fetched sources, which is a no-op.


- The interface for creating and updating lock files has been overhauled:

- [`nix flake lock`](@docroot@/command-ref/new-cli/nix3-flake-lock.md) only creates lock files and adds missing inputs now.
It will *never* update existing inputs.

- [`nix flake update`](@docroot@/command-ref/new-cli/nix3-flake-update.md) does the same, but *will* update inputs.
- Passing no arguments will update all inputs of the current flake, just like it already did.
- Passing input names as arguments will ensure only those are updated. This replaces the functionality of `nix flake lock --update-input`
- To operate on a flake outside the current directory, you must now pass `--flake path/to/flake`.

- The flake-specific flags `--recreate-lock-file` and `--update-input` have been removed from all commands operating on installables.
They are superceded by `nix flake update`.
20 changes: 0 additions & 20 deletions src/libcmd/installables.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,6 @@ MixFlakeOptions::MixFlakeOptions()
{
auto category = "Common flake-related options";

addFlag({
.longName = "recreate-lock-file",
.description = "Recreate the flake's lock file from scratch.",
.category = category,
.handler = {&lockFlags.recreateLockFile, true}
});

addFlag({
.longName = "no-update-lock-file",
.description = "Do not allow any updates to the flake's lock file.",
Expand Down Expand Up @@ -71,19 +64,6 @@ MixFlakeOptions::MixFlakeOptions()
.handler = {&lockFlags.commitLockFile, true}
});

addFlag({
.longName = "update-input",
.description = "Update a specific flake input (ignoring its previous entry in the lock file).",
.category = category,
.labels = {"input-path"},
.handler = {[&](std::string s) {
lockFlags.inputUpdates.insert(flake::parseInputPath(s));
}},
.completer = {[&](size_t, std::string_view prefix) {
needsFlakeInputCompletion = {std::string(prefix)};
}}
});

addFlag({
.longName = "override-input",
.description = "Override a specific flake input (e.g. `dwarffs/nixpkgs`). This implies `--no-write-lock-file`.",
Expand Down
11 changes: 5 additions & 6 deletions src/libexpr/flake/flake.cc
Original file line number Diff line number Diff line change
Expand Up @@ -447,8 +447,8 @@ LockedFlake lockFlake(

assert(input.ref);

/* Do we have an entry in the existing lock file? And we
don't have a --update-input flag for this input? */
/* Do we have an entry in the existing lock file?
And the input is not in updateInputs? */
std::shared_ptr<LockedNode> oldLock;

updatesUsed.insert(inputPath);
Expand All @@ -472,9 +472,8 @@ LockedFlake lockFlake(

node->inputs.insert_or_assign(id, childNode);

/* If we have an --update-input flag for an input
of this input, then we must fetch the flake to
update it. */
/* If we have this input in updateInputs, then we
must fetch the flake to update it. */
auto lb = lockFlags.inputUpdates.lower_bound(inputPath);

auto mustRefetch =
Expand Down Expand Up @@ -621,7 +620,7 @@ LockedFlake lockFlake(

for (auto & i : lockFlags.inputUpdates)
if (!updatesUsed.count(i))
warn("the flag '--update-input %s' does not match any input", printInputPath(i));
warn("'%s' does not match any input of this flake", printInputPath(i));

/* Check 'follows' inputs. */
newLockFile.check();
Expand Down
38 changes: 17 additions & 21 deletions src/nix/flake-lock.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,36 @@ R""(

# Examples

* Update the `nixpkgs` and `nix` inputs of the flake in the current
directory:
* Create the lock file for the flake in the current directory:

```console
# nix flake lock --update-input nixpkgs --update-input nix
# nix flake lock
warning: creating lock file '/home/myself/repos/testflake/flake.lock':
• Added input 'nix':
'github:NixOS/nix/9fab14adbc3810d5cc1f88672fde1eee4358405c' (2023-06-28)
• Added input 'nixpkgs':
'github:NixOS/nixpkgs/3d2d8f281a27d466fa54b469b5993f7dde198375' (2023-06-30)
```

# Description

This command updates the lock file of a flake (`flake.lock`) so that
it contains a lock for every flake input specified in
`flake.nix`. Existing lock file entries are not updated unless
required by a flag such as `--update-input`.
* Add missing inputs to the lock file for a flake in a different directory:

Note that every command that operates on a flake will also update the
lock file if needed, and supports the same flags. Therefore,
```console
# nix flake lock ~/repos/another
warning: updating lock file '/home/myself/repos/another/flake.lock':
• Added input 'nixpkgs':
'github:NixOS/nixpkgs/3d2d8f281a27d466fa54b469b5993f7dde198375' (2023-06-30)

```console
# nix flake lock --update-input nixpkgs
# nix build
```
Note: When trying to refer to a flake in a direct descendant directory, write `./another`
instead of `another`, else Nix will try look up the flake in the registry.
```

is equivalent to:
# Description

```console
# nix build --update-input nixpkgs
```
This command adds inputs to the lock file of a flake (`flake.lock`)
so that it contains a lock for every flake input specified in
`flake.nix`. Existing lock file entries are not updated.

Thus, this command is only useful if you want to update the lock file
separately from any other action such as building.
If you want to update existing lock entries, use
[`nix flake update`](@docroot@/command-ref/new-cli/nix3-flake-update.md)

)""
50 changes: 33 additions & 17 deletions src/nix/flake-update.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ R""(

# Examples

* Recreate the lock file (i.e. update all inputs) and commit the new
lock file:
* Update all inputs (i.e. recreate the lock file from scratch):

```console
# nix flake update
Expand All @@ -14,26 +13,43 @@ R""(
• Updated input 'nixpkgs':
'github:NixOS/nixpkgs/3d2d8f281a27d466fa54b469b5993f7dde198375' (2023-06-30)
→ 'github:NixOS/nixpkgs/a3a3dda3bacf61e8a39258a0ed9c924eeca8e293' (2023-07-05)
warning: committed new revision '158bcbd9d6cc08ab859c0810186c1beebc982aad'
```

# Description
* Update only a single input:

```console
# nix flake update nixpkgs
warning: updating lock file '/home/myself/repos/testflake/flake.lock':
• Updated input 'nixpkgs':
'github:NixOS/nixpkgs/3d2d8f281a27d466fa54b469b5993f7dde198375' (2023-06-30)
→ 'github:NixOS/nixpkgs/a3a3dda3bacf61e8a39258a0ed9c924eeca8e293' (2023-07-05)
```

* Update only a single input of a flake in a different directory:

This command recreates the lock file of a flake (`flake.lock`), thus
updating the lock for every unlocked input (like `nixpkgs`) to its
current version. This is equivalent to passing `--recreate-lock-file`
to any command that operates on a flake. That is,
```console
# nix flake update nixpkgs --flake ~/repos/another
warning: updating lock file '/home/myself/repos/another/flake.lock':
• Updated input 'nixpkgs':
'github:NixOS/nixpkgs/3d2d8f281a27d466fa54b469b5993f7dde198375' (2023-06-30)
→ 'github:NixOS/nixpkgs/a3a3dda3bacf61e8a39258a0ed9c924eeca8e293' (2023-07-05)

Note: When trying to refer to a flake in a direct descendant directory, write `./another`
instead of `another`, else Nix will try look up the flake in the registry.
```

# Description

```console
# nix flake update
# nix build
```
This command updates the inputs in a lock file (`flake.lock`).
**By default, all inputs are updated**. If the lock file doesn't exist
yet, it will be created. If inputs are not in the lock file yet, they will be added.

is equivalent to:
Unlike other `nix flake` commands, `nix flake update` takes a list of names of inputs
to update as its positional arguments and operates on the flake in the current directory.
You can pass a different flake-url with `--flake` to override that default.

```console
# nix build --recreate-lock-file
```
The related command [`nix flake lock`](@docroot@/command-ref/new-cli/nix3-flake-lock.md)
also creates lock files and adds missing inputs, but is safer as it
will never update inputs already in the lock file.

)""
36 changes: 33 additions & 3 deletions src/nix/flake.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,11 @@ using namespace nix;
using namespace nix::flake;
using json = nlohmann::json;

struct CmdFlakeUpdate;
class FlakeCommand : virtual Args, public MixFlakeOptions
{
friend struct CmdFlakeUpdate;

std::string flakeUrl = ".";

public:
Expand Down Expand Up @@ -60,16 +63,32 @@ class FlakeCommand : virtual Args, public MixFlakeOptions

struct CmdFlakeUpdate : FlakeCommand
{
private:

std::vector<std::string> passedInputs;

public:

std::string description() override
{
return "update flake lock file";
}

CmdFlakeUpdate()
{
expectedArgs.clear();
addFlag({
.longName="flake",
.description="The flake to operate on. Default is the current directory.",
.labels={"flake-url"},
.handler={&flakeUrl},
.completer = {[&](size_t, std::string_view prefix) {
completeFlakeRef(getStore(), prefix);
}}
});
expectArgs("inputs", &passedInputs);

/* Remove flags that don't make sense. */
removeFlag("recreate-lock-file");
removeFlag("update-input");
removeFlag("no-update-lock-file");
removeFlag("no-write-lock-file");
}
Expand All @@ -85,7 +104,18 @@ struct CmdFlakeUpdate : FlakeCommand
{
settings.tarballTtl = 0;

lockFlags.recreateLockFile = true;
for (auto& input : passedInputs) {
auto inputPath = flake::parseInputPath(input);
if (lockFlags.inputUpdates.contains(inputPath))
warn("Input '%s' was specified multiple times. You may have done this by accident.");
lockFlags.inputUpdates.insert(inputPath);
}
auto updateAll = lockFlags.inputUpdates.empty();

// auto flake = flake::getFlake(*getEvalState(), getFlakeRef(), true);
// auto scheme = flake.lockedRef.input.toURL().scheme == "github";

lockFlags.recreateLockFile = updateAll;
lockFlags.writeLockFile = true;
lockFlags.applyNixConfig = true;

Expand Down
4 changes: 2 additions & 2 deletions tests/completions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ EOF
## With tilde expansion
[[ "$(HOME=$PWD NIX_GET_COMPLETIONS=4 nix build '~/foo' --override-input '')" == $'normal\na\t' ]]
## Out of order
[[ "$(NIX_GET_COMPLETIONS=3 nix build --update-input '' ./foo)" == $'normal\na\t' ]]
[[ "$(NIX_GET_COMPLETIONS=4 nix build ./foo --update-input '' ./bar)" == $'normal\na\t\nb\t' ]]
[[ "$(NIX_GET_COMPLETIONS=3 nix build --override-input '' '' ./foo)" == $'normal\na\t' ]]
[[ "$(NIX_GET_COMPLETIONS=4 nix build ./foo --override-input '' '' ./bar)" == $'normal\na\t\nb\t' ]]

# Cli flag completion
NIX_GET_COMPLETIONS=2 nix build --log-form | grep -- "--log-format"
Expand Down
3 changes: 2 additions & 1 deletion tests/flakes/circular.sh
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ git -C $flakeB commit -a -m 'Foo'
sed -i $flakeB/flake.nix -e 's/456/789/'
git -C $flakeB commit -a -m 'Foo'

[[ $(nix eval --update-input b $flakeA#foo) = 1912 ]]
nix flake update b --flake $flakeA
[[ $(nix eval $flakeA#foo) = 1912 ]]

# Test list-inputs with circular dependencies
nix flake metadata $flakeA
Expand Down
10 changes: 6 additions & 4 deletions tests/flakes/flakes.sh
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ nix build -o $TEST_ROOT/result flake4#xyzzy
nix flake lock $flake3Dir
[[ -z $(git -C $flake3Dir diff master || echo failed) ]]

nix flake update $flake3Dir --override-flake flake2 nixpkgs
nix flake update --flake $flake3Dir --override-flake flake2 nixpkgs
[[ ! -z $(git -C $flake3Dir diff master || echo failed) ]]

# Make branch "removeXyzzy" where flake3 doesn't have xyzzy anymore
Expand Down Expand Up @@ -435,7 +435,9 @@ cat > $flake3Dir/flake.nix <<EOF
}
EOF

nix flake update $flake3Dir
cd $flake3Dir
nix flake update
cd -
[[ $(jq -c .nodes.flake2.inputs.flake1 $flake3Dir/flake.lock) =~ '["foo"]' ]]
[[ $(jq .nodes.foo.locked.url $flake3Dir/flake.lock) =~ flake7 ]]

Expand Down Expand Up @@ -474,11 +476,11 @@ nix flake lock $flake3Dir --override-input flake2/flake1 flake1
nix flake lock $flake3Dir --override-input flake2/flake1 flake1/master/$hash1
[[ $(jq -r .nodes.flake1_2.locked.rev $flake3Dir/flake.lock) =~ $hash1 ]]

# Test --update-input.
# Test update
nix flake lock $flake3Dir
[[ $(jq -r .nodes.flake1_2.locked.rev $flake3Dir/flake.lock) = $hash1 ]]

nix flake lock $flake3Dir --update-input flake2/flake1
nix flake update flake2/flake1 --flake $flake3Dir
[[ $(jq -r .nodes.flake1_2.locked.rev $flake3Dir/flake.lock) =~ $hash2 ]]

# Test 'nix flake metadata --json'.
Expand Down
2 changes: 1 addition & 1 deletion tests/flakes/follow-paths.sh
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ git -C $flakeFollowsA add flake.nix flakeB/flake.nix \

nix flake metadata $flakeFollowsA

nix flake update $flakeFollowsA
nix flake update --flake $flakeFollowsA

nix flake lock $flakeFollowsA

Expand Down

0 comments on commit 944f6ab

Please sign in to comment.