Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve error on conflict for nix profile install #7788

Conversation

bobvanderlinden
Copy link
Member

@bobvanderlinden bobvanderlinden commented Feb 8, 2023

Motivation

Currently nix profile install gives a confusing and unhelpful error message whenever a package is installed that has conflicting files. This often happens when installing a different version of the same package.

This PR is an attempt to improve the experience in such situations to some extend. I see this as a small improvement, but it doesn't really reach the end-goal of a good UX yet.

As an example, this is what happens before this PR:

$ nix profile install github:cachix/devenv/v0.5
$ nix profile install github:cachix/devenv/v0.4
error: files '/nix/store/k0gwhiwfs8c218kph78vx75bph51iw31-devenv/bin/devenv' and '/nix/store/7i4hxhw44lr7r64zlmp4zq7cqpsx7smw-devenv/bin/devenv' have the same priority 5; use 'nix-env --set-flag priority NUMBER INSTALLED_PKGNAME' or type 'nix profile install --help' if using 'nix profile' to find out how to change the priority of one of the conflicting packages (0 being the highest priority)

This is what happens after this PR:

$ nix profile install github:cachix/devenv/v0.5
$ nix profile install github:cachix/devenv/v0.4
error: There is an existing package that has a conflicting file:

         /nix/store/7i4hxhw44lr7r64zlmp4zq7cqpsx7smw-devenv/bin/devenv

       The conflicting file:

         /nix/store/k0gwhiwfs8c218kph78vx75bph51iw31-devenv/bin/devenv

       You can remove the existing package using:

         nix profile remove github:cachix/devenv/v0.4

       You can also install the new package next to the existing package by assigning a priority to the package.
       The conflicting packages have a priority of 5.
       You can prioritize the new package using:

         nix profile install github:cachix/devenv/v0.4 --priority 4

       You can prioritize the existing package using:

         nix profile install github:cachix/devenv/v0.4 --priority 6

The new changes allows nix profile install to give more context.

This also avoids mentions of nix-env and nix profile when using builtins.buildEnv. Since buildEnv can be used in other places (unrelated to the Nix profile), it makes sense to avoid mentioning nix-env and nix profile, as they likely do not apply in these cases.

Context

Related to #7530

See my suggestion for a good UX on nix profiles. The current PR is merely an improvement for the error message on conflicts.

Checklist for maintainers

Maintainers: tick if completed or explain if not relevant

  • agreed on idea
  • agreed on implementation strategy
  • tests, as appropriate
    • functional tests - tests/**.sh
    • unit tests - src/*/tests
    • integration tests - tests/nixos/*
  • documentation in the manual
  • code and comments are self-explanatory
  • commit message explains why the change was made
  • new feature or incompatible change: updated release notes

@bobvanderlinden bobvanderlinden marked this pull request as draft February 8, 2023 22:59
@domenkozar
Copy link
Member

domenkozar commented Feb 10, 2023

This looks great to me in terms of the error message improvement, but I'll let those that know the codebase comment on the C++ bits.

Thanks for improving this, it's quite a frustrating experience currently for devenv users to upgrade :)

@bobvanderlinden bobvanderlinden marked this pull request as ready for review February 10, 2023 13:25
@bobvanderlinden bobvanderlinden force-pushed the pr-improve-nix-profile-install-error branch from 99a44d3 to 9b6b19b Compare February 10, 2023 13:32
@bobvanderlinden bobvanderlinden marked this pull request as draft February 10, 2023 17:31
@bobvanderlinden bobvanderlinden force-pushed the pr-improve-nix-profile-install-error branch 2 times, most recently from 777ad46 to 57b2d9b Compare February 11, 2023 09:43
@bobvanderlinden bobvanderlinden marked this pull request as ready for review February 11, 2023 09:44
@bobvanderlinden
Copy link
Member Author

I made some more changes so that the INSTALLABLE of the suggested nix profile install commands can be filled in. The implementation first throws an error containing the conflicting files. Then the package path (/nix/store/XXXX-package) is looked up for the conflicting files. Lastly the INSTALLABLE from the manifest is found using the package path. All of this information is used in the resulting error.

@domenkozar domenkozar added the error-messages Confusing messages and better diagnostics label Feb 16, 2023
@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/contributing-to-nix/25605/1

src/nix/profile.cc Outdated Show resolved Hide resolved
src/libstore/path.hh Outdated Show resolved Hide resolved
src/nix/profile.cc Outdated Show resolved Hide resolved
src/libstore/path.cc Outdated Show resolved Hide resolved
@Ericson2314 Ericson2314 self-assigned this Feb 19, 2023
@Ericson2314
Copy link
Member

@bobvanderlinden fair warning I don't yet have perms to merge this, but I can still shepherd along making it an easier approval for those that do.

@Ericson2314
Copy link
Member

@bobvanderlinden This is starting to look quite good! Thanks for doing this!

Correct me if I am wrong, but BuildEnvFileConflictError is just used in a private-to-the-file static function, so you should be able to not expose it in the header, but just have it in buildenv.cc.

Since it is for internal use only, and will always be caught, I think it would be also fine to just make it inherit std::exception rather than Error, and then you don't have to write a nice message which would be dead code.

@bobvanderlinden bobvanderlinden force-pushed the pr-improve-nix-profile-install-error branch from 7ece87f to dfa6f75 Compare February 22, 2023 19:57
@bobvanderlinden
Copy link
Member Author

@bobvanderlinden This is starting to look quite good! Thanks for doing this!

Correct me if I am wrong, but BuildEnvFileConflictError is just used in a private-to-the-file static function, so you should be able to not expose it in the header, but just have it in buildenv.cc.
Since it is for internal use only, and will always be caught, I think it would be also fine to just make it inherit std::exception rather than Error, and then you don't have to write a nice message which would be dead code.

Ah you're right! That makes a lot of sense, thanks 👍 Updated the PR.

src/nix/profile.cc Outdated Show resolved Hide resolved
@Ericson2314
Copy link
Member

Thanks @bobvanderlinden, this is very close to being ready!

@bobvanderlinden bobvanderlinden force-pushed the pr-improve-nix-profile-install-error branch from dfa6f75 to bb863a3 Compare February 22, 2023 23:59
@bobvanderlinden
Copy link
Member Author

Thanks @bobvanderlinden, this is very close to being ready!

Thanks for the quick reviews and suggestions. This improves my long forgotten C++ knowledge a bit too. 🥳

tests/nix-profile.sh Outdated Show resolved Hide resolved
Copy link
Contributor

@fricklerhandwerk fricklerhandwerk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In really like the informative error message, we can use lots more of that! Only suggestions on more concise wording from my side. Great work.

src/nix/profile.cc Outdated Show resolved Hide resolved
src/nix/profile.cc Outdated Show resolved Hide resolved
src/nix/profile.cc Outdated Show resolved Hide resolved
src/nix/profile.cc Outdated Show resolved Hide resolved
src/nix/profile.cc Outdated Show resolved Hide resolved
@bobvanderlinden bobvanderlinden force-pushed the pr-improve-nix-profile-install-error branch 2 times, most recently from 9481aa4 to 551e032 Compare February 25, 2023 19:43
@bobvanderlinden
Copy link
Member Author

The test did show that I made a mistake with the nix profile remove command where the conflicting installable was mixed up with the original installable, which I have now fixed. Good idea to add this test. Glad I did.

Thanks you all for the suggestions. I've incorporated most of them and resolved the discussions. Quite a few improvements to the PR already 👍

ideally we'd make this a markdown message and run a formatter on them for better presentation

Is this something I can look into for this PR?

@roberth
Copy link
Member

roberth commented Feb 25, 2023

ideally we'd make this a markdown message and run a formatter on them for better presentation

Is this something I can look into for this PR?

Better to do that in a followup, although it may make the testing story worse, as the layout becomes dependent on the length of the inputs.

@bobvanderlinden bobvanderlinden force-pushed the pr-improve-nix-profile-install-error branch from 551e032 to d186eb3 Compare February 26, 2023 14:33
@bobvanderlinden bobvanderlinden marked this pull request as draft February 27, 2023 10:06
At the moment an Error is thrown that only holds an error message
regarding `nix-env` and `nix profile`. These tools make use of
builtins.buildEnv, but buildEnv is also used in other places. These
places are unrelated to Nix profiles, so the error shouldn't mention
these tools.

This generic error is now BuildEnvFileConflictError, which holds more
contextual information about the files that were conflicting while
building the environment.
@bobvanderlinden bobvanderlinden force-pushed the pr-improve-nix-profile-install-error branch from 7cfd0b4 to 1fe5d17 Compare February 27, 2023 20:41
@bobvanderlinden
Copy link
Member Author

I have reworked the implementation in this PR and left the tests as-is.

I have removed BuildProfileConflictError and opted to merely throw BuildEnvFileConflictError. BuildEnvFileConflictError now holds fileA and fileB, which represent the 2 files that were conflicting inside buildEnv. Since we do not know at that time whether the files were from the original package or the newly installed package, I have called them A and B.

Determining which file belongs to the original/new package is done entirely in CmdProfileInstall::run. Packages that are being installed are placed at the end of manifest.elements, so from this I look up any package that matches one of the conflicting file paths at the end of manifest.elements to find which the new package and its conflicting file. I do the same thing for the already installed package, but by looking at the beginning of manifest.elements.

This gives an implementation that doesn't run into sorting issues that I can into before. Bonus: the code is cleaner this way as well.

Whenever a file conflict happens during "nix profile install" an error
is shown that was previously thrown inside builtins.buildEnv.

We catch BuildProfileConflictError here so that we can provide the user
with more useful instructions on what to do next.

Most notably, we give the user concrete commands to use with all
parameters  already filled in. This avoids the need for the user to look
up these commands in manual pages.
@bobvanderlinden bobvanderlinden force-pushed the pr-improve-nix-profile-install-error branch from 1fe5d17 to 3efa476 Compare February 28, 2023 08:28
@bobvanderlinden
Copy link
Member Author

bobvanderlinden commented Feb 28, 2023

Hmm, MacOS in CI failed to build due to usage of C++20 ranges. I guess a different version of clang is used on MacOS to build Nix?
I now avoided using ranges and replaced it with begin() and rbegin() iterators. I tried compiling using clang and using nix develop .#nix-gccStdenv as well. 🤞

EDIT: The test failed again, this time because Nix in CI outputs a warning for running in offline mode, where-as locally that did not happen. I have opted for ignoring all warning: lines in the test.

@fricklerhandwerk
Copy link
Contributor

@Ericson2314 I'll unsubscribe since the user-facing part is good, please continue with shepherding the implementation.

@fricklerhandwerk fricklerhandwerk removed their assignment Feb 28, 2023
@bobvanderlinden bobvanderlinden marked this pull request as ready for review February 28, 2023 17:44
@Ericson2314
Copy link
Member

Implementation looks good to me!

@fricklerhandwerk
Copy link
Contributor

Merging it then.

@fricklerhandwerk fricklerhandwerk merged commit 306e5c5 into NixOS:master Mar 1, 2023
@bobvanderlinden
Copy link
Member Author

Thank you all 🥳👍

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/nix-team-report-2022-10-2023-03/27486/1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
error-messages Confusing messages and better diagnostics
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

9 participants