Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
202 changes: 106 additions & 96 deletions src/libcmd/installables.cc
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ void completeFlakeRef(ref<Store> store, std::string_view prefix)
}
}

DerivedPath Installable::toDerivedPath()
DerivedPathWithInfo Installable::toDerivedPath()
{
auto buildables = toDerivedPaths();
if (buildables.size() != 1)
Expand Down Expand Up @@ -422,21 +422,9 @@ struct InstallableStorePath : Installable
return req.to_string(*store);
}

DerivedPaths toDerivedPaths() override
DerivedPathsWithInfo toDerivedPaths() override
{
return { req };
}

StorePathSet toDrvPaths(ref<Store> store) override
{
return std::visit(overloaded {
[&](const DerivedPath::Built & bfd) -> StorePathSet {
return { bfd.drvPath };
},
[&](const DerivedPath::Opaque & bo) -> StorePathSet {
return { getDeriver(store, *this, bo.path) };
},
}, req.raw());
return {{.path = req, .info = {} }};
}

std::optional<StorePath> getStorePath() override
Expand All @@ -452,34 +440,6 @@ struct InstallableStorePath : Installable
}
};

DerivedPaths InstallableValue::toDerivedPaths()
{
DerivedPaths res;

std::map<StorePath, std::set<std::string>> drvsToOutputs;
RealisedPath::Set drvsToCopy;

// Group by derivation, helps with .all in particular
for (auto & drv : toDerivations()) {
for (auto & outputName : drv.outputsToInstall)
drvsToOutputs[drv.drvPath].insert(outputName);
drvsToCopy.insert(drv.drvPath);
}

for (auto & i : drvsToOutputs)
res.push_back(DerivedPath::Built { i.first, i.second });

return res;
}

StorePathSet InstallableValue::toDrvPaths(ref<Store> store)
{
StorePathSet res;
for (auto & drv : toDerivations())
res.insert(drv.drvPath);
return res;
}

struct InstallableAttrPath : InstallableValue
{
SourceExprCommand & cmd;
Expand Down Expand Up @@ -509,40 +469,45 @@ struct InstallableAttrPath : InstallableValue
return {vRes, pos};
}

virtual std::vector<InstallableValue::DerivationInfo> toDerivations() override;
};
DerivedPathsWithInfo toDerivedPaths() override
{
auto v = toValue(*state).first;

std::vector<InstallableValue::DerivationInfo> InstallableAttrPath::toDerivations()
{
auto v = toValue(*state).first;
Bindings & autoArgs = *cmd.getAutoArgs(*state);

Bindings & autoArgs = *cmd.getAutoArgs(*state);
DrvInfos drvInfos;
getDerivations(*state, *v, "", autoArgs, drvInfos, false);

DrvInfos drvInfos;
getDerivations(*state, *v, "", autoArgs, drvInfos, false);
// Backward compatibility hack: group results by drvPath. This
// helps keep .all output together.
std::map<StorePath, DerivedPath::Built> byDrvPath;

std::vector<DerivationInfo> res;
for (auto & drvInfo : drvInfos) {
auto drvPath = drvInfo.queryDrvPath();
if (!drvPath)
throw Error("'%s' is not a derivation", what());
for (auto & drvInfo : drvInfos) {
auto drvPath = drvInfo.queryDrvPath();
if (!drvPath)
throw Error("'%s' is not a derivation", what());

std::set<std::string> outputsToInstall;
std::set<std::string> outputsToInstall;

if (auto outputNames = std::get_if<OutputNames>(&outputsSpec))
outputsToInstall = *outputNames;
else
for (auto & output : drvInfo.queryOutputs(false, std::get_if<DefaultOutputs>(&outputsSpec)))
outputsToInstall.insert(output.first);
if (auto outputNames = std::get_if<OutputNames>(&outputsSpec))
outputsToInstall = *outputNames;
else
for (auto & output : drvInfo.queryOutputs(false, std::get_if<DefaultOutputs>(&outputsSpec)))
outputsToInstall.insert(output.first);

res.push_back(DerivationInfo {
.drvPath = *drvPath,
.outputsToInstall = std::move(outputsToInstall)
});
}
auto derivedPath = byDrvPath.emplace(*drvPath, DerivedPath::Built { .drvPath = *drvPath }).first;

return res;
}
for (auto & output : outputsToInstall)
derivedPath->second.outputs.insert(output);
}

DerivedPathsWithInfo res;
for (auto & [_, info] : byDrvPath)
res.push_back({ .path = { info } });

return res;
}
};

std::vector<std::string> InstallableFlake::getActualAttrPaths()
{
Expand Down Expand Up @@ -630,16 +595,46 @@ InstallableFlake::InstallableFlake(
throw UsageError("'--arg' and '--argstr' are incompatible with flakes");
}

std::tuple<std::string, FlakeRef, InstallableValue::DerivationInfo> InstallableFlake::toDerivation()
DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
{
Activity act(*logger, lvlTalkative, actUnknown, fmt("evaluating derivation '%s'", what()));

auto attr = getCursor(*state);

auto attrPath = attr->getAttrPathStr();

if (!attr->isDerivation())
throw Error("flake output attribute '%s' is not a derivation", attrPath);
if (!attr->isDerivation()) {

// FIXME: use eval cache?
auto v = attr->forceValue();

if (v.type() == nPath) {
PathSet context;
auto storePath = state->copyPathToStore(context, Path(v.path));
return {{
.path = DerivedPath::Opaque {
.path = std::move(storePath),
}
}};
}

else if (v.type() == nString) {
PathSet context;
auto s = state->forceString(v, context, noPos, fmt("while evaluating the flake output attribute '%s'", attrPath));
auto storePath = state->store->maybeParseStorePath(s);
if (storePath && context.count(std::string(s))) {
return {{
.path = DerivedPath::Opaque {
.path = std::move(*storePath),
}
}};
} else
throw Error("flake output attribute '%s' evaluates to the string '%s' which is not a store path", attrPath, s);
}

else
throw Error("flake output attribute '%s' is not a derivation or path", attrPath);
}

auto drvPath = attr->forceDerivation();

Expand Down Expand Up @@ -674,20 +669,19 @@ std::tuple<std::string, FlakeRef, InstallableValue::DerivationInfo> InstallableF
if (auto outputNames = std::get_if<OutputNames>(&outputsSpec))
outputsToInstall = *outputNames;

auto drvInfo = DerivationInfo {
.drvPath = std::move(drvPath),
.outputsToInstall = std::move(outputsToInstall),
.priority = priority,
};

return {attrPath, getLockedFlake()->flake.lockedRef, std::move(drvInfo)};
}

std::vector<InstallableValue::DerivationInfo> InstallableFlake::toDerivations()
{
std::vector<DerivationInfo> res;
res.push_back(std::get<2>(toDerivation()));
return res;
return {{
.path = DerivedPath::Built {
.drvPath = std::move(drvPath),
.outputs = std::move(outputsToInstall),
},
.info = {
.priority = priority,
.originalRef = flakeRef,
.resolvedRef = getLockedFlake()->flake.lockedRef,
.attrPath = attrPath,
.outputsSpec = outputsSpec,
}
}};
}

std::pair<Value *, PosIdx> InstallableFlake::toValue(EvalState & state)
Expand Down Expand Up @@ -895,13 +889,19 @@ std::vector<std::pair<std::shared_ptr<Installable>, BuiltPathWithResult>> Instal
if (mode == Realise::Nothing)
settings.readOnlyMode = true;

struct Aux
{
ExtraPathInfo info;
std::shared_ptr<Installable> installable;
};

std::vector<DerivedPath> pathsToBuild;
std::map<DerivedPath, std::vector<std::shared_ptr<Installable>>> backmap;
std::map<DerivedPath, std::vector<Aux>> backmap;

for (auto & i : installables) {
for (auto b : i->toDerivedPaths()) {
pathsToBuild.push_back(b);
backmap[b].push_back(i);
pathsToBuild.push_back(b.path);
backmap[b.path].push_back({.info = b.info, .installable = i});
}
}

Expand All @@ -914,7 +914,7 @@ std::vector<std::pair<std::shared_ptr<Installable>, BuiltPathWithResult>> Instal
printMissing(store, pathsToBuild, lvlError);

for (auto & path : pathsToBuild) {
for (auto & installable : backmap[path]) {
for (auto & aux : backmap[path]) {
std::visit(overloaded {
[&](const DerivedPath::Built & bfd) {
OutputPathMap outputs;
Expand Down Expand Up @@ -943,10 +943,14 @@ std::vector<std::pair<std::shared_ptr<Installable>, BuiltPathWithResult>> Instal
output, *drvOutput->second);
}
}
res.push_back({installable, {.path = BuiltPath::Built { bfd.drvPath, outputs }}});
res.push_back({aux.installable, {
.path = BuiltPath::Built { bfd.drvPath, outputs },
.info = aux.info}});
},
[&](const DerivedPath::Opaque & bo) {
res.push_back({installable, {.path = BuiltPath::Opaque { bo.path }}});
res.push_back({aux.installable, {
.path = BuiltPath::Opaque { bo.path },
.info = aux.info}});
},
}, path.raw());
}
Expand All @@ -962,16 +966,22 @@ std::vector<std::pair<std::shared_ptr<Installable>, BuiltPathWithResult>> Instal
if (!buildResult.success())
buildResult.rethrow();

for (auto & installable : backmap[buildResult.path]) {
for (auto & aux : backmap[buildResult.path]) {
std::visit(overloaded {
[&](const DerivedPath::Built & bfd) {
std::map<std::string, StorePath> outputs;
for (auto & path : buildResult.builtOutputs)
outputs.emplace(path.first.outputName, path.second.outPath);
res.push_back({installable, {.path = BuiltPath::Built { bfd.drvPath, outputs }, .result = buildResult}});
res.push_back({aux.installable, {
.path = BuiltPath::Built { bfd.drvPath, outputs },
.info = aux.info,
.result = buildResult}});
},
[&](const DerivedPath::Opaque & bo) {
res.push_back({installable, {.path = BuiltPath::Opaque { bo.path }, .result = buildResult}});
res.push_back({aux.installable, {
.path = BuiltPath::Opaque { bo.path },
.info = aux.info,
.result = buildResult}});
},
}, buildResult.path.raw());
}
Expand Down Expand Up @@ -1056,7 +1066,7 @@ StorePathSet Installable::toDerivations(
[&](const DerivedPath::Built & bfd) {
drvPaths.insert(bfd.drvPath);
},
}, b.raw());
}, b.path.raw());

return drvPaths;
}
Expand Down
47 changes: 24 additions & 23 deletions src/libcmd/installables.hh
Original file line number Diff line number Diff line change
Expand Up @@ -52,26 +52,42 @@ enum class OperateOn {
Derivation
};

struct ExtraPathInfo
{
std::optional<NixInt> priority;
std::optional<FlakeRef> originalRef;
std::optional<FlakeRef> resolvedRef;
std::optional<std::string> attrPath;
// FIXME: merge with DerivedPath's 'outputs' field?
std::optional<OutputsSpec> outputsSpec;
};

/* A derived path with any additional info that commands might
need from the derivation. */
struct DerivedPathWithInfo
{
DerivedPath path;
ExtraPathInfo info;
};

struct BuiltPathWithResult
{
BuiltPath path;
ExtraPathInfo info;
std::optional<BuildResult> result;
};

typedef std::vector<DerivedPathWithInfo> DerivedPathsWithInfo;

struct Installable
{
virtual ~Installable() { }

virtual std::string what() const = 0;

virtual DerivedPaths toDerivedPaths() = 0;

virtual StorePathSet toDrvPaths(ref<Store> store)
{
throw Error("'%s' cannot be converted to a derivation path", what());
}
virtual DerivedPathsWithInfo toDerivedPaths() = 0;

DerivedPath toDerivedPath();
DerivedPathWithInfo toDerivedPath();

UnresolvedApp toApp(EvalState & state);

Expand Down Expand Up @@ -146,19 +162,6 @@ struct InstallableValue : Installable
ref<EvalState> state;

InstallableValue(ref<EvalState> state) : state(state) {}

struct DerivationInfo
{
StorePath drvPath;
std::set<std::string> outputsToInstall;
std::optional<NixInt> priority;
};

virtual std::vector<DerivationInfo> toDerivations() = 0;

DerivedPaths toDerivedPaths() override;

StorePathSet toDrvPaths(ref<Store> store) override;
};

struct InstallableFlake : InstallableValue
Expand Down Expand Up @@ -186,9 +189,7 @@ struct InstallableFlake : InstallableValue

Value * getFlakeOutputs(EvalState & state, const flake::LockedFlake & lockedFlake);

std::tuple<std::string, FlakeRef, DerivationInfo> toDerivation();

std::vector<DerivationInfo> toDerivations() override;
DerivedPathsWithInfo toDerivedPaths() override;

std::pair<Value *, PosIdx> toValue(EvalState & state) override;

Expand Down
Loading