forked from lix-project/lix
Merge pull request #4818 from NixOS/ca/cli-use-builtpaths
Enforce the use of properly built paths in libcmd
This commit is contained in:
commit
6849ae82de
|
@ -54,7 +54,7 @@ void StoreCommand::run()
|
||||||
run(getStore());
|
run(getStore());
|
||||||
}
|
}
|
||||||
|
|
||||||
RealisedPathsCommand::RealisedPathsCommand(bool recursive)
|
BuiltPathsCommand::BuiltPathsCommand(bool recursive)
|
||||||
: recursive(recursive)
|
: recursive(recursive)
|
||||||
{
|
{
|
||||||
if (recursive)
|
if (recursive)
|
||||||
|
@ -81,39 +81,45 @@ RealisedPathsCommand::RealisedPathsCommand(bool recursive)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void RealisedPathsCommand::run(ref<Store> store)
|
void BuiltPathsCommand::run(ref<Store> store)
|
||||||
{
|
{
|
||||||
std::vector<RealisedPath> paths;
|
BuiltPaths paths;
|
||||||
if (all) {
|
if (all) {
|
||||||
if (installables.size())
|
if (installables.size())
|
||||||
throw UsageError("'--all' does not expect arguments");
|
throw UsageError("'--all' does not expect arguments");
|
||||||
// XXX: Only uses opaque paths, ignores all the realisations
|
// XXX: Only uses opaque paths, ignores all the realisations
|
||||||
for (auto & p : store->queryAllValidPaths())
|
for (auto & p : store->queryAllValidPaths())
|
||||||
paths.push_back(p);
|
paths.push_back(BuiltPath::Opaque{p});
|
||||||
} else {
|
} else {
|
||||||
auto pathSet = toRealisedPaths(store, realiseMode, operateOn, installables);
|
paths = toBuiltPaths(store, realiseMode, operateOn, installables);
|
||||||
if (recursive) {
|
if (recursive) {
|
||||||
auto roots = std::move(pathSet);
|
// XXX: This only computes the store path closure, ignoring
|
||||||
pathSet = {};
|
// intermediate realisations
|
||||||
RealisedPath::closure(*store, roots, pathSet);
|
StorePathSet pathsRoots, pathsClosure;
|
||||||
|
for (auto & root: paths) {
|
||||||
|
auto rootFromThis = root.outPaths();
|
||||||
|
pathsRoots.insert(rootFromThis.begin(), rootFromThis.end());
|
||||||
|
}
|
||||||
|
store->computeFSClosure(pathsRoots, pathsClosure);
|
||||||
|
for (auto & path : pathsClosure)
|
||||||
|
paths.push_back(BuiltPath::Opaque{path});
|
||||||
}
|
}
|
||||||
for (auto & path : pathSet)
|
|
||||||
paths.push_back(path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
run(store, std::move(paths));
|
run(store, std::move(paths));
|
||||||
}
|
}
|
||||||
|
|
||||||
StorePathsCommand::StorePathsCommand(bool recursive)
|
StorePathsCommand::StorePathsCommand(bool recursive)
|
||||||
: RealisedPathsCommand(recursive)
|
: BuiltPathsCommand(recursive)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void StorePathsCommand::run(ref<Store> store, std::vector<RealisedPath> paths)
|
void StorePathsCommand::run(ref<Store> store, BuiltPaths paths)
|
||||||
{
|
{
|
||||||
StorePaths storePaths;
|
StorePaths storePaths;
|
||||||
for (auto & p : paths)
|
for (auto& builtPath : paths)
|
||||||
storePaths.push_back(p.path());
|
for (auto& p : builtPath.outPaths())
|
||||||
|
storePaths.push_back(p);
|
||||||
|
|
||||||
run(store, std::move(storePaths));
|
run(store, std::move(storePaths));
|
||||||
}
|
}
|
||||||
|
@ -162,7 +168,7 @@ void MixProfile::updateProfile(const StorePath & storePath)
|
||||||
profile2, storePath));
|
profile2, storePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MixProfile::updateProfile(const DerivedPathsWithHints & buildables)
|
void MixProfile::updateProfile(const BuiltPaths & buildables)
|
||||||
{
|
{
|
||||||
if (!profile) return;
|
if (!profile) return;
|
||||||
|
|
||||||
|
@ -170,15 +176,12 @@ void MixProfile::updateProfile(const DerivedPathsWithHints & buildables)
|
||||||
|
|
||||||
for (auto & buildable : buildables) {
|
for (auto & buildable : buildables) {
|
||||||
std::visit(overloaded {
|
std::visit(overloaded {
|
||||||
[&](DerivedPathWithHints::Opaque bo) {
|
[&](BuiltPath::Opaque bo) {
|
||||||
result.push_back(bo.path);
|
result.push_back(bo.path);
|
||||||
},
|
},
|
||||||
[&](DerivedPathWithHints::Built bfd) {
|
[&](BuiltPath::Built bfd) {
|
||||||
for (auto & output : bfd.outputs) {
|
for (auto & output : bfd.outputs) {
|
||||||
/* Output path should be known because we just tried to
|
result.push_back(output.second);
|
||||||
build it. */
|
|
||||||
assert(output.second);
|
|
||||||
result.push_back(*output.second);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}, buildable.raw());
|
}, buildable.raw());
|
||||||
|
|
|
@ -143,7 +143,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
/* A command that operates on zero or more store paths. */
|
/* A command that operates on zero or more store paths. */
|
||||||
struct RealisedPathsCommand : public InstallablesCommand
|
struct BuiltPathsCommand : public InstallablesCommand
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -156,26 +156,26 @@ protected:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
RealisedPathsCommand(bool recursive = false);
|
BuiltPathsCommand(bool recursive = false);
|
||||||
|
|
||||||
using StoreCommand::run;
|
using StoreCommand::run;
|
||||||
|
|
||||||
virtual void run(ref<Store> store, std::vector<RealisedPath> paths) = 0;
|
virtual void run(ref<Store> store, BuiltPaths paths) = 0;
|
||||||
|
|
||||||
void run(ref<Store> store) override;
|
void run(ref<Store> store) override;
|
||||||
|
|
||||||
bool useDefaultInstallables() override { return !all; }
|
bool useDefaultInstallables() override { return !all; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StorePathsCommand : public RealisedPathsCommand
|
struct StorePathsCommand : public BuiltPathsCommand
|
||||||
{
|
{
|
||||||
StorePathsCommand(bool recursive = false);
|
StorePathsCommand(bool recursive = false);
|
||||||
|
|
||||||
using RealisedPathsCommand::run;
|
using BuiltPathsCommand::run;
|
||||||
|
|
||||||
virtual void run(ref<Store> store, std::vector<StorePath> storePaths) = 0;
|
virtual void run(ref<Store> store, std::vector<StorePath> storePaths) = 0;
|
||||||
|
|
||||||
void run(ref<Store> store, std::vector<RealisedPath> paths) override;
|
void run(ref<Store> store, BuiltPaths paths) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* A command that operates on exactly one store path. */
|
/* A command that operates on exactly one store path. */
|
||||||
|
@ -216,7 +216,7 @@ static RegisterCommand registerCommand2(std::vector<std::string> && name)
|
||||||
return RegisterCommand(std::move(name), [](){ return make_ref<T>(); });
|
return RegisterCommand(std::move(name), [](){ return make_ref<T>(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
DerivedPathsWithHints build(ref<Store> store, Realise mode,
|
BuiltPaths build(ref<Store> store, Realise mode,
|
||||||
std::vector<std::shared_ptr<Installable>> installables, BuildMode bMode = bmNormal);
|
std::vector<std::shared_ptr<Installable>> installables, BuildMode bMode = bmNormal);
|
||||||
|
|
||||||
std::set<StorePath> toStorePaths(ref<Store> store,
|
std::set<StorePath> toStorePaths(ref<Store> store,
|
||||||
|
@ -231,7 +231,7 @@ std::set<StorePath> toDerivations(ref<Store> store,
|
||||||
std::vector<std::shared_ptr<Installable>> installables,
|
std::vector<std::shared_ptr<Installable>> installables,
|
||||||
bool useDeriver = false);
|
bool useDeriver = false);
|
||||||
|
|
||||||
std::set<RealisedPath> toRealisedPaths(
|
BuiltPaths toBuiltPaths(
|
||||||
ref<Store> store,
|
ref<Store> store,
|
||||||
Realise mode,
|
Realise mode,
|
||||||
OperateOn operateOn,
|
OperateOn operateOn,
|
||||||
|
@ -252,7 +252,7 @@ struct MixProfile : virtual StoreCommand
|
||||||
|
|
||||||
/* If 'profile' is set, make it point at the store path produced
|
/* If 'profile' is set, make it point at the store path produced
|
||||||
by 'buildables'. */
|
by 'buildables'. */
|
||||||
void updateProfile(const DerivedPathsWithHints & buildables);
|
void updateProfile(const BuiltPaths & buildables);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MixDefaultProfile : MixProfile
|
struct MixDefaultProfile : MixProfile
|
||||||
|
|
|
@ -285,9 +285,9 @@ void completeFlakeRef(ref<Store> store, std::string_view prefix)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DerivedPathWithHints Installable::toDerivedPathWithHints()
|
DerivedPath Installable::toDerivedPath()
|
||||||
{
|
{
|
||||||
auto buildables = toDerivedPathsWithHints();
|
auto buildables = toDerivedPaths();
|
||||||
if (buildables.size() != 1)
|
if (buildables.size() != 1)
|
||||||
throw Error("installable '%s' evaluates to %d derivations, where only one is expected", what(), buildables.size());
|
throw Error("installable '%s' evaluates to %d derivations, where only one is expected", what(), buildables.size());
|
||||||
return std::move(buildables[0]);
|
return std::move(buildables[0]);
|
||||||
|
@ -321,22 +321,19 @@ struct InstallableStorePath : Installable
|
||||||
|
|
||||||
std::string what() override { return store->printStorePath(storePath); }
|
std::string what() override { return store->printStorePath(storePath); }
|
||||||
|
|
||||||
DerivedPathsWithHints toDerivedPathsWithHints() override
|
DerivedPaths toDerivedPaths() override
|
||||||
{
|
{
|
||||||
if (storePath.isDerivation()) {
|
if (storePath.isDerivation()) {
|
||||||
std::map<std::string, std::optional<StorePath>> outputs;
|
|
||||||
auto drv = store->readDerivation(storePath);
|
auto drv = store->readDerivation(storePath);
|
||||||
for (auto & [name, output] : drv.outputsAndOptPaths(*store))
|
|
||||||
outputs.emplace(name, output.second);
|
|
||||||
return {
|
return {
|
||||||
DerivedPathWithHints::Built {
|
DerivedPath::Built {
|
||||||
.drvPath = storePath,
|
.drvPath = storePath,
|
||||||
.outputs = std::move(outputs)
|
.outputs = drv.outputNames(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
DerivedPathWithHints::Opaque {
|
DerivedPath::Opaque {
|
||||||
.path = storePath,
|
.path = storePath,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -349,22 +346,22 @@ struct InstallableStorePath : Installable
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
DerivedPathsWithHints InstallableValue::toDerivedPathsWithHints()
|
DerivedPaths InstallableValue::toDerivedPaths()
|
||||||
{
|
{
|
||||||
DerivedPathsWithHints res;
|
DerivedPaths res;
|
||||||
|
|
||||||
std::map<StorePath, std::map<std::string, std::optional<StorePath>>> drvsToOutputs;
|
std::map<StorePath, std::set<std::string>> drvsToOutputs;
|
||||||
|
|
||||||
// Group by derivation, helps with .all in particular
|
// Group by derivation, helps with .all in particular
|
||||||
for (auto & drv : toDerivations()) {
|
for (auto & drv : toDerivations()) {
|
||||||
auto outputName = drv.outputName;
|
auto outputName = drv.outputName;
|
||||||
if (outputName == "")
|
if (outputName == "")
|
||||||
throw Error("derivation '%s' lacks an 'outputName' attribute", state->store->printStorePath(drv.drvPath));
|
throw Error("derivation '%s' lacks an 'outputName' attribute", state->store->printStorePath(drv.drvPath));
|
||||||
drvsToOutputs[drv.drvPath].insert_or_assign(outputName, drv.outPath);
|
drvsToOutputs[drv.drvPath].insert(outputName);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto & i : drvsToOutputs)
|
for (auto & i : drvsToOutputs)
|
||||||
res.push_back(DerivedPathWithHints::Built { i.first, i.second });
|
res.push_back(DerivedPath::Built { i.first, i.second });
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -675,32 +672,67 @@ std::shared_ptr<Installable> SourceExprCommand::parseInstallable(
|
||||||
return installables.front();
|
return installables.front();
|
||||||
}
|
}
|
||||||
|
|
||||||
DerivedPathsWithHints build(ref<Store> store, Realise mode,
|
BuiltPaths getBuiltPaths(ref<Store> store, DerivedPaths hopefullyBuiltPaths)
|
||||||
|
{
|
||||||
|
BuiltPaths res;
|
||||||
|
for (auto& b : hopefullyBuiltPaths)
|
||||||
|
std::visit(
|
||||||
|
overloaded{
|
||||||
|
[&](DerivedPath::Opaque bo) {
|
||||||
|
res.push_back(BuiltPath::Opaque{bo.path});
|
||||||
|
},
|
||||||
|
[&](DerivedPath::Built bfd) {
|
||||||
|
OutputPathMap outputs;
|
||||||
|
auto drv = store->readDerivation(bfd.drvPath);
|
||||||
|
auto outputHashes = staticOutputHashes(*store, drv);
|
||||||
|
auto drvOutputs = drv.outputsAndOptPaths(*store);
|
||||||
|
for (auto& output : bfd.outputs) {
|
||||||
|
if (!outputHashes.count(output))
|
||||||
|
throw Error(
|
||||||
|
"the derivation '%s' doesn't have an output "
|
||||||
|
"named '%s'",
|
||||||
|
store->printStorePath(bfd.drvPath), output);
|
||||||
|
if (settings.isExperimentalFeatureEnabled(
|
||||||
|
"ca-derivations")) {
|
||||||
|
auto outputId =
|
||||||
|
DrvOutput{outputHashes.at(output), output};
|
||||||
|
auto realisation =
|
||||||
|
store->queryRealisation(outputId);
|
||||||
|
if (!realisation)
|
||||||
|
throw Error(
|
||||||
|
"cannot operate on an output of unbuilt "
|
||||||
|
"content-addresed derivation '%s'",
|
||||||
|
outputId.to_string());
|
||||||
|
outputs.insert_or_assign(
|
||||||
|
output, realisation->outPath);
|
||||||
|
} else {
|
||||||
|
// If ca-derivations isn't enabled, assume that
|
||||||
|
// the output path is statically known.
|
||||||
|
assert(drvOutputs.count(output));
|
||||||
|
assert(drvOutputs.at(output).second);
|
||||||
|
outputs.insert_or_assign(
|
||||||
|
output, *drvOutputs.at(output).second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.push_back(BuiltPath::Built{bfd.drvPath, outputs});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
b.raw());
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
BuiltPaths build(ref<Store> store, Realise mode,
|
||||||
std::vector<std::shared_ptr<Installable>> installables, BuildMode bMode)
|
std::vector<std::shared_ptr<Installable>> installables, BuildMode bMode)
|
||||||
{
|
{
|
||||||
if (mode == Realise::Nothing)
|
if (mode == Realise::Nothing)
|
||||||
settings.readOnlyMode = true;
|
settings.readOnlyMode = true;
|
||||||
|
|
||||||
DerivedPathsWithHints buildables;
|
|
||||||
|
|
||||||
std::vector<DerivedPath> pathsToBuild;
|
std::vector<DerivedPath> pathsToBuild;
|
||||||
|
|
||||||
for (auto & i : installables) {
|
for (auto & i : installables) {
|
||||||
for (auto & b : i->toDerivedPathsWithHints()) {
|
auto b = i->toDerivedPaths();
|
||||||
std::visit(overloaded {
|
pathsToBuild.insert(pathsToBuild.end(), b.begin(), b.end());
|
||||||
[&](DerivedPathWithHints::Opaque bo) {
|
|
||||||
pathsToBuild.push_back(bo);
|
|
||||||
},
|
|
||||||
[&](DerivedPathWithHints::Built bfd) {
|
|
||||||
StringSet outputNames;
|
|
||||||
for (auto & output : bfd.outputs)
|
|
||||||
outputNames.insert(output.first);
|
|
||||||
pathsToBuild.push_back(
|
|
||||||
DerivedPath::Built{bfd.drvPath, outputNames});
|
|
||||||
},
|
|
||||||
}, b.raw());
|
|
||||||
buildables.push_back(std::move(b));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode == Realise::Nothing)
|
if (mode == Realise::Nothing)
|
||||||
|
@ -708,57 +740,26 @@ DerivedPathsWithHints build(ref<Store> store, Realise mode,
|
||||||
else if (mode == Realise::Outputs)
|
else if (mode == Realise::Outputs)
|
||||||
store->buildPaths(pathsToBuild, bMode);
|
store->buildPaths(pathsToBuild, bMode);
|
||||||
|
|
||||||
return buildables;
|
return getBuiltPaths(store, pathsToBuild);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<RealisedPath> toRealisedPaths(
|
BuiltPaths toBuiltPaths(
|
||||||
ref<Store> store,
|
ref<Store> store,
|
||||||
Realise mode,
|
Realise mode,
|
||||||
OperateOn operateOn,
|
OperateOn operateOn,
|
||||||
std::vector<std::shared_ptr<Installable>> installables)
|
std::vector<std::shared_ptr<Installable>> installables)
|
||||||
{
|
{
|
||||||
std::set<RealisedPath> res;
|
|
||||||
if (operateOn == OperateOn::Output) {
|
if (operateOn == OperateOn::Output) {
|
||||||
for (auto & b : build(store, mode, installables))
|
return build(store, mode, installables);
|
||||||
std::visit(overloaded {
|
|
||||||
[&](DerivedPathWithHints::Opaque bo) {
|
|
||||||
res.insert(bo.path);
|
|
||||||
},
|
|
||||||
[&](DerivedPathWithHints::Built bfd) {
|
|
||||||
auto drv = store->readDerivation(bfd.drvPath);
|
|
||||||
auto outputHashes = staticOutputHashes(*store, drv);
|
|
||||||
for (auto & output : bfd.outputs) {
|
|
||||||
if (settings.isExperimentalFeatureEnabled("ca-derivations")) {
|
|
||||||
if (!outputHashes.count(output.first))
|
|
||||||
throw Error(
|
|
||||||
"the derivation '%s' doesn't have an output named '%s'",
|
|
||||||
store->printStorePath(bfd.drvPath),
|
|
||||||
output.first);
|
|
||||||
auto outputId = DrvOutput{outputHashes.at(output.first), output.first};
|
|
||||||
auto realisation = store->queryRealisation(outputId);
|
|
||||||
if (!realisation)
|
|
||||||
throw Error("cannot operate on an output of unbuilt content-addresed derivation '%s'", outputId.to_string());
|
|
||||||
res.insert(RealisedPath{*realisation});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// If ca-derivations isn't enabled, behave as if
|
|
||||||
// all the paths are opaque to keep the default
|
|
||||||
// behavior
|
|
||||||
assert(output.second);
|
|
||||||
res.insert(*output.second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}, b.raw());
|
|
||||||
} else {
|
} else {
|
||||||
if (mode == Realise::Nothing)
|
if (mode == Realise::Nothing)
|
||||||
settings.readOnlyMode = true;
|
settings.readOnlyMode = true;
|
||||||
|
|
||||||
auto drvPaths = toDerivations(store, installables, true);
|
BuiltPaths res;
|
||||||
res.insert(drvPaths.begin(), drvPaths.end());
|
for (auto & drvPath : toDerivations(store, installables, true))
|
||||||
|
res.push_back(BuiltPath::Opaque{drvPath});
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StorePathSet toStorePaths(ref<Store> store,
|
StorePathSet toStorePaths(ref<Store> store,
|
||||||
|
@ -766,8 +767,10 @@ StorePathSet toStorePaths(ref<Store> store,
|
||||||
std::vector<std::shared_ptr<Installable>> installables)
|
std::vector<std::shared_ptr<Installable>> installables)
|
||||||
{
|
{
|
||||||
StorePathSet outPaths;
|
StorePathSet outPaths;
|
||||||
for (auto & path : toRealisedPaths(store, mode, operateOn, installables))
|
for (auto & path : toBuiltPaths(store, mode, operateOn, installables)) {
|
||||||
outPaths.insert(path.path());
|
auto thisOutPaths = path.outPaths();
|
||||||
|
outPaths.insert(thisOutPaths.begin(), thisOutPaths.end());
|
||||||
|
}
|
||||||
return outPaths;
|
return outPaths;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -789,9 +792,9 @@ StorePathSet toDerivations(ref<Store> store,
|
||||||
StorePathSet drvPaths;
|
StorePathSet drvPaths;
|
||||||
|
|
||||||
for (auto & i : installables)
|
for (auto & i : installables)
|
||||||
for (auto & b : i->toDerivedPathsWithHints())
|
for (auto & b : i->toDerivedPaths())
|
||||||
std::visit(overloaded {
|
std::visit(overloaded {
|
||||||
[&](DerivedPathWithHints::Opaque bo) {
|
[&](DerivedPath::Opaque bo) {
|
||||||
if (!useDeriver)
|
if (!useDeriver)
|
||||||
throw Error("argument '%s' did not evaluate to a derivation", i->what());
|
throw Error("argument '%s' did not evaluate to a derivation", i->what());
|
||||||
auto derivers = store->queryValidDerivers(bo.path);
|
auto derivers = store->queryValidDerivers(bo.path);
|
||||||
|
@ -800,7 +803,7 @@ StorePathSet toDerivations(ref<Store> store,
|
||||||
// FIXME: use all derivers?
|
// FIXME: use all derivers?
|
||||||
drvPaths.insert(*derivers.begin());
|
drvPaths.insert(*derivers.begin());
|
||||||
},
|
},
|
||||||
[&](DerivedPathWithHints::Built bfd) {
|
[&](DerivedPath::Built bfd) {
|
||||||
drvPaths.insert(bfd.drvPath);
|
drvPaths.insert(bfd.drvPath);
|
||||||
},
|
},
|
||||||
}, b.raw());
|
}, b.raw());
|
||||||
|
|
|
@ -29,9 +29,9 @@ struct Installable
|
||||||
|
|
||||||
virtual std::string what() = 0;
|
virtual std::string what() = 0;
|
||||||
|
|
||||||
virtual DerivedPathsWithHints toDerivedPathsWithHints() = 0;
|
virtual DerivedPaths toDerivedPaths() = 0;
|
||||||
|
|
||||||
DerivedPathWithHints toDerivedPathWithHints();
|
DerivedPath toDerivedPath();
|
||||||
|
|
||||||
App toApp(EvalState & state);
|
App toApp(EvalState & state);
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ struct InstallableValue : Installable
|
||||||
|
|
||||||
virtual std::vector<DerivationInfo> toDerivations() = 0;
|
virtual std::vector<DerivationInfo> toDerivations() = 0;
|
||||||
|
|
||||||
DerivedPathsWithHints toDerivedPathsWithHints() override;
|
DerivedPaths toDerivedPaths() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct InstallableFlake : InstallableValue
|
struct InstallableFlake : InstallableValue
|
||||||
|
|
|
@ -11,18 +11,33 @@ nlohmann::json DerivedPath::Opaque::toJSON(ref<Store> store) const {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
nlohmann::json DerivedPathWithHints::Built::toJSON(ref<Store> store) const {
|
nlohmann::json BuiltPath::Built::toJSON(ref<Store> store) const {
|
||||||
nlohmann::json res;
|
nlohmann::json res;
|
||||||
res["drvPath"] = store->printStorePath(drvPath);
|
res["drvPath"] = store->printStorePath(drvPath);
|
||||||
for (const auto& [output, path] : outputs) {
|
for (const auto& [output, path] : outputs) {
|
||||||
res["outputs"][output] = path ? store->printStorePath(*path) : "";
|
res["outputs"][output] = store->printStorePath(path);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
nlohmann::json derivedPathsWithHintsToJSON(const DerivedPathsWithHints & buildables, ref<Store> store) {
|
StorePathSet BuiltPath::outPaths() const
|
||||||
|
{
|
||||||
|
return std::visit(
|
||||||
|
overloaded{
|
||||||
|
[](BuiltPath::Opaque p) { return StorePathSet{p.path}; },
|
||||||
|
[](BuiltPath::Built b) {
|
||||||
|
StorePathSet res;
|
||||||
|
for (auto & [_, path] : b.outputs)
|
||||||
|
res.insert(path);
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
}, raw()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
nlohmann::json derivedPathsWithHintsToJSON(const BuiltPaths & buildables, ref<Store> store) {
|
||||||
auto res = nlohmann::json::array();
|
auto res = nlohmann::json::array();
|
||||||
for (const DerivedPathWithHints & buildable : buildables) {
|
for (const BuiltPath & buildable : buildables) {
|
||||||
std::visit([&res, store](const auto & buildable) {
|
std::visit([&res, store](const auto & buildable) {
|
||||||
res.push_back(buildable.toJSON(store));
|
res.push_back(buildable.toJSON(store));
|
||||||
}, buildable.raw());
|
}, buildable.raw());
|
||||||
|
@ -74,4 +89,30 @@ DerivedPath DerivedPath::parse(const Store & store, std::string_view s)
|
||||||
: (DerivedPath) DerivedPath::Built::parse(store, s);
|
: (DerivedPath) DerivedPath::Built::parse(store, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RealisedPath::Set BuiltPath::toRealisedPaths(Store & store) const
|
||||||
|
{
|
||||||
|
RealisedPath::Set res;
|
||||||
|
std::visit(
|
||||||
|
overloaded{
|
||||||
|
[&](BuiltPath::Opaque p) { res.insert(p.path); },
|
||||||
|
[&](BuiltPath::Built p) {
|
||||||
|
auto drvHashes =
|
||||||
|
staticOutputHashes(store, store.readDerivation(p.drvPath));
|
||||||
|
for (auto& [outputName, outputPath] : p.outputs) {
|
||||||
|
if (settings.isExperimentalFeatureEnabled(
|
||||||
|
"ca-derivations")) {
|
||||||
|
auto thisRealisation = store.queryRealisation(
|
||||||
|
DrvOutput{drvHashes.at(outputName), outputName});
|
||||||
|
assert(thisRealisation); // We’ve built it, so we must h
|
||||||
|
// ve the realisation
|
||||||
|
res.insert(*thisRealisation);
|
||||||
|
} else {
|
||||||
|
res.insert(outputPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
raw());
|
||||||
|
return res;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
#include "path.hh"
|
#include "path.hh"
|
||||||
|
#include "realisation.hh"
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
|
@ -79,51 +80,44 @@ struct DerivedPath : _DerivedPathRaw {
|
||||||
/**
|
/**
|
||||||
* A built derived path with hints in the form of optional concrete output paths.
|
* A built derived path with hints in the form of optional concrete output paths.
|
||||||
*
|
*
|
||||||
* See 'DerivedPathWithHints' for more an explanation.
|
* See 'BuiltPath' for more an explanation.
|
||||||
*/
|
*/
|
||||||
struct DerivedPathWithHintsBuilt {
|
struct BuiltPathBuilt {
|
||||||
StorePath drvPath;
|
StorePath drvPath;
|
||||||
std::map<std::string, std::optional<StorePath>> outputs;
|
std::map<std::string, StorePath> outputs;
|
||||||
|
|
||||||
nlohmann::json toJSON(ref<Store> store) const;
|
nlohmann::json toJSON(ref<Store> store) const;
|
||||||
static DerivedPathWithHintsBuilt parse(const Store & store, std::string_view);
|
static BuiltPathBuilt parse(const Store & store, std::string_view);
|
||||||
};
|
};
|
||||||
|
|
||||||
using _DerivedPathWithHintsRaw = std::variant<
|
using _BuiltPathRaw = std::variant<
|
||||||
DerivedPath::Opaque,
|
DerivedPath::Opaque,
|
||||||
DerivedPathWithHintsBuilt
|
BuiltPathBuilt
|
||||||
>;
|
>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A derived path with hints in the form of optional concrete output paths in the built case.
|
* A built path. Similar to a `DerivedPath`, but enriched with the corresponding
|
||||||
*
|
* output path(s).
|
||||||
* This type is currently just used by the CLI. The paths are filled in
|
|
||||||
* during evaluation for derivations that know what paths they will
|
|
||||||
* produce in advanced, i.e. input-addressed or fixed-output content
|
|
||||||
* addressed derivations.
|
|
||||||
*
|
|
||||||
* That isn't very good, because it puts floating content-addressed
|
|
||||||
* derivations "at a disadvantage". It would be better to never rely on
|
|
||||||
* the output path of unbuilt derivations, and exclusively use the
|
|
||||||
* realizations types to work with built derivations' concrete output
|
|
||||||
* paths.
|
|
||||||
*/
|
*/
|
||||||
// FIXME Stop using and delete this, or if that is not possible move out of libstore to libcmd.
|
struct BuiltPath : _BuiltPathRaw {
|
||||||
struct DerivedPathWithHints : _DerivedPathWithHintsRaw {
|
using Raw = _BuiltPathRaw;
|
||||||
using Raw = _DerivedPathWithHintsRaw;
|
|
||||||
using Raw::Raw;
|
using Raw::Raw;
|
||||||
|
|
||||||
using Opaque = DerivedPathOpaque;
|
using Opaque = DerivedPathOpaque;
|
||||||
using Built = DerivedPathWithHintsBuilt;
|
using Built = BuiltPathBuilt;
|
||||||
|
|
||||||
inline const Raw & raw() const {
|
inline const Raw & raw() const {
|
||||||
return static_cast<const Raw &>(*this);
|
return static_cast<const Raw &>(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StorePathSet outPaths() const;
|
||||||
|
RealisedPath::Set toRealisedPaths(Store & store) const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<DerivedPathWithHints> DerivedPathsWithHints;
|
typedef std::vector<DerivedPath> DerivedPaths;
|
||||||
|
typedef std::vector<BuiltPath> BuiltPaths;
|
||||||
|
|
||||||
nlohmann::json derivedPathsWithHintsToJSON(const DerivedPathsWithHints & buildables, ref<Store> store);
|
nlohmann::json derivedPathsWithHintsToJSON(const BuiltPaths & buildables, ref<Store> store);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,12 +63,12 @@ struct CmdBuild : InstallablesCommand, MixDryRun, MixJSON, MixProfile
|
||||||
for (const auto & [_i, buildable] : enumerate(buildables)) {
|
for (const auto & [_i, buildable] : enumerate(buildables)) {
|
||||||
auto i = _i;
|
auto i = _i;
|
||||||
std::visit(overloaded {
|
std::visit(overloaded {
|
||||||
[&](DerivedPathWithHints::Opaque bo) {
|
[&](BuiltPath::Opaque bo) {
|
||||||
std::string symlink = outLink;
|
std::string symlink = outLink;
|
||||||
if (i) symlink += fmt("-%d", i);
|
if (i) symlink += fmt("-%d", i);
|
||||||
store2->addPermRoot(bo.path, absPath(symlink));
|
store2->addPermRoot(bo.path, absPath(symlink));
|
||||||
},
|
},
|
||||||
[&](DerivedPathWithHints::Built bfd) {
|
[&](BuiltPath::Built bfd) {
|
||||||
auto builtOutputs = store->queryDerivationOutputMap(bfd.drvPath);
|
auto builtOutputs = store->queryDerivationOutputMap(bfd.drvPath);
|
||||||
for (auto & output : builtOutputs) {
|
for (auto & output : builtOutputs) {
|
||||||
std::string symlink = outLink;
|
std::string symlink = outLink;
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
using namespace nix;
|
using namespace nix;
|
||||||
|
|
||||||
struct CmdCopy : RealisedPathsCommand
|
struct CmdCopy : BuiltPathsCommand
|
||||||
{
|
{
|
||||||
std::string srcUri, dstUri;
|
std::string srcUri, dstUri;
|
||||||
|
|
||||||
|
@ -16,10 +16,10 @@ struct CmdCopy : RealisedPathsCommand
|
||||||
|
|
||||||
SubstituteFlag substitute = NoSubstitute;
|
SubstituteFlag substitute = NoSubstitute;
|
||||||
|
|
||||||
using RealisedPathsCommand::run;
|
using BuiltPathsCommand::run;
|
||||||
|
|
||||||
CmdCopy()
|
CmdCopy()
|
||||||
: RealisedPathsCommand(true)
|
: BuiltPathsCommand(true)
|
||||||
{
|
{
|
||||||
addFlag({
|
addFlag({
|
||||||
.longName = "from",
|
.longName = "from",
|
||||||
|
@ -75,16 +75,22 @@ struct CmdCopy : RealisedPathsCommand
|
||||||
if (srcUri.empty() && dstUri.empty())
|
if (srcUri.empty() && dstUri.empty())
|
||||||
throw UsageError("you must pass '--from' and/or '--to'");
|
throw UsageError("you must pass '--from' and/or '--to'");
|
||||||
|
|
||||||
RealisedPathsCommand::run(store);
|
BuiltPathsCommand::run(store);
|
||||||
}
|
}
|
||||||
|
|
||||||
void run(ref<Store> srcStore, std::vector<RealisedPath> paths) override
|
void run(ref<Store> srcStore, BuiltPaths paths) override
|
||||||
{
|
{
|
||||||
ref<Store> dstStore = dstUri.empty() ? openStore() : openStore(dstUri);
|
ref<Store> dstStore = dstUri.empty() ? openStore() : openStore(dstUri);
|
||||||
|
|
||||||
|
RealisedPath::Set stuffToCopy;
|
||||||
|
|
||||||
|
for (auto & builtPath : paths) {
|
||||||
|
auto theseRealisations = builtPath.toRealisedPaths(*srcStore);
|
||||||
|
stuffToCopy.insert(theseRealisations.begin(), theseRealisations.end());
|
||||||
|
}
|
||||||
|
|
||||||
copyPaths(
|
copyPaths(
|
||||||
srcStore, dstStore, RealisedPath::Set(paths.begin(), paths.end()),
|
srcStore, dstStore, stuffToCopy, NoRepair, checkSigs, substitute);
|
||||||
NoRepair, checkSigs, substitute);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -265,9 +265,9 @@ struct Common : InstallableCommand, MixProfile
|
||||||
for (auto & [installable_, dir_] : redirects) {
|
for (auto & [installable_, dir_] : redirects) {
|
||||||
auto dir = absPath(dir_);
|
auto dir = absPath(dir_);
|
||||||
auto installable = parseInstallable(store, installable_);
|
auto installable = parseInstallable(store, installable_);
|
||||||
auto buildable = installable->toDerivedPathWithHints();
|
auto builtPaths = toStorePaths(
|
||||||
auto doRedirect = [&](const StorePath & path)
|
store, Realise::Nothing, OperateOn::Output, {installable});
|
||||||
{
|
for (auto & path: builtPaths) {
|
||||||
auto from = store->printStorePath(path);
|
auto from = store->printStorePath(path);
|
||||||
if (script.find(from) == std::string::npos)
|
if (script.find(from) == std::string::npos)
|
||||||
warn("'%s' (path '%s') is not used by this build environment", installable->what(), from);
|
warn("'%s' (path '%s') is not used by this build environment", installable->what(), from);
|
||||||
|
@ -275,16 +275,7 @@ struct Common : InstallableCommand, MixProfile
|
||||||
printInfo("redirecting '%s' to '%s'", from, dir);
|
printInfo("redirecting '%s' to '%s'", from, dir);
|
||||||
rewrites.insert({from, dir});
|
rewrites.insert({from, dir});
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
std::visit(overloaded {
|
|
||||||
[&](const DerivedPathWithHints::Opaque & bo) {
|
|
||||||
doRedirect(bo.path);
|
|
||||||
},
|
|
||||||
[&](const DerivedPathWithHints::Built & bfd) {
|
|
||||||
for (auto & [outputName, path] : bfd.outputs)
|
|
||||||
if (path) doRedirect(*path);
|
|
||||||
},
|
|
||||||
}, buildable.raw());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rewriteStrings(script, rewrites);
|
return rewriteStrings(script, rewrites);
|
||||||
|
|
|
@ -30,15 +30,15 @@ struct CmdLog : InstallableCommand
|
||||||
|
|
||||||
subs.push_front(store);
|
subs.push_front(store);
|
||||||
|
|
||||||
auto b = installable->toDerivedPathWithHints();
|
auto b = installable->toDerivedPath();
|
||||||
|
|
||||||
RunPager pager;
|
RunPager pager;
|
||||||
for (auto & sub : subs) {
|
for (auto & sub : subs) {
|
||||||
auto log = std::visit(overloaded {
|
auto log = std::visit(overloaded {
|
||||||
[&](DerivedPathWithHints::Opaque bo) {
|
[&](DerivedPath::Opaque bo) {
|
||||||
return sub->getBuildLog(bo.path);
|
return sub->getBuildLog(bo.path);
|
||||||
},
|
},
|
||||||
[&](DerivedPathWithHints::Built bfd) {
|
[&](DerivedPath::Built bfd) {
|
||||||
return sub->getBuildLog(bfd.drvPath);
|
return sub->getBuildLog(bfd.drvPath);
|
||||||
},
|
},
|
||||||
}, b.raw());
|
}, b.raw());
|
||||||
|
|
|
@ -259,11 +259,11 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
|
||||||
ProfileElement element;
|
ProfileElement element;
|
||||||
|
|
||||||
std::visit(overloaded {
|
std::visit(overloaded {
|
||||||
[&](DerivedPathWithHints::Opaque bo) {
|
[&](BuiltPath::Opaque bo) {
|
||||||
pathsToBuild.push_back(bo);
|
pathsToBuild.push_back(bo);
|
||||||
element.storePaths.insert(bo.path);
|
element.storePaths.insert(bo.path);
|
||||||
},
|
},
|
||||||
[&](DerivedPathWithHints::Built bfd) {
|
[&](BuiltPath::Built bfd) {
|
||||||
// TODO: Why are we querying if we know the output
|
// TODO: Why are we querying if we know the output
|
||||||
// names already? Is it just to figure out what the
|
// names already? Is it just to figure out what the
|
||||||
// default one is?
|
// default one is?
|
||||||
|
|
|
@ -28,7 +28,7 @@ struct CmdRealisation : virtual NixMultiCommand
|
||||||
|
|
||||||
static auto rCmdRealisation = registerCommand<CmdRealisation>("realisation");
|
static auto rCmdRealisation = registerCommand<CmdRealisation>("realisation");
|
||||||
|
|
||||||
struct CmdRealisationInfo : RealisedPathsCommand, MixJSON
|
struct CmdRealisationInfo : BuiltPathsCommand, MixJSON
|
||||||
{
|
{
|
||||||
std::string description() override
|
std::string description() override
|
||||||
{
|
{
|
||||||
|
@ -44,12 +44,19 @@ struct CmdRealisationInfo : RealisedPathsCommand, MixJSON
|
||||||
|
|
||||||
Category category() override { return catSecondary; }
|
Category category() override { return catSecondary; }
|
||||||
|
|
||||||
void run(ref<Store> store, std::vector<RealisedPath> paths) override
|
void run(ref<Store> store, BuiltPaths paths) override
|
||||||
{
|
{
|
||||||
settings.requireExperimentalFeature("ca-derivations");
|
settings.requireExperimentalFeature("ca-derivations");
|
||||||
|
RealisedPath::Set realisations;
|
||||||
|
|
||||||
|
for (auto & builtPath : paths) {
|
||||||
|
auto theseRealisations = builtPath.toRealisedPaths(*store);
|
||||||
|
realisations.insert(theseRealisations.begin(), theseRealisations.end());
|
||||||
|
}
|
||||||
|
|
||||||
if (json) {
|
if (json) {
|
||||||
nlohmann::json res = nlohmann::json::array();
|
nlohmann::json res = nlohmann::json::array();
|
||||||
for (auto & path : paths) {
|
for (auto & path : realisations) {
|
||||||
nlohmann::json currentPath;
|
nlohmann::json currentPath;
|
||||||
if (auto realisation = std::get_if<Realisation>(&path.raw))
|
if (auto realisation = std::get_if<Realisation>(&path.raw))
|
||||||
currentPath = realisation->toJSON();
|
currentPath = realisation->toJSON();
|
||||||
|
@ -61,7 +68,7 @@ struct CmdRealisationInfo : RealisedPathsCommand, MixJSON
|
||||||
std::cout << res.dump();
|
std::cout << res.dump();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (auto & path : paths) {
|
for (auto & path : realisations) {
|
||||||
if (auto realisation = std::get_if<Realisation>(&path.raw)) {
|
if (auto realisation = std::get_if<Realisation>(&path.raw)) {
|
||||||
std::cout <<
|
std::cout <<
|
||||||
realisation->id.to_string() << " " <<
|
realisation->id.to_string() << " " <<
|
||||||
|
|
Loading…
Reference in a new issue