(in)compatibility of nix store subcommand with CppNix (new add vs. old add-file and add-path subcommands) #780

Open
opened 2025-03-29 22:10:44 +00:00 by wamserma · 6 comments

Describe the bug

With https://github.com/NixOS/nix/pull/9357 CppNix merged the add-file and add-path subcommands of nix store into a singe add subcommand. This has not been reflected in Lix (d169c092fc/lix/nix/add-to-store.cc as of opening this issue).

This breaks downstream tooling such as nix-playground, which uses the unified command: c1a5c79f4a/nix_playground/build.py (L44)

Steps To Reproduce

  1. Run touch delicious.icecream && nix store add delicious.icecream
  2. Get error: 'add' is not a recognised command

Expected behavior

  1. Run touch delicious.icecream && nix store add delicious.icecream
  2. Get /nix/store/kphh26dlb2w2mhydjqaiqn02zcxgz0j2-delicious.icecream (produced by CppNix 2.24.12 nix store add delicious.icecream)

nix --version output

nix (Lix, like Nix) 2.91.1

## Describe the bug With https://github.com/NixOS/nix/pull/9357 CppNix merged the `add-file` and `add-path` subcommands of `nix store` into a singe `add` subcommand. This has not been reflected in Lix (https://git.lix.systems/lix-project/lix/src/commit/d169c092fc28838a253be136d17fe7de1292c728/lix/nix/add-to-store.cc as of opening this issue). This breaks downstream tooling such as nix-playground, which uses the unified command: https://github.com/LaunchPlatform/nix-playground/blob/c1a5c79f4abbfdd57ee01cd498532519f18a3f55/nix_playground/build.py#L44 ## Steps To Reproduce 1. Run `touch delicious.icecream && nix store add delicious.icecream` 2. Get `error: 'add' is not a recognised command` ## Expected behavior 1. Run `touch delicious.icecream && nix store add delicious.icecream` 2. Get `/nix/store/kphh26dlb2w2mhydjqaiqn02zcxgz0j2-delicious.icecream` (produced by CppNix 2.24.12 `nix store add delicious.icecream`) ## `nix --version` output nix (Lix, like Nix) 2.91.1
Owner

I am not sure what the correct way to handle this is. It's possible to pick the change if it looks reasonable, but it sucks to be dragged into making changes just because CppNix did them, even if they're a good idea. Having this unstable CLI be the locus of user complaints whenever it differs from CppNix by either option of not changing or changing in ways that break scripts is untenable in the long term.

The ideal solution here is to stop making compatibility promises that prevent us having control over our destiny.

Probably the fix to this one is picking the change, assuming it doesn't regress anything, since it sounds reasonable.

The downstream software in question was never compatible with 2.18 since that file didn't exist at all.

I am not sure what the correct way to handle this is. It's possible to pick the change if it looks reasonable, but it sucks to be dragged into making changes just because CppNix did them, even if they're a good idea. Having this unstable CLI be the locus of user complaints whenever it differs from CppNix by either option of not changing *or* changing in ways that break scripts is untenable in the long term. The ideal solution here is to stop making compatibility promises that prevent us having control over our destiny. Probably the fix to this one is picking the change, assuming it doesn't regress anything, since it *sounds* reasonable. The downstream software in question was never compatible with 2.18 since that file didn't exist at all.
Owner

Probably the fix to this one is picking the change, assuming it doesn't regress anything, since it sounds reasonable.

please do not, because it will regress something. the new command unnecessarily exposes implementation details that'll prevent us making meaningful improvements to the store layer without breaking the commands again.

> Probably the fix to this one is picking the change, assuming it doesn't regress anything, since it sounds reasonable. please do not, because it will regress something. the new command unnecessarily exposes implementation details that'll prevent us making meaningful improvements to the store layer without breaking the commands *again*.
Author

The ideal solution here is to stop making compatibility promises that prevent us having control over our destiny.

This was merely an observation and by no means seen as a broken promise. Especially given that this stuff is still marked as experimental.

Probably the fix to this one is picking the change, assuming it doesn't regress anything, since it sounds reasonable.

TBH, I am still undecided how this command should be implemented. I can somewhat understand why add-path has been taken as default for add and add-files is now available as add --flat, but I do not like the ergonomics of having nix command subcommand --flag. The change itself is rather trivial (just adopting the RegisterCommand calls at the of the source file).

w.r.t. to regressions: the subcommand in question was not available for long, so probably has low adoption and CppNix at least added deprecation warnings in their patch instead of doing a hard switch.

> The ideal solution here is to stop making compatibility promises that prevent us having control over our destiny. This was merely an observation and by no means seen as a broken promise. Especially given that this stuff is still marked as experimental. > Probably the fix to this one is picking the change, assuming it doesn't regress anything, since it sounds reasonable. TBH, I am still undecided how this command should be implemented. I can somewhat understand why `add-path` has been taken as default for `add` and `add-files` is now available as `add --flat`, but I do not like the ergonomics of having `nix command subcommand --flag`. The change itself is rather trivial (just adopting the RegisterCommand calls at the of the source file). w.r.t. to regressions: the subcommand in question was not available for long, so probably has low adoption and CppNix at least added deprecation warnings in their patch instead of doing a hard switch.
Author

The ideal solution here is to stop making compatibility promises that prevent us having control over our destiny.

This was merely an observation and by no means seen as a broken promise. Especially given that this stuff is still marked as experimental.

Probably the fix to this one is picking the change, assuming it doesn't regress anything, since it sounds reasonable.

TBH, I am still undecided how this command should be implemented. I can somewhat understand why add-path has been taken as default for add and add-files is now available as add --flat, but I do not like the ergonomics of having nix command subcommand --flag. The change itself is rather trivial (just adopting the RegisterCommand calls at the of the source file).

w.r.t. to regressions: the subcommand in question was not available for long, so probably has low adoption and CppNix at least added deprecation warnings in their patch instead of doing a hard switch.

> The ideal solution here is to stop making compatibility promises that prevent us having control over our destiny. This was merely an observation and by no means seen as a broken promise. Especially given that this stuff is still marked as experimental. > Probably the fix to this one is picking the change, assuming it doesn't regress anything, since it sounds reasonable. TBH, I am still undecided how this command should be implemented. I can somewhat understand why `add-path` has been taken as default for `add` and `add-files` is now available as `add --flat`, but I do not like the ergonomics of having `nix command subcommand --flag`. The change itself is rather trivial (just adopting the RegisterCommand calls at the of the source file). w.r.t. to regressions: the subcommand in question was not available for long, so probably has low adoption and CppNix at least added deprecation warnings in their patch instead of doing a hard switch.
Owner

@pennae wrote in #780 (comment):

Probably the fix to this one is picking the change, assuming it doesn't regress anything, since it sounds reasonable.

please do not, because it will regress something. the new command unnecessarily exposes implementation details that'll prevent us making meaningful improvements to the store layer without breaking the commands again.

Oh? As far as I can tell the way it's been written today leaks approximately the same amount: the mode flag exists already and allows either recursive, flat or text modes. That being said, there being three modes for adding single files to the store is kind of pointless since every store path has a nar hash already and adding a single file probably could just make three hard links for compatibility with any of the non nar modes. Anyway I'm not sure of the specifics of the improvements you're planning.

@pennae wrote in https://git.lix.systems/lix-project/lix/issues/780#issuecomment-9989: > > Probably the fix to this one is picking the change, assuming it doesn't regress anything, since it sounds reasonable. > > please do not, because it will regress something. the new command unnecessarily exposes implementation details that'll prevent us making meaningful improvements to the store layer without breaking the commands _again_. Oh? As far as I can tell the way it's been written today leaks approximately the same amount: the mode flag exists already and allows either recursive, flat or text modes. That being said, there being three modes for adding single files to the store is kind of pointless since every store path has a nar hash already and adding a single file probably could just make three hard links for compatibility with any of the non nar modes. Anyway I'm not sure of the specifics of the improvements you're planning.
Owner

exposing nar as the canonical format to create path hashes nails us down to not changing this unless we want to break the abi. creating compatibility hardlinks will not be possible for directories, creating symlinks will be wrong, and in any case we'll be unable to distinguish a compat-linked object from an object that was added with an old method and will have to deal with tremendously complicated GC (since every object may now exist multiple times, opening multiple race windows even once we've dealt with everything else)

we could of course sidestep this somewhat by sticking to the old recursive/flat wording without specifying behavior, but then we're still incompatible and have gained nothing except breaking things for no reason

exposing nar as the canonical format to create path hashes nails us down to not changing this unless we want to break the abi. creating compatibility hardlinks will not be possible for directories, creating symlinks will be wrong, and in any case we'll be unable to distinguish a compat-linked object from an object that was added with an old method and will have to deal with tremendously complicated GC (since every object may now exist multiple times, opening multiple race windows even once we've dealt with everything else) we could of course sidestep this somewhat by sticking to the old recursive/flat wording without specifying behavior, but then we're still incompatible and have gained nothing except breaking things for no reason
Sign in to join this conversation.
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lix-project/lix#780
No description provided.