Merge branch 'more-stringviews' of https://github.com/pennae/nix
This commit is contained in:
commit
cd35bbbeef
|
@ -121,7 +121,7 @@ Pos findPackageFilename(EvalState & state, Value & v, std::string what)
|
||||||
std::string filename(pos, 0, colon);
|
std::string filename(pos, 0, colon);
|
||||||
unsigned int lineno;
|
unsigned int lineno;
|
||||||
try {
|
try {
|
||||||
lineno = std::stoi(std::string(pos, colon + 1));
|
lineno = std::stoi(std::string(pos, colon + 1, string::npos));
|
||||||
} catch (std::invalid_argument & e) {
|
} catch (std::invalid_argument & e) {
|
||||||
throw ParseError("cannot parse line number '%s'", pos);
|
throw ParseError("cannot parse line number '%s'", pos);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "eval.hh"
|
#include "eval.hh"
|
||||||
#include "hash.hh"
|
#include "hash.hh"
|
||||||
|
#include "types.hh"
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
#include "derivations.hh"
|
#include "derivations.hh"
|
||||||
|
@ -1694,7 +1695,7 @@ void EvalState::concatLists(Value & v, size_t nrLists, Value * * lists, const Po
|
||||||
void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
PathSet context;
|
PathSet context;
|
||||||
std::vector<std::string> s;
|
std::vector<BackedStringView> s;
|
||||||
size_t sSize = 0;
|
size_t sSize = 0;
|
||||||
NixInt n = 0;
|
NixInt n = 0;
|
||||||
NixFloat nf = 0;
|
NixFloat nf = 0;
|
||||||
|
@ -1705,7 +1706,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
||||||
const auto str = [&] {
|
const auto str = [&] {
|
||||||
std::string result;
|
std::string result;
|
||||||
result.reserve(sSize);
|
result.reserve(sSize);
|
||||||
for (const auto & part : s) result += part;
|
for (const auto & part : s) result += *part;
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
/* c_str() is not str().c_str() because we want to create a string
|
/* c_str() is not str().c_str() because we want to create a string
|
||||||
|
@ -1715,15 +1716,18 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
||||||
char * result = allocString(sSize + 1);
|
char * result = allocString(sSize + 1);
|
||||||
char * tmp = result;
|
char * tmp = result;
|
||||||
for (const auto & part : s) {
|
for (const auto & part : s) {
|
||||||
memcpy(tmp, part.c_str(), part.size());
|
memcpy(tmp, part->data(), part->size());
|
||||||
tmp += part.size();
|
tmp += part->size();
|
||||||
}
|
}
|
||||||
*tmp = 0;
|
*tmp = 0;
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Value values[es->size()];
|
||||||
|
Value * vTmpP = values;
|
||||||
|
|
||||||
for (auto & [i_pos, i] : *es) {
|
for (auto & [i_pos, i] : *es) {
|
||||||
Value vTmp;
|
Value & vTmp = *vTmpP++;
|
||||||
i->eval(state, env, vTmp);
|
i->eval(state, env, vTmp);
|
||||||
|
|
||||||
/* If the first element is a path, then the result will also
|
/* If the first element is a path, then the result will also
|
||||||
|
@ -1756,9 +1760,9 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
||||||
/* skip canonization of first path, which would only be not
|
/* skip canonization of first path, which would only be not
|
||||||
canonized in the first place if it's coming from a ./${foo} type
|
canonized in the first place if it's coming from a ./${foo} type
|
||||||
path */
|
path */
|
||||||
s.emplace_back(
|
auto part = state.coerceToString(i_pos, vTmp, context, false, firstType == nString, !first);
|
||||||
state.coerceToString(i_pos, vTmp, context, false, firstType == nString, !first));
|
sSize += part->size();
|
||||||
sSize += s.back().size();
|
s.emplace_back(std::move(part));
|
||||||
}
|
}
|
||||||
|
|
||||||
first = false;
|
first = false;
|
||||||
|
@ -1857,7 +1861,7 @@ void EvalState::forceFunction(Value & v, const Pos & pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
string EvalState::forceString(Value & v, const Pos & pos)
|
std::string_view EvalState::forceString(Value & v, const Pos & pos)
|
||||||
{
|
{
|
||||||
forceValue(v, pos);
|
forceValue(v, pos);
|
||||||
if (v.type() != nString) {
|
if (v.type() != nString) {
|
||||||
|
@ -1866,7 +1870,7 @@ string EvalState::forceString(Value & v, const Pos & pos)
|
||||||
else
|
else
|
||||||
throwTypeError("value is %1% while a string was expected", v);
|
throwTypeError("value is %1% while a string was expected", v);
|
||||||
}
|
}
|
||||||
return string(v.string.s);
|
return v.string.s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1901,17 +1905,17 @@ std::vector<std::pair<Path, std::string>> Value::getContext()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
string EvalState::forceString(Value & v, PathSet & context, const Pos & pos)
|
std::string_view EvalState::forceString(Value & v, PathSet & context, const Pos & pos)
|
||||||
{
|
{
|
||||||
string s = forceString(v, pos);
|
auto s = forceString(v, pos);
|
||||||
copyContext(v, context);
|
copyContext(v, context);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
string EvalState::forceStringNoCtx(Value & v, const Pos & pos)
|
std::string_view EvalState::forceStringNoCtx(Value & v, const Pos & pos)
|
||||||
{
|
{
|
||||||
string s = forceString(v, pos);
|
auto s = forceString(v, pos);
|
||||||
if (v.string.context) {
|
if (v.string.context) {
|
||||||
if (pos)
|
if (pos)
|
||||||
throwEvalError(pos, "the string '%1%' is not allowed to refer to a store path (such as '%2%')",
|
throwEvalError(pos, "the string '%1%' is not allowed to refer to a store path (such as '%2%')",
|
||||||
|
@ -1942,34 +1946,35 @@ std::optional<string> EvalState::tryAttrsToString(const Pos & pos, Value & v,
|
||||||
if (i != v.attrs->end()) {
|
if (i != v.attrs->end()) {
|
||||||
Value v1;
|
Value v1;
|
||||||
callFunction(*i->value, v, v1, pos);
|
callFunction(*i->value, v, v1, pos);
|
||||||
return coerceToString(pos, v1, context, coerceMore, copyToStore);
|
return coerceToString(pos, v1, context, coerceMore, copyToStore).toOwned();
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
|
BackedStringView EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
|
||||||
bool coerceMore, bool copyToStore, bool canonicalizePath)
|
bool coerceMore, bool copyToStore, bool canonicalizePath)
|
||||||
{
|
{
|
||||||
forceValue(v, pos);
|
forceValue(v, pos);
|
||||||
|
|
||||||
string s;
|
|
||||||
|
|
||||||
if (v.type() == nString) {
|
if (v.type() == nString) {
|
||||||
copyContext(v, context);
|
copyContext(v, context);
|
||||||
return v.string.s;
|
return std::string_view(v.string.s);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v.type() == nPath) {
|
if (v.type() == nPath) {
|
||||||
Path path(canonicalizePath ? canonPath(v.path) : v.path);
|
BackedStringView path(PathView(v.path));
|
||||||
return copyToStore ? copyPathToStore(context, path) : path;
|
if (canonicalizePath)
|
||||||
|
path = canonPath(*path);
|
||||||
|
if (copyToStore)
|
||||||
|
path = copyPathToStore(context, std::move(path).toOwned());
|
||||||
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v.type() == nAttrs) {
|
if (v.type() == nAttrs) {
|
||||||
auto maybeString = tryAttrsToString(pos, v, context, coerceMore, copyToStore);
|
auto maybeString = tryAttrsToString(pos, v, context, coerceMore, copyToStore);
|
||||||
if (maybeString) {
|
if (maybeString)
|
||||||
return *maybeString;
|
return std::move(*maybeString);
|
||||||
}
|
|
||||||
auto i = v.attrs->find(sOutPath);
|
auto i = v.attrs->find(sOutPath);
|
||||||
if (i == v.attrs->end()) throwTypeError(pos, "cannot coerce a set to a string");
|
if (i == v.attrs->end()) throwTypeError(pos, "cannot coerce a set to a string");
|
||||||
return coerceToString(pos, *i->value, context, coerceMore, copyToStore);
|
return coerceToString(pos, *i->value, context, coerceMore, copyToStore);
|
||||||
|
@ -1991,14 +1996,13 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
|
||||||
if (v.isList()) {
|
if (v.isList()) {
|
||||||
string result;
|
string result;
|
||||||
for (auto [n, v2] : enumerate(v.listItems())) {
|
for (auto [n, v2] : enumerate(v.listItems())) {
|
||||||
result += coerceToString(pos, *v2,
|
result += *coerceToString(pos, *v2, context, coerceMore, copyToStore);
|
||||||
context, coerceMore, copyToStore);
|
|
||||||
if (n < v.listSize() - 1
|
if (n < v.listSize() - 1
|
||||||
/* !!! not quite correct */
|
/* !!! not quite correct */
|
||||||
&& (!v2->isList() || v2->listSize() != 0))
|
&& (!v2->isList() || v2->listSize() != 0))
|
||||||
result += " ";
|
result += " ";
|
||||||
}
|
}
|
||||||
return result;
|
return std::move(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2032,7 +2036,7 @@ string EvalState::copyPathToStore(PathSet & context, const Path & path)
|
||||||
|
|
||||||
Path EvalState::coerceToPath(const Pos & pos, Value & v, PathSet & context)
|
Path EvalState::coerceToPath(const Pos & pos, Value & v, PathSet & context)
|
||||||
{
|
{
|
||||||
string path = coerceToString(pos, v, context, false, false);
|
string path = coerceToString(pos, v, context, false, false).toOwned();
|
||||||
if (path == "" || path[0] != '/')
|
if (path == "" || path[0] != '/')
|
||||||
throwEvalError(pos, "string '%1%' doesn't represent an absolute path", path);
|
throwEvalError(pos, "string '%1%' doesn't represent an absolute path", path);
|
||||||
return path;
|
return path;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "attr-set.hh"
|
#include "attr-set.hh"
|
||||||
|
#include "types.hh"
|
||||||
#include "value.hh"
|
#include "value.hh"
|
||||||
#include "nixexpr.hh"
|
#include "nixexpr.hh"
|
||||||
#include "symbol-table.hh"
|
#include "symbol-table.hh"
|
||||||
|
@ -201,8 +202,8 @@ public:
|
||||||
void resetFileCache();
|
void resetFileCache();
|
||||||
|
|
||||||
/* Look up a file in the search path. */
|
/* Look up a file in the search path. */
|
||||||
Path findFile(const string & path);
|
Path findFile(const std::string_view path);
|
||||||
Path findFile(SearchPath & searchPath, const string & path, const Pos & pos = noPos);
|
Path findFile(SearchPath & searchPath, const std::string_view path, const Pos & pos = noPos);
|
||||||
|
|
||||||
/* If the specified search path element is a URI, download it. */
|
/* If the specified search path element is a URI, download it. */
|
||||||
std::pair<bool, std::string> resolveSearchPathElem(const SearchPathElem & elem);
|
std::pair<bool, std::string> resolveSearchPathElem(const SearchPathElem & elem);
|
||||||
|
@ -236,9 +237,9 @@ public:
|
||||||
inline void forceList(Value & v);
|
inline void forceList(Value & v);
|
||||||
inline void forceList(Value & v, const Pos & pos);
|
inline void forceList(Value & v, const Pos & pos);
|
||||||
void forceFunction(Value & v, const Pos & pos); // either lambda or primop
|
void forceFunction(Value & v, const Pos & pos); // either lambda or primop
|
||||||
string forceString(Value & v, const Pos & pos = noPos);
|
std::string_view forceString(Value & v, const Pos & pos = noPos);
|
||||||
string forceString(Value & v, PathSet & context, const Pos & pos = noPos);
|
std::string_view forceString(Value & v, PathSet & context, const Pos & pos = noPos);
|
||||||
string forceStringNoCtx(Value & v, const Pos & pos = noPos);
|
std::string_view forceStringNoCtx(Value & v, const Pos & pos = noPos);
|
||||||
|
|
||||||
/* Return true iff the value `v' denotes a derivation (i.e. a
|
/* Return true iff the value `v' denotes a derivation (i.e. a
|
||||||
set with attribute `type = "derivation"'). */
|
set with attribute `type = "derivation"'). */
|
||||||
|
@ -251,7 +252,7 @@ public:
|
||||||
string. If `coerceMore' is set, also converts nulls, integers,
|
string. If `coerceMore' is set, also converts nulls, integers,
|
||||||
booleans and lists to a string. If `copyToStore' is set,
|
booleans and lists to a string. If `copyToStore' is set,
|
||||||
referenced paths are copied to the Nix store as a side effect. */
|
referenced paths are copied to the Nix store as a side effect. */
|
||||||
string coerceToString(const Pos & pos, Value & v, PathSet & context,
|
BackedStringView coerceToString(const Pos & pos, Value & v, PathSet & context,
|
||||||
bool coerceMore = false, bool copyToStore = true,
|
bool coerceMore = false, bool copyToStore = true,
|
||||||
bool canonicalizePath = true);
|
bool canonicalizePath = true);
|
||||||
|
|
||||||
|
@ -309,8 +310,8 @@ private:
|
||||||
friend struct ExprAttrs;
|
friend struct ExprAttrs;
|
||||||
friend struct ExprLet;
|
friend struct ExprLet;
|
||||||
|
|
||||||
Expr * parse(char * text, size_t length, FileOrigin origin, const Path & path,
|
Expr * parse(char * text, size_t length, FileOrigin origin, const PathView path,
|
||||||
const Path & basePath, StaticEnv & staticEnv);
|
const PathView basePath, StaticEnv & staticEnv);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
|
@ -250,10 +250,12 @@ static Flake getFlake(
|
||||||
for (auto & setting : *nixConfig->value->attrs) {
|
for (auto & setting : *nixConfig->value->attrs) {
|
||||||
forceTrivialValue(state, *setting.value, *setting.pos);
|
forceTrivialValue(state, *setting.value, *setting.pos);
|
||||||
if (setting.value->type() == nString)
|
if (setting.value->type() == nString)
|
||||||
flake.config.settings.insert({setting.name, state.forceStringNoCtx(*setting.value, *setting.pos)});
|
flake.config.settings.insert({setting.name, string(state.forceStringNoCtx(*setting.value, *setting.pos))});
|
||||||
else if (setting.value->type() == nPath) {
|
else if (setting.value->type() == nPath) {
|
||||||
PathSet emptyContext = {};
|
PathSet emptyContext = {};
|
||||||
flake.config.settings.insert({setting.name, state.coerceToString(*setting.pos, *setting.value, emptyContext, false, true, true)});
|
flake.config.settings.emplace(
|
||||||
|
setting.name,
|
||||||
|
state.coerceToString(*setting.pos, *setting.value, emptyContext, false, true, true) .toOwned());
|
||||||
}
|
}
|
||||||
else if (setting.value->type() == nInt)
|
else if (setting.value->type() == nInt)
|
||||||
flake.config.settings.insert({setting.name, state.forceInt(*setting.value, *setting.pos)});
|
flake.config.settings.insert({setting.name, state.forceInt(*setting.value, *setting.pos)});
|
||||||
|
@ -265,7 +267,7 @@ static Flake getFlake(
|
||||||
if (elem->type() != nString)
|
if (elem->type() != nString)
|
||||||
throw TypeError("list element in flake configuration setting '%s' is %s while a string is expected",
|
throw TypeError("list element in flake configuration setting '%s' is %s while a string is expected",
|
||||||
setting.name, showType(*setting.value));
|
setting.name, showType(*setting.value));
|
||||||
ss.push_back(state.forceStringNoCtx(*elem, *setting.pos));
|
ss.emplace_back(state.forceStringNoCtx(*elem, *setting.pos));
|
||||||
}
|
}
|
||||||
flake.config.settings.insert({setting.name, ss});
|
flake.config.settings.insert({setting.name, ss});
|
||||||
}
|
}
|
||||||
|
@ -726,7 +728,7 @@ static void prim_getFlake(EvalState & state, const Pos & pos, Value * * args, Va
|
||||||
{
|
{
|
||||||
state.requireExperimentalFeatureOnEvaluation(Xp::Flakes, "builtins.getFlake", pos);
|
state.requireExperimentalFeatureOnEvaluation(Xp::Flakes, "builtins.getFlake", pos);
|
||||||
|
|
||||||
auto flakeRefS = state.forceStringNoCtx(*args[0], pos);
|
string flakeRefS(state.forceStringNoCtx(*args[0], pos));
|
||||||
auto flakeRef = parseFlakeRef(flakeRefS, {}, true);
|
auto flakeRef = parseFlakeRef(flakeRefS, {}, true);
|
||||||
if (evalSettings.pureEval && !flakeRef.input.isImmutable())
|
if (evalSettings.pureEval && !flakeRef.input.isImmutable())
|
||||||
throw Error("cannot call 'getFlake' on mutable flake reference '%s', at %s (use --impure to override)", flakeRefS, pos);
|
throw Error("cannot call 'getFlake' on mutable flake reference '%s', at %s (use --impure to override)", flakeRefS, pos);
|
||||||
|
|
|
@ -104,7 +104,7 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall)
|
||||||
/* For each output... */
|
/* For each output... */
|
||||||
for (auto elem : i->value->listItems()) {
|
for (auto elem : i->value->listItems()) {
|
||||||
/* Evaluate the corresponding set. */
|
/* Evaluate the corresponding set. */
|
||||||
string name = state->forceStringNoCtx(*elem, *i->pos);
|
string name(state->forceStringNoCtx(*elem, *i->pos));
|
||||||
Bindings::iterator out = attrs->find(state->symbols.create(name));
|
Bindings::iterator out = attrs->find(state->symbols.create(name));
|
||||||
if (out == attrs->end()) continue; // FIXME: throw error?
|
if (out == attrs->end()) continue; // FIXME: throw error?
|
||||||
state->forceAttrs(*out->value);
|
state->forceAttrs(*out->value);
|
||||||
|
|
|
@ -163,7 +163,7 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void parseJSON(EvalState & state, const string & s_, Value & v)
|
void parseJSON(EvalState & state, const std::string_view & s_, Value & v)
|
||||||
{
|
{
|
||||||
JSONSax parser(state, v);
|
JSONSax parser(state, v);
|
||||||
bool res = json::sax_parse(s_, &parser);
|
bool res = json::sax_parse(s_, &parser);
|
||||||
|
|
|
@ -8,6 +8,6 @@ namespace nix {
|
||||||
|
|
||||||
MakeError(JSONParseError, EvalError);
|
MakeError(JSONParseError, EvalError);
|
||||||
|
|
||||||
void parseJSON(EvalState & state, const string & s, Value & v);
|
void parseJSON(EvalState & state, const std::string_view & s, Value & v);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -598,7 +598,7 @@ namespace nix {
|
||||||
|
|
||||||
|
|
||||||
Expr * EvalState::parse(char * text, size_t length, FileOrigin origin,
|
Expr * EvalState::parse(char * text, size_t length, FileOrigin origin,
|
||||||
const Path & path, const Path & basePath, StaticEnv & staticEnv)
|
const PathView path, const PathView basePath, StaticEnv & staticEnv)
|
||||||
{
|
{
|
||||||
yyscan_t scanner;
|
yyscan_t scanner;
|
||||||
ParseData data(*this);
|
ParseData data(*this);
|
||||||
|
@ -709,24 +709,24 @@ void EvalState::addToSearchPath(const string & s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Path EvalState::findFile(const string & path)
|
Path EvalState::findFile(const std::string_view path)
|
||||||
{
|
{
|
||||||
return findFile(searchPath, path);
|
return findFile(searchPath, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Path EvalState::findFile(SearchPath & searchPath, const string & path, const Pos & pos)
|
Path EvalState::findFile(SearchPath & searchPath, const std::string_view path, const Pos & pos)
|
||||||
{
|
{
|
||||||
for (auto & i : searchPath) {
|
for (auto & i : searchPath) {
|
||||||
std::string suffix;
|
std::string suffix;
|
||||||
if (i.first.empty())
|
if (i.first.empty())
|
||||||
suffix = "/" + path;
|
suffix = concatStrings("/", path);
|
||||||
else {
|
else {
|
||||||
auto s = i.first.size();
|
auto s = i.first.size();
|
||||||
if (path.compare(0, s, i.first) != 0 ||
|
if (path.compare(0, s, i.first) != 0 ||
|
||||||
(path.size() > s && path[s] != '/'))
|
(path.size() > s && path[s] != '/'))
|
||||||
continue;
|
continue;
|
||||||
suffix = path.size() == s ? "" : "/" + string(path, s);
|
suffix = path.size() == s ? "" : concatStrings("/", path.substr(s));
|
||||||
}
|
}
|
||||||
auto r = resolveSearchPathElem(i);
|
auto r = resolveSearchPathElem(i);
|
||||||
if (!r.first) continue;
|
if (!r.first) continue;
|
||||||
|
@ -735,7 +735,7 @@ Path EvalState::findFile(SearchPath & searchPath, const string & path, const Pos
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasPrefix(path, "nix/"))
|
if (hasPrefix(path, "nix/"))
|
||||||
return corepkgsPrefix + path.substr(4);
|
return concatStrings(corepkgsPrefix, path.substr(4));
|
||||||
|
|
||||||
throw ThrownError({
|
throw ThrownError({
|
||||||
.msg = hintfmt(evalSettings.pureEval
|
.msg = hintfmt(evalSettings.pureEval
|
||||||
|
|
|
@ -314,7 +314,7 @@ void prim_importNative(EvalState & state, const Pos & pos, Value * * args, Value
|
||||||
{
|
{
|
||||||
auto path = realisePath(state, pos, *args[0]);
|
auto path = realisePath(state, pos, *args[0]);
|
||||||
|
|
||||||
string sym = state.forceStringNoCtx(*args[1], pos);
|
string sym(state.forceStringNoCtx(*args[1], pos));
|
||||||
|
|
||||||
void *handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
|
void *handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
|
||||||
if (!handle)
|
if (!handle)
|
||||||
|
@ -350,10 +350,11 @@ void prim_exec(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
PathSet context;
|
PathSet context;
|
||||||
auto program = state.coerceToString(pos, *elems[0], context, false, false);
|
auto program = state.coerceToString(pos, *elems[0], context, false, false).toOwned();
|
||||||
Strings commandArgs;
|
Strings commandArgs;
|
||||||
for (unsigned int i = 1; i < args[0]->listSize(); ++i)
|
for (unsigned int i = 1; i < args[0]->listSize(); ++i) {
|
||||||
commandArgs.emplace_back(state.coerceToString(pos, *elems[i], context, false, false));
|
commandArgs.push_back(state.coerceToString(pos, *elems[i], context, false, false).toOwned());
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
auto _ = state.realiseContext(context); // FIXME: Handle CA derivations
|
auto _ = state.realiseContext(context); // FIXME: Handle CA derivations
|
||||||
} catch (InvalidPathError & e) {
|
} catch (InvalidPathError & e) {
|
||||||
|
@ -706,7 +707,7 @@ static RegisterPrimOp primop_abort({
|
||||||
.fun = [](EvalState & state, const Pos & pos, Value * * args, Value & v)
|
.fun = [](EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
PathSet context;
|
PathSet context;
|
||||||
string s = state.coerceToString(pos, *args[0], context);
|
string s = state.coerceToString(pos, *args[0], context).toOwned();
|
||||||
throw Abort("evaluation aborted with the following error message: '%1%'", s);
|
throw Abort("evaluation aborted with the following error message: '%1%'", s);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -724,7 +725,7 @@ static RegisterPrimOp primop_throw({
|
||||||
.fun = [](EvalState & state, const Pos & pos, Value * * args, Value & v)
|
.fun = [](EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
PathSet context;
|
PathSet context;
|
||||||
string s = state.coerceToString(pos, *args[0], context);
|
string s = state.coerceToString(pos, *args[0], context).toOwned();
|
||||||
throw ThrownError(s);
|
throw ThrownError(s);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -736,7 +737,7 @@ static void prim_addErrorContext(EvalState & state, const Pos & pos, Value * * a
|
||||||
v = *args[1];
|
v = *args[1];
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
PathSet context;
|
PathSet context;
|
||||||
e.addTrace(std::nullopt, state.coerceToString(pos, *args[0], context));
|
e.addTrace(std::nullopt, state.coerceToString(pos, *args[0], context).toOwned());
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -825,7 +826,7 @@ static RegisterPrimOp primop_tryEval({
|
||||||
/* Return an environment variable. Use with care. */
|
/* Return an environment variable. Use with care. */
|
||||||
static void prim_getEnv(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_getEnv(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
string name = state.forceStringNoCtx(*args[0], pos);
|
string name(state.forceStringNoCtx(*args[0], pos));
|
||||||
v.mkString(evalSettings.restrictEval || evalSettings.pureEval ? "" : getEnv(name).value_or(""));
|
v.mkString(evalSettings.restrictEval || evalSettings.pureEval ? "" : getEnv(name).value_or(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -975,7 +976,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
|
||||||
const string & key = i->name;
|
const string & key = i->name;
|
||||||
vomit("processing attribute '%1%'", key);
|
vomit("processing attribute '%1%'", key);
|
||||||
|
|
||||||
auto handleHashMode = [&](const std::string & s) {
|
auto handleHashMode = [&](const std::string_view s) {
|
||||||
if (s == "recursive") ingestionMethod = FileIngestionMethod::Recursive;
|
if (s == "recursive") ingestionMethod = FileIngestionMethod::Recursive;
|
||||||
else if (s == "flat") ingestionMethod = FileIngestionMethod::Flat;
|
else if (s == "flat") ingestionMethod = FileIngestionMethod::Flat;
|
||||||
else
|
else
|
||||||
|
@ -1030,7 +1031,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
|
||||||
else if (i->name == state.sArgs) {
|
else if (i->name == state.sArgs) {
|
||||||
state.forceList(*i->value, pos);
|
state.forceList(*i->value, pos);
|
||||||
for (auto elem : i->value->listItems()) {
|
for (auto elem : i->value->listItems()) {
|
||||||
string s = state.coerceToString(posDrvName, *elem, context, true);
|
string s = state.coerceToString(posDrvName, *elem, context, true).toOwned();
|
||||||
drv.args.push_back(s);
|
drv.args.push_back(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1066,7 +1067,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
auto s = state.coerceToString(*i->pos, *i->value, context, true);
|
auto s = state.coerceToString(*i->pos, *i->value, context, true).toOwned();
|
||||||
drv.env.emplace(key, s);
|
drv.env.emplace(key, s);
|
||||||
if (i->name == state.sBuilder) drv.builder = std::move(s);
|
if (i->name == state.sBuilder) drv.builder = std::move(s);
|
||||||
else if (i->name == state.sSystem) drv.platform = std::move(s);
|
else if (i->name == state.sSystem) drv.platform = std::move(s);
|
||||||
|
@ -1399,7 +1400,7 @@ static RegisterPrimOp primop_pathExists({
|
||||||
static void prim_baseNameOf(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_baseNameOf(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
PathSet context;
|
PathSet context;
|
||||||
v.mkString(baseNameOf(state.coerceToString(pos, *args[0], context, false, false)), context);
|
v.mkString(baseNameOf(*state.coerceToString(pos, *args[0], context, false, false)), context);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_baseNameOf({
|
static RegisterPrimOp primop_baseNameOf({
|
||||||
|
@ -1419,7 +1420,8 @@ static RegisterPrimOp primop_baseNameOf({
|
||||||
static void prim_dirOf(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_dirOf(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
PathSet context;
|
PathSet context;
|
||||||
Path dir = dirOf(state.coerceToString(pos, *args[0], context, false, false));
|
auto path = state.coerceToString(pos, *args[0], context, false, false);
|
||||||
|
auto dir = dirOf(*path);
|
||||||
if (args[0]->type() == nPath) v.mkPath(dir); else v.mkString(dir, context);
|
if (args[0]->type() == nPath) v.mkPath(dir); else v.mkString(dir, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1486,7 +1488,7 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
|
||||||
);
|
);
|
||||||
|
|
||||||
PathSet context;
|
PathSet context;
|
||||||
string path = state.coerceToString(pos, *i->value, context, false, false);
|
string path = state.coerceToString(pos, *i->value, context, false, false).toOwned();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto rewrites = state.realiseContext(context);
|
auto rewrites = state.realiseContext(context);
|
||||||
|
@ -1502,7 +1504,7 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
|
||||||
searchPath.emplace_back(prefix, path);
|
searchPath.emplace_back(prefix, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
string path = state.forceStringNoCtx(*args[1], pos);
|
auto path = state.forceStringNoCtx(*args[1], pos);
|
||||||
|
|
||||||
v.mkPath(state.checkSourcePath(state.findFile(searchPath, path, pos)));
|
v.mkPath(state.checkSourcePath(state.findFile(searchPath, path, pos)));
|
||||||
}
|
}
|
||||||
|
@ -1516,7 +1518,7 @@ static RegisterPrimOp primop_findFile(RegisterPrimOp::Info {
|
||||||
/* Return the cryptographic hash of a file in base-16. */
|
/* Return the cryptographic hash of a file in base-16. */
|
||||||
static void prim_hashFile(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_hashFile(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
string type = state.forceStringNoCtx(*args[0], pos);
|
auto type = state.forceStringNoCtx(*args[0], pos);
|
||||||
std::optional<HashType> ht = parseHashType(type);
|
std::optional<HashType> ht = parseHashType(type);
|
||||||
if (!ht)
|
if (!ht)
|
||||||
throw Error({
|
throw Error({
|
||||||
|
@ -1723,7 +1725,7 @@ static RegisterPrimOp primop_toJSON({
|
||||||
/* Parse a JSON string to a value. */
|
/* Parse a JSON string to a value. */
|
||||||
static void prim_fromJSON(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_fromJSON(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
string s = state.forceStringNoCtx(*args[0], pos);
|
auto s = state.forceStringNoCtx(*args[0], pos);
|
||||||
try {
|
try {
|
||||||
parseJSON(state, s, v);
|
parseJSON(state, s, v);
|
||||||
} catch (JSONParseError &e) {
|
} catch (JSONParseError &e) {
|
||||||
|
@ -1752,8 +1754,8 @@ static RegisterPrimOp primop_fromJSON({
|
||||||
static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
PathSet context;
|
PathSet context;
|
||||||
string name = state.forceStringNoCtx(*args[0], pos);
|
string name(state.forceStringNoCtx(*args[0], pos));
|
||||||
string contents = state.forceString(*args[1], context, pos);
|
string contents(state.forceString(*args[1], context, pos));
|
||||||
|
|
||||||
StorePathSet refs;
|
StorePathSet refs;
|
||||||
|
|
||||||
|
@ -2153,7 +2155,7 @@ static RegisterPrimOp primop_attrValues({
|
||||||
/* Dynamic version of the `.' operator. */
|
/* Dynamic version of the `.' operator. */
|
||||||
void prim_getAttr(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
void prim_getAttr(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
string attr = state.forceStringNoCtx(*args[0], pos);
|
auto attr = state.forceStringNoCtx(*args[0], pos);
|
||||||
state.forceAttrs(*args[1], pos);
|
state.forceAttrs(*args[1], pos);
|
||||||
Bindings::iterator i = getAttr(
|
Bindings::iterator i = getAttr(
|
||||||
state,
|
state,
|
||||||
|
@ -2183,7 +2185,7 @@ static RegisterPrimOp primop_getAttr({
|
||||||
/* Return position information of the specified attribute. */
|
/* Return position information of the specified attribute. */
|
||||||
static void prim_unsafeGetAttrPos(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_unsafeGetAttrPos(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
string attr = state.forceStringNoCtx(*args[0], pos);
|
auto attr = state.forceStringNoCtx(*args[0], pos);
|
||||||
state.forceAttrs(*args[1], pos);
|
state.forceAttrs(*args[1], pos);
|
||||||
Bindings::iterator i = args[1]->attrs->find(state.symbols.create(attr));
|
Bindings::iterator i = args[1]->attrs->find(state.symbols.create(attr));
|
||||||
if (i == args[1]->attrs->end())
|
if (i == args[1]->attrs->end())
|
||||||
|
@ -2201,7 +2203,7 @@ static RegisterPrimOp primop_unsafeGetAttrPos(RegisterPrimOp::Info {
|
||||||
/* Dynamic version of the `?' operator. */
|
/* Dynamic version of the `?' operator. */
|
||||||
static void prim_hasAttr(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_hasAttr(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
string attr = state.forceStringNoCtx(*args[0], pos);
|
auto attr = state.forceStringNoCtx(*args[0], pos);
|
||||||
state.forceAttrs(*args[1], pos);
|
state.forceAttrs(*args[1], pos);
|
||||||
v.mkBool(args[1]->attrs->find(state.symbols.create(attr)) != args[1]->attrs->end());
|
v.mkBool(args[1]->attrs->find(state.symbols.create(attr)) != args[1]->attrs->end());
|
||||||
}
|
}
|
||||||
|
@ -2300,7 +2302,7 @@ static void prim_listToAttrs(EvalState & state, const Pos & pos, Value * * args,
|
||||||
pos
|
pos
|
||||||
);
|
);
|
||||||
|
|
||||||
string name = state.forceStringNoCtx(*j->value, *j->pos);
|
auto name = state.forceStringNoCtx(*j->value, *j->pos);
|
||||||
|
|
||||||
Symbol sym = state.symbols.create(name);
|
Symbol sym = state.symbols.create(name);
|
||||||
if (seen.insert(sym).second) {
|
if (seen.insert(sym).second) {
|
||||||
|
@ -3032,7 +3034,7 @@ static void prim_groupBy(EvalState & state, const Pos & pos, Value * * args, Val
|
||||||
for (auto vElem : args[1]->listItems()) {
|
for (auto vElem : args[1]->listItems()) {
|
||||||
Value res;
|
Value res;
|
||||||
state.callFunction(*args[0], *vElem, res, pos);
|
state.callFunction(*args[0], *vElem, res, pos);
|
||||||
string name = state.forceStringNoCtx(res, pos);
|
auto name = state.forceStringNoCtx(res, pos);
|
||||||
Symbol sym = state.symbols.create(name);
|
Symbol sym = state.symbols.create(name);
|
||||||
auto vector = attrs.try_emplace(sym, ValueVector()).first;
|
auto vector = attrs.try_emplace(sym, ValueVector()).first;
|
||||||
vector->second.push_back(vElem);
|
vector->second.push_back(vElem);
|
||||||
|
@ -3288,8 +3290,8 @@ static RegisterPrimOp primop_lessThan({
|
||||||
static void prim_toString(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_toString(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
PathSet context;
|
PathSet context;
|
||||||
string s = state.coerceToString(pos, *args[0], context, true, false);
|
auto s = state.coerceToString(pos, *args[0], context, true, false);
|
||||||
v.mkString(s, context);
|
v.mkString(*s, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_toString({
|
static RegisterPrimOp primop_toString({
|
||||||
|
@ -3325,7 +3327,7 @@ static void prim_substring(EvalState & state, const Pos & pos, Value * * args, V
|
||||||
int start = state.forceInt(*args[0], pos);
|
int start = state.forceInt(*args[0], pos);
|
||||||
int len = state.forceInt(*args[1], pos);
|
int len = state.forceInt(*args[1], pos);
|
||||||
PathSet context;
|
PathSet context;
|
||||||
string s = state.coerceToString(pos, *args[2], context);
|
auto s = state.coerceToString(pos, *args[2], context);
|
||||||
|
|
||||||
if (start < 0)
|
if (start < 0)
|
||||||
throw EvalError({
|
throw EvalError({
|
||||||
|
@ -3333,7 +3335,7 @@ static void prim_substring(EvalState & state, const Pos & pos, Value * * args, V
|
||||||
.errPos = pos
|
.errPos = pos
|
||||||
});
|
});
|
||||||
|
|
||||||
v.mkString((unsigned int) start >= s.size() ? "" : string(s, start, len), context);
|
v.mkString((unsigned int) start >= s->size() ? "" : s->substr(start, len), context);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_substring({
|
static RegisterPrimOp primop_substring({
|
||||||
|
@ -3359,8 +3361,8 @@ static RegisterPrimOp primop_substring({
|
||||||
static void prim_stringLength(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_stringLength(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
PathSet context;
|
PathSet context;
|
||||||
string s = state.coerceToString(pos, *args[0], context);
|
auto s = state.coerceToString(pos, *args[0], context);
|
||||||
v.mkInt(s.size());
|
v.mkInt(s->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_stringLength({
|
static RegisterPrimOp primop_stringLength({
|
||||||
|
@ -3376,7 +3378,7 @@ static RegisterPrimOp primop_stringLength({
|
||||||
/* Return the cryptographic hash of a string in base-16. */
|
/* Return the cryptographic hash of a string in base-16. */
|
||||||
static void prim_hashString(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_hashString(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
string type = state.forceStringNoCtx(*args[0], pos);
|
auto type = state.forceStringNoCtx(*args[0], pos);
|
||||||
std::optional<HashType> ht = parseHashType(type);
|
std::optional<HashType> ht = parseHashType(type);
|
||||||
if (!ht)
|
if (!ht)
|
||||||
throw Error({
|
throw Error({
|
||||||
|
@ -3385,7 +3387,7 @@ static void prim_hashString(EvalState & state, const Pos & pos, Value * * args,
|
||||||
});
|
});
|
||||||
|
|
||||||
PathSet context; // discarded
|
PathSet context; // discarded
|
||||||
string s = state.forceString(*args[1], context, pos);
|
auto s = state.forceString(*args[1], context, pos);
|
||||||
|
|
||||||
v.mkString(hashString(*ht, s).to_string(Base16, false));
|
v.mkString(hashString(*ht, s).to_string(Base16, false));
|
||||||
}
|
}
|
||||||
|
@ -3403,7 +3405,18 @@ static RegisterPrimOp primop_hashString({
|
||||||
|
|
||||||
struct RegexCache
|
struct RegexCache
|
||||||
{
|
{
|
||||||
std::unordered_map<std::string, std::regex> cache;
|
// TODO use C++20 transparent comparison when available
|
||||||
|
std::unordered_map<std::string_view, std::regex> cache;
|
||||||
|
std::list<std::string> keys;
|
||||||
|
|
||||||
|
std::regex get(std::string_view re)
|
||||||
|
{
|
||||||
|
auto it = cache.find(re);
|
||||||
|
if (it != cache.end())
|
||||||
|
return it->second;
|
||||||
|
keys.emplace_back(re);
|
||||||
|
return cache.emplace(keys.back(), std::regex(keys.back(), std::regex::extended)).first->second;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<RegexCache> makeRegexCache()
|
std::shared_ptr<RegexCache> makeRegexCache()
|
||||||
|
@ -3417,15 +3430,13 @@ void prim_match(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
auto regex = state.regexCache->cache.find(re);
|
auto regex = state.regexCache->get(re);
|
||||||
if (regex == state.regexCache->cache.end())
|
|
||||||
regex = state.regexCache->cache.emplace(re, std::regex(re, std::regex::extended)).first;
|
|
||||||
|
|
||||||
PathSet context;
|
PathSet context;
|
||||||
const std::string str = state.forceString(*args[1], context, pos);
|
const auto str = state.forceString(*args[1], context, pos);
|
||||||
|
|
||||||
std::smatch match;
|
std::cmatch match;
|
||||||
if (!std::regex_match(str, match, regex->second)) {
|
if (!std::regex_match(str.begin(), str.end(), match, regex)) {
|
||||||
v.mkNull();
|
v.mkNull();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3500,15 +3511,13 @@ void prim_split(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
auto regex = state.regexCache->cache.find(re);
|
auto regex = state.regexCache->get(re);
|
||||||
if (regex == state.regexCache->cache.end())
|
|
||||||
regex = state.regexCache->cache.emplace(re, std::regex(re, std::regex::extended)).first;
|
|
||||||
|
|
||||||
PathSet context;
|
PathSet context;
|
||||||
const std::string str = state.forceString(*args[1], context, pos);
|
const auto str = state.forceString(*args[1], context, pos);
|
||||||
|
|
||||||
auto begin = std::sregex_iterator(str.begin(), str.end(), regex->second);
|
auto begin = std::cregex_iterator(str.begin(), str.end(), regex);
|
||||||
auto end = std::sregex_iterator();
|
auto end = std::cregex_iterator();
|
||||||
|
|
||||||
// Any matches results are surrounded by non-matching results.
|
// Any matches results are surrounded by non-matching results.
|
||||||
const size_t len = std::distance(begin, end);
|
const size_t len = std::distance(begin, end);
|
||||||
|
@ -3520,9 +3529,9 @@ void prim_split(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::sregex_iterator i = begin; i != end; ++i) {
|
for (auto i = begin; i != end; ++i) {
|
||||||
assert(idx <= 2 * len + 1 - 3);
|
assert(idx <= 2 * len + 1 - 3);
|
||||||
std::smatch match = *i;
|
auto match = *i;
|
||||||
|
|
||||||
// Add a string for non-matched characters.
|
// Add a string for non-matched characters.
|
||||||
(v.listElems()[idx++] = state.allocValue())->mkString(match.prefix().str());
|
(v.listElems()[idx++] = state.allocValue())->mkString(match.prefix().str());
|
||||||
|
@ -3613,7 +3622,7 @@ static void prim_concatStringsSep(EvalState & state, const Pos & pos, Value * *
|
||||||
|
|
||||||
for (auto elem : args[1]->listItems()) {
|
for (auto elem : args[1]->listItems()) {
|
||||||
if (first) first = false; else res += sep;
|
if (first) first = false; else res += sep;
|
||||||
res += state.coerceToString(pos, *elem, context);
|
res += *state.coerceToString(pos, *elem, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
v.mkString(res, context);
|
v.mkString(res, context);
|
||||||
|
@ -3643,14 +3652,14 @@ static void prim_replaceStrings(EvalState & state, const Pos & pos, Value * * ar
|
||||||
vector<string> from;
|
vector<string> from;
|
||||||
from.reserve(args[0]->listSize());
|
from.reserve(args[0]->listSize());
|
||||||
for (auto elem : args[0]->listItems())
|
for (auto elem : args[0]->listItems())
|
||||||
from.push_back(state.forceString(*elem, pos));
|
from.emplace_back(state.forceString(*elem, pos));
|
||||||
|
|
||||||
vector<std::pair<string, PathSet>> to;
|
vector<std::pair<string, PathSet>> to;
|
||||||
to.reserve(args[1]->listSize());
|
to.reserve(args[1]->listSize());
|
||||||
for (auto elem : args[1]->listItems()) {
|
for (auto elem : args[1]->listItems()) {
|
||||||
PathSet ctx;
|
PathSet ctx;
|
||||||
auto s = state.forceString(*elem, ctx, pos);
|
auto s = state.forceString(*elem, ctx, pos);
|
||||||
to.push_back(std::make_pair(std::move(s), std::move(ctx)));
|
to.emplace_back(s, std::move(ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
PathSet context;
|
PathSet context;
|
||||||
|
@ -3712,7 +3721,7 @@ static RegisterPrimOp primop_replaceStrings({
|
||||||
|
|
||||||
static void prim_parseDrvName(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_parseDrvName(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
string name = state.forceStringNoCtx(*args[0], pos);
|
auto name = state.forceStringNoCtx(*args[0], pos);
|
||||||
DrvName parsed(name);
|
DrvName parsed(name);
|
||||||
auto attrs = state.buildBindings(2);
|
auto attrs = state.buildBindings(2);
|
||||||
attrs.alloc(state.sName).mkString(parsed.name);
|
attrs.alloc(state.sName).mkString(parsed.name);
|
||||||
|
@ -3736,8 +3745,8 @@ static RegisterPrimOp primop_parseDrvName({
|
||||||
|
|
||||||
static void prim_compareVersions(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_compareVersions(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
string version1 = state.forceStringNoCtx(*args[0], pos);
|
auto version1 = state.forceStringNoCtx(*args[0], pos);
|
||||||
string version2 = state.forceStringNoCtx(*args[1], pos);
|
auto version2 = state.forceStringNoCtx(*args[1], pos);
|
||||||
v.mkInt(compareVersions(version1, version2));
|
v.mkInt(compareVersions(version1, version2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3756,14 +3765,14 @@ static RegisterPrimOp primop_compareVersions({
|
||||||
|
|
||||||
static void prim_splitVersion(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_splitVersion(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
string version = state.forceStringNoCtx(*args[0], pos);
|
auto version = state.forceStringNoCtx(*args[0], pos);
|
||||||
auto iter = version.cbegin();
|
auto iter = version.cbegin();
|
||||||
Strings components;
|
Strings components;
|
||||||
while (iter != version.cend()) {
|
while (iter != version.cend()) {
|
||||||
auto component = nextComponent(iter, version.cend());
|
auto component = nextComponent(iter, version.cend());
|
||||||
if (component.empty())
|
if (component.empty())
|
||||||
break;
|
break;
|
||||||
components.emplace_back(std::move(component));
|
components.emplace_back(component);
|
||||||
}
|
}
|
||||||
state.mkList(v, components.size());
|
state.mkList(v, components.size());
|
||||||
for (const auto & [n, component] : enumerate(components))
|
for (const auto & [n, component] : enumerate(components))
|
||||||
|
|
|
@ -7,7 +7,8 @@ namespace nix {
|
||||||
static void prim_unsafeDiscardStringContext(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_unsafeDiscardStringContext(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
PathSet context;
|
PathSet context;
|
||||||
v.mkString(state.coerceToString(pos, *args[0], context));
|
auto s = state.coerceToString(pos, *args[0], context);
|
||||||
|
v.mkString(*s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_unsafeDiscardStringContext("__unsafeDiscardStringContext", 1, prim_unsafeDiscardStringContext);
|
static RegisterPrimOp primop_unsafeDiscardStringContext("__unsafeDiscardStringContext", 1, prim_unsafeDiscardStringContext);
|
||||||
|
@ -32,13 +33,13 @@ static RegisterPrimOp primop_hasContext("__hasContext", 1, prim_hasContext);
|
||||||
static void prim_unsafeDiscardOutputDependency(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_unsafeDiscardOutputDependency(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
PathSet context;
|
PathSet context;
|
||||||
string s = state.coerceToString(pos, *args[0], context);
|
auto s = state.coerceToString(pos, *args[0], context);
|
||||||
|
|
||||||
PathSet context2;
|
PathSet context2;
|
||||||
for (auto & p : context)
|
for (auto & p : context)
|
||||||
context2.insert(p.at(0) == '=' ? string(p, 1) : p);
|
context2.insert(p.at(0) == '=' ? string(p, 1) : p);
|
||||||
|
|
||||||
v.mkString(s, context2);
|
v.mkString(*s, context2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_unsafeDiscardOutputDependency("__unsafeDiscardOutputDependency", 1, prim_unsafeDiscardOutputDependency);
|
static RegisterPrimOp primop_unsafeDiscardOutputDependency("__unsafeDiscardOutputDependency", 1, prim_unsafeDiscardOutputDependency);
|
||||||
|
@ -180,7 +181,7 @@ static void prim_appendContext(EvalState & state, const Pos & pos, Value * * arg
|
||||||
}
|
}
|
||||||
for (auto elem : iter->value->listItems()) {
|
for (auto elem : iter->value->listItems()) {
|
||||||
auto name = state.forceStringNoCtx(*elem, *iter->pos);
|
auto name = state.forceStringNoCtx(*elem, *iter->pos);
|
||||||
context.insert("!" + name + "!" + string(i.name));
|
context.insert(concatStrings("!", name, "!", i.name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * ar
|
||||||
std::string url;
|
std::string url;
|
||||||
std::optional<Hash> rev;
|
std::optional<Hash> rev;
|
||||||
std::optional<std::string> ref;
|
std::optional<std::string> ref;
|
||||||
std::string name = "source";
|
std::string_view name = "source";
|
||||||
PathSet context;
|
PathSet context;
|
||||||
|
|
||||||
state.forceValue(*args[0], pos);
|
state.forceValue(*args[0], pos);
|
||||||
|
@ -22,14 +22,14 @@ static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * ar
|
||||||
state.forceAttrs(*args[0], pos);
|
state.forceAttrs(*args[0], pos);
|
||||||
|
|
||||||
for (auto & attr : *args[0]->attrs) {
|
for (auto & attr : *args[0]->attrs) {
|
||||||
string n(attr.name);
|
std::string_view n(attr.name);
|
||||||
if (n == "url")
|
if (n == "url")
|
||||||
url = state.coerceToString(*attr.pos, *attr.value, context, false, false);
|
url = state.coerceToString(*attr.pos, *attr.value, context, false, false).toOwned();
|
||||||
else if (n == "rev") {
|
else if (n == "rev") {
|
||||||
// Ugly: unlike fetchGit, here the "rev" attribute can
|
// Ugly: unlike fetchGit, here the "rev" attribute can
|
||||||
// be both a revision or a branch/tag name.
|
// be both a revision or a branch/tag name.
|
||||||
auto value = state.forceStringNoCtx(*attr.value, *attr.pos);
|
auto value = state.forceStringNoCtx(*attr.value, *attr.pos);
|
||||||
if (std::regex_match(value, revRegex))
|
if (std::regex_match(value.begin(), value.end(), revRegex))
|
||||||
rev = Hash::parseAny(value, htSHA1);
|
rev = Hash::parseAny(value, htSHA1);
|
||||||
else
|
else
|
||||||
ref = value;
|
ref = value;
|
||||||
|
@ -50,7 +50,7 @@ static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * ar
|
||||||
});
|
});
|
||||||
|
|
||||||
} else
|
} else
|
||||||
url = state.coerceToString(pos, *args[0], context, false, false);
|
url = state.coerceToString(pos, *args[0], context, false, false).toOwned();
|
||||||
|
|
||||||
// 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.
|
||||||
|
@ -62,7 +62,7 @@ static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * ar
|
||||||
fetchers::Attrs attrs;
|
fetchers::Attrs attrs;
|
||||||
attrs.insert_or_assign("type", "hg");
|
attrs.insert_or_assign("type", "hg");
|
||||||
attrs.insert_or_assign("url", url.find("://") != std::string::npos ? url : "file://" + url);
|
attrs.insert_or_assign("url", url.find("://") != std::string::npos ? url : "file://" + url);
|
||||||
attrs.insert_or_assign("name", name);
|
attrs.insert_or_assign("name", string(name));
|
||||||
if (ref) attrs.insert_or_assign("ref", *ref);
|
if (ref) attrs.insert_or_assign("ref", *ref);
|
||||||
if (rev) attrs.insert_or_assign("rev", rev->gitRev());
|
if (rev) attrs.insert_or_assign("rev", rev->gitRev());
|
||||||
auto input = fetchers::Input::fromAttrs(std::move(attrs));
|
auto input = fetchers::Input::fromAttrs(std::move(attrs));
|
||||||
|
|
|
@ -125,7 +125,7 @@ static void fetchTree(
|
||||||
if (attr.name == state.sType) continue;
|
if (attr.name == state.sType) continue;
|
||||||
state.forceValue(*attr.value, *attr.pos);
|
state.forceValue(*attr.value, *attr.pos);
|
||||||
if (attr.value->type() == nPath || attr.value->type() == nString) {
|
if (attr.value->type() == nPath || attr.value->type() == nString) {
|
||||||
auto s = state.coerceToString(*attr.pos, *attr.value, context, false, false);
|
auto s = state.coerceToString(*attr.pos, *attr.value, context, false, false).toOwned();
|
||||||
attrs.emplace(attr.name,
|
attrs.emplace(attr.name,
|
||||||
attr.name == "url"
|
attr.name == "url"
|
||||||
? type == "git"
|
? type == "git"
|
||||||
|
@ -151,7 +151,7 @@ static void fetchTree(
|
||||||
|
|
||||||
input = fetchers::Input::fromAttrs(std::move(attrs));
|
input = fetchers::Input::fromAttrs(std::move(attrs));
|
||||||
} else {
|
} else {
|
||||||
auto url = state.coerceToString(pos, *args[0], context, false, false);
|
auto url = state.coerceToString(pos, *args[0], context, false, false).toOwned();
|
||||||
|
|
||||||
if (type == "git") {
|
if (type == "git") {
|
||||||
fetchers::Attrs attrs;
|
fetchers::Attrs attrs;
|
||||||
|
|
|
@ -9,7 +9,7 @@ static void prim_fromTOML(EvalState & state, const Pos & pos, Value * * args, Va
|
||||||
{
|
{
|
||||||
auto toml = state.forceStringNoCtx(*args[0], pos);
|
auto toml = state.forceStringNoCtx(*args[0], pos);
|
||||||
|
|
||||||
std::istringstream tomlStream(toml);
|
std::istringstream tomlStream(string{toml});
|
||||||
|
|
||||||
std::function<void(Value &, toml::value)> visit;
|
std::function<void(Value &, toml::value)> visit;
|
||||||
|
|
||||||
|
|
|
@ -699,10 +699,10 @@ void writeDerivation(Sink & out, const Store & store, const BasicDerivation & dr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string hashPlaceholder(const std::string & outputName)
|
std::string hashPlaceholder(const std::string_view outputName)
|
||||||
{
|
{
|
||||||
// FIXME: memoize?
|
// FIXME: memoize?
|
||||||
return "/" + hashString(htSHA256, "nix-output:" + outputName).to_string(Base32, false);
|
return "/" + hashString(htSHA256, concatStrings("nix-output:", outputName)).to_string(Base32, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string downstreamPlaceholder(const Store & store, const StorePath & drvPath, std::string_view outputName)
|
std::string downstreamPlaceholder(const Store & store, const StorePath & drvPath, std::string_view outputName)
|
||||||
|
|
|
@ -236,7 +236,7 @@ void writeDerivation(Sink & out, const Store & store, const BasicDerivation & dr
|
||||||
It is used as a placeholder to allow derivations to refer to their
|
It is used as a placeholder to allow derivations to refer to their
|
||||||
own outputs without needing to use the hash of a derivation in
|
own outputs without needing to use the hash of a derivation in
|
||||||
itself, making the hash near-impossible to calculate. */
|
itself, making the hash near-impossible to calculate. */
|
||||||
std::string hashPlaceholder(const std::string & outputName);
|
std::string hashPlaceholder(const std::string_view outputName);
|
||||||
|
|
||||||
/* This creates an opaque and almost certainly unique string
|
/* This creates an opaque and almost certainly unique string
|
||||||
deterministically from a derivation path and output name.
|
deterministically from a derivation path and output name.
|
||||||
|
|
|
@ -56,8 +56,8 @@ bool DrvName::matches(const DrvName & n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
string nextComponent(string::const_iterator & p,
|
std::string_view nextComponent(std::string_view::const_iterator & p,
|
||||||
const string::const_iterator end)
|
const std::string_view::const_iterator end)
|
||||||
{
|
{
|
||||||
/* Skip any dots and dashes (component separators). */
|
/* Skip any dots and dashes (component separators). */
|
||||||
while (p != end && (*p == '.' || *p == '-')) ++p;
|
while (p != end && (*p == '.' || *p == '-')) ++p;
|
||||||
|
@ -67,18 +67,18 @@ string nextComponent(string::const_iterator & p,
|
||||||
/* If the first character is a digit, consume the longest sequence
|
/* If the first character is a digit, consume the longest sequence
|
||||||
of digits. Otherwise, consume the longest sequence of
|
of digits. Otherwise, consume the longest sequence of
|
||||||
non-digit, non-separator characters. */
|
non-digit, non-separator characters. */
|
||||||
string s;
|
auto s = p;
|
||||||
if (isdigit(*p))
|
if (isdigit(*p))
|
||||||
while (p != end && isdigit(*p)) s += *p++;
|
while (p != end && isdigit(*p)) p++;
|
||||||
else
|
else
|
||||||
while (p != end && (!isdigit(*p) && *p != '.' && *p != '-'))
|
while (p != end && (!isdigit(*p) && *p != '.' && *p != '-'))
|
||||||
s += *p++;
|
p++;
|
||||||
|
|
||||||
return s;
|
return {s, size_t(p - s)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool componentsLT(const string & c1, const string & c2)
|
static bool componentsLT(const std::string_view c1, const std::string_view c2)
|
||||||
{
|
{
|
||||||
auto n1 = string2Int<int>(c1);
|
auto n1 = string2Int<int>(c1);
|
||||||
auto n2 = string2Int<int>(c2);
|
auto n2 = string2Int<int>(c2);
|
||||||
|
@ -94,14 +94,14 @@ static bool componentsLT(const string & c1, const string & c2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int compareVersions(const string & v1, const string & v2)
|
int compareVersions(const std::string_view v1, const std::string_view v2)
|
||||||
{
|
{
|
||||||
string::const_iterator p1 = v1.begin();
|
auto p1 = v1.begin();
|
||||||
string::const_iterator p2 = v2.begin();
|
auto p2 = v2.begin();
|
||||||
|
|
||||||
while (p1 != v1.end() || p2 != v2.end()) {
|
while (p1 != v1.end() || p2 != v2.end()) {
|
||||||
string c1 = nextComponent(p1, v1.end());
|
auto c1 = nextComponent(p1, v1.end());
|
||||||
string c2 = nextComponent(p2, v2.end());
|
auto c2 = nextComponent(p2, v2.end());
|
||||||
if (componentsLT(c1, c2)) return -1;
|
if (componentsLT(c1, c2)) return -1;
|
||||||
else if (componentsLT(c2, c1)) return 1;
|
else if (componentsLT(c2, c1)) return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,9 +27,9 @@ private:
|
||||||
|
|
||||||
typedef list<DrvName> DrvNames;
|
typedef list<DrvName> DrvNames;
|
||||||
|
|
||||||
string nextComponent(string::const_iterator & p,
|
std::string_view nextComponent(std::string_view::const_iterator & p,
|
||||||
const string::const_iterator end);
|
const std::string_view::const_iterator end);
|
||||||
int compareVersions(const string & v1, const string & v2);
|
int compareVersions(const std::string_view v1, const std::string_view v2);
|
||||||
DrvNames drvNamesFromArgs(const Strings & opArgs);
|
DrvNames drvNamesFromArgs(const Strings & opArgs);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ static void makeWritable(const Path & path)
|
||||||
struct MakeReadOnly
|
struct MakeReadOnly
|
||||||
{
|
{
|
||||||
Path path;
|
Path path;
|
||||||
MakeReadOnly(const Path & path) : path(path) { }
|
MakeReadOnly(const PathView path) : path(path) { }
|
||||||
~MakeReadOnly()
|
~MakeReadOnly()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
@ -205,12 +205,13 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats,
|
||||||
/* Make the containing directory writable, but only if it's not
|
/* Make the containing directory writable, but only if it's not
|
||||||
the store itself (we don't want or need to mess with its
|
the store itself (we don't want or need to mess with its
|
||||||
permissions). */
|
permissions). */
|
||||||
bool mustToggle = dirOf(path) != realStoreDir.get();
|
const Path dirOfPath(dirOf(path));
|
||||||
if (mustToggle) makeWritable(dirOf(path));
|
bool mustToggle = dirOfPath != realStoreDir.get();
|
||||||
|
if (mustToggle) makeWritable(dirOfPath);
|
||||||
|
|
||||||
/* When we're done, make the directory read-only again and reset
|
/* When we're done, make the directory read-only again and reset
|
||||||
its timestamp back to 0. */
|
its timestamp back to 0. */
|
||||||
MakeReadOnly makeReadOnly(mustToggle ? dirOf(path) : "");
|
MakeReadOnly makeReadOnly(mustToggle ? dirOfPath : "");
|
||||||
|
|
||||||
Path tempLink = (format("%1%/.tmp-link-%2%-%3%")
|
Path tempLink = (format("%1%/.tmp-link-%2%-%3%")
|
||||||
% realStoreDir % getpid() % random()).str();
|
% realStoreDir % getpid() % random()).str();
|
||||||
|
|
|
@ -170,7 +170,7 @@ std::string writeStructuredAttrsShell(const nlohmann::json & json)
|
||||||
|
|
||||||
auto handleSimpleType = [](const nlohmann::json & value) -> std::optional<std::string> {
|
auto handleSimpleType = [](const nlohmann::json & value) -> std::optional<std::string> {
|
||||||
if (value.is_string())
|
if (value.is_string())
|
||||||
return shellEscape(value);
|
return shellEscape(value.get<std::string_view>());
|
||||||
|
|
||||||
if (value.is_number()) {
|
if (value.is_number()) {
|
||||||
auto f = value.get<float>();
|
auto f = value.get<float>();
|
||||||
|
|
|
@ -259,7 +259,7 @@ Hash::Hash(std::string_view rest, HashType type, bool isSRI)
|
||||||
throw BadHash("hash '%s' has wrong length for hash type '%s'", rest, printHashType(this->type));
|
throw BadHash("hash '%s' has wrong length for hash type '%s'", rest, printHashType(this->type));
|
||||||
}
|
}
|
||||||
|
|
||||||
Hash newHashAllowEmpty(std::string hashStr, std::optional<HashType> ht)
|
Hash newHashAllowEmpty(std::string_view hashStr, std::optional<HashType> ht)
|
||||||
{
|
{
|
||||||
if (hashStr.empty()) {
|
if (hashStr.empty()) {
|
||||||
if (!ht)
|
if (!ht)
|
||||||
|
|
|
@ -107,7 +107,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Helper that defaults empty hashes to the 0 hash. */
|
/* Helper that defaults empty hashes to the 0 hash. */
|
||||||
Hash newHashAllowEmpty(std::string hashStr, std::optional<HashType> ht);
|
Hash newHashAllowEmpty(std::string_view hashStr, std::optional<HashType> ht);
|
||||||
|
|
||||||
/* Print a hash in base-16 if it's MD5, or base-32 otherwise. */
|
/* Print a hash in base-16 if it's MD5, or base-32 otherwise. */
|
||||||
string printHash16or32(const Hash & hash);
|
string printHash16or32(const Hash & hash);
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <variant>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
@ -47,4 +48,63 @@ struct Explicit {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* This wants to be a little bit like rust's Cow type.
|
||||||
|
Some parts of the evaluator benefit greatly from being able to reuse
|
||||||
|
existing allocations for strings, but have to be able to also use
|
||||||
|
newly allocated storage for values.
|
||||||
|
|
||||||
|
We do not define implicit conversions, even with ref qualifiers,
|
||||||
|
since those can easily become ambiguous to the reader and can degrade
|
||||||
|
into copying behaviour we want to avoid. */
|
||||||
|
class BackedStringView {
|
||||||
|
private:
|
||||||
|
std::variant<std::string, std::string_view> data;
|
||||||
|
|
||||||
|
/* Needed to introduce a temporary since operator-> must return
|
||||||
|
a pointer. Without this we'd need to store the view object
|
||||||
|
even when we already own a string. */
|
||||||
|
class Ptr {
|
||||||
|
private:
|
||||||
|
std::string_view view;
|
||||||
|
public:
|
||||||
|
Ptr(std::string_view view): view(view) {}
|
||||||
|
const std::string_view * operator->() const { return &view; }
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
BackedStringView(std::string && s): data(std::move(s)) {}
|
||||||
|
BackedStringView(std::string_view sv): data(sv) {}
|
||||||
|
template<size_t N>
|
||||||
|
BackedStringView(const char (& lit)[N]): data(std::string_view(lit)) {}
|
||||||
|
|
||||||
|
BackedStringView(const BackedStringView &) = delete;
|
||||||
|
BackedStringView & operator=(const BackedStringView &) = delete;
|
||||||
|
|
||||||
|
/* We only want move operations defined since the sole purpose of
|
||||||
|
this type is to avoid copies. */
|
||||||
|
BackedStringView(BackedStringView && other) = default;
|
||||||
|
BackedStringView & operator=(BackedStringView && other) = default;
|
||||||
|
|
||||||
|
bool isOwned() const
|
||||||
|
{
|
||||||
|
return std::holds_alternative<std::string>(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string toOwned() &&
|
||||||
|
{
|
||||||
|
return isOwned()
|
||||||
|
? std::move(std::get<std::string>(data))
|
||||||
|
: std::string(std::get<std::string_view>(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view operator*() const
|
||||||
|
{
|
||||||
|
return isOwned()
|
||||||
|
? std::get<std::string>(data)
|
||||||
|
: std::get<std::string_view>(data);
|
||||||
|
}
|
||||||
|
Ptr operator->() const { return Ptr(**this); }
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,7 @@ void replaceEnv(std::map<std::string, std::string> newEnv)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Path absPath(Path path, std::optional<Path> dir, bool resolveSymlinks)
|
Path absPath(Path path, std::optional<PathView> dir, bool resolveSymlinks)
|
||||||
{
|
{
|
||||||
if (path[0] != '/') {
|
if (path[0] != '/') {
|
||||||
if (!dir) {
|
if (!dir) {
|
||||||
|
@ -95,12 +95,12 @@ Path absPath(Path path, std::optional<Path> dir, bool resolveSymlinks)
|
||||||
if (!getcwd(buf, sizeof(buf)))
|
if (!getcwd(buf, sizeof(buf)))
|
||||||
#endif
|
#endif
|
||||||
throw SysError("cannot get cwd");
|
throw SysError("cannot get cwd");
|
||||||
dir = buf;
|
path = concatStrings(buf, "/", path);
|
||||||
#ifdef __GNU__
|
#ifdef __GNU__
|
||||||
free(buf);
|
free(buf);
|
||||||
#endif
|
#endif
|
||||||
}
|
} else
|
||||||
path = *dir + "/" + path;
|
path = concatStrings(*dir, "/", path);
|
||||||
}
|
}
|
||||||
return canonPath(path, resolveSymlinks);
|
return canonPath(path, resolveSymlinks);
|
||||||
}
|
}
|
||||||
|
@ -172,7 +172,7 @@ Path canonPath(PathView path, bool resolveSymlinks)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Path dirOf(const Path & path)
|
Path dirOf(const PathView path)
|
||||||
{
|
{
|
||||||
Path::size_type pos = path.rfind('/');
|
Path::size_type pos = path.rfind('/');
|
||||||
if (pos == string::npos)
|
if (pos == string::npos)
|
||||||
|
@ -1344,9 +1344,11 @@ std::string toLower(const std::string & s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string shellEscape(const std::string & s)
|
std::string shellEscape(const std::string_view s)
|
||||||
{
|
{
|
||||||
std::string r = "'";
|
std::string r;
|
||||||
|
r.reserve(s.size() + 2);
|
||||||
|
r += "'";
|
||||||
for (auto & i : s)
|
for (auto & i : s)
|
||||||
if (i == '\'') r += "'\\''"; else r += i;
|
if (i == '\'') r += "'\\''"; else r += i;
|
||||||
r += '\'';
|
r += '\'';
|
||||||
|
@ -1751,7 +1753,7 @@ void bind(int fd, const std::string & path)
|
||||||
|
|
||||||
if (path.size() + 1 >= sizeof(addr.sun_path)) {
|
if (path.size() + 1 >= sizeof(addr.sun_path)) {
|
||||||
Pid pid = startProcess([&]() {
|
Pid pid = startProcess([&]() {
|
||||||
auto dir = dirOf(path);
|
Path dir = dirOf(path);
|
||||||
if (chdir(dir.c_str()) == -1)
|
if (chdir(dir.c_str()) == -1)
|
||||||
throw SysError("chdir to '%s' failed", dir);
|
throw SysError("chdir to '%s' failed", dir);
|
||||||
std::string base(baseNameOf(path));
|
std::string base(baseNameOf(path));
|
||||||
|
@ -1780,7 +1782,7 @@ void connect(int fd, const std::string & path)
|
||||||
|
|
||||||
if (path.size() + 1 >= sizeof(addr.sun_path)) {
|
if (path.size() + 1 >= sizeof(addr.sun_path)) {
|
||||||
Pid pid = startProcess([&]() {
|
Pid pid = startProcess([&]() {
|
||||||
auto dir = dirOf(path);
|
Path dir = dirOf(path);
|
||||||
if (chdir(dir.c_str()) == -1)
|
if (chdir(dir.c_str()) == -1)
|
||||||
throw SysError("chdir to '%s' failed", dir);
|
throw SysError("chdir to '%s' failed", dir);
|
||||||
std::string base(baseNameOf(path));
|
std::string base(baseNameOf(path));
|
||||||
|
|
|
@ -49,7 +49,7 @@ void clearEnv();
|
||||||
specified directory, or the current directory otherwise. The path
|
specified directory, or the current directory otherwise. The path
|
||||||
is also canonicalised. */
|
is also canonicalised. */
|
||||||
Path absPath(Path path,
|
Path absPath(Path path,
|
||||||
std::optional<Path> dir = {},
|
std::optional<PathView> dir = {},
|
||||||
bool resolveSymlinks = false);
|
bool resolveSymlinks = false);
|
||||||
|
|
||||||
/* Canonicalise a path by removing all `.' or `..' components and
|
/* Canonicalise a path by removing all `.' or `..' components and
|
||||||
|
@ -62,7 +62,7 @@ Path canonPath(PathView path, bool resolveSymlinks = false);
|
||||||
everything before the final `/'. If the path is the root or an
|
everything before the final `/'. If the path is the root or an
|
||||||
immediate child thereof (e.g., `/foo'), this means `/'
|
immediate child thereof (e.g., `/foo'), this means `/'
|
||||||
is returned.*/
|
is returned.*/
|
||||||
Path dirOf(const Path & path);
|
Path dirOf(const PathView path);
|
||||||
|
|
||||||
/* Return the base name of the given canonical path, i.e., everything
|
/* Return the base name of the given canonical path, i.e., everything
|
||||||
following the final `/' (trailing slashes are removed). */
|
following the final `/' (trailing slashes are removed). */
|
||||||
|
@ -148,6 +148,9 @@ Path getDataDir();
|
||||||
/* Create a directory and all its parents, if necessary. Returns the
|
/* Create a directory and all its parents, if necessary. Returns the
|
||||||
list of created directories, in order of creation. */
|
list of created directories, in order of creation. */
|
||||||
Paths createDirs(const Path & path);
|
Paths createDirs(const Path & path);
|
||||||
|
inline Paths createDirs(PathView path) {
|
||||||
|
return createDirs(Path(path));
|
||||||
|
}
|
||||||
|
|
||||||
/* Create a symlink. */
|
/* Create a symlink. */
|
||||||
void createSymlink(const Path & target, const Path & link,
|
void createSymlink(const Path & target, const Path & link,
|
||||||
|
@ -187,6 +190,7 @@ public:
|
||||||
void cancel();
|
void cancel();
|
||||||
void reset(const Path & p, bool recursive = true);
|
void reset(const Path & p, bool recursive = true);
|
||||||
operator Path() const { return path; }
|
operator Path() const { return path; }
|
||||||
|
operator PathView() const { return path; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -491,7 +495,7 @@ std::string toLower(const std::string & s);
|
||||||
|
|
||||||
|
|
||||||
/* Escape a string as a shell word. */
|
/* Escape a string as a shell word. */
|
||||||
std::string shellEscape(const std::string & s);
|
std::string shellEscape(const std::string_view s);
|
||||||
|
|
||||||
|
|
||||||
/* Exception handling in destructors: print an error message, then
|
/* Exception handling in destructors: print an error message, then
|
||||||
|
|
|
@ -472,9 +472,11 @@ struct CmdDevelop : Common, MixEnvironment
|
||||||
else {
|
else {
|
||||||
script = "[ -n \"$PS1\" ] && [ -e ~/.bashrc ] && source ~/.bashrc;\n" + script;
|
script = "[ -n \"$PS1\" ] && [ -e ~/.bashrc ] && source ~/.bashrc;\n" + script;
|
||||||
if (developSettings.bashPrompt != "")
|
if (developSettings.bashPrompt != "")
|
||||||
script += fmt("[ -n \"$PS1\" ] && PS1=%s;\n", shellEscape(developSettings.bashPrompt));
|
script += fmt("[ -n \"$PS1\" ] && PS1=%s;\n",
|
||||||
|
shellEscape(developSettings.bashPrompt.get()));
|
||||||
if (developSettings.bashPromptSuffix != "")
|
if (developSettings.bashPromptSuffix != "")
|
||||||
script += fmt("[ -n \"$PS1\" ] && PS1+=%s;\n", shellEscape(developSettings.bashPromptSuffix));
|
script += fmt("[ -n \"$PS1\" ] && PS1+=%s;\n",
|
||||||
|
shellEscape(developSettings.bashPromptSuffix.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
writeFull(rcFileFd.get(), script);
|
writeFull(rcFileFd.get(), script);
|
||||||
|
|
|
@ -107,7 +107,7 @@ struct CmdEval : MixJSON, InstallableCommand
|
||||||
|
|
||||||
else if (raw) {
|
else if (raw) {
|
||||||
stopProgressBar();
|
stopProgressBar();
|
||||||
std::cout << state->coerceToString(noPos, *v, context);
|
std::cout << *state->coerceToString(noPos, *v, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (json) {
|
else if (json) {
|
||||||
|
|
|
@ -38,7 +38,7 @@ string resolveMirrorUrl(EvalState & state, string url)
|
||||||
if (mirrorList->value->listSize() < 1)
|
if (mirrorList->value->listSize() < 1)
|
||||||
throw Error("mirror URL '%s' did not expand to anything", url);
|
throw Error("mirror URL '%s' did not expand to anything", url);
|
||||||
|
|
||||||
auto mirror = state.forceString(*mirrorList->value->listElems()[0]);
|
string mirror(state.forceString(*mirrorList->value->listElems()[0]));
|
||||||
return mirror + (hasSuffix(mirror, "/") ? "" : "/") + string(s, p + 1);
|
return mirror + (hasSuffix(mirror, "/") ? "" : "/") + string(s, p + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -463,7 +463,7 @@ bool NixRepl::processLine(string line)
|
||||||
if (v.type() == nPath || v.type() == nString) {
|
if (v.type() == nPath || v.type() == nString) {
|
||||||
PathSet context;
|
PathSet context;
|
||||||
auto filename = state->coerceToString(noPos, v, context);
|
auto filename = state->coerceToString(noPos, v, context);
|
||||||
pos.file = state->symbols.create(filename);
|
pos.file = state->symbols.create(*filename);
|
||||||
} else if (v.isLambda()) {
|
} else if (v.isLambda()) {
|
||||||
pos = v.lambda.fun->pos;
|
pos = v.lambda.fun->pos;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -107,7 +107,7 @@ Path resolveSymlink(const Path & path)
|
||||||
auto target = readLink(path);
|
auto target = readLink(path);
|
||||||
return hasPrefix(target, "/")
|
return hasPrefix(target, "/")
|
||||||
? target
|
? target
|
||||||
: dirOf(path) + "/" + target;
|
: concatStrings(dirOf(path), "/", target);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<string> resolveTree(const Path & path, PathSet & deps)
|
std::set<string> resolveTree(const Path & path, PathSet & deps)
|
||||||
|
|
Loading…
Reference in a new issue