aboutsummaryrefslogtreecommitdiff
path: root/src/nix/profile.cc
diff options
context:
space:
mode:
authorValentin Gagarin <valentin.gagarin@tweag.io>2023-03-01 11:48:43 +0100
committerGitHub <noreply@github.com>2023-03-01 11:48:43 +0100
commit306e5c5ce5a38fecb90b2d2a3c6159fd2ad9c5cc (patch)
tree0e7e4866a63700e14e501eaeb975f31b57c2a73b /src/nix/profile.cc
parentd5af43cb420fd5228c6e07a62fc53fcadb626aa3 (diff)
parent12538605fdc99be846b736080558567edbb8a393 (diff)
Merge pull request #7788 from bobvanderlinden/pr-improve-nix-profile-install-error
Improve error on conflict for nix profile install
Diffstat (limited to 'src/nix/profile.cc')
-rw-r--r--src/nix/profile.cc58
1 files changed, 57 insertions, 1 deletions
diff --git a/src/nix/profile.cc b/src/nix/profile.cc
index 208542a5c..711fbe2f0 100644
--- a/src/nix/profile.cc
+++ b/src/nix/profile.cc
@@ -330,7 +330,63 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
manifest.elements.push_back(std::move(element));
}
- updateProfile(manifest.build(store));
+ try {
+ updateProfile(manifest.build(store));
+ } catch (BuildEnvFileConflictError & conflictError) {
+ // FIXME use C++20 std::ranges once macOS has it
+ // See https://github.com/NixOS/nix/compare/3efa476c5439f8f6c1968a6ba20a31d1239c2f04..1fe5d172ece51a619e879c4b86f603d9495cc102
+ auto findRefByFilePath = [&]<typename Iterator>(Iterator begin, Iterator end) {
+ for (auto it = begin; it != end; it++) {
+ auto profileElement = *it;
+ for (auto & storePath : profileElement.storePaths) {
+ if (conflictError.fileA.starts_with(store->printStorePath(storePath))) {
+ return std::pair(conflictError.fileA, profileElement.source->originalRef);
+ }
+ if (conflictError.fileB.starts_with(store->printStorePath(storePath))) {
+ return std::pair(conflictError.fileB, profileElement.source->originalRef);
+ }
+ }
+ }
+ throw conflictError;
+ };
+ // There are 2 conflicting files. We need to find out which one is from the already installed package and
+ // which one is the package that is the new package that is being installed.
+ // The first matching package is the one that was already installed (original).
+ auto [originalConflictingFilePath, originalConflictingRef] = findRefByFilePath(manifest.elements.begin(), manifest.elements.end());
+ // The last matching package is the one that was going to be installed (new).
+ auto [newConflictingFilePath, newConflictingRef] = findRefByFilePath(manifest.elements.rbegin(), manifest.elements.rend());
+
+ throw Error(
+ "An existing package already provides the following file:\n"
+ "\n"
+ " %1%\n"
+ "\n"
+ "This is the conflicting file from the new package:\n"
+ "\n"
+ " %2%\n"
+ "\n"
+ "To remove the existing package:\n"
+ "\n"
+ " nix profile remove %3%\n"
+ "\n"
+ "The new package can also be installed next to the existing one by assigning a different priority.\n"
+ "The conflicting packages have a priority of %5%.\n"
+ "To prioritise the new package:\n"
+ "\n"
+ " nix profile install %4% --priority %6%\n"
+ "\n"
+ "To prioritise the existing package:\n"
+ "\n"
+ " nix profile install %4% --priority %7%\n",
+ originalConflictingFilePath,
+ newConflictingFilePath,
+ originalConflictingRef.to_string(),
+ newConflictingRef.to_string(),
+ conflictError.priority,
+ conflictError.priority - 1,
+ conflictError.priority + 1
+ );
+ }
}
};