diff --git a/src/nix/command.hh b/src/nix/command.hh index b159408c3..479e6fd37 100644 --- a/src/nix/command.hh +++ b/src/nix/command.hh @@ -51,7 +51,7 @@ struct Installable { virtual std::string what() = 0; - virtual Buildables toBuildable() + virtual Buildables toBuildable(bool singular = false) { throw Error("argument '%s' cannot be built", what()); } @@ -97,8 +97,6 @@ struct InstallablesCommand : virtual Args, SourceExprCommand expectArgs("installables", &_installables); } - std::vector> parseInstallables(ref store, Strings ss); - enum ToStorePathsMode { Build, NoBuild, DryRun }; PathSet toStorePaths(ref store, ToStorePathsMode mode); @@ -112,6 +110,22 @@ private: Strings _installables; }; +struct InstallableCommand : virtual Args, SourceExprCommand +{ + std::shared_ptr installable; + + InstallableCommand() + { + expectArg("installable", &_installable); + } + + void prepare() override; + +private: + + std::string _installable; +}; + /* A command that operates on zero or more store paths. */ struct StorePathsCommand : public InstallablesCommand { diff --git a/src/nix/edit.cc b/src/nix/edit.cc index fd07913bc..127be321e 100644 --- a/src/nix/edit.cc +++ b/src/nix/edit.cc @@ -8,7 +8,7 @@ using namespace nix; -struct CmdEdit : InstallablesCommand +struct CmdEdit : InstallableCommand { std::string name() override { @@ -34,44 +34,42 @@ struct CmdEdit : InstallablesCommand { auto state = getEvalState(); - for (auto & i : installables) { - auto v = i->toValue(*state); + auto v = installable->toValue(*state); - Value * v2; - try { - auto dummyArgs = state->allocBindings(0); - v2 = findAlongAttrPath(*state, "meta.position", *dummyArgs, *v); - } catch (Error &) { - throw Error("package '%s' has no source location information", i->what()); - } - - auto pos = state->forceString(*v2); - debug("position is %s", pos); - - auto colon = pos.rfind(':'); - if (colon == std::string::npos) - throw Error("cannot parse meta.position attribute '%s'", pos); - - std::string filename(pos, 0, colon); - int lineno = std::stoi(std::string(pos, colon + 1)); - - auto editor = getEnv("EDITOR", "cat"); - - Strings args{editor}; - - if (editor.find("emacs") != std::string::npos || - editor.find("nano") != std::string::npos || - editor.find("vim") != std::string::npos) - args.push_back(fmt("+%d", lineno)); - - args.push_back(filename); - - stopProgressBar(); - - execvp(editor.c_str(), stringsToCharPtrs(args).data()); - - throw SysError("cannot run editor '%s'", editor); + Value * v2; + try { + auto dummyArgs = state->allocBindings(0); + v2 = findAlongAttrPath(*state, "meta.position", *dummyArgs, *v); + } catch (Error &) { + throw Error("package '%s' has no source location information", installable->what()); } + + auto pos = state->forceString(*v2); + debug("position is %s", pos); + + auto colon = pos.rfind(':'); + if (colon == std::string::npos) + throw Error("cannot parse meta.position attribute '%s'", pos); + + std::string filename(pos, 0, colon); + int lineno = std::stoi(std::string(pos, colon + 1)); + + auto editor = getEnv("EDITOR", "cat"); + + Strings args{editor}; + + if (editor.find("emacs") != std::string::npos || + editor.find("nano") != std::string::npos || + editor.find("vim") != std::string::npos) + args.push_back(fmt("+%d", lineno)); + + args.push_back(filename); + + stopProgressBar(); + + execvp(editor.c_str(), stringsToCharPtrs(args).data()); + + throw SysError("cannot run editor '%s'", editor); } }; diff --git a/src/nix/installables.cc b/src/nix/installables.cc index 9d812fee4..bdd273d50 100644 --- a/src/nix/installables.cc +++ b/src/nix/installables.cc @@ -78,7 +78,7 @@ struct InstallableStoreDrv : Installable std::string what() override { return storePath; } - Buildables toBuildable() override + Buildables toBuildable(bool singular) override { return {{storePath, {}}}; } @@ -92,25 +92,21 @@ struct InstallableStorePath : Installable std::string what() override { return storePath; } - Buildables toBuildable() override + Buildables toBuildable(bool singular) override { return {{storePath, {}}}; } }; -struct InstallableExpr : Installable +struct InstallableValue : Installable { - InstallablesCommand & installables; - std::string text; + SourceExprCommand & cmd; - InstallableExpr(InstallablesCommand & installables, const std::string & text) - : installables(installables), text(text) { } + InstallableValue(SourceExprCommand & cmd) : cmd(cmd) { } - std::string what() override { return text; } - - Buildables toBuildable() override + Buildables toBuildable(bool singular) override { - auto state = installables.getEvalState(); + auto state = cmd.getEvalState(); auto v = toValue(*state); @@ -121,6 +117,9 @@ struct InstallableExpr : Installable DrvInfos drvs; getDerivations(*state, *v, "", autoArgs, drvs, false); + if (singular && drvs.size() != 1) + throw Error("installable '%s' evaluates to %d derivations, where only one is expected", what(), drvs.size()); + Buildables res; for (auto & drv : drvs) @@ -129,6 +128,16 @@ struct InstallableExpr : Installable return res; } +}; + +struct InstallableExpr : InstallableValue +{ + std::string text; + + InstallableExpr(SourceExprCommand & cmd, const std::string & text) + : InstallableValue(cmd), text(text) { } + + std::string what() override { return text; } Value * toValue(EvalState & state) override { @@ -138,42 +147,19 @@ struct InstallableExpr : Installable } }; -struct InstallableAttrPath : Installable +struct InstallableAttrPath : InstallableValue { - InstallablesCommand & installables; std::string attrPath; - InstallableAttrPath(InstallablesCommand & installables, const std::string & attrPath) - : installables(installables), attrPath(attrPath) + InstallableAttrPath(SourceExprCommand & cmd, const std::string & attrPath) + : InstallableValue(cmd), attrPath(attrPath) { } std::string what() override { return attrPath; } - Buildables toBuildable() override - { - auto state = installables.getEvalState(); - - auto v = toValue(*state); - - // FIXME - std::map autoArgs_; - Bindings & autoArgs(*evalAutoArgs(*state, autoArgs_)); - - DrvInfos drvs; - getDerivations(*state, *v, "", autoArgs, drvs, false); - - Buildables res; - - for (auto & drv : drvs) - for (auto & output : drv.queryOutputs()) - res.emplace(output.second, Whence{output.first, drv.queryDrvPath()}); - - return res; - } - Value * toValue(EvalState & state) override { - auto source = installables.getSourceExpr(state); + auto source = cmd.getSourceExpr(state); // FIXME std::map autoArgs_; @@ -190,20 +176,21 @@ struct InstallableAttrPath : Installable std::string attrRegex = R"([A-Za-z_][A-Za-z0-9-_+]*)"; static std::regex attrPathRegex(fmt(R"(%1%(\.%1%)*)", attrRegex)); -std::vector> InstallablesCommand::parseInstallables(ref store, Strings ss) +static std::vector> parseInstallables( + SourceExprCommand & cmd, ref store, Strings ss, bool useDefaultInstallables) { std::vector> result; - if (ss.empty() && useDefaultInstallables()) { - if (file == "") - file = "."; + if (ss.empty() && useDefaultInstallables) { + if (cmd.file == "") + cmd.file = "."; ss = Strings{""}; } for (auto & s : ss) { if (s.compare(0, 1, "(") == 0) - result.push_back(std::make_shared(*this, s)); + result.push_back(std::make_shared(cmd, s)); else if (s.find("/") != std::string::npos) { @@ -218,7 +205,7 @@ std::vector> InstallablesCommand::parseInstallables } else if (s == "" || std::regex_match(s, attrPathRegex)) - result.push_back(std::make_shared(*this, s)); + result.push_back(std::make_shared(cmd, s)); else throw UsageError("don't know what to do with argument '%s'", s); @@ -250,7 +237,14 @@ PathSet InstallablesCommand::toStorePaths(ref store, ToStorePathsMode mod void InstallablesCommand::prepare() { - installables = parseInstallables(getStore(), _installables); + installables = parseInstallables(*this, getStore(), _installables, useDefaultInstallables()); +} + +void InstallableCommand::prepare() +{ + auto installables = parseInstallables(*this, getStore(), {_installable}, false); + assert(installables.size() == 1); + installable = installables.front(); } } diff --git a/src/nix/log.cc b/src/nix/log.cc index 0fb45c145..ba5e71c10 100644 --- a/src/nix/log.cc +++ b/src/nix/log.cc @@ -2,10 +2,11 @@ #include "common-args.hh" #include "shared.hh" #include "store-api.hh" +#include "progress-bar.hh" using namespace nix; -struct CmdLog : InstallablesCommand +struct CmdLog : InstallableCommand { CmdLog() { @@ -27,21 +28,22 @@ struct CmdLog : InstallablesCommand subs.push_front(store); - for (auto & inst : installables) { - for (auto & b : inst->toBuildable()) { - auto path = b.second.drvPath != "" ? b.second.drvPath : b.first; - bool found = false; - for (auto & sub : subs) { - auto log = sub->getBuildLog(path); + for (auto & b : installable->toBuildable(true)) { + + for (auto & sub : subs) { + auto log = b.second.drvPath != "" ? sub->getBuildLog(b.second.drvPath) : nullptr; + if (!log) { + log = sub->getBuildLog(b.first); if (!log) continue; - std::cout << *log; - found = true; - break; } - if (!found) - throw Error("build log of path '%s' is not available", path); + stopProgressBar(); + printInfo("got build log for '%s' from '%s'", b.first, sub->getUri()); + std::cout << *log; + return; } } + + throw Error("build log of '%s' is not available", installable->what()); } }; diff --git a/src/nix/main.cc b/src/nix/main.cc index 9781b5854..ec9b58b20 100644 --- a/src/nix/main.cc +++ b/src/nix/main.cc @@ -8,6 +8,7 @@ #include "shared.hh" #include "store-api.hh" #include "progress-bar.hh" +#include "finally.hh" extern std::string chrootHelperName; @@ -84,6 +85,8 @@ void mainWrapped(int argc, char * * argv) if (!args.command) args.showHelpAndExit(); + Finally f([]() { stopProgressBar(); }); + if (isatty(STDERR_FILENO)) startProgressBar(); diff --git a/src/nix/progress-bar.cc b/src/nix/progress-bar.cc index f48cfa13b..9bc405239 100644 --- a/src/nix/progress-bar.cc +++ b/src/nix/progress-bar.cc @@ -116,7 +116,7 @@ public: { auto state(state_.lock()); if (!state->active) return; - state->active = true; + state->active = false; std::string status = getStatus(*state); writeToStderr("\r\e[K"); if (status != "")