diff --git a/src/nix/build.cc b/src/nix/build.cc index 4239dd3ff..64bcafd2d 100644 --- a/src/nix/build.cc +++ b/src/nix/build.cc @@ -23,9 +23,20 @@ struct CmdBuild : MixDryRun, InstallablesCommand void run(ref store) override { - auto paths = toStorePaths(store, dryRun ? DryRun : Build); + auto buildables = toBuildables(store, dryRun ? DryRun : Build); - printError("build result: %s", showPaths(paths)); + for (size_t i = 0; i < buildables.size(); ++i) { + auto & b(buildables[i]); + + for (auto & output : b.outputs) { + if (auto store2 = store.dynamic_pointer_cast()) { + std::string symlink = "result"; + if (i) symlink += fmt("-%d", i); + if (output.first != "out") symlink += fmt("-%s", output.first); + store2->addPermRoot(output.second, absPath(symlink), true); + } + } + } } }; diff --git a/src/nix/command.hh b/src/nix/command.hh index 479e6fd37..b052c42b1 100644 --- a/src/nix/command.hh +++ b/src/nix/command.hh @@ -44,18 +44,25 @@ private: std::shared_ptr _store; }; -struct Whence { std::string outputName; Path drvPath; }; -typedef std::map Buildables; +struct Buildable +{ + Path drvPath; // may be empty + std::map outputs; +}; + +typedef std::vector Buildables; struct Installable { virtual std::string what() = 0; - virtual Buildables toBuildable(bool singular = false) + virtual Buildables toBuildables() { throw Error("argument '%s' cannot be built", what()); } + Buildable toBuildable(); + virtual Value * toValue(EvalState & state) { throw Error("argument '%s' cannot be evaluated", what()); @@ -97,9 +104,11 @@ struct InstallablesCommand : virtual Args, SourceExprCommand expectArgs("installables", &_installables); } - enum ToStorePathsMode { Build, NoBuild, DryRun }; + enum RealiseMode { Build, NoBuild, DryRun }; - PathSet toStorePaths(ref store, ToStorePathsMode mode); + Buildables toBuildables(ref store, RealiseMode mode); + + PathSet toStorePaths(ref store, RealiseMode mode); void prepare() override; diff --git a/src/nix/installables.cc b/src/nix/installables.cc index fdb6004fb..f3c7d3075 100644 --- a/src/nix/installables.cc +++ b/src/nix/installables.cc @@ -70,17 +70,27 @@ ref SourceExprCommand::getEvalState() return ref(evalState); } +Buildable Installable::toBuildable() +{ + auto buildables = toBuildables(); + if (buildables.size() != 1) + throw Error("installable '%s' evaluates to %d derivations, where only one is expected", what(), buildables.size()); + return std::move(buildables[0]); +} + struct InstallableStoreDrv : Installable { - Path storePath; + Path drvPath; - InstallableStoreDrv(const Path & storePath) : storePath(storePath) { } + InstallableStoreDrv(const Path & drvPath) : drvPath(drvPath) { } - std::string what() override { return storePath; } + std::string what() override { return drvPath; } - Buildables toBuildable(bool singular) override + Buildables toBuildables() override { - return {{storePath, {}}}; + Buildable b = {drvPath}; + // FIXME: add outputs? + return {b}; } }; @@ -92,9 +102,9 @@ struct InstallableStorePath : Installable std::string what() override { return storePath; } - Buildables toBuildable(bool singular) override + Buildables toBuildables() override { - return {{storePath, {}}}; + return {{"", {{"out", storePath}}}}; } }; @@ -104,7 +114,7 @@ struct InstallableValue : Installable InstallableValue(SourceExprCommand & cmd) : cmd(cmd) { } - Buildables toBuildable(bool singular) override + Buildables toBuildables() override { auto state = cmd.getEvalState(); @@ -117,16 +127,32 @@ struct InstallableValue : 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) - for (auto & output : drv.queryOutputs()) - res.emplace(output.second, Whence{output.first, drv.queryDrvPath()}); + PathSet drvPaths; - return res; + for (auto & drv : drvs) { + Buildable b{drv.queryDrvPath()}; + drvPaths.insert(b.drvPath); + + auto outputName = drv.queryOutputName(); + if (outputName == "") + throw Error("derivation '%s' lacks an 'outputName' attribute", b.drvPath); + + b.outputs.emplace(outputName, drv.queryOutPath()); + + res.push_back(std::move(b)); + } + + // Hack to recognize .all: if all drvs have the same drvPath, + // merge the buildables. + if (drvPaths.size() == 1) { + Buildable b{*drvPaths.begin()}; + for (auto & b2 : res) + b.outputs.insert(b2.outputs.begin(), b2.outputs.end()); + return {b}; + } else + return res; } }; @@ -214,23 +240,38 @@ static std::vector> parseInstallables( return result; } -PathSet InstallablesCommand::toStorePaths(ref store, ToStorePathsMode mode) +Buildables InstallablesCommand::toBuildables(ref store, RealiseMode mode) { if (mode != Build) settings.readOnlyMode = true; - PathSet outPaths, buildables; + Buildables buildables; - for (auto & i : installables) - for (auto & b : i->toBuildable()) { - outPaths.insert(b.first); - buildables.insert(b.second.drvPath != "" ? b.second.drvPath : b.first); + PathSet pathsToBuild; + + for (auto & i : installables) { + for (auto & b : i->toBuildables()) { + if (b.drvPath != "") + pathsToBuild.insert(b.drvPath); + buildables.push_back(std::move(b)); } + } if (mode == DryRun) - printMissing(store, buildables, lvlError); + printMissing(store, pathsToBuild, lvlError); else if (mode == Build) - store->buildPaths(buildables); + store->buildPaths(pathsToBuild); + + return buildables; +} + +PathSet InstallablesCommand::toStorePaths(ref store, RealiseMode mode) +{ + PathSet outPaths; + + for (auto & b : toBuildables(store, mode)) + for (auto & output : b.outputs) + outPaths.insert(output.second); return outPaths; } diff --git a/src/nix/log.cc b/src/nix/log.cc index ba5e71c10..15ae61d08 100644 --- a/src/nix/log.cc +++ b/src/nix/log.cc @@ -24,23 +24,25 @@ struct CmdLog : InstallableCommand void run(ref store) override { + settings.readOnlyMode = true; + auto subs = getDefaultSubstituters(); subs.push_front(store); - for (auto & b : installable->toBuildable(true)) { + auto b = installable->toBuildable(); - 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; - } - stopProgressBar(); - printInfo("got build log for '%s' from '%s'", b.first, sub->getUri()); - std::cout << *log; - return; + for (auto & sub : subs) { + auto log = b.drvPath != "" ? sub->getBuildLog(b.drvPath) : nullptr; + for (auto & output : b.outputs) { + if (log) break; + log = sub->getBuildLog(output.second); } + if (!log) continue; + stopProgressBar(); + printInfo("got build log for '%s' from '%s'", installable->what(), sub->getUri()); + std::cout << *log; + return; } throw Error("build log of '%s' is not available", installable->what());