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
{
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;
};
struct Whence { std::string outputName; Path drvPath; };
typedef std::map<Path, Whence> Buildables;
struct Buildable
{
Path drvPath; // may be empty
std::map<std::string, Path> outputs;
};
typedef std::vector<Buildable> 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> store, ToStorePathsMode mode);
Buildables toBuildables(ref<Store> store, RealiseMode mode);
PathSet toStorePaths(ref<Store> store, RealiseMode mode);
void prepare() override;

View file

@ -70,17 +70,27 @@ ref<EvalState> SourceExprCommand::getEvalState()
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
{
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<std::shared_ptr<Installable>> parseInstallables(
return result;
}
PathSet InstallablesCommand::toStorePaths(ref<Store> store, ToStorePathsMode mode)
Buildables InstallablesCommand::toBuildables(ref<Store> 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> store, RealiseMode mode)
{
PathSet outPaths;
for (auto & b : toBuildables(store, mode))
for (auto & output : b.outputs)
outPaths.insert(output.second);
return outPaths;
}

View file

@ -24,23 +24,25 @@ struct CmdLog : InstallableCommand
void run(ref<Store> 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());