nix build: Create result symlinks

This commit is contained in:
Eelco Dolstra 2017-09-06 16:03:22 +02:00
parent 1277aab219
commit df4342bc17
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE
4 changed files with 104 additions and 41 deletions

View file

@ -23,9 +23,20 @@ struct CmdBuild : MixDryRun, InstallablesCommand
void run(ref<Store> store) override void run(ref<Store> 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<LocalFSStore>()) {
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);
}
}
}
} }
}; };

View file

@ -44,18 +44,25 @@ private:
std::shared_ptr<Store> _store; std::shared_ptr<Store> _store;
}; };
struct Whence { std::string outputName; Path drvPath; }; struct Buildable
typedef std::map<Path, Whence> Buildables; {
Path drvPath; // may be empty
std::map<std::string, Path> outputs;
};
typedef std::vector<Buildable> Buildables;
struct Installable struct Installable
{ {
virtual std::string what() = 0; virtual std::string what() = 0;
virtual Buildables toBuildable(bool singular = false) virtual Buildables toBuildables()
{ {
throw Error("argument '%s' cannot be built", what()); throw Error("argument '%s' cannot be built", what());
} }
Buildable toBuildable();
virtual Value * toValue(EvalState & state) virtual Value * toValue(EvalState & state)
{ {
throw Error("argument '%s' cannot be evaluated", what()); throw Error("argument '%s' cannot be evaluated", what());
@ -97,9 +104,11 @@ struct InstallablesCommand : virtual Args, SourceExprCommand
expectArgs("installables", &_installables); expectArgs("installables", &_installables);
} }
enum ToStorePathsMode { Build, NoBuild, DryRun }; enum RealiseMode { Build, NoBuild, DryRun };
PathSet toStorePaths(ref<Store> store, ToStorePathsMode mode); Buildables toBuildables(ref<Store> store, RealiseMode mode);
PathSet toStorePaths(ref<Store> store, RealiseMode mode);
void prepare() override; void prepare() override;

View file

@ -70,17 +70,27 @@ ref<EvalState> SourceExprCommand::getEvalState()
return ref<EvalState>(evalState); return ref<EvalState>(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 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; } 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) { } InstallableValue(SourceExprCommand & cmd) : cmd(cmd) { }
Buildables toBuildable(bool singular) override Buildables toBuildables() override
{ {
auto state = cmd.getEvalState(); auto state = cmd.getEvalState();
@ -117,15 +127,31 @@ struct InstallableValue : Installable
DrvInfos drvs; DrvInfos drvs;
getDerivations(*state, *v, "", autoArgs, drvs, false); 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; Buildables res;
for (auto & drv : drvs) PathSet drvPaths;
for (auto & output : drv.queryOutputs())
res.emplace(output.second, Whence{output.first, drv.queryDrvPath()});
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; return res;
} }
}; };
@ -214,23 +240,38 @@ static std::vector<std::shared_ptr<Installable>> parseInstallables(
return result; return result;
} }
PathSet InstallablesCommand::toStorePaths(ref<Store> store, ToStorePathsMode mode) Buildables InstallablesCommand::toBuildables(ref<Store> store, RealiseMode mode)
{ {
if (mode != Build) if (mode != Build)
settings.readOnlyMode = true; settings.readOnlyMode = true;
PathSet outPaths, buildables; Buildables buildables;
for (auto & i : installables) PathSet pathsToBuild;
for (auto & b : i->toBuildable()) {
outPaths.insert(b.first); for (auto & i : installables) {
buildables.insert(b.second.drvPath != "" ? b.second.drvPath : b.first); for (auto & b : i->toBuildables()) {
if (b.drvPath != "")
pathsToBuild.insert(b.drvPath);
buildables.push_back(std::move(b));
}
} }
if (mode == DryRun) if (mode == DryRun)
printMissing(store, buildables, lvlError); printMissing(store, pathsToBuild, lvlError);
else if (mode == Build) else if (mode == Build)
store->buildPaths(buildables); store->buildPaths(pathsToBuild);
return buildables;
}
PathSet InstallablesCommand::toStorePaths(ref<Store> store, RealiseMode mode)
{
PathSet outPaths;
for (auto & b : toBuildables(store, mode))
for (auto & output : b.outputs)
outPaths.insert(output.second);
return outPaths; return outPaths;
} }

View file

@ -24,24 +24,26 @@ struct CmdLog : InstallableCommand
void run(ref<Store> store) override void run(ref<Store> store) override
{ {
settings.readOnlyMode = true;
auto subs = getDefaultSubstituters(); auto subs = getDefaultSubstituters();
subs.push_front(store); subs.push_front(store);
for (auto & b : installable->toBuildable(true)) { auto b = installable->toBuildable();
for (auto & sub : subs) { for (auto & sub : subs) {
auto log = b.second.drvPath != "" ? sub->getBuildLog(b.second.drvPath) : nullptr; auto log = b.drvPath != "" ? sub->getBuildLog(b.drvPath) : nullptr;
if (!log) { for (auto & output : b.outputs) {
log = sub->getBuildLog(b.first); if (log) break;
if (!log) continue; log = sub->getBuildLog(output.second);
} }
if (!log) continue;
stopProgressBar(); stopProgressBar();
printInfo("got build log for '%s' from '%s'", b.first, sub->getUri()); printInfo("got build log for '%s' from '%s'", installable->what(), sub->getUri());
std::cout << *log; std::cout << *log;
return; return;
} }
}
throw Error("build log of '%s' is not available", installable->what()); throw Error("build log of '%s' is not available", installable->what());
} }