diff options
author | Ben Burdette <bburdette@protonmail.com> | 2022-04-07 13:42:01 -0600 |
---|---|---|
committer | Ben Burdette <bburdette@protonmail.com> | 2022-04-07 13:42:01 -0600 |
commit | 1a93ac8133381eb692416c4e46b1706faa5cd89f (patch) | |
tree | 9a559f977ad6213c055099f6f2ab6be96f0c551b /src/nix | |
parent | d2ec9b4e15718e42720787140d7825dcbfd73249 (diff) | |
parent | 8b1e328d5d0ae7d3a4a8f6012ec065b59674ed4a (diff) |
Merge remote-tracking branch 'upstream/master' into upstream-merge
Diffstat (limited to 'src/nix')
33 files changed, 442 insertions, 297 deletions
diff --git a/src/nix/app.cc b/src/nix/app.cc index e104cc9c1..803d028f0 100644 --- a/src/nix/app.cc +++ b/src/nix/app.cc @@ -4,6 +4,7 @@ #include "eval-cache.hh" #include "names.hh" #include "command.hh" +#include "derivations.hh" namespace nix { @@ -70,7 +71,7 @@ UnresolvedApp Installable::toApp(EvalState & state) std::vector<StorePathWithOutputs> context2; for (auto & [path, name] : context) - context2.push_back({state.store->parseStorePath(path), {name}}); + context2.push_back({path, {name}}); return UnresolvedApp{App { .context = std::move(context2), @@ -114,7 +115,7 @@ App UnresolvedApp::resolve(ref<Store> evalStore, ref<Store> store) installableContext.push_back( std::make_shared<InstallableDerivedPath>(store, ctxElt.toDerivedPath())); - auto builtContext = build(evalStore, store, Realise::Outputs, installableContext); + auto builtContext = Installable::build(evalStore, store, Realise::Outputs, installableContext); res.program = resolveString(*store, unresolved.program, builtContext); if (!store->isInStore(res.program)) throw Error("app program '%s' is not in the Nix store", res.program); diff --git a/src/nix/build.cc b/src/nix/build.cc index 6e31757a2..840c7ca38 100644 --- a/src/nix/build.cc +++ b/src/nix/build.cc @@ -52,15 +52,26 @@ struct CmdBuild : InstallablesCommand, MixDryRun, MixJSON, MixProfile void run(ref<Store> store) override { - auto buildables = build( + if (dryRun) { + std::vector<DerivedPath> pathsToBuild; + + for (auto & i : installables) { + auto b = i->toDerivedPaths(); + pathsToBuild.insert(pathsToBuild.end(), b.begin(), b.end()); + } + printMissing(store, pathsToBuild, lvlError); + if (json) + logger->cout("%s", derivedPathsToJSON(pathsToBuild, store).dump()); + return; + } + + auto buildables = Installable::build( getEvalStore(), store, - dryRun ? Realise::Derivation : Realise::Outputs, + Realise::Outputs, installables, buildMode); if (json) logger->cout("%s", derivedPathsWithHintsToJSON(buildables, store).dump()); - if (dryRun) return; - if (outLink != "") if (auto store2 = store.dynamic_pointer_cast<LocalFSStore>()) for (const auto & [_i, buildable] : enumerate(buildables)) { diff --git a/src/nix/bundle.cc b/src/nix/bundle.cc index 113ceca33..81fb8464a 100644 --- a/src/nix/bundle.cc +++ b/src/nix/bundle.cc @@ -9,7 +9,7 @@ using namespace nix; struct CmdBundle : InstallableCommand { - std::string bundler = "github:matthewbauer/nix-bundle"; + std::string bundler = "github:NixOS/bundlers"; std::optional<Path> outLink; CmdBundle() @@ -49,9 +49,11 @@ struct CmdBundle : InstallableCommand Category category() override { return catSecondary; } + // FIXME: cut&paste from CmdRun. Strings getDefaultFlakeAttrPaths() override { Strings res{ + "apps." + settings.thisSystem.get() + ".default", "defaultApp." + settings.thisSystem.get() }; for (auto & s : SourceExprCommand::getDefaultFlakeAttrPaths()) @@ -61,10 +63,7 @@ struct CmdBundle : InstallableCommand Strings getDefaultFlakeAttrPathPrefixes() override { - Strings res{ - "apps." + settings.thisSystem.get() + "." - - }; + Strings res{"apps." + settings.thisSystem.get() + "."}; for (auto & s : SourceExprCommand::getDefaultFlakeAttrPathPrefixes()) res.push_back(s); return res; @@ -74,21 +73,18 @@ struct CmdBundle : InstallableCommand { auto evalState = getEvalState(); - auto [progFlakeRef, progName] = parseFlakeRefWithFragment(installable->what(), absPath(".")); - const flake::LockFlags lockFlagsProg{ .writeLockFile = false }; - auto programInstallable = InstallableFlake(this, - evalState, std::move(progFlakeRef), - Strings{progName == "" ? "defaultApp" : progName}, - Strings(this->getDefaultFlakeAttrPathPrefixes()), - lockFlagsProg); - auto val = programInstallable.toValue(*evalState).first; + auto val = installable->toValue(*evalState).first; auto [bundlerFlakeRef, bundlerName] = parseFlakeRefWithFragment(bundler, absPath(".")); const flake::LockFlags lockFlags{ .writeLockFile = false }; - auto bundler = InstallableFlake(this, - evalState, std::move(bundlerFlakeRef), - Strings{bundlerName == "" ? "defaultBundler." + settings.thisSystem.get() : settings.thisSystem.get() + "." + bundlerName, bundlerName}, - Strings({"","bundlers."}), lockFlags); + InstallableFlake bundler{this, + evalState, std::move(bundlerFlakeRef), bundlerName, + {"bundlers." + settings.thisSystem.get() + ".default", + "defaultBundler." + settings.thisSystem.get() + }, + {"bundlers." + settings.thisSystem.get() + "."}, + lockFlags + }; auto vRes = evalState->allocValue(); evalState->callFunction(*bundler.toValue(*evalState).first, *val, *vRes, noPos); @@ -101,13 +97,13 @@ struct CmdBundle : InstallableCommand throw Error("the bundler '%s' does not produce a derivation", bundler.what()); PathSet context2; - StorePath drvPath = store->parseStorePath(evalState->coerceToPath(*attr1->pos, *attr1->value, context2)); + auto drvPath = evalState->coerceToStorePath(*attr1->pos, *attr1->value, context2); auto attr2 = vRes->attrs->get(evalState->sOutPath); if (!attr2) throw Error("the bundler '%s' does not produce a derivation", bundler.what()); - StorePath outPath = store->parseStorePath(evalState->coerceToPath(*attr2->pos, *attr2->value, context2)); + auto outPath = evalState->coerceToStorePath(*attr2->pos, *attr2->value, context2); store->buildPaths({ DerivedPath::Built { drvPath } }); diff --git a/src/nix/bundle.md b/src/nix/bundle.md index a5186a996..2bb70711f 100644 --- a/src/nix/bundle.md +++ b/src/nix/bundle.md @@ -42,24 +42,26 @@ homepage](https://github.com/NixOS/bundlers) for more details. If no flake output attribute is given, `nix bundle` tries the following flake output attributes: -* `defaultBundler.<system>` +* `bundlers.<system>.default` If an attribute *name* is given, `nix run` tries the following flake output attributes: -* `bundler.<system>.<name>` +* `bundlers.<system>.<name>` # Bundlers A bundler is specified by a flake output attribute named -`bundlers.<system>.<name>` or `defaultBundler.<system>`. It looks like this: +`bundlers.<system>.<name>`. It looks like this: ```nix -bundlers.x86_64-linux.identity = drv: drv; +bundlers.x86_64-linux = rec { + identity = drv: drv; -bundlers.x86_64-linux.blender_2_79 = drv: self.packages.x86_64-linux.blender_2_79; + blender_2_79 = drv: self.packages.x86_64-linux.blender_2_79; -defaultBundler.x86_64-linux = drv: drv; + default = identity; +}; ``` A bundler must be a function that accepts an arbitrary value (typically a diff --git a/src/nix/daemon.cc b/src/nix/daemon.cc index 6a40a0bd3..940923d3b 100644 --- a/src/nix/daemon.cc +++ b/src/nix/daemon.cc @@ -76,7 +76,7 @@ static void setSigChldAction(bool autoReap) } -bool matchUser(const string & user, const string & group, const Strings & users) +bool matchUser(const std::string & user, const std::string & group, const Strings & users) { if (find(users.begin(), users.end(), "*") != users.end()) return true; @@ -85,12 +85,12 @@ bool matchUser(const string & user, const string & group, const Strings & users) return true; for (auto & i : users) - if (string(i, 0, 1) == "@") { - if (group == string(i, 1)) return true; + if (i.substr(0, 1) == "@") { + if (group == i.substr(1)) return true; struct group * gr = getgrnam(i.c_str() + 1); if (!gr) continue; for (char * * mem = gr->gr_mem; *mem; mem++) - if (user == string(*mem)) return true; + if (user == std::string(*mem)) return true; } return false; @@ -198,10 +198,10 @@ static void daemonLoop() PeerInfo peer = getPeerInfo(remote.get()); struct passwd * pw = peer.uidKnown ? getpwuid(peer.uid) : 0; - string user = pw ? pw->pw_name : std::to_string(peer.uid); + std::string user = pw ? pw->pw_name : std::to_string(peer.uid); struct group * gr = peer.gidKnown ? getgrgid(peer.gid) : 0; - string group = gr ? gr->gr_name : std::to_string(peer.gid); + std::string group = gr ? gr->gr_name : std::to_string(peer.gid); Strings trustedUsers = settings.trustedUsers; Strings allowedUsers = settings.allowedUsers; @@ -212,7 +212,7 @@ static void daemonLoop() if ((!trusted && !matchUser(user, group, allowedUsers)) || group == settings.buildUsersGroup) throw Error("user '%1%' is not allowed to connect to the Nix daemon", user); - printInfo(format((string) "accepted connection from pid %1%, user %2%" + (trusted ? " (trusted)" : "")) + printInfo(format((std::string) "accepted connection from pid %1%, user %2%" + (trusted ? " (trusted)" : "")) % (peer.pidKnown ? std::to_string(peer.pid) : "<unknown>") % (peer.uidKnown ? user : "<unknown>")); @@ -234,7 +234,7 @@ static void daemonLoop() // For debugging, stuff the pid into argv[1]. if (peer.pidKnown && savedArgv[1]) { - string processName = std::to_string(peer.pid); + auto processName = std::to_string(peer.pid); strncpy(savedArgv[1], processName.c_str(), strlen(savedArgv[1])); } diff --git a/src/nix/develop.cc b/src/nix/develop.cc index 42e13436a..7fc74d34e 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -196,21 +196,22 @@ static StorePath getDerivationEnvironment(ref<Store> store, ref<Store> evalStore drv.inputSrcs.insert(std::move(getEnvShPath)); if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) { for (auto & output : drv.outputs) { - output.second = { - .output = DerivationOutputDeferred{}, - }; + output.second = DerivationOutput::Deferred {}, drv.env[output.first] = hashPlaceholder(output.first); } } else { for (auto & output : drv.outputs) { - output.second = { .output = DerivationOutputInputAddressed { .path = StorePath::dummy } }; + output.second = DerivationOutput::Deferred { }; drv.env[output.first] = ""; } - Hash h = std::get<0>(hashDerivationModulo(*evalStore, drv, true)); + auto hashesModulo = hashDerivationModulo(*evalStore, drv, true); for (auto & output : drv.outputs) { + Hash h = hashesModulo.hashes.at(output.first); auto outPath = store->makeOutputPath(output.first, h, drv.name); - output.second = { .output = DerivationOutputInputAddressed { .path = outPath } }; + output.second = DerivationOutput::InputAddressed { + .path = outPath, + }; drv.env[output.first] = store->printStorePath(outPath); } } @@ -307,7 +308,7 @@ struct Common : InstallableCommand, MixProfile for (auto & [installable_, dir_] : redirects) { auto dir = absPath(dir_); auto installable = parseInstallable(store, installable_); - auto builtPaths = toStorePaths( + auto builtPaths = Installable::toStorePaths( getEvalStore(), store, Realise::Nothing, OperateOn::Output, {installable}); for (auto & path: builtPaths) { auto from = store->printStorePath(path); @@ -325,8 +326,15 @@ struct Common : InstallableCommand, MixProfile Strings getDefaultFlakeAttrPaths() override { - return {"devShell." + settings.thisSystem.get(), "defaultPackage." + settings.thisSystem.get()}; + Strings paths{ + "devShells." + settings.thisSystem.get() + ".default", + "devShell." + settings.thisSystem.get(), + }; + for (auto & p : SourceExprCommand::getDefaultFlakeAttrPaths()) + paths.push_back(p); + return paths; } + Strings getDefaultFlakeAttrPathPrefixes() override { auto res = SourceExprCommand::getDefaultFlakeAttrPathPrefixes(); @@ -340,7 +348,7 @@ struct Common : InstallableCommand, MixProfile if (path && hasSuffix(path->to_string(), "-env")) return *path; else { - auto drvs = toDerivations(store, {installable}); + auto drvs = Installable::toDerivations(store, {installable}); if (drvs.size() != 1) throw Error("'%s' needs to evaluate to a single derivation, but it evaluated to %d derivations", @@ -498,12 +506,14 @@ struct CmdDevelop : Common, MixEnvironment this, state, installable->nixpkgsFlakeRef(), - Strings{"bashInteractive"}, + "bashInteractive", + Strings{}, Strings{"legacyPackages." + settings.thisSystem.get() + "."}, nixpkgsLockFlags); shell = store->printStorePath( - toStorePath(getEvalStore(), store, Realise::Outputs, OperateOn::Output, bashInstallable)) + "/bin/bash"; + Installable::toStorePath(getEvalStore(), store, Realise::Outputs, OperateOn::Output, bashInstallable)) + + "/bin/bash"; } catch (Error &) { ignoreException(); } diff --git a/src/nix/develop.md b/src/nix/develop.md index 3e7e339d5..8bcff66c9 100644 --- a/src/nix/develop.md +++ b/src/nix/develop.md @@ -88,9 +88,9 @@ the flake's `nixConfig` attribute. If no flake output attribute is given, `nix develop` tries the following flake output attributes: -* `devShell.<system>` +* `devShells.<system>.default` -* `defaultPackage.<system>` +* `packages.<system>.default` If a flake output *name* is given, `nix develop` tries the following flake output attributes: diff --git a/src/nix/diff-closures.cc b/src/nix/diff-closures.cc index 734c41e0e..0621d662c 100644 --- a/src/nix/diff-closures.cc +++ b/src/nix/diff-closures.cc @@ -131,9 +131,9 @@ struct CmdDiffClosures : SourceExprCommand void run(ref<Store> store) override { auto before = parseInstallable(store, _before); - auto beforePath = toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, before); + auto beforePath = Installable::toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, before); auto after = parseInstallable(store, _after); - auto afterPath = toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, after); + auto afterPath = Installable::toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, after); printClosureDiff(store, beforePath, afterPath, ""); } }; diff --git a/src/nix/doctor.cc b/src/nix/doctor.cc index 4f3003448..ea87e3d87 100644 --- a/src/nix/doctor.cc +++ b/src/nix/doctor.cc @@ -24,12 +24,12 @@ std::string formatProtocol(unsigned int proto) } bool checkPass(const std::string & msg) { - logger->log(ANSI_GREEN "[PASS] " ANSI_NORMAL + msg); + notice(ANSI_GREEN "[PASS] " ANSI_NORMAL + msg); return true; } bool checkFail(const std::string & msg) { - logger->log(ANSI_RED "[FAIL] " ANSI_NORMAL + msg); + notice(ANSI_RED "[FAIL] " ANSI_NORMAL + msg); return false; } diff --git a/src/nix/edit.md b/src/nix/edit.md index 80563d06b..89bd09abf 100644 --- a/src/nix/edit.md +++ b/src/nix/edit.md @@ -24,8 +24,8 @@ this attribute to the location of the definition of the `meta.description`, `version` or `name` derivation attributes. The editor to invoke is specified by the `EDITOR` environment -variable. It defaults to `cat`. If the editor is `emacs`, `nano` or -`vim`, it is passed the line number of the derivation using the -argument `+<lineno>`. +variable. It defaults to `cat`. If the editor is `emacs`, `nano`, +`vim` or `kak`, it is passed the line number of the derivation using +the argument `+<lineno>`. )"" diff --git a/src/nix/flake-init.md b/src/nix/flake-init.md index 890038016..fc1f4f805 100644 --- a/src/nix/flake-init.md +++ b/src/nix/flake-init.md @@ -24,19 +24,23 @@ R""( This command creates a flake in the current directory by copying the files of a template. It will not overwrite existing files. The default -template is `templates#defaultTemplate`, but this can be overridden +template is `templates#templates.default`, but this can be overridden using `-t`. # Template definitions -A flake can declare templates through its `templates` and -`defaultTemplate` output attributes. A template has two attributes: +A flake can declare templates through its `templates` output +attribute. A template has two attributes: * `description`: A one-line description of the template, in CommonMark syntax. * `path`: The path of the directory to be copied. +* `welcomeText`: A block of markdown text to display when a user initializes a + new flake based on this template. + + Here is an example: ``` @@ -45,9 +49,19 @@ outputs = { self }: { templates.rust = { path = ./rust; description = "A simple Rust/Cargo project"; + welcomeText = '' + # Simple Rust/Cargo Template + ## Intended usage + The intended usage of this flake is... + + ## More info + - [Rust language](https://www.rust-lang.org/) + - [Rust on the NixOS Wiki](https://nixos.wiki/wiki/Rust) + - ... + ''; }; - templates.defaultTemplate = self.templates.rust; + templates.default = self.templates.rust; } ``` diff --git a/src/nix/flake-show.md b/src/nix/flake-show.md index e484cf47e..f3b74285d 100644 --- a/src/nix/flake-show.md +++ b/src/nix/flake-show.md @@ -13,10 +13,13 @@ R""( │ │ └───build: derivation 'patchelf-0.12.20201207.f34751b' │ └───x86_64-linux │ └───build: derivation 'patchelf-0.12.20201207.f34751b' - ├───defaultPackage - │ ├───aarch64-linux: package 'patchelf-0.12.20201207.f34751b' - │ ├───i686-linux: package 'patchelf-0.12.20201207.f34751b' - │ └───x86_64-linux: package 'patchelf-0.12.20201207.f34751b' + ├───packages + │ ├───aarch64-linux + │ │ └───default: package 'patchelf-0.12.20201207.f34751b' + │ ├───i686-linux + │ │ └───default: package 'patchelf-0.12.20201207.f34751b' + │ └───x86_64-linux + │ └───default: package 'patchelf-0.12.20201207.f34751b' ├───hydraJobs │ ├───build │ │ ├───aarch64-linux: derivation 'patchelf-0.12.20201207.f34751b' diff --git a/src/nix/flake.cc b/src/nix/flake.cc index 4bc79820c..a876bb3af 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -13,6 +13,7 @@ #include "registry.hh" #include "json.hh" #include "eval-cache.hh" +#include "markdown.hh" #include <nlohmann/json.hpp> #include <queue> @@ -326,7 +327,7 @@ struct CmdFlakeCheck : FlakeCommand if (!drvInfo) throw Error("flake attribute '%s' is not a derivation", attrPath); // FIXME: check meta attributes - return std::make_optional(store->parseStorePath(drvInfo->queryDrvPath())); + return drvInfo->queryDrvPath(); } catch (Error & e) { e.addTrace(pos, hintfmt("while checking the derivation '%s'", attrPath)); reportError(e); @@ -462,7 +463,7 @@ struct CmdFlakeCheck : FlakeCommand for (auto & attr : *v.attrs) { std::string name(attr.name); - if (name != "path" && name != "description") + if (name != "path" && name != "description" && name != "welcomeText") throw Error("template '%s' has unsupported attribute '%s'", attrPath, name); } } catch (Error & e) { @@ -500,6 +501,18 @@ struct CmdFlakeCheck : FlakeCommand state->forceValue(vOutput, pos); + std::string_view replacement = + name == "defaultPackage" ? "packages.<system>.default" : + name == "defaultApps" ? "apps.<system>.default" : + name == "defaultTemplate" ? "templates.default" : + name == "defaultBundler" ? "bundlers.<system>.default" : + name == "overlay" ? "overlays.default" : + name == "devShell" ? "devShells.<system>.default" : + name == "nixosModule" ? "nixosModules.default" : + ""; + if (replacement != "") + warn("flake output attribute '%s' is deprecated; use '%s' instead", name, replacement); + if (name == "checks") { state->forceAttrs(vOutput, pos); for (auto & attr : *vOutput.attrs) { @@ -649,12 +662,14 @@ struct CmdFlakeCheck : FlakeCommand } }; +static Strings defaultTemplateAttrPathsPrefixes{"templates."}; +static Strings defaultTemplateAttrPaths = {"templates.default", "defaultTemplate"}; + struct CmdFlakeInitCommon : virtual Args, EvalCommand { std::string templateUrl = "templates"; Path destDir; - const Strings attrsPathPrefixes{"templates."}; const LockFlags lockFlags{ .writeLockFile = false }; CmdFlakeInitCommon() @@ -669,8 +684,8 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand completeFlakeRefWithFragment( getEvalState(), lockFlags, - attrsPathPrefixes, - {"defaultTemplate"}, + defaultTemplateAttrPathsPrefixes, + defaultTemplateAttrPaths, prefix); }} }); @@ -685,15 +700,21 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand auto [templateFlakeRef, templateName] = parseFlakeRefWithFragment(templateUrl, absPath(".")); auto installable = InstallableFlake(nullptr, - evalState, std::move(templateFlakeRef), - Strings{templateName == "" ? "defaultTemplate" : templateName}, - Strings(attrsPathPrefixes), lockFlags); + evalState, std::move(templateFlakeRef), templateName, + defaultTemplateAttrPaths, + defaultTemplateAttrPathsPrefixes, + lockFlags); auto [cursor, attrPath] = installable.getCursor(*evalState); - auto templateDir = cursor->getAttr("path")->getString(); + auto templateDirAttr = cursor->getAttr("path"); + auto templateDir = templateDirAttr->getString(); - assert(store->isInStore(templateDir)); + if (!store->isInStore(templateDir)) + throw TypeError( + "'%s' was not found in the Nix store\n" + "If you've set '%s' to a string, try using a path instead.", + templateDir, templateDirAttr->getAttrPathStr()); std::vector<Path> files; @@ -728,6 +749,7 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand else throw Error("file '%s' has unsupported type", from2); files.push_back(to2); + notice("wrote: %s", to2); } }; @@ -738,6 +760,11 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand for (auto & s : files) args.push_back(s); runProgram("git", true, args); } + auto welcomeText = cursor->maybeGetAttr("welcomeText"); + if (welcomeText) { + notice("\n"); + notice(renderMarkdownToTerminal(welcomeText->getString())); + } } }; diff --git a/src/nix/flake.md b/src/nix/flake.md index accddd436..d59915eeb 100644 --- a/src/nix/flake.md +++ b/src/nix/flake.md @@ -209,6 +209,38 @@ Currently the `type` attribute can be one of the following: * `github:edolstra/dwarffs/unstable` * `github:edolstra/dwarffs/d3f2baba8f425779026c6ec04021b2e927f61e31` +* `sourcehut`: Similar to `github`, is a more efficient way to fetch + SourceHut repositories. The following attributes are required: + + * `owner`: The owner of the repository (including leading `~`). + + * `repo`: The name of the repository. + + Like `github`, these are downloaded as tarball archives. + + The URL syntax for `sourcehut` flakes is: + + `sourcehut:<owner>/<repo>(/<rev-or-ref>)?(\?<params>)?` + + `<rev-or-ref>` works the same as `github`. Either a branch or tag name + (`ref`), or a commit hash (`rev`) can be specified. + + Since SourceHut allows for self-hosting, you can specify `host` as + a parameter, to point to any instances other than `git.sr.ht`. + + Currently, `ref` name resolution only works for Git repositories. + You can refer to Mercurial repositories by simply changing `host` to + `hg.sr.ht` (or any other Mercurial instance). With the caveat + that you must explicitly specify a commit hash (`rev`). + + Some examples: + + * `sourcehut:~misterio/nix-colors` + * `sourcehut:~misterio/nix-colors/main` + * `sourcehut:~misterio/nix-colors?host=git.example.org` + * `sourcehut:~misterio/nix-colors/182b4b8709b8ffe4e9774a4c5d6877bf6bb9a21c` + * `sourcehut:~misterio/nix-colors/21c1a380a6915d890d408e9f22203436a35bb2de?host=hg.sr.ht` + * `indirect`: Indirections through the flake registry. These have the form @@ -236,7 +268,7 @@ derivation): outputs = { self, nixpkgs }: { - defaultPackage.x86_64-linux = + packages.x86_64-linux.default = # Notice the reference to nixpkgs here. with import nixpkgs { system = "x86_64-linux"; }; stdenv.mkDerivation { diff --git a/src/nix/hash.cc b/src/nix/hash.cc index 4535e4ab0..60d9593a7 100644 --- a/src/nix/hash.cc +++ b/src/nix/hash.cc @@ -177,7 +177,7 @@ static int compatNixHash(int argc, char * * argv) else if (*arg == "--base32") base32 = true; else if (*arg == "--truncate") truncate = true; else if (*arg == "--type") { - string s = getArg(*arg, arg, end); + std::string s = getArg(*arg, arg, end); ht = parseHashType(s); } else if (*arg == "--to-base16") op = opTo16; diff --git a/src/nix/log.cc b/src/nix/log.cc index fd3c1d787..72d02ef11 100644 --- a/src/nix/log.cc +++ b/src/nix/log.cc @@ -2,6 +2,7 @@ #include "common-args.hh" #include "shared.hh" #include "store-api.hh" +#include "log-store.hh" #include "progress-bar.hh" using namespace nix; @@ -34,17 +35,24 @@ struct CmdLog : InstallableCommand RunPager pager; for (auto & sub : subs) { + auto * logSubP = dynamic_cast<LogStore *>(&*sub); + if (!logSubP) { + printInfo("Skipped '%s' which does not support retrieving build logs", sub->getUri()); + continue; + } + auto & logSub = *logSubP; + auto log = std::visit(overloaded { [&](const DerivedPath::Opaque & bo) { - return sub->getBuildLog(bo.path); + return logSub.getBuildLog(bo.path); }, [&](const DerivedPath::Built & bfd) { - return sub->getBuildLog(bfd.drvPath); + return logSub.getBuildLog(bfd.drvPath); }, }, b.raw()); if (!log) continue; stopProgressBar(); - printInfo("got build log for '%s' from '%s'", installable->what(), sub->getUri()); + printInfo("got build log for '%s' from '%s'", installable->what(), logSub.getUri()); std::cout << *log; return; } diff --git a/src/nix/main.cc b/src/nix/main.cc index b923f2535..6198681e7 100644 --- a/src/nix/main.cc +++ b/src/nix/main.cc @@ -117,7 +117,7 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs {"hash-path", {"hash", "path"}}, {"ls-nar", {"nar", "ls"}}, {"ls-store", {"store", "ls"}}, - {"make-content-addressable", {"store", "make-content-addressable"}}, + {"make-content-addressable", {"store", "make-content-addressed"}}, {"optimise-store", {"store", "optimise"}}, {"ping-store", {"store", "ping"}}, {"sign-paths", {"store", "sign"}}, @@ -289,6 +289,7 @@ void mainWrapped(int argc, char * * argv) } if (argc == 2 && std::string(argv[1]) == "__dump-builtins") { + settings.experimentalFeatures = {Xp::Flakes, Xp::FetchClosure}; evalSettings.pureEval = false; EvalState state({}, openStore("dummy://")); auto res = nlohmann::json::object(); diff --git a/src/nix/make-content-addressable.cc b/src/nix/make-content-addressable.cc deleted file mode 100644 index 2e75a3b61..000000000 --- a/src/nix/make-content-addressable.cc +++ /dev/null @@ -1,102 +0,0 @@ -#include "command.hh" -#include "store-api.hh" -#include "references.hh" -#include "common-args.hh" -#include "json.hh" - -using namespace nix; - -struct CmdMakeContentAddressable : StorePathsCommand, MixJSON -{ - CmdMakeContentAddressable() - { - realiseMode = Realise::Outputs; - } - - std::string description() override - { - return "rewrite a path or closure to content-addressed form"; - } - - std::string doc() override - { - return - #include "make-content-addressable.md" - ; - } - - void run(ref<Store> store, StorePaths && storePaths) override - { - auto paths = store->topoSortPaths(StorePathSet(storePaths.begin(), storePaths.end())); - - std::reverse(paths.begin(), paths.end()); - - std::map<StorePath, StorePath> remappings; - - auto jsonRoot = json ? std::make_unique<JSONObject>(std::cout) : nullptr; - auto jsonRewrites = json ? std::make_unique<JSONObject>(jsonRoot->object("rewrites")) : nullptr; - - for (auto & path : paths) { - auto pathS = store->printStorePath(path); - auto oldInfo = store->queryPathInfo(path); - std::string oldHashPart(path.hashPart()); - - StringSink sink; - store->narFromPath(path, sink); - - StringMap rewrites; - - StorePathSet references; - bool hasSelfReference = false; - for (auto & ref : oldInfo->references) { - if (ref == path) - hasSelfReference = true; - else { - auto i = remappings.find(ref); - auto replacement = i != remappings.end() ? i->second : ref; - // FIXME: warn about unremapped paths? - if (replacement != ref) - rewrites.insert_or_assign(store->printStorePath(ref), store->printStorePath(replacement)); - references.insert(std::move(replacement)); - } - } - - sink.s = rewriteStrings(sink.s, rewrites); - - HashModuloSink hashModuloSink(htSHA256, oldHashPart); - hashModuloSink(sink.s); - - auto narHash = hashModuloSink.finish().first; - - ValidPathInfo info { - store->makeFixedOutputPath(FileIngestionMethod::Recursive, narHash, path.name(), references, hasSelfReference), - narHash, - }; - info.references = std::move(references); - if (hasSelfReference) info.references.insert(info.path); - info.narSize = sink.s.size(); - info.ca = FixedOutputHash { - .method = FileIngestionMethod::Recursive, - .hash = info.narHash, - }; - - if (!json) - notice("rewrote '%s' to '%s'", pathS, store->printStorePath(info.path)); - - auto source = sinkToSource([&](Sink & nextSink) { - RewritingSink rsink2(oldHashPart, std::string(info.path.hashPart()), nextSink); - rsink2(sink.s); - rsink2.flush(); - }); - - store->addToStore(info, *source); - - if (json) - jsonRewrites->attr(store->printStorePath(path), store->printStorePath(info.path)); - - remappings.insert_or_assign(std::move(path), std::move(info.path)); - } - } -}; - -static auto rCmdMakeContentAddressable = registerCommand2<CmdMakeContentAddressable>({"store", "make-content-addressable"}); diff --git a/src/nix/make-content-addressed.cc b/src/nix/make-content-addressed.cc new file mode 100644 index 000000000..34860c38f --- /dev/null +++ b/src/nix/make-content-addressed.cc @@ -0,0 +1,55 @@ +#include "command.hh" +#include "store-api.hh" +#include "make-content-addressed.hh" +#include "common-args.hh" +#include "json.hh" + +using namespace nix; + +struct CmdMakeContentAddressed : virtual CopyCommand, virtual StorePathsCommand, MixJSON +{ + CmdMakeContentAddressed() + { + realiseMode = Realise::Outputs; + } + + std::string description() override + { + return "rewrite a path or closure to content-addressed form"; + } + + std::string doc() override + { + return + #include "make-content-addressed.md" + ; + } + + void run(ref<Store> srcStore, StorePaths && storePaths) override + { + auto dstStore = dstUri.empty() ? openStore() : openStore(dstUri); + + auto remappings = makeContentAddressed(*srcStore, *dstStore, + StorePathSet(storePaths.begin(), storePaths.end())); + + if (json) { + JSONObject jsonRoot(std::cout); + JSONObject jsonRewrites(jsonRoot.object("rewrites")); + for (auto & path : storePaths) { + auto i = remappings.find(path); + assert(i != remappings.end()); + jsonRewrites.attr(srcStore->printStorePath(path), srcStore->printStorePath(i->second)); + } + } else { + for (auto & path : storePaths) { + auto i = remappings.find(path); + assert(i != remappings.end()); + notice("rewrote '%s' to '%s'", + srcStore->printStorePath(path), + srcStore->printStorePath(i->second)); + } + } + } +}; + +static auto rCmdMakeContentAddressed = registerCommand2<CmdMakeContentAddressed>({"store", "make-content-addressed"}); diff --git a/src/nix/make-content-addressable.md b/src/nix/make-content-addressed.md index 3dd847edc..215683e6d 100644 --- a/src/nix/make-content-addressable.md +++ b/src/nix/make-content-addressed.md @@ -5,7 +5,7 @@ R""( * Create a content-addressed representation of the closure of GNU Hello: ```console - # nix store make-content-addressable -r nixpkgs#hello + # nix store make-content-addressed nixpkgs#hello … rewrote '/nix/store/v5sv61sszx301i0x6xysaqzla09nksnd-hello-2.10' to '/nix/store/5skmmcb9svys5lj3kbsrjg7vf2irid63-hello-2.10' ``` @@ -29,7 +29,7 @@ R""( system closure: ```console - # nix store make-content-addressable -r /run/current-system + # nix store make-content-addressed /run/current-system ``` # Description diff --git a/src/nix/nix.md b/src/nix/nix.md index 1dc59362d..0dacadee6 100644 --- a/src/nix/nix.md +++ b/src/nix/nix.md @@ -97,11 +97,9 @@ the Nix store. Here are the recognised types of installables: For example, if `/foo/bar/flake.nix` exists, then `/foo/bar/baz/` will resolve to `path:/foo/bar` - - If *attrpath* is omitted, Nix tries some default values; for most - subcommands, the default is `defaultPackage.`*system* - (e.g. `defaultPackage.x86_64-linux`), but some subcommands have + subcommands, the default is `packages.`*system*`.default` + (e.g. `packages.x86_64-linux.default`), but some subcommands have other defaults. If *attrpath* *is* specified, *attrpath* is interpreted as relative to one or more prefixes; for most subcommands, these are `packages.`*system*, diff --git a/src/nix/path-info.cc b/src/nix/path-info.cc index 3743d7504..d690fe594 100644 --- a/src/nix/path-info.cc +++ b/src/nix/path-info.cc @@ -97,7 +97,7 @@ struct CmdPathInfo : StorePathsCommand, MixJSON for (auto & storePath : storePaths) { auto info = store->queryPathInfo(storePath); - auto storePathS = store->printStorePath(storePath); + auto storePathS = store->printStorePath(info->path); std::cout << storePathS; diff --git a/src/nix/prefetch.cc b/src/nix/prefetch.cc index 094d2a519..f2dd44ba4 100644 --- a/src/nix/prefetch.cc +++ b/src/nix/prefetch.cc @@ -16,7 +16,7 @@ using namespace nix; /* If ‘url’ starts with ‘mirror://’, then resolve it using the list of mirrors defined in Nixpkgs. */ -string resolveMirrorUrl(EvalState & state, string url) +std::string resolveMirrorUrl(EvalState & state, const std::string & url) { if (url.substr(0, 9) != "mirror://") return url; @@ -38,8 +38,8 @@ string resolveMirrorUrl(EvalState & state, string url) if (mirrorList->value->listSize() < 1) throw Error("mirror URL '%s' did not expand to anything", url); - string mirror(state.forceString(*mirrorList->value->listElems()[0])); - return mirror + (hasSuffix(mirror, "/") ? "" : "/") + string(s, p + 1); + std::string mirror(state.forceString(*mirrorList->value->listElems()[0])); + return mirror + (hasSuffix(mirror, "/") ? "" : "/") + s.substr(p + 1); } std::tuple<StorePath, Hash> prefetchFile( @@ -128,10 +128,10 @@ static int main_nix_prefetch_url(int argc, char * * argv) { { HashType ht = htSHA256; - std::vector<string> args; + std::vector<std::string> args; bool printPath = getEnv("PRINT_PATH") == "1"; bool fromExpr = false; - string attrPath; + std::string attrPath; bool unpack = false; bool executable = false; std::optional<std::string> name; @@ -147,7 +147,7 @@ static int main_nix_prefetch_url(int argc, char * * argv) else if (*arg == "--version") printVersion("nix-prefetch-url"); else if (*arg == "--type") { - string s = getArg(*arg, arg, end); + auto s = getArg(*arg, arg, end); ht = parseHashType(s); } else if (*arg == "--print-path") @@ -186,7 +186,7 @@ static int main_nix_prefetch_url(int argc, char * * argv) /* If -A is given, get the URL from the specified Nix expression. */ - string url; + std::string url; if (!fromExpr) { if (args.empty()) throw UsageError("you must specify a URL"); diff --git a/src/nix/profile-list.md b/src/nix/profile-list.md index 5c29c0b02..bdab9a208 100644 --- a/src/nix/profile-list.md +++ b/src/nix/profile-list.md @@ -8,7 +8,7 @@ R""( # nix profile list 0 flake:nixpkgs#legacyPackages.x86_64-linux.spotify github:NixOS/nixpkgs/c23db78bbd474c4d0c5c3c551877523b4a50db06#legacyPackages.x86_64-linux.spotify /nix/store/akpdsid105phbbvknjsdh7hl4v3fhjkr-spotify-1.1.46.916.g416cacf1 1 flake:nixpkgs#legacyPackages.x86_64-linux.zoom-us github:NixOS/nixpkgs/c23db78bbd474c4d0c5c3c551877523b4a50db06#legacyPackages.x86_64-linux.zoom-us /nix/store/89pmjmbih5qpi7accgacd17ybpgp4xfm-zoom-us-5.4.53350.1027 - 2 flake:blender-bin#defaultPackage.x86_64-linux github:edolstra/nix-warez/d09d7eea893dcb162e89bc67f6dc1ced14abfc27?dir=blender#defaultPackage.x86_64-linux /nix/store/zfgralhqjnam662kqsgq6isjw8lhrflz-blender-bin-2.91.0 + 2 flake:blender-bin#packages.x86_64-linux.default github:edolstra/nix-warez/d09d7eea893dcb162e89bc67f6dc1ced14abfc27?dir=blender#packages.x86_64-linux.default /nix/store/zfgralhqjnam662kqsgq6isjw8lhrflz-blender-bin-2.91.0 ``` # Description diff --git a/src/nix/profile.cc b/src/nix/profile.cc index 9b7c999af..b151e48d6 100644 --- a/src/nix/profile.cc +++ b/src/nix/profile.cc @@ -61,6 +61,26 @@ struct ProfileElement { return std::tuple(describe(), storePaths) < std::tuple(other.describe(), other.storePaths); } + + void updateStorePaths( + ref<Store> evalStore, + ref<Store> store, + const BuiltPaths & builtPaths) + { + // FIXME: respect meta.outputsToInstall + storePaths.clear(); + for (auto & buildable : builtPaths) { + std::visit(overloaded { + [&](const BuiltPath::Opaque & bo) { + storePaths.insert(bo.path); + }, + [&](const BuiltPath::Built & bfd) { + for (auto & output : bfd.outputs) + storePaths.insert(output.second); + }, + }, buildable.raw()); + } + } }; struct ProfileManifest @@ -77,18 +97,30 @@ struct ProfileManifest auto json = nlohmann::json::parse(readFile(manifestPath)); auto version = json.value("version", 0); - if (version != 1) - throw Error("profile manifest '%s' has unsupported version %d", manifestPath, version); + std::string sUrl; + std::string sOriginalUrl; + switch(version){ + case 1: + sUrl = "uri"; + sOriginalUrl = "originalUri"; + break; + case 2: + sUrl = "url"; + sOriginalUrl = "originalUrl"; + break; + default: + throw Error("profile manifest '%s' has unsupported version %d", manifestPath, version); + } for (auto & e : json["elements"]) { ProfileElement element; for (auto & p : e["storePaths"]) element.storePaths.insert(state.store->parseStorePath((std::string) p)); element.active = e["active"]; - if (e.value("uri", "") != "") { + if (e.value(sUrl,"") != "") { element.source = ProfileElementSource{ - parseFlakeRef(e["originalUri"]), - parseFlakeRef(e["uri"]), + parseFlakeRef(e[sOriginalUrl]), + parseFlakeRef(e[sUrl]), e["attrPath"] }; } @@ -105,7 +137,7 @@ struct ProfileManifest for (auto & drvInfo : drvInfos) { ProfileElement element; - element.storePaths = {state.store->parseStorePath(drvInfo.queryOutPath())}; + element.storePaths = {drvInfo.queryOutPath()}; elements.emplace_back(std::move(element)); } } @@ -122,14 +154,14 @@ struct ProfileManifest obj["storePaths"] = paths; obj["active"] = element.active; if (element.source) { - obj["originalUri"] = element.source->originalRef.to_string(); - obj["uri"] = element.source->resolvedRef.to_string(); + obj["originalUrl"] = element.source->originalRef.to_string(); + obj["url"] = element.source->resolvedRef.to_string(); obj["attrPath"] = element.source->attrPath; } array.push_back(obj); } nlohmann::json json; - json["version"] = 1; + json["version"] = 2; json["elements"] = array; return json.dump(); } @@ -214,6 +246,16 @@ struct ProfileManifest } }; +static std::map<Installable *, BuiltPaths> +builtPathsPerInstallable( + const std::vector<std::pair<std::shared_ptr<Installable>, BuiltPath>> & builtPaths) +{ + std::map<Installable *, BuiltPaths> res; + for (auto & [installable, builtPath] : builtPaths) + res[installable.get()].push_back(builtPath); + return res; +} + struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile { std::string description() override @@ -232,54 +274,28 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile { ProfileManifest manifest(*getEvalState(), *profile); - std::vector<DerivedPath> pathsToBuild; + auto builtPaths = builtPathsPerInstallable( + Installable::build2( + getEvalStore(), store, Realise::Outputs, installables, bmNormal)); for (auto & installable : installables) { + ProfileElement element; + if (auto installable2 = std::dynamic_pointer_cast<InstallableFlake>(installable)) { + // FIXME: make build() return this? auto [attrPath, resolvedRef, drv] = installable2->toDerivation(); - - ProfileElement element; - if (!drv.outPath) - throw UnimplementedError("CA derivations are not yet supported by 'nix profile'"); - element.storePaths = {*drv.outPath}; // FIXME element.source = ProfileElementSource{ installable2->flakeRef, resolvedRef, attrPath, }; + } - pathsToBuild.push_back(DerivedPath::Built{drv.drvPath, StringSet{drv.outputName}}); + element.updateStorePaths(getEvalStore(), store, builtPaths[installable.get()]); - manifest.elements.emplace_back(std::move(element)); - } else { - auto buildables = build(getEvalStore(), store, Realise::Outputs, {installable}, bmNormal); - - for (auto & buildable : buildables) { - ProfileElement element; - - std::visit(overloaded { - [&](const BuiltPath::Opaque & bo) { - pathsToBuild.push_back(bo); - element.storePaths.insert(bo.path); - }, - [&](const BuiltPath::Built & bfd) { - // TODO: Why are we querying if we know the output - // names already? Is it just to figure out what the - // default one is? - for (auto & output : store->queryDerivationOutputMap(bfd.drvPath)) { - pathsToBuild.push_back(DerivedPath::Built{bfd.drvPath, {output.first}}); - element.storePaths.insert(output.second); - } - }, - }, buildable.raw()); - - manifest.elements.emplace_back(std::move(element)); - } - } + manifest.elements.push_back(std::move(element)); } - store->buildPaths(pathsToBuild); - updateProfile(manifest.build(store)); } }; @@ -295,7 +311,11 @@ public: expectArgs("elements", &_matchers); } - typedef std::variant<size_t, Path, std::regex> Matcher; + struct RegexPattern { + std::string pattern; + std::regex reg; + }; + typedef std::variant<size_t, Path, RegexPattern> Matcher; std::vector<Matcher> getMatchers(ref<Store> store) { @@ -307,7 +327,7 @@ public: else if (store->isStorePath(s)) res.push_back(s); else - res.push_back(std::regex(s, std::regex::extended | std::regex::icase)); + res.push_back(RegexPattern{s,std::regex(s, std::regex::extended | std::regex::icase)}); } return res; @@ -320,9 +340,9 @@ public: 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<std::regex>(&matcher)) { + } else if (auto regex = std::get_if<RegexPattern>(&matcher)) { if (element.source - && std::regex_match(element.source->attrPath, *regex)) + && std::regex_match(element.source->attrPath, regex->reg)) return true; } } @@ -355,16 +375,30 @@ struct CmdProfileRemove : virtual EvalCommand, MixDefaultProfile, MixProfileElem for (size_t i = 0; i < oldManifest.elements.size(); ++i) { auto & element(oldManifest.elements[i]); - if (!matches(*store, element, i, matchers)) + if (!matches(*store, element, i, matchers)) { newManifest.elements.push_back(std::move(element)); + } else { + notice("removing '%s'", element.describe()); + } } - // FIXME: warn about unused matchers? - + auto removedCount = oldManifest.elements.size() - newManifest.elements.size(); printInfo("removed %d packages, kept %d packages", - oldManifest.elements.size() - newManifest.elements.size(), + removedCount, newManifest.elements.size()); + if (removedCount == 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); + } + } + warn ("Use 'nix profile list' to see the current profile."); + } updateProfile(newManifest.build(store)); } }; @@ -389,47 +423,71 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf auto matchers = getMatchers(store); - // FIXME: code duplication - std::vector<DerivedPath> pathsToBuild; + std::vector<std::shared_ptr<Installable>> installables; + std::vector<size_t> indices; + + 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.isImmutable() + && !element.source->originalRef.input.isLocked() && matches(*store, element, i, matchers)) { + upgradedCount++; + Activity act(*logger, lvlChatty, actUnknown, fmt("checking '%s' for updates", element.source->attrPath)); - InstallableFlake installable( + auto installable = std::make_shared<InstallableFlake>( this, getEvalState(), FlakeRef(element.source->originalRef), - {element.source->attrPath}, - {}, + "", + Strings{element.source->attrPath}, + Strings{}, lockFlags); - auto [attrPath, resolvedRef, drv] = installable.toDerivation(); + auto [attrPath, resolvedRef, drv] = installable->toDerivation(); if (element.source->resolvedRef == resolvedRef) continue; printInfo("upgrading '%s' from flake '%s' to '%s'", element.source->attrPath, element.source->resolvedRef, resolvedRef); - if (!drv.outPath) - throw UnimplementedError("CA derivations are not yet supported by 'nix profile'"); - element.storePaths = {*drv.outPath}; // FIXME element.source = ProfileElementSource{ - installable.flakeRef, + installable->flakeRef, resolvedRef, attrPath, }; - pathsToBuild.push_back(DerivedPath::Built{drv.drvPath, {drv.outputName}}); + installables.push_back(installable); + indices.push_back(i); } } - store->buildPaths(pathsToBuild); + 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); + } + } + warn ("Use 'nix profile list' to see the current profile."); + } + + auto builtPaths = builtPathsPerInstallable( + Installable::build2( + getEvalStore(), store, Realise::Outputs, installables, bmNormal)); + + for (size_t i = 0; i < installables.size(); ++i) { + auto & installable = installables.at(i); + auto & element = manifest.elements[indices.at(i)]; + element.updateStorePaths(getEvalStore(), store, builtPaths[installable.get()]); + } updateProfile(manifest.build(store)); } diff --git a/src/nix/profile.md b/src/nix/profile.md index d3ddcd3d1..8dade051d 100644 --- a/src/nix/profile.md +++ b/src/nix/profile.md @@ -70,7 +70,7 @@ are installed in this version of the profile. It looks like this: { "active": true, "attrPath": "legacyPackages.x86_64-linux.zoom-us", - "originalUri": "flake:nixpkgs", + "originalUrl": "flake:nixpkgs", "storePaths": [ "/nix/store/wbhg2ga8f3h87s9h5k0slxk0m81m4cxl-zoom-us-5.3.469451.0927" ], @@ -84,11 +84,11 @@ are installed in this version of the profile. It looks like this: Each object in the array `elements` denotes an installed package and has the following fields: -* `originalUri`: The [flake reference](./nix3-flake.md) specified by +* `originalUrl`: The [flake reference](./nix3-flake.md) specified by the user at the time of installation (e.g. `nixpkgs`). This is also the flake reference that will be used by `nix profile upgrade`. -* `uri`: The immutable flake reference to which `originalUri` +* `uri`: The immutable flake reference to which `originalUrl` resolved. * `attrPath`: The flake output attribute that provided this @@ -96,7 +96,7 @@ has the following fields: user specified, but the one resulting from applying the default attribute paths and prefixes; for instance, `hello` might resolve to `packages.x86_64-linux.hello` and the empty string to - `defaultPackage.x86_64-linux`. + `packages.x86_64-linux.default`. * `storePath`: The paths in the Nix store containing the package. diff --git a/src/nix/run.cc b/src/nix/run.cc index bae64ed39..25a8fa8d3 100644 --- a/src/nix/run.cc +++ b/src/nix/run.cc @@ -38,9 +38,12 @@ void runProgramInStore(ref<Store> store, unshare(CLONE_NEWUSER) doesn't work in a multithreaded program (which "nix" is), so we exec() a single-threaded helper program (chrootHelper() below) to do the work. */ - auto store2 = store.dynamic_pointer_cast<LocalStore>(); + auto store2 = store.dynamic_pointer_cast<LocalFSStore>(); - if (store2 && store->storeDir != store2->getRealStoreDir()) { + if (!store2) + throw Error("store '%s' is not a local store so it does not support command execution", store->getUri()); + + if (store->storeDir != store2->getRealStoreDir()) { Strings helperArgs = { chrootHelperName, store->storeDir, store2->getRealStoreDir(), program }; for (auto & arg : args) helperArgs.push_back(arg); @@ -91,7 +94,7 @@ struct CmdShell : InstallablesCommand, MixEnvironment void run(ref<Store> store) override { - auto outPaths = toStorePaths(getEvalStore(), store, Realise::Outputs, OperateOn::Output, installables); + auto outPaths = Installable::toStorePaths(getEvalStore(), store, Realise::Outputs, OperateOn::Output, installables); auto accessor = store->getFSAccessor(); @@ -158,7 +161,10 @@ struct CmdRun : InstallableCommand Strings getDefaultFlakeAttrPaths() override { - Strings res{"defaultApp." + settings.thisSystem.get()}; + Strings res{ + "apps." + settings.thisSystem.get() + ".default", + "defaultApp." + settings.thisSystem.get(), + }; for (auto & s : SourceExprCommand::getDefaultFlakeAttrPaths()) res.push_back(s); return res; @@ -176,6 +182,7 @@ struct CmdRun : InstallableCommand { auto state = getEvalState(); + lockFlags.applyNixConfig = true; auto app = installable->toApp(*state).resolve(getEvalStore(), store); Strings allArgs{app.program}; diff --git a/src/nix/run.md b/src/nix/run.md index cd3b978c0..a0f362076 100644 --- a/src/nix/run.md +++ b/src/nix/run.md @@ -58,9 +58,9 @@ For instance, if `name` is set to `hello-1.10`, `nix run` will run If no flake output attribute is given, `nix run` tries the following flake output attributes: -* `defaultApp.<system>` +* `apps.<system>.default` -* `defaultPackage.<system>` +* `packages.<system>.default` If an attribute *name* is given, `nix run` tries the following flake output attributes: @@ -74,7 +74,7 @@ output attributes: # Apps An app is specified by a flake output attribute named -`apps.<system>.<name>` or `defaultApp.<system>`. It looks like this: +`apps.<system>.<name>`. It looks like this: ```nix apps.x86_64-linux.blender_2_79 = { diff --git a/src/nix/show-derivation.cc b/src/nix/show-derivation.cc index c614be68d..fb46b4dbf 100644 --- a/src/nix/show-derivation.cc +++ b/src/nix/show-derivation.cc @@ -40,7 +40,7 @@ struct CmdShowDerivation : InstallablesCommand void run(ref<Store> store) override { - auto drvPaths = toDerivations(store, installables, true); + auto drvPaths = Installable::toDerivations(store, installables, true); if (recursive) { StorePathSet closure; @@ -65,19 +65,23 @@ struct CmdShowDerivation : InstallablesCommand auto & outputName = _outputName; // work around clang bug auto outputObj { outputsObj.object(outputName) }; std::visit(overloaded { - [&](const DerivationOutputInputAddressed & doi) { + [&](const DerivationOutput::InputAddressed & doi) { outputObj.attr("path", store->printStorePath(doi.path)); }, - [&](const DerivationOutputCAFixed & dof) { + [&](const DerivationOutput::CAFixed & dof) { outputObj.attr("path", store->printStorePath(dof.path(*store, drv.name, outputName))); outputObj.attr("hashAlgo", dof.hash.printMethodAlgo()); outputObj.attr("hash", dof.hash.hash.to_string(Base16, false)); }, - [&](const DerivationOutputCAFloating & dof) { + [&](const DerivationOutput::CAFloating & dof) { outputObj.attr("hashAlgo", makeFileIngestionPrefix(dof.method) + printHashType(dof.hashType)); }, - [&](const DerivationOutputDeferred &) {}, - }, output.output); + [&](const DerivationOutput::Deferred &) {}, + [&](const DerivationOutput::Impure & doi) { + outputObj.attr("hashAlgo", makeFileIngestionPrefix(doi.method) + printHashType(doi.hashType)); + outputObj.attr("impure", true); + }, + }, output.raw()); } } diff --git a/src/nix/store-copy-log.cc b/src/nix/store-copy-log.cc index 079cd6b3e..2e288f743 100644 --- a/src/nix/store-copy-log.cc +++ b/src/nix/store-copy-log.cc @@ -1,6 +1,8 @@ #include "command.hh" #include "shared.hh" #include "store-api.hh" +#include "store-cast.hh" +#include "log-store.hh" #include "sync.hh" #include "thread-pool.hh" @@ -26,7 +28,10 @@ struct CmdCopyLog : virtual CopyCommand, virtual InstallablesCommand void run(ref<Store> srcStore) override { + auto & srcLogStore = require<LogStore>(*srcStore); + auto dstStore = getDstStore(); + auto & dstLogStore = require<LogStore>(*dstStore); StorePathSet drvPaths; @@ -35,8 +40,8 @@ struct CmdCopyLog : virtual CopyCommand, virtual InstallablesCommand drvPaths.insert(drvPath); for (auto & drvPath : drvPaths) { - if (auto log = srcStore->getBuildLog(drvPath)) - dstStore->addBuildLog(drvPath, *log); + if (auto log = srcLogStore.getBuildLog(drvPath)) + dstLogStore.addBuildLog(drvPath, *log); else throw Error("build log for '%s' is not available", srcStore->printStorePath(drvPath)); } diff --git a/src/nix/store-delete.cc b/src/nix/store-delete.cc index e4a3cb554..ca43f1530 100644 --- a/src/nix/store-delete.cc +++ b/src/nix/store-delete.cc @@ -2,6 +2,8 @@ #include "common-args.hh" #include "shared.hh" #include "store-api.hh" +#include "store-cast.hh" +#include "gc-store.hh" using namespace nix; @@ -32,12 +34,14 @@ struct CmdStoreDelete : StorePathsCommand void run(ref<Store> store, std::vector<StorePath> && storePaths) override { + auto & gcStore = require<GcStore>(*store); + for (auto & path : storePaths) options.pathsToDelete.insert(path); GCResults results; PrintFreed freed(true, results); - store->collectGarbage(options, results); + gcStore.collectGarbage(options, results); } }; diff --git a/src/nix/store-gc.cc b/src/nix/store-gc.cc index a2d74066e..8b9b5d164 100644 --- a/src/nix/store-gc.cc +++ b/src/nix/store-gc.cc @@ -2,6 +2,8 @@ #include "common-args.hh" #include "shared.hh" #include "store-api.hh" +#include "store-cast.hh" +#include "gc-store.hh" using namespace nix; @@ -33,10 +35,12 @@ struct CmdStoreGC : StoreCommand, MixDryRun void run(ref<Store> store) override { + auto & gcStore = require<GcStore>(*store); + options.action = dryRun ? GCOptions::gcReturnDead : GCOptions::gcDeleteDead; GCResults results; PrintFreed freed(options.action == GCOptions::gcDeleteDead, results); - store->collectGarbage(options, results); + gcStore.collectGarbage(options, results); } }; diff --git a/src/nix/why-depends.cc b/src/nix/why-depends.cc index 657df30d7..1d9ab28ba 100644 --- a/src/nix/why-depends.cc +++ b/src/nix/why-depends.cc @@ -82,9 +82,9 @@ struct CmdWhyDepends : SourceExprCommand void run(ref<Store> store) override { auto package = parseInstallable(store, _package); - auto packagePath = toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, package); + auto packagePath = Installable::toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, package); auto dependency = parseInstallable(store, _dependency); - auto dependencyPath = toStorePath(getEvalStore(), store, Realise::Derivation, operateOn, dependency); + auto dependencyPath = Installable::toStorePath(getEvalStore(), store, Realise::Derivation, operateOn, dependency); auto dependencyPathHash = dependencyPath.hashPart(); StorePathSet closure; @@ -157,11 +157,11 @@ struct CmdWhyDepends : SourceExprCommand closure (i.e., that have a non-infinite distance to 'dependency'). Print every edge on a path between `package` and `dependency`. */ - std::function<void(Node &, const string &, const string &)> printNode; + std::function<void(Node &, const std::string &, const std::string &)> printNode; struct BailOut { }; - printNode = [&](Node & node, const string & firstPad, const string & tailPad) { + printNode = [&](Node & node, const std::string & firstPad, const std::string & tailPad) { auto pathS = store->printStorePath(node.path); assert(node.dist != inf); @@ -171,12 +171,6 @@ struct CmdWhyDepends : SourceExprCommand node.visited ? "\e[38;5;244m" : "", firstPad != "" ? "→ " : "", pathS); - } else { - logger->cout("%s%s%s%s" ANSI_NORMAL, - firstPad, - node.visited ? "\e[38;5;244m" : "", - firstPad != "" ? treeLast : "", - pathS); } if (node.path == dependencyPath && !all @@ -184,7 +178,7 @@ struct CmdWhyDepends : SourceExprCommand throw BailOut(); if (node.visited) return; - node.visited = true; + if (precise) node.visited = true; /* Sort the references by distance to `dependency` to ensure that the shortest path is printed first. */ @@ -267,6 +261,16 @@ struct CmdWhyDepends : SourceExprCommand if (!all) break; } + if (!precise) { + auto pathS = store->printStorePath(ref.second->path); + logger->cout("%s%s%s%s" ANSI_NORMAL, + firstPad, + ref.second->visited ? "\e[38;5;244m" : "", + last ? treeLast : treeConn, + pathS); + node.visited = true; + } + printNode(*ref.second, tailPad + (last ? treeNull : treeLine), tailPad + (last ? treeNull : treeLine)); @@ -275,6 +279,9 @@ struct CmdWhyDepends : SourceExprCommand RunPager pager; try { + if (!precise) { + logger->cout("%s", store->printStorePath(graph.at(packagePath).path)); + } printNode(graph.at(packagePath), "", ""); } catch (BailOut & ) { } } |