Merge pull request #4818 from NixOS/ca/cli-use-builtpaths

Enforce the use of properly built paths in libcmd
This commit is contained in:
Eelco Dolstra 2021-05-17 16:15:40 +02:00 committed by GitHub
commit 6849ae82de
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 212 additions and 167 deletions

View file

@ -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());

View file

@ -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

View file

@ -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());

View file

@ -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

View file

@ -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); // Weve built it, so we must h
// ve the realisation
res.insert(*thisRealisation);
} else {
res.insert(outputPath);
}
}
},
},
raw());
return res;
}
} }

View file

@ -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);
} }

View file

@ -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;

View file

@ -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);
} }
}; };

View file

@ -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);

View file

@ -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());

View file

@ -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?

View file

@ -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() << " " <<