forked from lix-project/lix
Merge pull request #7484 from edolstra/fix-7417
InstallableFlake::toDerivedPaths(): Support paths and store paths
This commit is contained in:
commit
1c98daf6e8
|
@ -358,7 +358,7 @@ void completeFlakeRef(ref<Store> store, std::string_view prefix)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DerivedPath Installable::toDerivedPath()
|
DerivedPathWithInfo Installable::toDerivedPath()
|
||||||
{
|
{
|
||||||
auto buildables = toDerivedPaths();
|
auto buildables = toDerivedPaths();
|
||||||
if (buildables.size() != 1)
|
if (buildables.size() != 1)
|
||||||
|
@ -422,21 +422,9 @@ struct InstallableStorePath : Installable
|
||||||
return req.to_string(*store);
|
return req.to_string(*store);
|
||||||
}
|
}
|
||||||
|
|
||||||
DerivedPaths toDerivedPaths() override
|
DerivedPathsWithInfo toDerivedPaths() override
|
||||||
{
|
{
|
||||||
return { req };
|
return {{.path = req, .info = {} }};
|
||||||
}
|
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<StorePath> getStorePath() override
|
std::optional<StorePath> getStorePath() override
|
||||||
|
@ -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
|
struct InstallableAttrPath : InstallableValue
|
||||||
{
|
{
|
||||||
SourceExprCommand & cmd;
|
SourceExprCommand & cmd;
|
||||||
|
@ -509,40 +469,45 @@ struct InstallableAttrPath : InstallableValue
|
||||||
return {vRes, pos};
|
return {vRes, pos};
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::vector<InstallableValue::DerivationInfo> toDerivations() override;
|
DerivedPathsWithInfo toDerivedPaths() override
|
||||||
};
|
{
|
||||||
|
auto v = toValue(*state).first;
|
||||||
|
|
||||||
std::vector<InstallableValue::DerivationInfo> InstallableAttrPath::toDerivations()
|
Bindings & autoArgs = *cmd.getAutoArgs(*state);
|
||||||
{
|
|
||||||
auto v = toValue(*state).first;
|
|
||||||
|
|
||||||
Bindings & autoArgs = *cmd.getAutoArgs(*state);
|
DrvInfos drvInfos;
|
||||||
|
getDerivations(*state, *v, "", autoArgs, drvInfos, false);
|
||||||
|
|
||||||
DrvInfos drvInfos;
|
// Backward compatibility hack: group results by drvPath. This
|
||||||
getDerivations(*state, *v, "", autoArgs, drvInfos, false);
|
// helps keep .all output together.
|
||||||
|
std::map<StorePath, DerivedPath::Built> byDrvPath;
|
||||||
|
|
||||||
std::vector<DerivationInfo> res;
|
for (auto & drvInfo : drvInfos) {
|
||||||
for (auto & drvInfo : drvInfos) {
|
auto drvPath = drvInfo.queryDrvPath();
|
||||||
auto drvPath = drvInfo.queryDrvPath();
|
if (!drvPath)
|
||||||
if (!drvPath)
|
throw Error("'%s' is not a derivation", what());
|
||||||
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))
|
if (auto outputNames = std::get_if<OutputNames>(&outputsSpec))
|
||||||
outputsToInstall = *outputNames;
|
outputsToInstall = *outputNames;
|
||||||
else
|
else
|
||||||
for (auto & output : drvInfo.queryOutputs(false, std::get_if<DefaultOutputs>(&outputsSpec)))
|
for (auto & output : drvInfo.queryOutputs(false, std::get_if<DefaultOutputs>(&outputsSpec)))
|
||||||
outputsToInstall.insert(output.first);
|
outputsToInstall.insert(output.first);
|
||||||
|
|
||||||
res.push_back(DerivationInfo {
|
auto derivedPath = byDrvPath.emplace(*drvPath, DerivedPath::Built { .drvPath = *drvPath }).first;
|
||||||
.drvPath = *drvPath,
|
|
||||||
.outputsToInstall = std::move(outputsToInstall)
|
for (auto & output : outputsToInstall)
|
||||||
});
|
derivedPath->second.outputs.insert(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
DerivedPathsWithInfo res;
|
||||||
|
for (auto & [_, info] : byDrvPath)
|
||||||
|
res.push_back({ .path = { info } });
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> InstallableFlake::getActualAttrPaths()
|
std::vector<std::string> InstallableFlake::getActualAttrPaths()
|
||||||
{
|
{
|
||||||
|
@ -630,7 +595,7 @@ InstallableFlake::InstallableFlake(
|
||||||
throw UsageError("'--arg' and '--argstr' are incompatible with flakes");
|
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()));
|
Activity act(*logger, lvlTalkative, actUnknown, fmt("evaluating derivation '%s'", what()));
|
||||||
|
|
||||||
|
@ -638,8 +603,38 @@ std::tuple<std::string, FlakeRef, InstallableValue::DerivationInfo> InstallableF
|
||||||
|
|
||||||
auto attrPath = attr->getAttrPathStr();
|
auto attrPath = attr->getAttrPathStr();
|
||||||
|
|
||||||
if (!attr->isDerivation())
|
if (!attr->isDerivation()) {
|
||||||
throw Error("flake output attribute '%s' is not a derivation", attrPath);
|
|
||||||
|
// 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();
|
auto drvPath = attr->forceDerivation();
|
||||||
|
|
||||||
|
@ -674,20 +669,19 @@ std::tuple<std::string, FlakeRef, InstallableValue::DerivationInfo> InstallableF
|
||||||
if (auto outputNames = std::get_if<OutputNames>(&outputsSpec))
|
if (auto outputNames = std::get_if<OutputNames>(&outputsSpec))
|
||||||
outputsToInstall = *outputNames;
|
outputsToInstall = *outputNames;
|
||||||
|
|
||||||
auto drvInfo = DerivationInfo {
|
return {{
|
||||||
.drvPath = std::move(drvPath),
|
.path = DerivedPath::Built {
|
||||||
.outputsToInstall = std::move(outputsToInstall),
|
.drvPath = std::move(drvPath),
|
||||||
.priority = priority,
|
.outputs = std::move(outputsToInstall),
|
||||||
};
|
},
|
||||||
|
.info = {
|
||||||
return {attrPath, getLockedFlake()->flake.lockedRef, std::move(drvInfo)};
|
.priority = priority,
|
||||||
}
|
.originalRef = flakeRef,
|
||||||
|
.resolvedRef = getLockedFlake()->flake.lockedRef,
|
||||||
std::vector<InstallableValue::DerivationInfo> InstallableFlake::toDerivations()
|
.attrPath = attrPath,
|
||||||
{
|
.outputsSpec = outputsSpec,
|
||||||
std::vector<DerivationInfo> res;
|
}
|
||||||
res.push_back(std::get<2>(toDerivation()));
|
}};
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<Value *, PosIdx> InstallableFlake::toValue(EvalState & state)
|
std::pair<Value *, PosIdx> InstallableFlake::toValue(EvalState & state)
|
||||||
|
@ -895,13 +889,19 @@ std::vector<std::pair<std::shared_ptr<Installable>, BuiltPathWithResult>> Instal
|
||||||
if (mode == Realise::Nothing)
|
if (mode == Realise::Nothing)
|
||||||
settings.readOnlyMode = true;
|
settings.readOnlyMode = true;
|
||||||
|
|
||||||
|
struct Aux
|
||||||
|
{
|
||||||
|
ExtraPathInfo info;
|
||||||
|
std::shared_ptr<Installable> installable;
|
||||||
|
};
|
||||||
|
|
||||||
std::vector<DerivedPath> pathsToBuild;
|
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 & i : installables) {
|
||||||
for (auto b : i->toDerivedPaths()) {
|
for (auto b : i->toDerivedPaths()) {
|
||||||
pathsToBuild.push_back(b);
|
pathsToBuild.push_back(b.path);
|
||||||
backmap[b].push_back(i);
|
backmap[b.path].push_back({.info = b.info, .installable = i});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -914,7 +914,7 @@ std::vector<std::pair<std::shared_ptr<Installable>, BuiltPathWithResult>> Instal
|
||||||
printMissing(store, pathsToBuild, lvlError);
|
printMissing(store, pathsToBuild, lvlError);
|
||||||
|
|
||||||
for (auto & path : pathsToBuild) {
|
for (auto & path : pathsToBuild) {
|
||||||
for (auto & installable : backmap[path]) {
|
for (auto & aux : backmap[path]) {
|
||||||
std::visit(overloaded {
|
std::visit(overloaded {
|
||||||
[&](const DerivedPath::Built & bfd) {
|
[&](const DerivedPath::Built & bfd) {
|
||||||
OutputPathMap outputs;
|
OutputPathMap outputs;
|
||||||
|
@ -943,10 +943,14 @@ std::vector<std::pair<std::shared_ptr<Installable>, BuiltPathWithResult>> Instal
|
||||||
output, *drvOutput->second);
|
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) {
|
[&](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());
|
}, path.raw());
|
||||||
}
|
}
|
||||||
|
@ -962,16 +966,22 @@ std::vector<std::pair<std::shared_ptr<Installable>, BuiltPathWithResult>> Instal
|
||||||
if (!buildResult.success())
|
if (!buildResult.success())
|
||||||
buildResult.rethrow();
|
buildResult.rethrow();
|
||||||
|
|
||||||
for (auto & installable : backmap[buildResult.path]) {
|
for (auto & aux : backmap[buildResult.path]) {
|
||||||
std::visit(overloaded {
|
std::visit(overloaded {
|
||||||
[&](const DerivedPath::Built & bfd) {
|
[&](const DerivedPath::Built & bfd) {
|
||||||
std::map<std::string, StorePath> outputs;
|
std::map<std::string, StorePath> outputs;
|
||||||
for (auto & path : buildResult.builtOutputs)
|
for (auto & path : buildResult.builtOutputs)
|
||||||
outputs.emplace(path.first.outputName, path.second.outPath);
|
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) {
|
[&](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());
|
}, buildResult.path.raw());
|
||||||
}
|
}
|
||||||
|
@ -1056,7 +1066,7 @@ StorePathSet Installable::toDerivations(
|
||||||
[&](const DerivedPath::Built & bfd) {
|
[&](const DerivedPath::Built & bfd) {
|
||||||
drvPaths.insert(bfd.drvPath);
|
drvPaths.insert(bfd.drvPath);
|
||||||
},
|
},
|
||||||
}, b.raw());
|
}, b.path.raw());
|
||||||
|
|
||||||
return drvPaths;
|
return drvPaths;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,26 +52,42 @@ enum class OperateOn {
|
||||||
Derivation
|
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
|
struct BuiltPathWithResult
|
||||||
{
|
{
|
||||||
BuiltPath path;
|
BuiltPath path;
|
||||||
|
ExtraPathInfo info;
|
||||||
std::optional<BuildResult> result;
|
std::optional<BuildResult> result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef std::vector<DerivedPathWithInfo> DerivedPathsWithInfo;
|
||||||
|
|
||||||
struct Installable
|
struct Installable
|
||||||
{
|
{
|
||||||
virtual ~Installable() { }
|
virtual ~Installable() { }
|
||||||
|
|
||||||
virtual std::string what() const = 0;
|
virtual std::string what() const = 0;
|
||||||
|
|
||||||
virtual DerivedPaths toDerivedPaths() = 0;
|
virtual DerivedPathsWithInfo toDerivedPaths() = 0;
|
||||||
|
|
||||||
virtual StorePathSet toDrvPaths(ref<Store> store)
|
DerivedPathWithInfo toDerivedPath();
|
||||||
{
|
|
||||||
throw Error("'%s' cannot be converted to a derivation path", what());
|
|
||||||
}
|
|
||||||
|
|
||||||
DerivedPath toDerivedPath();
|
|
||||||
|
|
||||||
UnresolvedApp toApp(EvalState & state);
|
UnresolvedApp toApp(EvalState & state);
|
||||||
|
|
||||||
|
@ -146,19 +162,6 @@ struct InstallableValue : Installable
|
||||||
ref<EvalState> state;
|
ref<EvalState> state;
|
||||||
|
|
||||||
InstallableValue(ref<EvalState> state) : state(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
|
struct InstallableFlake : InstallableValue
|
||||||
|
@ -186,9 +189,7 @@ struct InstallableFlake : InstallableValue
|
||||||
|
|
||||||
Value * getFlakeOutputs(EvalState & state, const flake::LockedFlake & lockedFlake);
|
Value * getFlakeOutputs(EvalState & state, const flake::LockedFlake & lockedFlake);
|
||||||
|
|
||||||
std::tuple<std::string, FlakeRef, DerivationInfo> toDerivation();
|
DerivedPathsWithInfo toDerivedPaths() override;
|
||||||
|
|
||||||
std::vector<DerivationInfo> toDerivations() override;
|
|
||||||
|
|
||||||
std::pair<Value *, PosIdx> toValue(EvalState & state) override;
|
std::pair<Value *, PosIdx> toValue(EvalState & state) override;
|
||||||
|
|
||||||
|
|
|
@ -2166,7 +2166,7 @@ BackedStringView EvalState::coerceToString(const PosIdx pos, Value & v, PathSet
|
||||||
if (canonicalizePath)
|
if (canonicalizePath)
|
||||||
path = canonPath(*path);
|
path = canonPath(*path);
|
||||||
if (copyToStore)
|
if (copyToStore)
|
||||||
path = copyPathToStore(context, std::move(path).toOwned());
|
path = store->printStorePath(copyPathToStore(context, std::move(path).toOwned()));
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2215,26 +2215,26 @@ BackedStringView EvalState::coerceToString(const PosIdx pos, Value & v, PathSet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string EvalState::copyPathToStore(PathSet & context, const Path & path)
|
StorePath EvalState::copyPathToStore(PathSet & context, const Path & path)
|
||||||
{
|
{
|
||||||
if (nix::isDerivation(path))
|
if (nix::isDerivation(path))
|
||||||
error("file names are not allowed to end in '%1%'", drvExtension).debugThrow<EvalError>();
|
error("file names are not allowed to end in '%1%'", drvExtension).debugThrow<EvalError>();
|
||||||
|
|
||||||
Path dstPath;
|
auto dstPath = [&]() -> StorePath
|
||||||
auto i = srcToStore.find(path);
|
{
|
||||||
if (i != srcToStore.end())
|
auto i = srcToStore.find(path);
|
||||||
dstPath = store->printStorePath(i->second);
|
if (i != srcToStore.end()) return i->second;
|
||||||
else {
|
|
||||||
auto p = settings.readOnlyMode
|
auto dstPath = settings.readOnlyMode
|
||||||
? store->computeStorePathForPath(std::string(baseNameOf(path)), checkSourcePath(path)).first
|
? store->computeStorePathForPath(std::string(baseNameOf(path)), checkSourcePath(path)).first
|
||||||
: store->addToStore(std::string(baseNameOf(path)), checkSourcePath(path), FileIngestionMethod::Recursive, htSHA256, defaultPathFilter, repair);
|
: store->addToStore(std::string(baseNameOf(path)), checkSourcePath(path), FileIngestionMethod::Recursive, htSHA256, defaultPathFilter, repair);
|
||||||
dstPath = store->printStorePath(p);
|
allowPath(dstPath);
|
||||||
allowPath(p);
|
srcToStore.insert_or_assign(path, dstPath);
|
||||||
srcToStore.insert_or_assign(path, std::move(p));
|
printMsg(lvlChatty, "copied source '%1%' -> '%2%'", path, store->printStorePath(dstPath));
|
||||||
printMsg(lvlChatty, "copied source '%1%' -> '%2%'", path, dstPath);
|
return dstPath;
|
||||||
}
|
}();
|
||||||
|
|
||||||
context.insert(dstPath);
|
context.insert(store->printStorePath(dstPath));
|
||||||
return dstPath;
|
return dstPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -379,7 +379,7 @@ public:
|
||||||
bool canonicalizePath = true,
|
bool canonicalizePath = true,
|
||||||
std::string_view errorCtx = "");
|
std::string_view errorCtx = "");
|
||||||
|
|
||||||
std::string copyPathToStore(PathSet & context, const Path & path);
|
StorePath copyPathToStore(PathSet & context, const Path & path);
|
||||||
|
|
||||||
/* Path coercion. Converts strings, paths and derivations to a
|
/* Path coercion. Converts strings, paths and derivations to a
|
||||||
path. The result is guaranteed to be a canonicalised, absolute
|
path. The result is guaranteed to be a canonicalised, absolute
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "value-to-json.hh"
|
#include "value-to-json.hh"
|
||||||
#include "eval-inline.hh"
|
#include "eval-inline.hh"
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
|
#include "store-api.hh"
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
@ -35,7 +36,7 @@ json printValueAsJSON(EvalState & state, bool strict,
|
||||||
|
|
||||||
case nPath:
|
case nPath:
|
||||||
if (copyToStore)
|
if (copyToStore)
|
||||||
out = state.copyPathToStore(context, v.path);
|
out = state.store->printStorePath(state.copyPathToStore(context, v.path));
|
||||||
else
|
else
|
||||||
out = v.path;
|
out = v.path;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -19,12 +19,11 @@ struct InstallableDerivedPath : Installable
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string what() const override { return derivedPath.to_string(*store); }
|
std::string what() const override { return derivedPath.to_string(*store); }
|
||||||
|
|
||||||
DerivedPaths toDerivedPaths() override
|
DerivedPathsWithInfo toDerivedPaths() override
|
||||||
{
|
{
|
||||||
return {derivedPath};
|
return {{derivedPath}};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<StorePath> getStorePath() override
|
std::optional<StorePath> getStorePath() override
|
||||||
|
|
|
@ -94,13 +94,15 @@ struct CmdBuild : InstallablesCommand, MixDryRun, MixJSON, MixProfile
|
||||||
if (dryRun) {
|
if (dryRun) {
|
||||||
std::vector<DerivedPath> pathsToBuild;
|
std::vector<DerivedPath> pathsToBuild;
|
||||||
|
|
||||||
for (auto & i : installables) {
|
for (auto & i : installables)
|
||||||
auto b = i->toDerivedPaths();
|
for (auto & b : i->toDerivedPaths())
|
||||||
pathsToBuild.insert(pathsToBuild.end(), b.begin(), b.end());
|
pathsToBuild.push_back(b.path);
|
||||||
}
|
|
||||||
printMissing(store, pathsToBuild, lvlError);
|
printMissing(store, pathsToBuild, lvlError);
|
||||||
|
|
||||||
if (json)
|
if (json)
|
||||||
logger->cout("%s", derivedPathsToJSON(pathsToBuild, store).dump());
|
logger->cout("%s", derivedPathsToJSON(pathsToBuild, store).dump());
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ struct CmdLog : InstallableCommand
|
||||||
[&](const DerivedPath::Built & bfd) {
|
[&](const DerivedPath::Built & bfd) {
|
||||||
return logSub.getBuildLog(bfd.drvPath);
|
return logSub.getBuildLog(bfd.drvPath);
|
||||||
},
|
},
|
||||||
}, b.raw());
|
}, b.path.raw());
|
||||||
if (!log) continue;
|
if (!log) continue;
|
||||||
stopProgressBar();
|
stopProgressBar();
|
||||||
printInfo("got build log for '%s' from '%s'", installable->what(), logSub.getUri());
|
printInfo("got build log for '%s' from '%s'", installable->what(), logSub.getUri());
|
||||||
|
|
|
@ -32,12 +32,14 @@ struct ProfileElementSource
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const int defaultPriority = 5;
|
||||||
|
|
||||||
struct ProfileElement
|
struct ProfileElement
|
||||||
{
|
{
|
||||||
StorePathSet storePaths;
|
StorePathSet storePaths;
|
||||||
std::optional<ProfileElementSource> source;
|
std::optional<ProfileElementSource> source;
|
||||||
bool active = true;
|
bool active = true;
|
||||||
int priority = 5;
|
int priority = defaultPriority;
|
||||||
|
|
||||||
std::string describe() const
|
std::string describe() const
|
||||||
{
|
{
|
||||||
|
@ -251,13 +253,20 @@ struct ProfileManifest
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::map<Installable *, BuiltPaths>
|
static std::map<Installable *, std::pair<BuiltPaths, ExtraPathInfo>>
|
||||||
builtPathsPerInstallable(
|
builtPathsPerInstallable(
|
||||||
const std::vector<std::pair<std::shared_ptr<Installable>, BuiltPathWithResult>> & builtPaths)
|
const std::vector<std::pair<std::shared_ptr<Installable>, BuiltPathWithResult>> & builtPaths)
|
||||||
{
|
{
|
||||||
std::map<Installable *, BuiltPaths> res;
|
std::map<Installable *, std::pair<BuiltPaths, ExtraPathInfo>> res;
|
||||||
for (auto & [installable, builtPath] : builtPaths)
|
for (auto & [installable, builtPath] : builtPaths) {
|
||||||
res[installable.get()].push_back(builtPath.path);
|
auto & r = res[installable.get()];
|
||||||
|
/* Note that there could be conflicting info
|
||||||
|
(e.g. meta.priority fields) if the installable returned
|
||||||
|
multiple derivations. So pick one arbitrarily. FIXME:
|
||||||
|
print a warning? */
|
||||||
|
r.first.push_back(builtPath.path);
|
||||||
|
r.second = builtPath.info;
|
||||||
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,28 +306,25 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
|
||||||
for (auto & installable : installables) {
|
for (auto & installable : installables) {
|
||||||
ProfileElement element;
|
ProfileElement element;
|
||||||
|
|
||||||
|
auto & [res, info] = builtPaths[installable.get()];
|
||||||
|
|
||||||
|
if (info.originalRef && info.resolvedRef && info.attrPath && info.outputsSpec) {
|
||||||
if (auto installable2 = std::dynamic_pointer_cast<InstallableFlake>(installable)) {
|
|
||||||
// FIXME: make build() return this?
|
|
||||||
auto [attrPath, resolvedRef, drv] = installable2->toDerivation();
|
|
||||||
element.source = ProfileElementSource {
|
element.source = ProfileElementSource {
|
||||||
installable2->flakeRef,
|
.originalRef = *info.originalRef,
|
||||||
resolvedRef,
|
.resolvedRef = *info.resolvedRef,
|
||||||
attrPath,
|
.attrPath = *info.attrPath,
|
||||||
installable2->outputsSpec
|
.outputs = *info.outputsSpec,
|
||||||
};
|
};
|
||||||
|
|
||||||
if(drv.priority) {
|
|
||||||
element.priority = *drv.priority;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(priority) { // if --priority was specified we want to override the priority of the installable
|
// If --priority was specified we want to override the
|
||||||
element.priority = *priority;
|
// priority of the installable.
|
||||||
};
|
element.priority =
|
||||||
|
priority
|
||||||
|
? *priority
|
||||||
|
: info.priority.value_or(defaultPriority);
|
||||||
|
|
||||||
element.updateStorePaths(getEvalStore(), store, builtPaths[installable.get()]);
|
element.updateStorePaths(getEvalStore(), store, res);
|
||||||
|
|
||||||
manifest.elements.push_back(std::move(element));
|
manifest.elements.push_back(std::move(element));
|
||||||
}
|
}
|
||||||
|
@ -476,18 +482,22 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf
|
||||||
Strings{},
|
Strings{},
|
||||||
lockFlags);
|
lockFlags);
|
||||||
|
|
||||||
auto [attrPath, resolvedRef, drv] = installable->toDerivation();
|
auto derivedPaths = installable->toDerivedPaths();
|
||||||
|
if (derivedPaths.empty()) continue;
|
||||||
|
auto & info = derivedPaths[0].info;
|
||||||
|
|
||||||
if (element.source->resolvedRef == resolvedRef) continue;
|
assert(info.resolvedRef && info.attrPath);
|
||||||
|
|
||||||
|
if (element.source->resolvedRef == info.resolvedRef) continue;
|
||||||
|
|
||||||
printInfo("upgrading '%s' from flake '%s' to '%s'",
|
printInfo("upgrading '%s' from flake '%s' to '%s'",
|
||||||
element.source->attrPath, element.source->resolvedRef, resolvedRef);
|
element.source->attrPath, element.source->resolvedRef, *info.resolvedRef);
|
||||||
|
|
||||||
element.source = ProfileElementSource {
|
element.source = ProfileElementSource {
|
||||||
installable->flakeRef,
|
.originalRef = installable->flakeRef,
|
||||||
resolvedRef,
|
.resolvedRef = *info.resolvedRef,
|
||||||
attrPath,
|
.attrPath = *info.attrPath,
|
||||||
installable->outputsSpec
|
.outputs = installable->outputsSpec,
|
||||||
};
|
};
|
||||||
|
|
||||||
installables.push_back(installable);
|
installables.push_back(installable);
|
||||||
|
@ -515,7 +525,7 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf
|
||||||
for (size_t i = 0; i < installables.size(); ++i) {
|
for (size_t i = 0; i < installables.size(); ++i) {
|
||||||
auto & installable = installables.at(i);
|
auto & installable = installables.at(i);
|
||||||
auto & element = manifest.elements[indices.at(i)];
|
auto & element = manifest.elements[indices.at(i)];
|
||||||
element.updateStorePaths(getEvalStore(), store, builtPaths[installable.get()]);
|
element.updateStorePaths(getEvalStore(), store, builtPaths[installable.get()].first);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateProfile(manifest.build(store));
|
updateProfile(manifest.build(store));
|
||||||
|
|
|
@ -33,13 +33,7 @@ struct CmdCopyLog : virtual CopyCommand, virtual InstallablesCommand
|
||||||
auto dstStore = getDstStore();
|
auto dstStore = getDstStore();
|
||||||
auto & dstLogStore = require<LogStore>(*dstStore);
|
auto & dstLogStore = require<LogStore>(*dstStore);
|
||||||
|
|
||||||
StorePathSet drvPaths;
|
for (auto & drvPath : Installable::toDerivations(getEvalStore(), installables, true)) {
|
||||||
|
|
||||||
for (auto & i : installables)
|
|
||||||
for (auto & drvPath : i->toDrvPaths(getEvalStore()))
|
|
||||||
drvPaths.insert(drvPath);
|
|
||||||
|
|
||||||
for (auto & drvPath : drvPaths) {
|
|
||||||
if (auto log = srcLogStore.getBuildLog(drvPath))
|
if (auto log = srcLogStore.getBuildLog(drvPath))
|
||||||
dstLogStore.addBuildLog(drvPath, *log);
|
dstLogStore.addBuildLog(drvPath, *log);
|
||||||
else
|
else
|
||||||
|
|
66
tests/flakes/build-paths.sh
Normal file
66
tests/flakes/build-paths.sh
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
source ./common.sh
|
||||||
|
|
||||||
|
flake1Dir=$TEST_ROOT/flake1
|
||||||
|
flake2Dir=$TEST_ROOT/flake2
|
||||||
|
|
||||||
|
mkdir -p $flake1Dir $flake2Dir
|
||||||
|
|
||||||
|
writeSimpleFlake $flake2Dir
|
||||||
|
tar cfz $TEST_ROOT/flake.tar.gz -C $TEST_ROOT flake2
|
||||||
|
hash=$(nix hash path $flake2Dir)
|
||||||
|
|
||||||
|
dep=$(nix store add-path ./common.sh)
|
||||||
|
|
||||||
|
cat > $flake1Dir/flake.nix <<EOF
|
||||||
|
{
|
||||||
|
inputs.flake2.url = "file://$TEST_ROOT/flake.tar.gz";
|
||||||
|
|
||||||
|
outputs = { self, flake2 }: {
|
||||||
|
|
||||||
|
a1 = builtins.fetchTarball {
|
||||||
|
#type = "tarball";
|
||||||
|
url = "file://$TEST_ROOT/flake.tar.gz";
|
||||||
|
sha256 = "$hash";
|
||||||
|
};
|
||||||
|
|
||||||
|
a2 = ./foo;
|
||||||
|
|
||||||
|
a3 = ./.;
|
||||||
|
|
||||||
|
a4 = self.outPath;
|
||||||
|
|
||||||
|
# FIXME
|
||||||
|
a5 = self;
|
||||||
|
|
||||||
|
a6 = flake2.outPath;
|
||||||
|
|
||||||
|
# FIXME
|
||||||
|
a7 = "${flake2}/config.nix";
|
||||||
|
|
||||||
|
# This is only allowed in impure mode.
|
||||||
|
a8 = builtins.storePath $dep;
|
||||||
|
|
||||||
|
a9 = "$dep";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo bar > $flake1Dir/foo
|
||||||
|
|
||||||
|
nix build --json --out-link $TEST_ROOT/result $flake1Dir#a1
|
||||||
|
[[ -e $TEST_ROOT/result/simple.nix ]]
|
||||||
|
|
||||||
|
nix build --json --out-link $TEST_ROOT/result $flake1Dir#a2
|
||||||
|
[[ $(cat $TEST_ROOT/result) = bar ]]
|
||||||
|
|
||||||
|
nix build --json --out-link $TEST_ROOT/result $flake1Dir#a3
|
||||||
|
|
||||||
|
nix build --json --out-link $TEST_ROOT/result $flake1Dir#a4
|
||||||
|
|
||||||
|
nix build --json --out-link $TEST_ROOT/result $flake1Dir#a6
|
||||||
|
[[ -e $TEST_ROOT/result/simple.nix ]]
|
||||||
|
|
||||||
|
nix build --impure --json --out-link $TEST_ROOT/result $flake1Dir#a8
|
||||||
|
diff common.sh $TEST_ROOT/result
|
||||||
|
|
||||||
|
(! nix build --impure --json --out-link $TEST_ROOT/result $flake1Dir#a9)
|
|
@ -9,6 +9,7 @@ nix_tests = \
|
||||||
flakes/check.sh \
|
flakes/check.sh \
|
||||||
flakes/unlocked-override.sh \
|
flakes/unlocked-override.sh \
|
||||||
flakes/absolute-paths.sh \
|
flakes/absolute-paths.sh \
|
||||||
|
flakes/build-paths.sh \
|
||||||
ca/gc.sh \
|
ca/gc.sh \
|
||||||
gc.sh \
|
gc.sh \
|
||||||
remote-store.sh \
|
remote-store.sh \
|
||||||
|
|
Loading…
Reference in a new issue