Nix/src/libcmd/installable-attr-path.cc

123 lines
3.4 KiB
C++
Raw Normal View History

#include "globals.hh"
#include "installable-attr-path.hh"
#include "outputs-spec.hh"
#include "util.hh"
#include "command.hh"
#include "attr-path.hh"
#include "common-eval-args.hh"
#include "derivations.hh"
#include "eval-inline.hh"
#include "eval.hh"
#include "get-drvs.hh"
#include "store-api.hh"
#include "shared.hh"
#include "flake/flake.hh"
#include "eval-cache.hh"
#include "url.hh"
#include "registry.hh"
#include "build-result.hh"
#include <regex>
#include <queue>
#include <nlohmann/json.hpp>
namespace nix {
InstallableAttrPath::InstallableAttrPath(
ref<EvalState> state,
SourceExprCommand & cmd,
Value * v,
const std::string & attrPath,
ExtendedOutputsSpec extendedOutputsSpec)
: InstallableValue(state)
, cmd(cmd)
, v(allocRootValue(v))
, attrPath(attrPath)
, extendedOutputsSpec(std::move(extendedOutputsSpec))
{ }
std::pair<Value *, PosIdx> InstallableAttrPath::toValue(EvalState & state)
{
auto [vRes, pos] = findAlongAttrPath(state, attrPath, *cmd.getAutoArgs(state), **v);
state.forceValue(*vRes, pos);
return {vRes, pos};
}
DerivedPathsWithInfo InstallableAttrPath::toDerivedPaths()
{
Make more string values work as installables As discussed in #7417, it would be good to make more string values work as installables. That is to say, if an installable refers to a value, and the value is a string, it used to not work at all, since #7484, it works somewhat, and this PR make it work some more. The new cases that are added for `BuiltPath` contexts: - Fixed input- or content-addressed derivation: ``` nix-repl> hello.out.outPath "/nix/store/jppfl2bp1zhx8sgs2mgifmsx6dv16mv2-hello-2.12" nix-repl> :p builtins.getContext hello.out.outPath { "/nix/store/c7jrxqjhdda93lhbkanqfs07x2bzazbm-hello-2.12.drv" = { outputs = [ "out" ]; }; } The string matches the specified single output of that derivation, so it should also be valid. - Floating content-addressed derivation: ``` nix-repl> (hello.overrideAttrs (_: { __contentAddressed = true; })).out.outPath "/1a08j26xqc0zm8agps8anxpjji410yvsx4pcgyn4bfan1ddkx2g0" nix-repl> :p builtins.getContext (hello.overrideAttrs (_: { __contentAddressed = true; })).out.outPath { "/nix/store/qc645pyf9wl37c6qvqzaqkwsm1gp48al-hello-2.12.drv" = { outputs = [ "out" ]; }; } ``` The string is not a path but a placeholder, however it also matches the context, and because it is a CA derivation we have no better option. This should also be valid. We may also want to think about richer attrset based values (also discussed in that issue and #6507), but this change "completes" our string-based building blocks, from which the others can be desugared into or at least described/document/taught in terms of. Progress towards #7417 Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
2023-01-10 23:18:59 +01:00
auto [v, pos] = toValue(*state);
if (std::optional derivedPathWithInfo = trySinglePathToDerivedPaths(
*v,
pos,
fmt("while evaluating the attribute '%s'", attrPath)))
{
return { *derivedPathWithInfo };
}
Bindings & autoArgs = *cmd.getAutoArgs(*state);
PackageInfos packageInfos;
getDerivations(*state, *v, "", autoArgs, packageInfos, false);
// Backward compatibility hack: group results by drvPath. This
// helps keep .all output together.
std::map<StorePath, OutputsSpec> byDrvPath;
for (auto & packageInfo : packageInfos) {
auto drvPath = packageInfo.queryDrvPath();
if (!drvPath)
throw Error("'%s' is not a derivation", what());
auto newOutputs = std::visit(overloaded {
[&](const ExtendedOutputsSpec::Default & d) -> OutputsSpec {
std::set<std::string> outputsToInstall;
for (auto & output : packageInfo.queryOutputs(false, true))
outputsToInstall.insert(output.first);
return OutputsSpec::Names { std::move(outputsToInstall) };
},
[&](const ExtendedOutputsSpec::Explicit & e) -> OutputsSpec {
return e;
},
}, extendedOutputsSpec.raw);
auto [iter, didInsert] = byDrvPath.emplace(*drvPath, newOutputs);
if (!didInsert)
iter->second = iter->second.union_(newOutputs);
}
DerivedPathsWithInfo res;
for (auto & [drvPath, outputs] : byDrvPath)
res.push_back({
.path = DerivedPath::Built {
.drvPath = makeConstantStorePathRef(drvPath),
.outputs = outputs,
},
.info = make_ref<ExtraPathInfoValue>(ExtraPathInfoValue::Value {
.extendedOutputsSpec = outputs,
/* FIXME: reconsider backwards compatibility above
so we can fill in this info. */
}),
});
return res;
}
InstallableAttrPath InstallableAttrPath::parse(
ref<EvalState> state,
SourceExprCommand & cmd,
Value * v,
std::string_view prefix,
ExtendedOutputsSpec extendedOutputsSpec)
{
return {
state, cmd, v,
prefix == "." ? "" : std::string { prefix },
std::move(extendedOutputsSpec),
};
}
}