mirror of
https://github.com/privatevoid-net/nix-super.git
synced 2024-11-10 08:16:15 +02:00
slim down parser.y
most EvalState and Expr members defined here could be elsewhere, where they'd be easier to maintain (not being embedded in a file with arcane syntax) and *somewhat* more faithfully placed according to the path of the file they're defined in.
This commit is contained in:
parent
835a6c7bcf
commit
e1aa585964
3 changed files with 166 additions and 176 deletions
|
@ -20,6 +20,8 @@
|
||||||
#include "gc-small-vector.hh"
|
#include "gc-small-vector.hh"
|
||||||
#include "url.hh"
|
#include "url.hh"
|
||||||
#include "fetch-to-store.hh"
|
#include "fetch-to-store.hh"
|
||||||
|
#include "tarball.hh"
|
||||||
|
#include "flake/flakeref.hh"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
@ -2636,6 +2638,168 @@ void EvalState::printStatistics()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SourcePath resolveExprPath(SourcePath path)
|
||||||
|
{
|
||||||
|
unsigned int followCount = 0, maxFollow = 1024;
|
||||||
|
|
||||||
|
/* If `path' is a symlink, follow it. This is so that relative
|
||||||
|
path references work. */
|
||||||
|
while (!path.path.isRoot()) {
|
||||||
|
// Basic cycle/depth limit to avoid infinite loops.
|
||||||
|
if (++followCount >= maxFollow)
|
||||||
|
throw Error("too many symbolic links encountered while traversing the path '%s'", path);
|
||||||
|
auto p = path.parent().resolveSymlinks() + path.baseName();
|
||||||
|
if (p.lstat().type != InputAccessor::tSymlink) break;
|
||||||
|
path = {path.accessor, CanonPath(p.readLink(), path.path.parent().value_or(CanonPath::root))};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If `path' refers to a directory, append `/default.nix'. */
|
||||||
|
if (path.resolveSymlinks().lstat().type == InputAccessor::tDirectory)
|
||||||
|
return path + "default.nix";
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Expr * EvalState::parseExprFromFile(const SourcePath & path)
|
||||||
|
{
|
||||||
|
return parseExprFromFile(path, staticBaseEnv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Expr * EvalState::parseExprFromFile(const SourcePath & path, std::shared_ptr<StaticEnv> & staticEnv)
|
||||||
|
{
|
||||||
|
auto buffer = path.resolveSymlinks().readFile();
|
||||||
|
// readFile hopefully have left some extra space for terminators
|
||||||
|
buffer.append("\0\0", 2);
|
||||||
|
return parse(buffer.data(), buffer.size(), Pos::Origin(path), path.parent(), staticEnv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Expr * EvalState::parseExprFromString(std::string s_, const SourcePath & basePath, std::shared_ptr<StaticEnv> & staticEnv)
|
||||||
|
{
|
||||||
|
auto s = make_ref<std::string>(std::move(s_));
|
||||||
|
s->append("\0\0", 2);
|
||||||
|
return parse(s->data(), s->size(), Pos::String{.source = s}, basePath, staticEnv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Expr * EvalState::parseExprFromString(std::string s, const SourcePath & basePath)
|
||||||
|
{
|
||||||
|
return parseExprFromString(std::move(s), basePath, staticBaseEnv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Expr * EvalState::parseStdin()
|
||||||
|
{
|
||||||
|
//Activity act(*logger, lvlTalkative, "parsing standard input");
|
||||||
|
auto buffer = drainFD(0);
|
||||||
|
// drainFD should have left some extra space for terminators
|
||||||
|
buffer.append("\0\0", 2);
|
||||||
|
auto s = make_ref<std::string>(std::move(buffer));
|
||||||
|
return parse(s->data(), s->size(), Pos::Stdin{.source = s}, rootPath(CanonPath::fromCwd()), staticBaseEnv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SourcePath EvalState::findFile(const std::string_view path)
|
||||||
|
{
|
||||||
|
return findFile(searchPath, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SourcePath EvalState::findFile(const SearchPath & searchPath, const std::string_view path, const PosIdx pos)
|
||||||
|
{
|
||||||
|
for (auto & i : searchPath.elements) {
|
||||||
|
auto suffixOpt = i.prefix.suffixIfPotentialMatch(path);
|
||||||
|
|
||||||
|
if (!suffixOpt) continue;
|
||||||
|
auto suffix = *suffixOpt;
|
||||||
|
|
||||||
|
auto rOpt = resolveSearchPathPath(i.path);
|
||||||
|
if (!rOpt) continue;
|
||||||
|
auto r = *rOpt;
|
||||||
|
|
||||||
|
Path res = suffix == "" ? r : concatStrings(r, "/", suffix);
|
||||||
|
if (pathExists(res)) return rootPath(CanonPath(canonPath(res)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasPrefix(path, "nix/"))
|
||||||
|
return {corepkgsFS, CanonPath(path.substr(3))};
|
||||||
|
|
||||||
|
debugThrow(ThrownError({
|
||||||
|
.msg = hintfmt(evalSettings.pureEval
|
||||||
|
? "cannot look up '<%s>' in pure evaluation mode (use '--impure' to override)"
|
||||||
|
: "file '%s' was not found in the Nix search path (add it using $NIX_PATH or -I)",
|
||||||
|
path),
|
||||||
|
.errPos = positions[pos]
|
||||||
|
}), 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::optional<std::string> EvalState::resolveSearchPathPath(const SearchPath::Path & value0, bool initAccessControl)
|
||||||
|
{
|
||||||
|
auto & value = value0.s;
|
||||||
|
auto i = searchPathResolved.find(value);
|
||||||
|
if (i != searchPathResolved.end()) return i->second;
|
||||||
|
|
||||||
|
std::optional<std::string> res;
|
||||||
|
|
||||||
|
if (EvalSettings::isPseudoUrl(value)) {
|
||||||
|
try {
|
||||||
|
auto storePath = fetchers::downloadTarball(
|
||||||
|
store, EvalSettings::resolvePseudoUrl(value), "source", false).storePath;
|
||||||
|
res = { store->toRealPath(storePath) };
|
||||||
|
} catch (FileTransferError & e) {
|
||||||
|
logWarning({
|
||||||
|
.msg = hintfmt("Nix search path entry '%1%' cannot be downloaded, ignoring", value)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (hasPrefix(value, "flake:")) {
|
||||||
|
experimentalFeatureSettings.require(Xp::Flakes);
|
||||||
|
auto flakeRef = parseFlakeRef(value.substr(6), {}, true, false);
|
||||||
|
debug("fetching flake search path element '%s''", value);
|
||||||
|
auto storePath = flakeRef.resolve(store).fetchTree(store).first;
|
||||||
|
res = { store->toRealPath(storePath) };
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
auto path = absPath(value);
|
||||||
|
|
||||||
|
/* Allow access to paths in the search path. */
|
||||||
|
if (initAccessControl) {
|
||||||
|
allowPath(path);
|
||||||
|
if (store->isInStore(path)) {
|
||||||
|
try {
|
||||||
|
StorePathSet closure;
|
||||||
|
store->computeFSClosure(store->toStorePath(path).first, closure);
|
||||||
|
for (auto & p : closure)
|
||||||
|
allowPath(p);
|
||||||
|
} catch (InvalidPath &) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pathExists(path))
|
||||||
|
res = { path };
|
||||||
|
else {
|
||||||
|
logWarning({
|
||||||
|
.msg = hintfmt("Nix search path entry '%1%' does not exist, ignoring", value)
|
||||||
|
});
|
||||||
|
res = std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res)
|
||||||
|
debug("resolved search path element '%s' to '%s'", value, *res);
|
||||||
|
else
|
||||||
|
debug("failed to resolve search path element '%s'", value);
|
||||||
|
|
||||||
|
searchPathResolved.emplace(value, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string ExternalValueBase::coerceToString(const Pos & pos, NixStringContext & context, bool copyMore, bool copyToStore) const
|
std::string ExternalValueBase::coerceToString(const Pos & pos, NixStringContext & context, bool copyMore, bool copyToStore) const
|
||||||
{
|
{
|
||||||
throw TypeError({
|
throw TypeError({
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
unsigned long Expr::nrExprs = 0;
|
||||||
|
|
||||||
ExprBlackHole eBlackHole;
|
ExprBlackHole eBlackHole;
|
||||||
|
|
||||||
// FIXME: remove, because *symbols* are abstract and do not have a single
|
// FIXME: remove, because *symbols* are abstract and do not have a single
|
||||||
|
|
|
@ -389,25 +389,11 @@ formal
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "eval.hh"
|
#include "eval.hh"
|
||||||
#include "filetransfer.hh"
|
|
||||||
#include "tarball.hh"
|
|
||||||
#include "store-api.hh"
|
|
||||||
#include "flake/flake.hh"
|
|
||||||
#include "fs-input-accessor.hh"
|
|
||||||
#include "memory-input-accessor.hh"
|
|
||||||
|
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
unsigned long Expr::nrExprs = 0;
|
|
||||||
|
|
||||||
Expr * EvalState::parse(
|
Expr * EvalState::parse(
|
||||||
char * text,
|
char * text,
|
||||||
size_t length,
|
size_t length,
|
||||||
|
@ -435,166 +421,4 @@ Expr * EvalState::parse(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SourcePath resolveExprPath(SourcePath path)
|
|
||||||
{
|
|
||||||
unsigned int followCount = 0, maxFollow = 1024;
|
|
||||||
|
|
||||||
/* If `path' is a symlink, follow it. This is so that relative
|
|
||||||
path references work. */
|
|
||||||
while (!path.path.isRoot()) {
|
|
||||||
// Basic cycle/depth limit to avoid infinite loops.
|
|
||||||
if (++followCount >= maxFollow)
|
|
||||||
throw Error("too many symbolic links encountered while traversing the path '%s'", path);
|
|
||||||
auto p = path.parent().resolveSymlinks() + path.baseName();
|
|
||||||
if (p.lstat().type != InputAccessor::tSymlink) break;
|
|
||||||
path = {path.accessor, CanonPath(p.readLink(), path.path.parent().value_or(CanonPath::root))};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If `path' refers to a directory, append `/default.nix'. */
|
|
||||||
if (path.resolveSymlinks().lstat().type == InputAccessor::tDirectory)
|
|
||||||
return path + "default.nix";
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Expr * EvalState::parseExprFromFile(const SourcePath & path)
|
|
||||||
{
|
|
||||||
return parseExprFromFile(path, staticBaseEnv);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Expr * EvalState::parseExprFromFile(const SourcePath & path, std::shared_ptr<StaticEnv> & staticEnv)
|
|
||||||
{
|
|
||||||
auto buffer = path.resolveSymlinks().readFile();
|
|
||||||
// readFile hopefully have left some extra space for terminators
|
|
||||||
buffer.append("\0\0", 2);
|
|
||||||
return parse(buffer.data(), buffer.size(), Pos::Origin(path), path.parent(), staticEnv);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Expr * EvalState::parseExprFromString(std::string s_, const SourcePath & basePath, std::shared_ptr<StaticEnv> & staticEnv)
|
|
||||||
{
|
|
||||||
auto s = make_ref<std::string>(std::move(s_));
|
|
||||||
s->append("\0\0", 2);
|
|
||||||
return parse(s->data(), s->size(), Pos::String{.source = s}, basePath, staticEnv);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Expr * EvalState::parseExprFromString(std::string s, const SourcePath & basePath)
|
|
||||||
{
|
|
||||||
return parseExprFromString(std::move(s), basePath, staticBaseEnv);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Expr * EvalState::parseStdin()
|
|
||||||
{
|
|
||||||
//Activity act(*logger, lvlTalkative, "parsing standard input");
|
|
||||||
auto buffer = drainFD(0);
|
|
||||||
// drainFD should have left some extra space for terminators
|
|
||||||
buffer.append("\0\0", 2);
|
|
||||||
auto s = make_ref<std::string>(std::move(buffer));
|
|
||||||
return parse(s->data(), s->size(), Pos::Stdin{.source = s}, rootPath(CanonPath::fromCwd()), staticBaseEnv);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
SourcePath EvalState::findFile(const std::string_view path)
|
|
||||||
{
|
|
||||||
return findFile(searchPath, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
SourcePath EvalState::findFile(const SearchPath & searchPath, const std::string_view path, const PosIdx pos)
|
|
||||||
{
|
|
||||||
for (auto & i : searchPath.elements) {
|
|
||||||
auto suffixOpt = i.prefix.suffixIfPotentialMatch(path);
|
|
||||||
|
|
||||||
if (!suffixOpt) continue;
|
|
||||||
auto suffix = *suffixOpt;
|
|
||||||
|
|
||||||
auto rOpt = resolveSearchPathPath(i.path);
|
|
||||||
if (!rOpt) continue;
|
|
||||||
auto r = *rOpt;
|
|
||||||
|
|
||||||
Path res = suffix == "" ? r : concatStrings(r, "/", suffix);
|
|
||||||
if (pathExists(res)) return rootPath(CanonPath(canonPath(res)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasPrefix(path, "nix/"))
|
|
||||||
return {corepkgsFS, CanonPath(path.substr(3))};
|
|
||||||
|
|
||||||
debugThrow(ThrownError({
|
|
||||||
.msg = hintfmt(evalSettings.pureEval
|
|
||||||
? "cannot look up '<%s>' in pure evaluation mode (use '--impure' to override)"
|
|
||||||
: "file '%s' was not found in the Nix search path (add it using $NIX_PATH or -I)",
|
|
||||||
path),
|
|
||||||
.errPos = positions[pos]
|
|
||||||
}), 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::optional<std::string> EvalState::resolveSearchPathPath(const SearchPath::Path & value0, bool initAccessControl)
|
|
||||||
{
|
|
||||||
auto & value = value0.s;
|
|
||||||
auto i = searchPathResolved.find(value);
|
|
||||||
if (i != searchPathResolved.end()) return i->second;
|
|
||||||
|
|
||||||
std::optional<std::string> res;
|
|
||||||
|
|
||||||
if (EvalSettings::isPseudoUrl(value)) {
|
|
||||||
try {
|
|
||||||
auto storePath = fetchers::downloadTarball(
|
|
||||||
store, EvalSettings::resolvePseudoUrl(value), "source", false).storePath;
|
|
||||||
res = { store->toRealPath(storePath) };
|
|
||||||
} catch (FileTransferError & e) {
|
|
||||||
logWarning({
|
|
||||||
.msg = hintfmt("Nix search path entry '%1%' cannot be downloaded, ignoring", value)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (hasPrefix(value, "flake:")) {
|
|
||||||
experimentalFeatureSettings.require(Xp::Flakes);
|
|
||||||
auto flakeRef = parseFlakeRef(value.substr(6), {}, true, false);
|
|
||||||
debug("fetching flake search path element '%s''", value);
|
|
||||||
auto storePath = flakeRef.resolve(store).fetchTree(store).first;
|
|
||||||
res = { store->toRealPath(storePath) };
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
auto path = absPath(value);
|
|
||||||
|
|
||||||
/* Allow access to paths in the search path. */
|
|
||||||
if (initAccessControl) {
|
|
||||||
allowPath(path);
|
|
||||||
if (store->isInStore(path)) {
|
|
||||||
try {
|
|
||||||
StorePathSet closure;
|
|
||||||
store->computeFSClosure(store->toStorePath(path).first, closure);
|
|
||||||
for (auto & p : closure)
|
|
||||||
allowPath(p);
|
|
||||||
} catch (InvalidPath &) { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pathExists(path))
|
|
||||||
res = { path };
|
|
||||||
else {
|
|
||||||
logWarning({
|
|
||||||
.msg = hintfmt("Nix search path entry '%1%' does not exist, ignoring", value)
|
|
||||||
});
|
|
||||||
res = std::nullopt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res)
|
|
||||||
debug("resolved search path element '%s' to '%s'", value, *res);
|
|
||||||
else
|
|
||||||
debug("failed to resolve search path element '%s'", value);
|
|
||||||
|
|
||||||
searchPathResolved.emplace(value, res);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue