forked from lix-project/lix
libexpr: extract eval path handling into new type
Change-Id: Icf38113076a4dd0f8515a27b501f405033aec73b
This commit is contained in:
parent
a65e9e5828
commit
32f7a93f71
15 changed files with 183 additions and 161 deletions
|
@ -252,7 +252,7 @@ static void main_nix_build(std::string programName, Strings argv)
|
||||||
else
|
else
|
||||||
/* If we're in a #! script, interpret filenames
|
/* If we're in a #! script, interpret filenames
|
||||||
relative to the script. */
|
relative to the script. */
|
||||||
exprs.push_back(state->parseExprFromFile(resolveExprPath(state->checkSourcePath(lookupFileArg(*state,
|
exprs.push_back(state->parseExprFromFile(resolveExprPath(state->paths.checkSourcePath(lookupFileArg(*state,
|
||||||
inShebang && !packages ? absPath(i, absPath(dirOf(script))) : i)))));
|
inShebang && !packages ? absPath(i, absPath(dirOf(script))) : i)))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,7 +166,7 @@ static int main_nix_instantiate(std::string programName, Strings argv)
|
||||||
|
|
||||||
if (findFile) {
|
if (findFile) {
|
||||||
for (auto & i : files) {
|
for (auto & i : files) {
|
||||||
auto p = state->findFile(i);
|
auto p = state->paths.findFile(i);
|
||||||
if (auto fn = p.getPhysicalPath())
|
if (auto fn = p.getPhysicalPath())
|
||||||
std::cout << fn->abs() << std::endl;
|
std::cout << fn->abs() << std::endl;
|
||||||
else
|
else
|
||||||
|
@ -185,7 +185,7 @@ static int main_nix_instantiate(std::string programName, Strings argv)
|
||||||
for (auto & i : files) {
|
for (auto & i : files) {
|
||||||
Expr & e = fromArgs
|
Expr & e = fromArgs
|
||||||
? state->parseExprFromString(i, CanonPath::fromCwd())
|
? state->parseExprFromString(i, CanonPath::fromCwd())
|
||||||
: state->parseExprFromFile(resolveExprPath(state->checkSourcePath(lookupFileArg(*state, i))));
|
: state->parseExprFromFile(resolveExprPath(state->paths.checkSourcePath(lookupFileArg(*state, i))));
|
||||||
processExpr(*state, attrPaths, parseOnly, strict, autoArgs,
|
processExpr(*state, attrPaths, parseOnly, strict, autoArgs,
|
||||||
evalOnly, outputKind, xmlOutputSourceLocation, e);
|
evalOnly, outputKind, xmlOutputSourceLocation, e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,7 +104,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
||||||
/* Construct a Nix expression that calls the user environment
|
/* Construct a Nix expression that calls the user environment
|
||||||
builder with the manifest as argument. */
|
builder with the manifest as argument. */
|
||||||
auto attrs = state.buildBindings(3);
|
auto attrs = state.buildBindings(3);
|
||||||
state.mkStorePathString(manifestFile, attrs.alloc("manifest"));
|
state.paths.mkStorePathString(manifestFile, attrs.alloc("manifest"));
|
||||||
attrs.insert(state.symbols.create("derivations"), &manifest);
|
attrs.insert(state.symbols.create("derivations"), &manifest);
|
||||||
Value args;
|
Value args;
|
||||||
args.mkAttrs(attrs);
|
args.mkAttrs(attrs);
|
||||||
|
|
|
@ -162,8 +162,8 @@ ProfileManifest::ProfileManifest(EvalState & state, const Path & profile)
|
||||||
}
|
}
|
||||||
} else if (pathExists(profile + "/manifest.nix")) {
|
} else if (pathExists(profile + "/manifest.nix")) {
|
||||||
// FIXME: needed because of pure mode; ugly.
|
// FIXME: needed because of pure mode; ugly.
|
||||||
state.allowPath(state.store->followLinksToStore(profile));
|
state.paths.allowPath(state.store->followLinksToStore(profile));
|
||||||
state.allowPath(state.store->followLinksToStore(profile + "/manifest.nix"));
|
state.paths.allowPath(state.store->followLinksToStore(profile + "/manifest.nix"));
|
||||||
|
|
||||||
auto drvInfos = queryInstalled(state, state.store->followLinksToStore(profile));
|
auto drvInfos = queryInstalled(state, state.store->followLinksToStore(profile));
|
||||||
|
|
||||||
|
|
|
@ -205,7 +205,7 @@ SourcePath lookupFileArg(EvalState & state, std::string_view fileArg)
|
||||||
return CanonPath(state.store->toRealPath(storePath));
|
return CanonPath(state.store->toRealPath(storePath));
|
||||||
} else if (fileArg.size() > 2 && fileArg.at(0) == '<' && fileArg.at(fileArg.size() - 1) == '>') {
|
} else if (fileArg.size() > 2 && fileArg.at(0) == '<' && fileArg.at(fileArg.size() - 1) == '>') {
|
||||||
Path p(fileArg.substr(1, fileArg.size() - 2));
|
Path p(fileArg.substr(1, fileArg.size() - 2));
|
||||||
return state.findFile(p);
|
return state.paths.findFile(p);
|
||||||
} else {
|
} else {
|
||||||
return CanonPath::fromCwd(fileArg);
|
return CanonPath::fromCwd(fileArg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -215,7 +215,7 @@ void SourceExprCommand::completeInstallable(AddCompletions & completions, std::s
|
||||||
evalSettings.pureEval.override(false);
|
evalSettings.pureEval.override(false);
|
||||||
auto state = getEvalState();
|
auto state = getEvalState();
|
||||||
Expr & e = state->parseExprFromFile(
|
Expr & e = state->parseExprFromFile(
|
||||||
resolveExprPath(state->checkSourcePath(lookupFileArg(*state, *file)))
|
resolveExprPath(state->paths.checkSourcePath(lookupFileArg(*state, *file)))
|
||||||
);
|
);
|
||||||
|
|
||||||
Value root;
|
Value root;
|
||||||
|
|
|
@ -271,44 +271,21 @@ EvalBuiltins::EvalBuiltins(
|
||||||
createBaseEnv(searchPath, storeDir);
|
createBaseEnv(searchPath, storeDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
EvalState::EvalState(
|
EvalPaths::EvalPaths(
|
||||||
const SearchPath & _searchPath,
|
const ref<Store> & store,
|
||||||
ref<Store> store,
|
const ref<Store> buildStore,
|
||||||
std::shared_ptr<Store> buildStore,
|
SearchPath searchPath,
|
||||||
std::function<ReplExitStatus(EvalState & es, ValMap const & extraEnv)> debugRepl)
|
EvalErrorContext & errors
|
||||||
: s(symbols)
|
)
|
||||||
, searchPath([&] {
|
: store(store)
|
||||||
SearchPath searchPath;
|
, buildStore(buildStore)
|
||||||
if (!evalSettings.pureEval) {
|
, searchPath_(std::move(searchPath))
|
||||||
for (auto & i : _searchPath.elements)
|
, errors(errors)
|
||||||
searchPath.elements.emplace_back(SearchPath::Elem {i});
|
|
||||||
for (auto & i : evalSettings.nixPath.get())
|
|
||||||
searchPath.elements.emplace_back(SearchPath::Elem::parse(i));
|
|
||||||
}
|
|
||||||
return searchPath;
|
|
||||||
}())
|
|
||||||
, builtins(mem, symbols, searchPath, store->config().storeDir)
|
|
||||||
, repair(NoRepair)
|
|
||||||
, store(store)
|
|
||||||
, buildStore(buildStore ? buildStore : store)
|
|
||||||
, debug{
|
|
||||||
debugRepl ? std::make_unique<DebugState>(
|
|
||||||
positions,
|
|
||||||
symbols,
|
|
||||||
[this, debugRepl](const ValMap & extraEnv) { return debugRepl(*this, extraEnv); }
|
|
||||||
)
|
|
||||||
: nullptr
|
|
||||||
}
|
|
||||||
, errors{positions, debug.get()}
|
|
||||||
{
|
{
|
||||||
countCalls = getEnv("NIX_COUNT_CALLS").value_or("0") != "0";
|
|
||||||
|
|
||||||
static_assert(sizeof(Env) <= 16, "environment must be <= 16 bytes");
|
|
||||||
|
|
||||||
if (evalSettings.restrictEval || evalSettings.pureEval) {
|
if (evalSettings.restrictEval || evalSettings.pureEval) {
|
||||||
allowedPaths = std::optional(PathSet());
|
allowedPaths = std::optional(PathSet());
|
||||||
|
|
||||||
for (auto & i : searchPath.elements) {
|
for (auto & i : searchPath_.elements) {
|
||||||
auto r = resolveSearchPathPath(i.path);
|
auto r = resolveSearchPathPath(i.path);
|
||||||
if (!r) continue;
|
if (!r) continue;
|
||||||
|
|
||||||
|
@ -329,32 +306,66 @@ EvalState::EvalState(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EvalState::EvalState(
|
||||||
|
const SearchPath & _searchPath,
|
||||||
|
ref<Store> store,
|
||||||
|
std::shared_ptr<Store> buildStore,
|
||||||
|
std::function<ReplExitStatus(EvalState & es, ValMap const & extraEnv)> debugRepl)
|
||||||
|
: s(symbols)
|
||||||
|
, paths(store, buildStore ? ref(buildStore) : store, [&] {
|
||||||
|
SearchPath searchPath;
|
||||||
|
if (!evalSettings.pureEval) {
|
||||||
|
for (auto & i : _searchPath.elements)
|
||||||
|
searchPath.elements.emplace_back(SearchPath::Elem {i});
|
||||||
|
for (auto & i : evalSettings.nixPath.get())
|
||||||
|
searchPath.elements.emplace_back(SearchPath::Elem::parse(i));
|
||||||
|
}
|
||||||
|
return searchPath;
|
||||||
|
}(), errors)
|
||||||
|
, builtins(mem, symbols, paths.searchPath(), store->config().storeDir)
|
||||||
|
, repair(NoRepair)
|
||||||
|
, store(store)
|
||||||
|
, debug{
|
||||||
|
debugRepl ? std::make_unique<DebugState>(
|
||||||
|
positions,
|
||||||
|
symbols,
|
||||||
|
[this, debugRepl](const ValMap & extraEnv) { return debugRepl(*this, extraEnv); }
|
||||||
|
)
|
||||||
|
: nullptr
|
||||||
|
}
|
||||||
|
, errors{positions, debug.get()}
|
||||||
|
{
|
||||||
|
countCalls = getEnv("NIX_COUNT_CALLS").value_or("0") != "0";
|
||||||
|
|
||||||
|
static_assert(sizeof(Env) <= 16, "environment must be <= 16 bytes");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
EvalState::~EvalState()
|
EvalState::~EvalState()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EvalState::allowPath(const Path & path)
|
void EvalPaths::allowPath(const Path & path)
|
||||||
{
|
{
|
||||||
if (allowedPaths)
|
if (allowedPaths)
|
||||||
allowedPaths->insert(path);
|
allowedPaths->insert(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EvalState::allowPath(const StorePath & storePath)
|
void EvalPaths::allowPath(const StorePath & storePath)
|
||||||
{
|
{
|
||||||
if (allowedPaths)
|
if (allowedPaths)
|
||||||
allowedPaths->insert(store->toRealPath(storePath));
|
allowedPaths->insert(store->toRealPath(storePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EvalState::allowAndSetStorePathString(const StorePath & storePath, Value & v)
|
void EvalPaths::allowAndSetStorePathString(const StorePath & storePath, Value & v)
|
||||||
{
|
{
|
||||||
allowPath(storePath);
|
allowPath(storePath);
|
||||||
|
|
||||||
mkStorePathString(storePath, v);
|
mkStorePathString(storePath, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
SourcePath EvalState::checkSourcePath(const SourcePath & path_)
|
SourcePath EvalPaths::checkSourcePath(const SourcePath & path_)
|
||||||
{
|
{
|
||||||
if (!allowedPaths) return path_;
|
if (!allowedPaths) return path_;
|
||||||
|
|
||||||
|
@ -401,7 +412,7 @@ SourcePath EvalState::checkSourcePath(const SourcePath & path_)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EvalState::checkURI(const std::string & uri)
|
void EvalPaths::checkURI(const std::string & uri)
|
||||||
{
|
{
|
||||||
if (!evalSettings.restrictEval) return;
|
if (!evalSettings.restrictEval) return;
|
||||||
|
|
||||||
|
@ -433,7 +444,7 @@ void EvalState::checkURI(const std::string & uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Path EvalState::toRealPath(const Path & path, const NixStringContext & context)
|
Path EvalPaths::toRealPath(const Path & path, const NixStringContext & context)
|
||||||
{
|
{
|
||||||
// FIXME: check whether 'path' is in 'context'.
|
// FIXME: check whether 'path' is in 'context'.
|
||||||
return
|
return
|
||||||
|
@ -796,7 +807,7 @@ void EvalState::mkPos(Value & v, PosIdx p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EvalState::mkStorePathString(const StorePath & p, Value & v)
|
void EvalPaths::mkStorePathString(const StorePath & p, Value & v)
|
||||||
{
|
{
|
||||||
v.mkString(
|
v.mkString(
|
||||||
store->printStorePath(p),
|
store->printStorePath(p),
|
||||||
|
@ -926,7 +937,7 @@ struct CachedEvalFile
|
||||||
|
|
||||||
void EvalState::evalFile(const SourcePath & path_, Value & v)
|
void EvalState::evalFile(const SourcePath & path_, Value & v)
|
||||||
{
|
{
|
||||||
auto path = checkSourcePath(path_);
|
auto path = paths.checkSourcePath(path_);
|
||||||
|
|
||||||
if (auto i = caches.fileEval.find(path); i != caches.fileEval.end()) {
|
if (auto i = caches.fileEval.find(path); i != caches.fileEval.end()) {
|
||||||
v = i->second->result;
|
v = i->second->result;
|
||||||
|
@ -940,7 +951,7 @@ void EvalState::evalFile(const SourcePath & path_, Value & v)
|
||||||
}
|
}
|
||||||
|
|
||||||
debug("evaluating file '%1%'", resolvedPath);
|
debug("evaluating file '%1%'", resolvedPath);
|
||||||
Expr & e = parseExprFromFile(checkSourcePath(resolvedPath));
|
Expr & e = parseExprFromFile(paths.checkSourcePath(resolvedPath));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto dts = debug
|
auto dts = debug
|
||||||
|
@ -2271,7 +2282,7 @@ BackedStringView EvalState::coerceToString(
|
||||||
// slash, as in /foo/${x}.
|
// slash, as in /foo/${x}.
|
||||||
v._path
|
v._path
|
||||||
: copyToStore
|
: copyToStore
|
||||||
? store->printStorePath(copyPathToStore(context, v.path()))
|
? store->printStorePath(paths.copyPathToStore(context, v.path(), repair))
|
||||||
: std::string(v.path().path.abs());
|
: std::string(v.path().path.abs());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2340,7 +2351,7 @@ BackedStringView EvalState::coerceToString(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
StorePath EvalState::copyPathToStore(NixStringContext & context, const SourcePath & path)
|
StorePath EvalPaths::copyPathToStore(NixStringContext & context, const SourcePath & path, RepairFlag repair)
|
||||||
{
|
{
|
||||||
if (nix::isDerivation(path.path.abs()))
|
if (nix::isDerivation(path.path.abs()))
|
||||||
errors.make<EvalError>("file names are not allowed to end in '%1%'", drvExtension).debugThrow();
|
errors.make<EvalError>("file names are not allowed to end in '%1%'", drvExtension).debugThrow();
|
||||||
|
@ -2731,13 +2742,13 @@ Expr & EvalState::parseStdin()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SourcePath EvalState::findFile(const std::string_view path)
|
SourcePath EvalPaths::findFile(const std::string_view path)
|
||||||
{
|
{
|
||||||
return findFile(searchPath, path);
|
return findFile(searchPath_, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SourcePath EvalState::findFile(const SearchPath & searchPath, const std::string_view path, const PosIdx pos)
|
SourcePath EvalPaths::findFile(const SearchPath & searchPath, const std::string_view path, const PosIdx pos)
|
||||||
{
|
{
|
||||||
for (auto & i : searchPath.elements) {
|
for (auto & i : searchPath.elements) {
|
||||||
auto suffixOpt = i.prefix.suffixIfPotentialMatch(path);
|
auto suffixOpt = i.prefix.suffixIfPotentialMatch(path);
|
||||||
|
@ -2765,7 +2776,7 @@ SourcePath EvalState::findFile(const SearchPath & searchPath, const std::string_
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::optional<std::string> EvalState::resolveSearchPathPath(const SearchPath::Path & value0)
|
std::optional<std::string> EvalPaths::resolveSearchPathPath(const SearchPath::Path & value0)
|
||||||
{
|
{
|
||||||
auto & value = value0.s;
|
auto & value = value0.s;
|
||||||
auto i = searchPathResolved.find(value);
|
auto i = searchPathResolved.find(value);
|
||||||
|
|
|
@ -360,29 +360,20 @@ struct EvalErrorContext
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class EvalPaths
|
||||||
class EvalState
|
|
||||||
{
|
{
|
||||||
friend class EvalBuiltins;
|
ref<Store> store;
|
||||||
|
|
||||||
public:
|
|
||||||
SymbolTable symbols;
|
|
||||||
PosTable positions;
|
|
||||||
const StaticSymbols s;
|
|
||||||
EvalMemory mem;
|
|
||||||
EvalRuntimeCaches caches;
|
|
||||||
|
|
||||||
private:
|
|
||||||
SearchPath searchPath;
|
|
||||||
|
|
||||||
public:
|
|
||||||
EvalBuiltins builtins;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If set, force copying files to the Nix store even if they
|
* Store used to build stuff.
|
||||||
* already exist there.
|
|
||||||
*/
|
*/
|
||||||
RepairFlag repair;
|
ref<Store> buildStore;
|
||||||
|
SearchPath searchPath_;
|
||||||
|
EvalErrorContext & errors;
|
||||||
|
|
||||||
|
public:
|
||||||
|
EvalPaths(const ref<Store> & store, const ref<Store> buildStore, SearchPath searchPath, EvalErrorContext & errors);
|
||||||
|
|
||||||
|
const SearchPath & searchPath() const { return searchPath_; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The allowed filesystem paths in restricted or pure evaluation
|
* The allowed filesystem paths in restricted or pure evaluation
|
||||||
|
@ -390,19 +381,6 @@ public:
|
||||||
*/
|
*/
|
||||||
std::optional<PathSet> allowedPaths;
|
std::optional<PathSet> allowedPaths;
|
||||||
|
|
||||||
/**
|
|
||||||
* Store used to materialise .drv files.
|
|
||||||
*/
|
|
||||||
const ref<Store> store;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store used to build stuff.
|
|
||||||
*/
|
|
||||||
const ref<Store> buildStore;
|
|
||||||
|
|
||||||
std::unique_ptr<DebugState> debug;
|
|
||||||
EvalErrorContext errors;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/* Cache for calls to addToStore(); maps source paths to the store
|
/* Cache for calls to addToStore(); maps source paths to the store
|
||||||
|
@ -417,15 +395,6 @@ private:
|
||||||
std::unordered_map<Path, SourcePath> resolvedPaths;
|
std::unordered_map<Path, SourcePath> resolvedPaths;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
EvalState(
|
|
||||||
const SearchPath & _searchPath,
|
|
||||||
ref<Store> store,
|
|
||||||
std::shared_ptr<Store> buildStore = nullptr,
|
|
||||||
std::function<ReplExitStatus(EvalState & es, ValMap const & extraEnv)> debugRepl = nullptr
|
|
||||||
);
|
|
||||||
~EvalState();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allow access to a path.
|
* Allow access to a path.
|
||||||
*/
|
*/
|
||||||
|
@ -461,6 +430,78 @@ public:
|
||||||
*/
|
*/
|
||||||
Path toRealPath(const Path & path, const NixStringContext & context);
|
Path toRealPath(const Path & path, const NixStringContext & context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Look up a file in the search path.
|
||||||
|
*/
|
||||||
|
SourcePath findFile(const std::string_view path);
|
||||||
|
SourcePath findFile(const SearchPath & searchPath, const std::string_view path, const PosIdx pos = noPos);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to resolve a search path value (not the optinal key part)
|
||||||
|
*
|
||||||
|
* If the specified search path element is a URI, download it.
|
||||||
|
*
|
||||||
|
* If it is not found, return `std::nullopt`
|
||||||
|
*/
|
||||||
|
std::optional<std::string> resolveSearchPathPath(const SearchPath::Path & path);
|
||||||
|
|
||||||
|
StorePath copyPathToStore(
|
||||||
|
NixStringContext & context, const SourcePath & path, RepairFlag repair = NoRepair
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a string representing a store path.
|
||||||
|
*
|
||||||
|
* The string is the printed store path with a context containing a
|
||||||
|
* single `NixStringContextElem::Opaque` element of that store path.
|
||||||
|
*/
|
||||||
|
void mkStorePathString(const StorePath & storePath, Value & v);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Realise the given context, and return a mapping from the placeholders
|
||||||
|
* used to construct the associated value to their final store path
|
||||||
|
*/
|
||||||
|
[[nodiscard]] StringMap realiseContext(const NixStringContext & context);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class EvalState
|
||||||
|
{
|
||||||
|
friend class EvalBuiltins;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SymbolTable symbols;
|
||||||
|
PosTable positions;
|
||||||
|
const StaticSymbols s;
|
||||||
|
EvalMemory mem;
|
||||||
|
EvalRuntimeCaches caches;
|
||||||
|
EvalPaths paths;
|
||||||
|
EvalBuiltins builtins;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set, force copying files to the Nix store even if they
|
||||||
|
* already exist there.
|
||||||
|
*/
|
||||||
|
RepairFlag repair;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store used to materialise .drv files.
|
||||||
|
*/
|
||||||
|
const ref<Store> store;
|
||||||
|
|
||||||
|
std::unique_ptr<DebugState> debug;
|
||||||
|
EvalErrorContext errors;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
EvalState(
|
||||||
|
const SearchPath & _searchPath,
|
||||||
|
ref<Store> store,
|
||||||
|
std::shared_ptr<Store> buildStore = nullptr,
|
||||||
|
std::function<ReplExitStatus(EvalState & es, ValMap const & extraEnv)> debugRepl = nullptr
|
||||||
|
);
|
||||||
|
~EvalState();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a Nix expression from the specified file.
|
* Parse a Nix expression from the specified file.
|
||||||
*/
|
*/
|
||||||
|
@ -491,21 +532,6 @@ public:
|
||||||
|
|
||||||
void resetFileCache();
|
void resetFileCache();
|
||||||
|
|
||||||
/**
|
|
||||||
* Look up a file in the search path.
|
|
||||||
*/
|
|
||||||
SourcePath findFile(const std::string_view path);
|
|
||||||
SourcePath findFile(const SearchPath & searchPath, const std::string_view path, const PosIdx pos = noPos);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Try to resolve a search path value (not the optinal key part)
|
|
||||||
*
|
|
||||||
* If the specified search path element is a URI, download it.
|
|
||||||
*
|
|
||||||
* If it is not found, return `std::nullopt`
|
|
||||||
*/
|
|
||||||
std::optional<std::string> resolveSearchPathPath(const SearchPath::Path & path);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluate an expression to normal form
|
* Evaluate an expression to normal form
|
||||||
*
|
*
|
||||||
|
@ -577,8 +603,6 @@ public:
|
||||||
bool coerceMore = false, bool copyToStore = true,
|
bool coerceMore = false, bool copyToStore = true,
|
||||||
bool canonicalizePath = true);
|
bool canonicalizePath = true);
|
||||||
|
|
||||||
StorePath copyPathToStore(NixStringContext & context, const SourcePath & path);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Path coercion.
|
* Path coercion.
|
||||||
*
|
*
|
||||||
|
@ -669,14 +693,6 @@ public:
|
||||||
void mkThunk_(Value & v, Expr & expr);
|
void mkThunk_(Value & v, Expr & expr);
|
||||||
void mkPos(Value & v, PosIdx pos);
|
void mkPos(Value & v, PosIdx pos);
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a string representing a store path.
|
|
||||||
*
|
|
||||||
* The string is the printed store path with a context containing a
|
|
||||||
* single `NixStringContextElem::Opaque` element of that store path.
|
|
||||||
*/
|
|
||||||
void mkStorePathString(const StorePath & storePath, Value & v);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a string representing a `SingleDerivedPath::Built`.
|
* Create a string representing a `SingleDerivedPath::Built`.
|
||||||
*
|
*
|
||||||
|
@ -735,12 +751,6 @@ public:
|
||||||
*/
|
*/
|
||||||
bool fullGC();
|
bool fullGC();
|
||||||
|
|
||||||
/**
|
|
||||||
* Realise the given context, and return a mapping from the placeholders
|
|
||||||
* used to construct the associated value to their final store path
|
|
||||||
*/
|
|
||||||
[[nodiscard]] StringMap realiseContext(const NixStringContext & context);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -68,7 +68,7 @@ static std::tuple<fetchers::Tree, FlakeRef, FlakeRef> fetchOrSubstituteTree(
|
||||||
debug("got tree '%s' from '%s'",
|
debug("got tree '%s' from '%s'",
|
||||||
state.store->printStorePath(tree.storePath), lockedRef);
|
state.store->printStorePath(tree.storePath), lockedRef);
|
||||||
|
|
||||||
state.allowPath(tree.storePath);
|
state.paths.allowPath(tree.storePath);
|
||||||
|
|
||||||
assert(!originalRef.input.getNarHash() || tree.storePath == originalRef.input.computeStorePath(*state.store));
|
assert(!originalRef.input.getNarHash() || tree.storePath == originalRef.input.computeStorePath(*state.store));
|
||||||
|
|
||||||
|
@ -242,8 +242,8 @@ static Flake getFlake(
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: symlink attack
|
// FIXME: symlink attack
|
||||||
auto resolvedFlakeFile = resolveExprPath(state.checkSourcePath(CanonPath(flakeFile)));
|
auto resolvedFlakeFile = resolveExprPath(state.paths.checkSourcePath(CanonPath(flakeFile)));
|
||||||
Expr & flakeExpr = state.parseExprFromFile(state.checkSourcePath(resolvedFlakeFile));
|
Expr & flakeExpr = state.parseExprFromFile(state.paths.checkSourcePath(resolvedFlakeFile));
|
||||||
|
|
||||||
// Enforce that 'flake.nix' is a direct attrset, not a computation.
|
// Enforce that 'flake.nix' is a direct attrset, not a computation.
|
||||||
if (!(dynamic_cast<ExprAttrs *>(&flakeExpr))) {
|
if (!(dynamic_cast<ExprAttrs *>(&flakeExpr))) {
|
||||||
|
|
|
@ -39,7 +39,7 @@ namespace nix {
|
||||||
* Miscellaneous
|
* Miscellaneous
|
||||||
*************************************************************/
|
*************************************************************/
|
||||||
|
|
||||||
StringMap EvalState::realiseContext(const NixStringContext & context)
|
StringMap EvalPaths::realiseContext(const NixStringContext & context)
|
||||||
{
|
{
|
||||||
std::vector<DerivedPath::Built> drvs;
|
std::vector<DerivedPath::Built> drvs;
|
||||||
StringMap res;
|
StringMap res;
|
||||||
|
@ -129,12 +129,12 @@ static SourcePath realisePath(EvalState & state, const PosIdx pos, Value & v, co
|
||||||
auto path = state.coerceToPath(noPos, v, context, "while realising the context of a path");
|
auto path = state.coerceToPath(noPos, v, context, "while realising the context of a path");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
StringMap rewrites = state.realiseContext(context);
|
StringMap rewrites = state.paths.realiseContext(context);
|
||||||
|
|
||||||
auto realPath = CanonPath(state.toRealPath(rewriteStrings(path.path.abs(), rewrites), context));
|
auto realPath = CanonPath(state.paths.toRealPath(rewriteStrings(path.path.abs(), rewrites), context));
|
||||||
|
|
||||||
return flags.checkForPureEval
|
return flags.checkForPureEval
|
||||||
? state.checkSourcePath(realPath)
|
? state.paths.checkSourcePath(realPath)
|
||||||
: realPath;
|
: realPath;
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
e.addTrace(state.positions[pos], "while realising the context of path '%s'", path);
|
e.addTrace(state.positions[pos], "while realising the context of path '%s'", path);
|
||||||
|
@ -323,7 +323,7 @@ void prim_exec(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||||
false, false).toOwned());
|
false, false).toOwned());
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
auto _ = state.realiseContext(context); // FIXME: Handle CA derivations
|
auto _ = state.paths.realiseContext(context); // FIXME: Handle CA derivations
|
||||||
} catch (InvalidPathError & e) {
|
} catch (InvalidPathError & e) {
|
||||||
e.addTrace(state.positions[pos], "while realising the context for builtins.exec");
|
e.addTrace(state.positions[pos], "while realising the context for builtins.exec");
|
||||||
throw;
|
throw;
|
||||||
|
@ -1173,7 +1173,7 @@ static void prim_storePath(EvalState & state, const PosIdx pos, Value * * args,
|
||||||
).atPos(pos).debugThrow();
|
).atPos(pos).debugThrow();
|
||||||
|
|
||||||
NixStringContext context;
|
NixStringContext context;
|
||||||
auto path = state.checkSourcePath(state.coerceToPath(pos, *args[0], context, "while evaluating the first argument passed to builtins.storePath")).path;
|
auto path = state.paths.checkSourcePath(state.coerceToPath(pos, *args[0], context, "while evaluating the first argument passed to builtins.storePath")).path;
|
||||||
/* Resolve symlinks in ‘path’, unless ‘path’ itself is a symlink
|
/* Resolve symlinks in ‘path’, unless ‘path’ itself is a symlink
|
||||||
directly in the store. The latter condition is necessary so
|
directly in the store. The latter condition is necessary so
|
||||||
e.g. nix-push does the right thing. */
|
e.g. nix-push does the right thing. */
|
||||||
|
@ -1207,6 +1207,7 @@ static void prim_pathExists(EvalState & state, const PosIdx pos, Value * * args,
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto checked = state
|
auto checked = state
|
||||||
|
.paths
|
||||||
.checkSourcePath(path)
|
.checkSourcePath(path)
|
||||||
.resolveSymlinks(mustBeDir ? SymlinkResolution::Full : SymlinkResolution::Ancestors);
|
.resolveSymlinks(mustBeDir ? SymlinkResolution::Full : SymlinkResolution::Ancestors);
|
||||||
|
|
||||||
|
@ -1305,7 +1306,7 @@ static void prim_findFile(EvalState & state, const PosIdx pos, Value * * args, V
|
||||||
false, false).toOwned();
|
false, false).toOwned();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto rewrites = state.realiseContext(context);
|
auto rewrites = state.paths.realiseContext(context);
|
||||||
path = rewriteStrings(path, rewrites);
|
path = rewriteStrings(path, rewrites);
|
||||||
} catch (InvalidPathError & e) {
|
} catch (InvalidPathError & e) {
|
||||||
state.errors.make<EvalError>(
|
state.errors.make<EvalError>(
|
||||||
|
@ -1323,7 +1324,7 @@ static void prim_findFile(EvalState & state, const PosIdx pos, Value * * args, V
|
||||||
|
|
||||||
auto path = state.forceStringNoCtx(*args[1], pos, "while evaluating the second argument passed to builtins.findFile");
|
auto path = state.forceStringNoCtx(*args[1], pos, "while evaluating the second argument passed to builtins.findFile");
|
||||||
|
|
||||||
v.mkPath(state.checkSourcePath(state.findFile(searchPath, path, pos)));
|
v.mkPath(state.paths.checkSourcePath(state.paths.findFile(searchPath, path, pos)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the cryptographic hash of a file in base-16. */
|
/* Return the cryptographic hash of a file in base-16. */
|
||||||
|
@ -1478,7 +1479,7 @@ static void prim_toFile(EvalState & state, const PosIdx pos, Value * * args, Val
|
||||||
used in args[1]. */
|
used in args[1]. */
|
||||||
|
|
||||||
/* Add the output of this to the allowed paths. */
|
/* Add the output of this to the allowed paths. */
|
||||||
state.allowAndSetStorePathString(storePath, v);
|
state.paths.allowAndSetStorePathString(storePath, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addPath(
|
static void addPath(
|
||||||
|
@ -1495,8 +1496,8 @@ static void addPath(
|
||||||
try {
|
try {
|
||||||
// FIXME: handle CA derivation outputs (where path needs to
|
// FIXME: handle CA derivation outputs (where path needs to
|
||||||
// be rewritten to the actual output).
|
// be rewritten to the actual output).
|
||||||
auto rewrites = state.realiseContext(context);
|
auto rewrites = state.paths.realiseContext(context);
|
||||||
path = state.toRealPath(rewriteStrings(path, rewrites), context);
|
path = state.paths.toRealPath(rewriteStrings(path, rewrites), context);
|
||||||
|
|
||||||
StorePathSet refs;
|
StorePathSet refs;
|
||||||
|
|
||||||
|
@ -1512,7 +1513,7 @@ static void addPath(
|
||||||
|
|
||||||
path = evalSettings.pureEval && expectedHash
|
path = evalSettings.pureEval && expectedHash
|
||||||
? path
|
? path
|
||||||
: state.checkSourcePath(CanonPath(path)).path.abs();
|
: state.paths.checkSourcePath(CanonPath(path)).path.abs();
|
||||||
|
|
||||||
PathFilter filter = filterFun ? ([&](const Path & path) {
|
PathFilter filter = filterFun ? ([&](const Path & path) {
|
||||||
auto st = lstat(path);
|
auto st = lstat(path);
|
||||||
|
@ -1552,9 +1553,9 @@ static void addPath(
|
||||||
"store path mismatch in (possibly filtered) path added from '%s'",
|
"store path mismatch in (possibly filtered) path added from '%s'",
|
||||||
path
|
path
|
||||||
).atPos(pos).debugThrow();
|
).atPos(pos).debugThrow();
|
||||||
state.allowAndSetStorePathString(dstPath, v);
|
state.paths.allowAndSetStorePathString(dstPath, v);
|
||||||
} else
|
} else
|
||||||
state.allowAndSetStorePathString(*expectedStorePath, v);
|
state.paths.allowAndSetStorePathString(*expectedStorePath, v);
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
e.addTrace(state.positions[pos], "while adding path '%s'", path);
|
e.addTrace(state.positions[pos], "while adding path '%s'", path);
|
||||||
throw;
|
throw;
|
||||||
|
|
|
@ -58,7 +58,7 @@ static void runFetchClosureWithRewrite(EvalState & state, const PosIdx pos, Stor
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
state.mkStorePathString(toPath, v);
|
state.paths.mkStorePathString(toPath, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -84,7 +84,7 @@ static void runFetchClosureWithContentAddressedPath(EvalState & state, const Pos
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
state.mkStorePathString(fromPath, v);
|
state.paths.mkStorePathString(fromPath, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -107,7 +107,7 @@ static void runFetchClosureWithInputAddressedPath(EvalState & state, const PosId
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
state.mkStorePathString(fromPath, v);
|
state.paths.mkStorePathString(fromPath, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef std::optional<StorePath> StorePathOrGap;
|
typedef std::optional<StorePath> StorePathOrGap;
|
||||||
|
|
|
@ -51,7 +51,7 @@ static void prim_fetchMercurial(EvalState & state, const PosIdx pos, Value * * a
|
||||||
|
|
||||||
// FIXME: git externals probably can be used to bypass the URI
|
// FIXME: git externals probably can be used to bypass the URI
|
||||||
// whitelist. Ah well.
|
// whitelist. Ah well.
|
||||||
state.checkURI(url);
|
state.paths.checkURI(url);
|
||||||
|
|
||||||
if (evalSettings.pureEval && !rev)
|
if (evalSettings.pureEval && !rev)
|
||||||
throw Error("in pure evaluation mode, 'fetchMercurial' requires a Mercurial revision");
|
throw Error("in pure evaluation mode, 'fetchMercurial' requires a Mercurial revision");
|
||||||
|
@ -68,7 +68,7 @@ static void prim_fetchMercurial(EvalState & state, const PosIdx pos, Value * * a
|
||||||
auto [tree, input2] = input.fetch(state.store);
|
auto [tree, input2] = input.fetch(state.store);
|
||||||
|
|
||||||
auto attrs2 = state.buildBindings(8);
|
auto attrs2 = state.buildBindings(8);
|
||||||
state.mkStorePathString(tree.storePath, attrs2.alloc(state.s.outPath));
|
state.paths.mkStorePathString(tree.storePath, attrs2.alloc(state.s.outPath));
|
||||||
if (input2.getRef())
|
if (input2.getRef())
|
||||||
attrs2.alloc("branch").mkString(*input2.getRef());
|
attrs2.alloc("branch").mkString(*input2.getRef());
|
||||||
// Backward compatibility: set 'rev' to
|
// Backward compatibility: set 'rev' to
|
||||||
|
@ -80,7 +80,7 @@ static void prim_fetchMercurial(EvalState & state, const PosIdx pos, Value * * a
|
||||||
attrs2.alloc("revCount").mkInt(*revCount);
|
attrs2.alloc("revCount").mkInt(*revCount);
|
||||||
v.mkAttrs(attrs2);
|
v.mkAttrs(attrs2);
|
||||||
|
|
||||||
state.allowPath(tree.storePath);
|
state.paths.allowPath(tree.storePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp r_fetchMercurial({
|
static RegisterPrimOp r_fetchMercurial({
|
||||||
|
|
|
@ -27,7 +27,7 @@ void emitTreeAttrs(
|
||||||
auto attrs = state.buildBindings(10);
|
auto attrs = state.buildBindings(10);
|
||||||
|
|
||||||
|
|
||||||
state.mkStorePathString(tree.storePath, attrs.alloc(state.s.outPath));
|
state.paths.mkStorePathString(tree.storePath, attrs.alloc(state.s.outPath));
|
||||||
|
|
||||||
// FIXME: support arbitrary input attributes.
|
// FIXME: support arbitrary input attributes.
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ void emitTreeAttrs(
|
||||||
|
|
||||||
std::string fixURI(std::string uri, EvalState & state, const std::string & defaultScheme = "file")
|
std::string fixURI(std::string uri, EvalState & state, const std::string & defaultScheme = "file")
|
||||||
{
|
{
|
||||||
state.checkURI(uri);
|
state.paths.checkURI(uri);
|
||||||
if (uri.find("://") == std::string::npos) {
|
if (uri.find("://") == std::string::npos) {
|
||||||
const auto p = ParsedURL {
|
const auto p = ParsedURL {
|
||||||
.scheme = defaultScheme,
|
.scheme = defaultScheme,
|
||||||
|
@ -194,7 +194,7 @@ static void fetchTree(
|
||||||
|
|
||||||
auto [tree, input2] = input.fetch(state.store);
|
auto [tree, input2] = input.fetch(state.store);
|
||||||
|
|
||||||
state.allowPath(tree.storePath);
|
state.paths.allowPath(tree.storePath);
|
||||||
|
|
||||||
emitTreeAttrs(state, tree, input2, v, params.emptyRevFallback, false);
|
emitTreeAttrs(state, tree, input2, v, params.emptyRevFallback, false);
|
||||||
}
|
}
|
||||||
|
@ -244,7 +244,7 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v
|
||||||
if (who == "fetchTarball")
|
if (who == "fetchTarball")
|
||||||
url = evalSettings.resolvePseudoUrl(*url);
|
url = evalSettings.resolvePseudoUrl(*url);
|
||||||
|
|
||||||
state.checkURI(*url);
|
state.paths.checkURI(*url);
|
||||||
|
|
||||||
if (name == "")
|
if (name == "")
|
||||||
name = baseNameOf(*url);
|
name = baseNameOf(*url);
|
||||||
|
@ -263,7 +263,7 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v
|
||||||
});
|
});
|
||||||
|
|
||||||
if (state.store->isValidPath(expectedPath)) {
|
if (state.store->isValidPath(expectedPath)) {
|
||||||
state.allowAndSetStorePathString(expectedPath, v);
|
state.paths.allowAndSetStorePathString(expectedPath, v);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -290,7 +290,7 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
state.allowAndSetStorePathString(storePath, v);
|
state.paths.allowAndSetStorePathString(storePath, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
void prim_fetchurl(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
void prim_fetchurl(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||||
|
|
|
@ -37,7 +37,7 @@ json printValueAsJSON(EvalState & state, bool strict,
|
||||||
case nPath:
|
case nPath:
|
||||||
if (copyToStore)
|
if (copyToStore)
|
||||||
out = state.store->printStorePath(
|
out = state.store->printStorePath(
|
||||||
state.copyPathToStore(context, v.path()));
|
state.paths.copyPathToStore(context, v.path(), state.repair));
|
||||||
else
|
else
|
||||||
out = v.path().path.abs();
|
out = v.path().path.abs();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -26,7 +26,7 @@ RC_GTEST_FIXTURE_PROP(
|
||||||
(const SingleDerivedPath::Opaque & o))
|
(const SingleDerivedPath::Opaque & o))
|
||||||
{
|
{
|
||||||
auto * v = state.mem.allocValue();
|
auto * v = state.mem.allocValue();
|
||||||
state.mkStorePathString(o.path, *v);
|
state.paths.mkStorePathString(o.path, *v);
|
||||||
auto d = state.coerceToSingleDerivedPath(noPos, *v, "");
|
auto d = state.coerceToSingleDerivedPath(noPos, *v, "");
|
||||||
RC_ASSERT(SingleDerivedPath { o } == d);
|
RC_ASSERT(SingleDerivedPath { o } == d);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue