forked from lix-project/lix
Make Buildable
a std::variant
I think this better captures the intent of what's going on: we either have an opaque store path, or a drv path with some outputs. Having this structure will also help us support CA derivations: we'll have to allow the outpath paths to be optional, so the structure we gain now makes up for the structure we loose then.
This commit is contained in:
parent
a7b8f79938
commit
e1de1fe0d8
|
@ -24,10 +24,6 @@ std::string makeFixedOutputCA(FileIngestionMethod method, const Hash & hash)
|
||||||
+ hash.to_string(Base32, true);
|
+ hash.to_string(Base32, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME Put this somewhere?
|
|
||||||
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
|
|
||||||
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
|
|
||||||
|
|
||||||
std::string renderContentAddress(ContentAddress ca) {
|
std::string renderContentAddress(ContentAddress ca) {
|
||||||
return std::visit(overloaded {
|
return std::visit(overloaded {
|
||||||
[](TextHash th) {
|
[](TextHash th) {
|
||||||
|
|
|
@ -865,10 +865,6 @@ void ValidPathInfo::sign(const Store & store, const SecretKey & secretKey)
|
||||||
sigs.insert(secretKey.signDetached(fingerprint(store)));
|
sigs.insert(secretKey.signDetached(fingerprint(store)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME Put this somewhere?
|
|
||||||
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
|
|
||||||
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
|
|
||||||
|
|
||||||
bool ValidPathInfo::isContentAddressed(const Store & store) const
|
bool ValidPathInfo::isContentAddressed(const Store & store) const
|
||||||
{
|
{
|
||||||
if (! ca) return false;
|
if (! ca) return false;
|
||||||
|
|
|
@ -601,4 +601,9 @@ constexpr auto enumerate(T && iterable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// C++17 std::visit boilerplate
|
||||||
|
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
|
||||||
|
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,17 +57,24 @@ struct CmdBuild : InstallablesCommand, MixDryRun, MixProfile
|
||||||
|
|
||||||
if (dryRun) return;
|
if (dryRun) return;
|
||||||
|
|
||||||
if (outLink != "") {
|
if (outLink != "")
|
||||||
for (size_t i = 0; i < buildables.size(); ++i) {
|
if (auto store2 = store.dynamic_pointer_cast<LocalFSStore>())
|
||||||
for (auto & output : buildables[i].outputs)
|
for (size_t i = 0; i < buildables.size(); ++i)
|
||||||
if (auto store2 = store.dynamic_pointer_cast<LocalFSStore>()) {
|
std::visit(overloaded {
|
||||||
std::string symlink = outLink;
|
[&](BuildableOpaque bo) {
|
||||||
if (i) symlink += fmt("-%d", i);
|
std::string symlink = outLink;
|
||||||
if (output.first != "out") symlink += fmt("-%s", output.first);
|
if (i) symlink += fmt("-%d", i);
|
||||||
store2->addPermRoot(output.second, absPath(symlink), true);
|
store2->addPermRoot(bo.path, absPath(symlink), true);
|
||||||
}
|
},
|
||||||
}
|
[&](BuildableFromDrv bfd) {
|
||||||
}
|
for (auto & output : bfd.outputs) {
|
||||||
|
std::string symlink = outLink;
|
||||||
|
if (i) symlink += fmt("-%d", i);
|
||||||
|
if (output.first != "out") symlink += fmt("-%s", output.first);
|
||||||
|
store2->addPermRoot(output.second, absPath(symlink), true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}, buildables[i]);
|
||||||
|
|
||||||
updateProfile(buildables);
|
updateProfile(buildables);
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,11 +131,18 @@ void MixProfile::updateProfile(const Buildables & buildables)
|
||||||
std::optional<StorePath> result;
|
std::optional<StorePath> result;
|
||||||
|
|
||||||
for (auto & buildable : buildables) {
|
for (auto & buildable : buildables) {
|
||||||
for (auto & output : buildable.outputs) {
|
std::visit(overloaded {
|
||||||
if (result)
|
[&](BuildableOpaque bo) {
|
||||||
throw Error("'--profile' requires that the arguments produce a single store path, but there are multiple");
|
result = bo.path;
|
||||||
result = output.second;
|
},
|
||||||
}
|
[&](BuildableFromDrv bfd) {
|
||||||
|
for (auto & output : bfd.outputs) {
|
||||||
|
if (result)
|
||||||
|
throw Error("'--profile' requires that the arguments produce a single store path, but there are multiple");
|
||||||
|
result = output.second;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}, buildable);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!result)
|
if (!result)
|
||||||
|
|
|
@ -307,16 +307,15 @@ struct InstallableStorePath : Installable
|
||||||
for (auto & [name, output] : store->readDerivation(storePath).outputs)
|
for (auto & [name, output] : store->readDerivation(storePath).outputs)
|
||||||
outputs.emplace(name, output.path);
|
outputs.emplace(name, output.path);
|
||||||
return {
|
return {
|
||||||
Buildable {
|
BuildableFromDrv {
|
||||||
.drvPath = storePath,
|
.drvPath = storePath,
|
||||||
.outputs = std::move(outputs)
|
.outputs = std::move(outputs)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
Buildable {
|
BuildableOpaque {
|
||||||
.drvPath = {},
|
.path = storePath,
|
||||||
.outputs = {{"out", storePath}}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -332,33 +331,20 @@ Buildables InstallableValue::toBuildables()
|
||||||
{
|
{
|
||||||
Buildables res;
|
Buildables res;
|
||||||
|
|
||||||
StorePathSet drvPaths;
|
std::map<StorePath, OutputPathMap> drvsToOutputs;
|
||||||
|
|
||||||
|
// Group by derivation, helps with .all in particular
|
||||||
for (auto & drv : toDerivations()) {
|
for (auto & drv : toDerivations()) {
|
||||||
Buildable b{.drvPath = drv.drvPath};
|
|
||||||
drvPaths.insert(drv.drvPath);
|
|
||||||
|
|
||||||
auto outputName = drv.outputName;
|
auto outputName = drv.outputName;
|
||||||
if (outputName == "")
|
if (outputName == "")
|
||||||
throw Error("derivation '%s' lacks an 'outputName' attribute", state->store->printStorePath(*b.drvPath));
|
throw Error("derivation '%s' lacks an 'outputName' attribute", state->store->printStorePath(drv.drvPath));
|
||||||
|
drvsToOutputs[drv.drvPath].insert_or_assign(outputName, drv.outPath);
|
||||||
b.outputs.emplace(outputName, drv.outPath);
|
|
||||||
|
|
||||||
res.push_back(std::move(b));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hack to recognize .all: if all drvs have the same drvPath,
|
for (auto & i : drvsToOutputs)
|
||||||
// merge the buildables.
|
res.push_back(BuildableFromDrv { i.first, i.second });
|
||||||
if (drvPaths.size() == 1) {
|
|
||||||
Buildable b{.drvPath = *drvPaths.begin()};
|
return res;
|
||||||
for (auto & b2 : res)
|
|
||||||
for (auto & output : b2.outputs)
|
|
||||||
b.outputs.insert_or_assign(output.first, output.second);
|
|
||||||
Buildables bs;
|
|
||||||
bs.push_back(std::move(b));
|
|
||||||
return bs;
|
|
||||||
} else
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct InstallableAttrPath : InstallableValue
|
struct InstallableAttrPath : InstallableValue
|
||||||
|
@ -653,14 +639,17 @@ Buildables build(ref<Store> store, Realise mode,
|
||||||
|
|
||||||
for (auto & i : installables) {
|
for (auto & i : installables) {
|
||||||
for (auto & b : i->toBuildables()) {
|
for (auto & b : i->toBuildables()) {
|
||||||
if (b.drvPath) {
|
std::visit(overloaded {
|
||||||
StringSet outputNames;
|
[&](BuildableOpaque bo) {
|
||||||
for (auto & output : b.outputs)
|
pathsToBuild.push_back({bo.path});
|
||||||
outputNames.insert(output.first);
|
},
|
||||||
pathsToBuild.push_back({*b.drvPath, outputNames});
|
[&](BuildableFromDrv bfd) {
|
||||||
} else
|
StringSet outputNames;
|
||||||
for (auto & output : b.outputs)
|
for (auto & output : bfd.outputs)
|
||||||
pathsToBuild.push_back({output.second});
|
outputNames.insert(output.first);
|
||||||
|
pathsToBuild.push_back({bfd.drvPath, outputNames});
|
||||||
|
},
|
||||||
|
}, b);
|
||||||
buildables.push_back(std::move(b));
|
buildables.push_back(std::move(b));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -681,16 +670,23 @@ StorePathSet toStorePaths(ref<Store> store,
|
||||||
|
|
||||||
if (operateOn == OperateOn::Output) {
|
if (operateOn == OperateOn::Output) {
|
||||||
for (auto & b : build(store, mode, installables))
|
for (auto & b : build(store, mode, installables))
|
||||||
for (auto & output : b.outputs)
|
std::visit(overloaded {
|
||||||
outPaths.insert(output.second);
|
[&](BuildableOpaque bo) {
|
||||||
|
outPaths.insert(bo.path);
|
||||||
|
},
|
||||||
|
[&](BuildableFromDrv bfd) {
|
||||||
|
for (auto & output : bfd.outputs)
|
||||||
|
outPaths.insert(output.second);
|
||||||
|
},
|
||||||
|
}, b);
|
||||||
} else {
|
} else {
|
||||||
if (mode == Realise::Nothing)
|
if (mode == Realise::Nothing)
|
||||||
settings.readOnlyMode = true;
|
settings.readOnlyMode = true;
|
||||||
|
|
||||||
for (auto & i : installables)
|
for (auto & i : installables)
|
||||||
for (auto & b : i->toBuildables())
|
for (auto & b : i->toBuildables())
|
||||||
if (b.drvPath)
|
if (auto bfd = std::get_if<BuildableFromDrv>(&b))
|
||||||
outPaths.insert(*b.drvPath);
|
outPaths.insert(bfd->drvPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
return outPaths;
|
return outPaths;
|
||||||
|
@ -714,20 +710,21 @@ StorePathSet toDerivations(ref<Store> store,
|
||||||
StorePathSet drvPaths;
|
StorePathSet drvPaths;
|
||||||
|
|
||||||
for (auto & i : installables)
|
for (auto & i : installables)
|
||||||
for (auto & b : i->toBuildables()) {
|
for (auto & b : i->toBuildables())
|
||||||
if (!b.drvPath) {
|
std::visit(overloaded {
|
||||||
if (!useDeriver)
|
[&](BuildableOpaque bo) {
|
||||||
throw Error("argument '%s' did not evaluate to a derivation", i->what());
|
if (!useDeriver)
|
||||||
for (auto & output : b.outputs) {
|
throw Error("argument '%s' did not evaluate to a derivation", i->what());
|
||||||
auto derivers = store->queryValidDerivers(output.second);
|
auto derivers = store->queryValidDerivers(bo.path);
|
||||||
if (derivers.empty())
|
if (derivers.empty())
|
||||||
throw Error("'%s' does not have a known deriver", i->what());
|
throw Error("'%s' does not have a known deriver", i->what());
|
||||||
// FIXME: use all derivers?
|
// FIXME: use all derivers?
|
||||||
drvPaths.insert(*derivers.begin());
|
drvPaths.insert(*derivers.begin());
|
||||||
}
|
},
|
||||||
} else
|
[&](BuildableFromDrv bfd) {
|
||||||
drvPaths.insert(*b.drvPath);
|
drvPaths.insert(bfd.drvPath);
|
||||||
}
|
},
|
||||||
|
}, b);
|
||||||
|
|
||||||
return drvPaths;
|
return drvPaths;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,12 +14,20 @@ struct SourceExprCommand;
|
||||||
|
|
||||||
namespace eval_cache { class EvalCache; class AttrCursor; }
|
namespace eval_cache { class EvalCache; class AttrCursor; }
|
||||||
|
|
||||||
struct Buildable
|
struct BuildableOpaque {
|
||||||
{
|
StorePath path;
|
||||||
std::optional<StorePath> drvPath;
|
};
|
||||||
|
|
||||||
|
struct BuildableFromDrv {
|
||||||
|
StorePath drvPath;
|
||||||
std::map<std::string, StorePath> outputs;
|
std::map<std::string, StorePath> outputs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef std::variant<
|
||||||
|
BuildableOpaque,
|
||||||
|
BuildableFromDrv
|
||||||
|
> Buildable;
|
||||||
|
|
||||||
typedef std::vector<Buildable> Buildables;
|
typedef std::vector<Buildable> Buildables;
|
||||||
|
|
||||||
struct App
|
struct App
|
||||||
|
|
|
@ -45,11 +45,14 @@ struct CmdLog : InstallableCommand
|
||||||
|
|
||||||
RunPager pager;
|
RunPager pager;
|
||||||
for (auto & sub : subs) {
|
for (auto & sub : subs) {
|
||||||
auto log = b.drvPath ? sub->getBuildLog(*b.drvPath) : nullptr;
|
auto log = std::visit(overloaded {
|
||||||
for (auto & output : b.outputs) {
|
[&](BuildableOpaque bo) {
|
||||||
if (log) break;
|
return sub->getBuildLog(bo.path);
|
||||||
log = sub->getBuildLog(output.second);
|
},
|
||||||
}
|
[&](BuildableFromDrv bfd) {
|
||||||
|
return sub->getBuildLog(bfd.drvPath);
|
||||||
|
},
|
||||||
|
}, b);
|
||||||
if (!log) continue;
|
if (!log) continue;
|
||||||
stopProgressBar();
|
stopProgressBar();
|
||||||
printInfo("got build log for '%s' from '%s'", installable->what(), sub->getUri());
|
printInfo("got build log for '%s' from '%s'", installable->what(), sub->getUri());
|
||||||
|
|
Loading…
Reference in a new issue