diff options
author | Qyriad <qyriad@qyriad.me> | 2024-05-01 18:51:16 -0600 |
---|---|---|
committer | Qyriad <qyriad@qyriad.me> | 2024-05-02 12:02:28 -0600 |
commit | f88423813f042cf40d9207409cd05cf4b75d87a0 (patch) | |
tree | d02a8cdc30d1978f79b8f98ba199225551ece77e /src | |
parent | 1425aa0b7cd0d3477589f75bea4fb9c74e057fed (diff) |
nix3-profile: allow using human-readable names to select packages
These names are parsed from the URL provided for that package
Based off of commit 257b768436a0e8ab7887f9b790c5b92a7fe51ef5
Upstream-PR: https://github.com/NixOS/nix/pull/8678
Co-authored-by: Felix Uhl <felix.uhl@outlook.com>
Change-Id: I76d5f9cfb11d3d2915b3dd1db21d7bb49e91f4fb
Diffstat (limited to 'src')
-rw-r--r-- | src/libcmd/cmd-profiles.cc | 26 | ||||
-rw-r--r-- | src/libcmd/cmd-profiles.hh | 3 | ||||
-rw-r--r-- | src/nix/profile-list.md | 9 | ||||
-rw-r--r-- | src/nix/profile-remove.md | 11 | ||||
-rw-r--r-- | src/nix/profile-upgrade.md | 11 | ||||
-rw-r--r-- | src/nix/profile.cc | 156 |
6 files changed, 158 insertions, 58 deletions
diff --git a/src/libcmd/cmd-profiles.cc b/src/libcmd/cmd-profiles.cc index 4d8ff7438..5fa7f902c 100644 --- a/src/libcmd/cmd-profiles.cc +++ b/src/libcmd/cmd-profiles.cc @@ -1,6 +1,9 @@ +#include <set> + #include "cmd-profiles.hh" #include "built-path.hh" #include "builtins/buildenv.hh" +#include "logging.hh" #include "names.hh" #include "store-api.hh" @@ -106,6 +109,8 @@ ProfileManifest::ProfileManifest(EvalState & state, const Path & profile) if (pathExists(manifestPath)) { auto json = nlohmann::json::parse(readFile(manifestPath)); + // Keep track of already found names so we can prevent duplicates. + std::set<std::string> foundNames; auto version = json.value("version", 0); std::string sUrl; @@ -139,6 +144,26 @@ ProfileManifest::ProfileManifest(EvalState & state, const Path & profile) e["attrPath"], e["outputs"].get<ExtendedOutputsSpec>()}; } + + std::string nameCandidate(element.identifier()); + + if (e.contains("name")) { + nameCandidate = e["name"]; + } else if (element.source) { + auto const url = parseURL(element.source->to_string()); + auto const name = getNameFromURL(url); + if (name) { + nameCandidate = *name; + } + } + + auto finalName = nameCandidate; + for (unsigned appendedIndex = 1; foundNames.contains(finalName); ++appendedIndex) { + finalName = nameCandidate + std::to_string(appendedIndex); + } + element.name = finalName; + foundNames.insert(element.name); + elements.emplace_back(std::move(element)); } } else if (pathExists(profile + "/manifest.nix")) { @@ -151,6 +176,7 @@ ProfileManifest::ProfileManifest(EvalState & state, const Path & profile) for (auto & drvInfo : drvInfos) { ProfileElement element; element.storePaths = {drvInfo.queryOutPath()}; + element.name = element.identifier(); elements.emplace_back(std::move(element)); } } diff --git a/src/libcmd/cmd-profiles.hh b/src/libcmd/cmd-profiles.hh index d03f9b1c2..7f2c8a76f 100644 --- a/src/libcmd/cmd-profiles.hh +++ b/src/libcmd/cmd-profiles.hh @@ -6,6 +6,8 @@ #include "flake/flakeref.hh" #include "get-drvs.hh" #include "types.hh" +#include "url.hh" +#include "url-name.hh" #include <string> #include <set> @@ -33,6 +35,7 @@ constexpr int DEFAULT_PRIORITY = 5; struct ProfileElement { StorePathSet storePaths; + std::string name; std::optional<ProfileElementSource> source; bool active = true; int priority = DEFAULT_PRIORITY; diff --git a/src/nix/profile-list.md b/src/nix/profile-list.md index 5d7fcc0ec..d807a69c6 100644 --- a/src/nix/profile-list.md +++ b/src/nix/profile-list.md @@ -6,6 +6,7 @@ R""( ```console # nix profile list + Name: gdb Index: 0 Flake attribute: legacyPackages.x86_64-linux.gdb Original flake URL: flake:nixpkgs @@ -13,6 +14,7 @@ R""( Store paths: /nix/store/indzcw5wvlhx6vwk7k4iq29q15chvr3d-gdb-11.1 Index: 1 + Name: blender-bin Flake attribute: packages.x86_64-linux.default Original flake URL: flake:blender-bin Locked flake URL: github:edolstra/nix-warez/91f2ffee657bf834e4475865ae336e2379282d34?dir=blender @@ -26,7 +28,7 @@ R""( # nix build github:edolstra/nix-warez/91f2ffee657bf834e4475865ae336e2379282d34?dir=blender#packages.x86_64-linux.default ``` - will build the package with index 1 shown above. + will build the package with name blender-bin shown above. # Description @@ -34,10 +36,13 @@ This command shows what packages are currently installed in a profile. For each installed package, it shows the following information: -* `Index`: An integer that can be used to unambiguously identify the +* `Name`: A unique name used to unambiguously identify the package in invocations of `nix profile remove` and `nix profile upgrade`. +* `Index`: An integer that can be used to unambiguously identify the package in invocations of `nix profile remove` and `nix profile upgrade`. + (*Deprecated, will be removed in a future version in favor of `Name`.*) + * `Flake attribute`: The flake output attribute path that provides the package (e.g. `packages.x86_64-linux.hello`). diff --git a/src/nix/profile-remove.md b/src/nix/profile-remove.md index ba85441d8..c76f4b09c 100644 --- a/src/nix/profile-remove.md +++ b/src/nix/profile-remove.md @@ -2,10 +2,17 @@ R""( # Examples -* Remove a package by position: +* Remove a package by name: ```console - # nix profile remove 3 + # nix profile remove hello + ``` + +* Remove a package by index + *(deprecated, will be removed in a future version)*: + + ```console + $ nix profile remove 3 ``` * Remove a package by attribute path: diff --git a/src/nix/profile-upgrade.md b/src/nix/profile-upgrade.md index 39cca428b..b13cb66bb 100644 --- a/src/nix/profile-upgrade.md +++ b/src/nix/profile-upgrade.md @@ -9,18 +9,19 @@ R""( # nix profile upgrade '.*' ``` -* Upgrade a specific package: +* Upgrade a specific package by name: + + ```console + # nix profile upgrade hello + ``` ```console # nix profile upgrade packages.x86_64-linux.hello ``` -* Upgrade a specific profile element by number: +* Upgrade a specific package by index: ```console - # nix profile list - 0 flake:nixpkgs#legacyPackages.x86_64-linux.spotify … - # nix profile upgrade 0 ``` diff --git a/src/nix/profile.cc b/src/nix/profile.cc index 67f97ca9b..f702c7c06 100644 --- a/src/nix/profile.cc +++ b/src/nix/profile.cc @@ -189,13 +189,24 @@ public: { std::vector<Matcher> res; + auto anyIndexMatchers = false; + for (auto & s : _matchers) { - if (auto n = string2Int<size_t>(s)) + if (auto n = string2Int<size_t>(s)) { res.push_back(*n); - else if (store->isStorePath(s)) + anyIndexMatchers = true; + } else if (store->isStorePath(s)) { res.push_back(s); - else + } else { res.push_back(RegexPattern{s,std::regex(s, std::regex::extended | std::regex::icase)}); + } + } + + if (anyIndexMatchers) { + warn( + "Indices are deprecated and be removed in a future version!\n" + " Refer to packages by their `Name` printed by `nix profile list`.\n" + ); } return res; @@ -206,12 +217,13 @@ public: for (auto & matcher : matchers) { if (auto n = std::get_if<size_t>(&matcher)) { if (*n == pos) return true; + } else if (auto path = std::get_if<Path>(&matcher)) { if (element.storePaths.count(store.parseStorePath(*path))) return true; } else if (auto regex = std::get_if<RegexPattern>(&matcher)) { - if (element.source - && std::regex_match(element.source->attrPath, regex->reg)) + if (std::regex_match(element.name, regex->reg)) { return true; + } } } @@ -294,62 +306,100 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf Installables installables; std::vector<size_t> indices; + auto matchedCount = 0; auto upgradedCount = 0; for (size_t i = 0; i < manifest.elements.size(); ++i) { auto & element(manifest.elements[i]); - if (element.source - && !element.source->originalRef.input.isLocked() - && matches(*store, element, i, matchers)) - { - upgradedCount++; + if (!matches(*store, element, i, matchers)) { + continue; + } - Activity act(*logger, lvlChatty, actUnknown, - fmt("checking '%s' for updates", element.source->attrPath)); + matchedCount += 1; - auto installable = make_ref<InstallableFlake>( - this, - getEvalState(), - FlakeRef(element.source->originalRef), - "", - element.source->outputs, - Strings{element.source->attrPath}, - Strings{}, - lockFlags); + if (!element.source) { + warn( + "Found package '%s', but it was not installed from a flake, so it can't be checked for upgrades", + element.identifier() + ); + continue; + } - auto derivedPaths = installable->toDerivedPaths(); - if (derivedPaths.empty()) continue; - auto * infop = dynamic_cast<ExtraPathInfoFlake *>(&*derivedPaths[0].info); - // `InstallableFlake` should use `ExtraPathInfoFlake`. - assert(infop); - auto & info = *infop; + if (element.source->originalRef.input.isLocked()) { + warn( + "Found package '%s', but it was installed from a locked flake reference so it can't be upgraded", + element.identifier() + ); + continue; + } - if (element.source->lockedRef == info.flake.lockedRef) continue; + upgradedCount++; - printInfo("upgrading '%s' from flake '%s' to '%s'", - element.source->attrPath, element.source->lockedRef, info.flake.lockedRef); + Activity act( + *logger, + lvlChatty, + actUnknown, + fmt("checking '%s' for updates", element.source->attrPath), + Logger::Fields{element.source->attrPath} + ); - element.source = ProfileElementSource { - .originalRef = installable->flakeRef, - .lockedRef = info.flake.lockedRef, - .attrPath = info.value.attrPath, - .outputs = installable->extendedOutputsSpec, - }; + auto installable = make_ref<InstallableFlake>( + this, + getEvalState(), + FlakeRef(element.source->originalRef), + "", + element.source->outputs, + Strings{element.source->attrPath}, + Strings{}, + lockFlags + ); - installables.push_back(installable); - indices.push_back(i); + auto derivedPaths = installable->toDerivedPaths(); + if (derivedPaths.empty()) { + continue; } + + auto * infop = dynamic_cast<ExtraPathInfoFlake *>(&*derivedPaths[0].info); + // `InstallableFlake` should use `ExtraPathInfoFlake`. + assert(infop); + auto & info = *infop; + + if (element.source->lockedRef == info.flake.lockedRef) { + continue; + } + + printInfo( + "upgrading '%s' from flake '%s' to '%s'", + element.source->attrPath, + element.source->lockedRef, + info.flake.lockedRef + ); + + element.source = ProfileElementSource { + .originalRef = installable->flakeRef, + .lockedRef = info.flake.lockedRef, + .attrPath = info.value.attrPath, + .outputs = installable->extendedOutputsSpec, + }; + + installables.push_back(installable); + indices.push_back(i); + } if (upgradedCount == 0) { - for (auto & matcher : matchers) { - if (const size_t * index = std::get_if<size_t>(&matcher)){ - warn("'%d' is not a valid index", *index); - } else if (const Path * path = std::get_if<Path>(&matcher)){ - warn("'%s' does not match any paths", *path); - } else if (const RegexPattern * regex = std::get_if<RegexPattern>(&matcher)){ - warn("'%s' does not match any packages", regex->pattern); + if (matchedCount == 0) { + for (auto & matcher : matchers) { + if (const size_t * index = std::get_if<size_t>(&matcher)){ + warn("'%d' is not a valid index", *index); + } else if (const Path * path = std::get_if<Path>(&matcher)){ + warn("'%s' does not match any paths", *path); + } else if (const RegexPattern * regex = std::get_if<RegexPattern>(&matcher)){ + warn("'%s' does not match any packages", regex->pattern); + } } + } else { + warn("Found some packages but none of them could be upgraded"); } warn ("Use 'nix profile list' to see the current profile."); } @@ -394,10 +444,18 @@ struct CmdProfileList : virtual EvalCommand, virtual StoreCommand, MixDefaultPro } else { for (size_t i = 0; i < manifest.elements.size(); ++i) { auto & element(manifest.elements[i]); - if (i) logger->cout(""); - logger->cout("Index: " ANSI_BOLD "%s" ANSI_NORMAL "%s", - i, - element.active ? "" : " " ANSI_RED "(inactive)" ANSI_NORMAL); + if (i) { + logger->cout(""); + } + logger->cout( + "Name: " ANSI_BOLD "%s" ANSI_NORMAL "%s", + element.name, + element.active ? "" : " " ANSI_RED "(inactive)" ANSI_NORMAL + ); + logger->cout( + "Index: " ANSI_BOLD "%s" ANSI_NORMAL "%S", + i + ); if (element.source) { logger->cout("Flake attribute: %s%s", element.source->attrPath, element.source->outputs.to_string()); logger->cout("Original flake URL: %s", element.source->originalRef.to_string()); |