aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr
diff options
context:
space:
mode:
Diffstat (limited to 'src/libexpr')
-rw-r--r--src/libexpr/attr-set.cc3
-rw-r--r--src/libexpr/attr-set.hh2
-rw-r--r--src/libexpr/eval.cc21
-rw-r--r--src/libexpr/eval.hh5
-rw-r--r--src/libexpr/lexer.l7
-rw-r--r--src/libexpr/names.cc2
-rw-r--r--src/libexpr/names.hh2
-rw-r--r--src/libexpr/primops.cc73
-rw-r--r--src/libexpr/primops.hh3
-rw-r--r--src/libexpr/primops/fetchGit.cc2
10 files changed, 83 insertions, 37 deletions
diff --git a/src/libexpr/attr-set.cc b/src/libexpr/attr-set.cc
index 910428c02..b284daa3c 100644
--- a/src/libexpr/attr-set.cc
+++ b/src/libexpr/attr-set.cc
@@ -7,13 +7,14 @@
namespace nix {
+/* Note: Various places expect the allocated memory to be zeroed. */
static void * allocBytes(size_t n)
{
void * p;
#if HAVE_BOEHMGC
p = GC_malloc(n);
#else
- p = malloc(n);
+ p = calloc(n, 1);
#endif
if (!p) throw std::bad_alloc();
return p;
diff --git a/src/libexpr/attr-set.hh b/src/libexpr/attr-set.hh
index e1fc2bf6d..3119a1848 100644
--- a/src/libexpr/attr-set.hh
+++ b/src/libexpr/attr-set.hh
@@ -83,7 +83,7 @@ public:
for (size_t n = 0; n < size_; n++)
res.emplace_back(&attrs[n]);
std::sort(res.begin(), res.end(), [](const Attr * a, const Attr * b) {
- return (string) a->name < (string) b->name;
+ return (const string &) a->name < (const string &) b->name;
});
return res;
}
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 11195af77..f94c23ea7 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -43,13 +43,14 @@ static char * dupString(const char * s)
}
+/* Note: Various places expect the allocated memory to be zeroed. */
static void * allocBytes(size_t n)
{
void * p;
#if HAVE_BOEHMGC
p = GC_malloc(n);
#else
- p = malloc(n);
+ p = calloc(n, 1);
#endif
if (!p) throw std::bad_alloc();
return p;
@@ -293,6 +294,10 @@ EvalState::EvalState(const Strings & _searchPath, ref<Store> store)
, sWrong(symbols.create("wrong"))
, sStructuredAttrs(symbols.create("__structuredAttrs"))
, sBuilder(symbols.create("builder"))
+ , sArgs(symbols.create("args"))
+ , sOutputHash(symbols.create("outputHash"))
+ , sOutputHashAlgo(symbols.create("outputHashAlgo"))
+ , sOutputHashMode(symbols.create("outputHashMode"))
, repair(NoRepair)
, store(store)
, baseEnv(allocEnv(128))
@@ -308,7 +313,7 @@ EvalState::EvalState(const Strings & _searchPath, ref<Store> store)
for (auto & i : _searchPath) addToSearchPath(i);
for (auto & i : paths) addToSearchPath(i);
}
- addToSearchPath("nix=" + settings.nixDataDir + "/nix/corepkgs");
+ addToSearchPath("nix=" + canonPath(settings.nixDataDir + "/nix/corepkgs", true));
if (settings.restrictEval || settings.pureEval) {
allowedPaths = PathSet();
@@ -404,7 +409,7 @@ Path EvalState::toRealPath(const Path & path, const PathSet & context)
};
-void EvalState::addConstant(const string & name, Value & v)
+Value * EvalState::addConstant(const string & name, Value & v)
{
Value * v2 = allocValue();
*v2 = v;
@@ -412,12 +417,18 @@ void EvalState::addConstant(const string & name, Value & v)
baseEnv.values[baseEnvDispl++] = v2;
string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name;
baseEnv.values[0]->attrs->push_back(Attr(symbols.create(name2), v2));
+ return v2;
}
Value * EvalState::addPrimOp(const string & name,
unsigned int arity, PrimOpFun primOp)
{
+ if (arity == 0) {
+ Value v;
+ primOp(*this, noPos, nullptr, v);
+ return addConstant(name, v);
+ }
Value * v = allocValue();
string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name;
Symbol sym = symbols.create(name2);
@@ -576,9 +587,7 @@ Env & EvalState::allocEnv(unsigned int size)
Env * env = (Env *) allocBytes(sizeof(Env) + size * sizeof(Value *));
env->size = size;
- /* Clear the values because maybeThunk() and lookupVar fromWith expect this. */
- for (unsigned i = 0; i < size; ++i)
- env->values[i] = 0;
+ /* We assume that env->values has been cleared by the allocator; maybeThunk() and lookupVar fromWith expect this. */
return *env;
}
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index 9e3d30d95..9d8799b79 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -69,7 +69,8 @@ public:
const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName, sValue,
sSystem, sOverrides, sOutputs, sOutputName, sIgnoreNulls,
sFile, sLine, sColumn, sFunctor, sToString,
- sRight, sWrong, sStructuredAttrs, sBuilder;
+ sRight, sWrong, sStructuredAttrs, sBuilder, sArgs,
+ sOutputHash, sOutputHashAlgo, sOutputHashMode;
Symbol sDerivationNix;
/* If set, force copying files to the Nix store even if they
@@ -210,7 +211,7 @@ private:
void createBaseEnv();
- void addConstant(const string & name, Value & v);
+ Value * addConstant(const string & name, Value & v);
Value * addPrimOp(const string & name,
unsigned int arity, PrimOpFun primOp);
diff --git a/src/libexpr/lexer.l b/src/libexpr/lexer.l
index 28a0a6a87..e5e01fb58 100644
--- a/src/libexpr/lexer.l
+++ b/src/libexpr/lexer.l
@@ -49,9 +49,10 @@ static void adjustLoc(YYLTYPE * loc, const char * s, size_t len)
}
-static Expr * unescapeStr(SymbolTable & symbols, const char * s)
+static Expr * unescapeStr(SymbolTable & symbols, const char * s, size_t length)
{
string t;
+ t.reserve(length);
char c;
while ((c = *s++)) {
if (c == '\\') {
@@ -150,7 +151,7 @@ or { return OR_KW; }
/* It is impossible to match strings ending with '$' with one
regex because trailing contexts are only valid at the end
of a rule. (A sane but undocumented limitation.) */
- yylval->e = unescapeStr(data->symbols, yytext);
+ yylval->e = unescapeStr(data->symbols, yytext, yyleng);
return STR;
}
<STRING>\$\{ { PUSH_STATE(INSIDE_DOLLAR_CURLY); return DOLLAR_CURLY; }
@@ -178,7 +179,7 @@ or { return OR_KW; }
return IND_STR;
}
<IND_STRING>\'\'\\. {
- yylval->e = unescapeStr(data->symbols, yytext + 2);
+ yylval->e = unescapeStr(data->symbols, yytext + 2, yyleng - 2);
return IND_STR;
}
<IND_STRING>\$\{ { PUSH_STATE(INSIDE_DOLLAR_CURLY); return DOLLAR_CURLY; }
diff --git a/src/libexpr/names.cc b/src/libexpr/names.cc
index 6d78d2116..382088c78 100644
--- a/src/libexpr/names.cc
+++ b/src/libexpr/names.cc
@@ -41,7 +41,7 @@ bool DrvName::matches(DrvName & n)
}
-static string nextComponent(string::const_iterator & p,
+string nextComponent(string::const_iterator & p,
const string::const_iterator end)
{
/* Skip any dots and dashes (component separators). */
diff --git a/src/libexpr/names.hh b/src/libexpr/names.hh
index 9667fc96f..13c3093e7 100644
--- a/src/libexpr/names.hh
+++ b/src/libexpr/names.hh
@@ -24,6 +24,8 @@ private:
typedef list<DrvName> DrvNames;
+string nextComponent(string::const_iterator & p,
+ const string::const_iterator end);
int compareVersions(const string & v1, const string & v2);
DrvNames drvNamesFromArgs(const Strings & opArgs);
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 466fd13e8..6778023f5 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -553,7 +553,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
for (auto & i : args[0]->attrs->lexicographicOrder()) {
if (i->name == state.sIgnoreNulls) continue;
- string key = i->name;
+ const string & key = i->name;
vomit("processing attribute '%1%'", key);
auto handleHashMode = [&](const std::string & s) {
@@ -589,7 +589,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
/* The `args' attribute is special: it supplies the
command-line arguments to the builder. */
- if (key == "args") {
+ if (i->name == state.sArgs) {
state.forceList(*i->value, pos);
for (unsigned int n = 0; n < i->value->listSize(); ++n) {
string s = state.coerceToString(posDrvName, *i->value->listElems()[n], context, true);
@@ -612,15 +612,13 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
drv.builder = state.forceString(*i->value, context, posDrvName);
else if (i->name == state.sSystem)
drv.platform = state.forceStringNoCtx(*i->value, posDrvName);
- else if (i->name == state.sName)
- drvName = state.forceStringNoCtx(*i->value, posDrvName);
- else if (key == "outputHash")
+ else if (i->name == state.sOutputHash)
outputHash = state.forceStringNoCtx(*i->value, posDrvName);
- else if (key == "outputHashAlgo")
+ else if (i->name == state.sOutputHashAlgo)
outputHashAlgo = state.forceStringNoCtx(*i->value, posDrvName);
- else if (key == "outputHashMode")
+ else if (i->name == state.sOutputHashMode)
handleHashMode(state.forceStringNoCtx(*i->value, posDrvName));
- else if (key == "outputs") {
+ else if (i->name == state.sOutputs) {
/* Require ‘outputs’ to be a list of strings. */
state.forceList(*i->value, posDrvName);
Strings ss;
@@ -634,14 +632,10 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
drv.env.emplace(key, s);
if (i->name == state.sBuilder) drv.builder = s;
else if (i->name == state.sSystem) drv.platform = s;
- else if (i->name == state.sName) {
- drvName = s;
- printMsg(lvlVomit, format("derivation name is '%1%'") % drvName);
- }
- else if (key == "outputHash") outputHash = s;
- else if (key == "outputHashAlgo") outputHashAlgo = s;
- else if (key == "outputHashMode") handleHashMode(s);
- else if (key == "outputs")
+ else if (i->name == state.sOutputHash) outputHash = s;
+ else if (i->name == state.sOutputHashAlgo) outputHashAlgo = s;
+ else if (i->name == state.sOutputHashMode) handleHashMode(s);
+ else if (i->name == state.sOutputs)
handleOutputs(tokenizeString<Strings>(s));
}
@@ -1138,8 +1132,11 @@ static void prim_attrNames(EvalState & state, const Pos & pos, Value * * args, V
state.mkList(v, args[0]->attrs->size());
size_t n = 0;
- for (auto & i : args[0]->attrs->lexicographicOrder())
- mkString(*(v.listElems()[n++] = state.allocValue()), i->name);
+ for (auto & i : *args[0]->attrs)
+ mkString(*(v.listElems()[n++] = state.allocValue()), i.name);
+
+ std::sort(v.listElems(), v.listElems() + n,
+ [](Value * v1, Value * v2) { return strcmp(v1->string.s, v2->string.s) < 0; });
}
@@ -1916,21 +1913,32 @@ static void prim_replaceStrings(EvalState & state, const Pos & pos, Value * * ar
auto s = state.forceString(*args[2], context, pos);
string res;
- for (size_t p = 0; p < s.size(); ) {
+ // Loops one past last character to handle the case where 'from' contains an empty string.
+ for (size_t p = 0; p <= s.size(); ) {
bool found = false;
auto i = from.begin();
auto j = to.begin();
for (; i != from.end(); ++i, ++j)
if (s.compare(p, i->size(), *i) == 0) {
found = true;
- p += i->size();
res += j->first;
+ if (i->empty()) {
+ if (p < s.size())
+ res += s[p];
+ p++;
+ } else {
+ p += i->size();
+ }
for (auto& path : j->second)
context.insert(path);
j->second.clear();
break;
}
- if (!found) res += s[p++];
+ if (!found) {
+ if (p < s.size())
+ res += s[p];
+ p++;
+ }
}
mkString(v, res, context);
@@ -1961,6 +1969,26 @@ static void prim_compareVersions(EvalState & state, const Pos & pos, Value * * a
}
+static void prim_splitVersion(EvalState & state, const Pos & pos, Value * * args, Value & v)
+{
+ string version = state.forceStringNoCtx(*args[0], pos);
+ auto iter = version.cbegin();
+ Strings components;
+ while (iter != version.cend()) {
+ auto component = nextComponent(iter, version.cend());
+ if (component.empty())
+ break;
+ components.emplace_back(std::move(component));
+ }
+ state.mkList(v, components.size());
+ unsigned int n = 0;
+ for (auto & component : components) {
+ auto listElem = v.listElems()[n++] = state.allocValue();
+ mkString(*listElem, std::move(component));
+ }
+}
+
+
/*************************************************************
* Networking
*************************************************************/
@@ -2196,6 +2224,7 @@ void EvalState::createBaseEnv()
// Versions
addPrimOp("__parseDrvName", 1, prim_parseDrvName);
addPrimOp("__compareVersions", 2, prim_compareVersions);
+ addPrimOp("__splitVersion", 1, prim_splitVersion);
// Derivations
addPrimOp("derivationStrict", 1, prim_derivationStrict);
@@ -2207,7 +2236,7 @@ void EvalState::createBaseEnv()
/* Add a wrapper around the derivation primop that computes the
`drvPath' and `outPath' attributes lazily. */
- string path = settings.nixDataDir + "/nix/corepkgs/derivation.nix";
+ string path = canonPath(settings.nixDataDir + "/nix/corepkgs/derivation.nix", true);
sDerivationNix = symbols.create(path);
evalFile(path, v);
addConstant("derivation", v);
diff --git a/src/libexpr/primops.hh b/src/libexpr/primops.hh
index 39d23b04a..31bf3f84f 100644
--- a/src/libexpr/primops.hh
+++ b/src/libexpr/primops.hh
@@ -9,6 +9,9 @@ struct RegisterPrimOp
{
typedef std::vector<std::tuple<std::string, size_t, PrimOpFun>> PrimOps;
static PrimOps * primOps;
+ /* You can register a constant by passing an arity of 0. fun
+ will get called during EvalState initialization, so there
+ may be primops not yet added and builtins is not yet sorted. */
RegisterPrimOp(std::string name, size_t arity, PrimOpFun fun);
};
diff --git a/src/libexpr/primops/fetchGit.cc b/src/libexpr/primops/fetchGit.cc
index 2e3e2634d..9fc0d4662 100644
--- a/src/libexpr/primops/fetchGit.cc
+++ b/src/libexpr/primops/fetchGit.cc
@@ -79,7 +79,7 @@ GitInfo exportGit(ref<Store> store, const std::string & uri,
ref = "HEAD"s;
}
- if (!ref) ref = "master"s;
+ if (!ref) ref = "HEAD"s;
if (rev != "" && !std::regex_match(rev, revRegex))
throw Error("invalid Git revision '%s'", rev);