diff options
-rw-r--r-- | src/libexpr/eval.hh | 4 | ||||
-rw-r--r-- | src/libexpr/primops.cc | 8 | ||||
-rw-r--r-- | src/libstore/derivations.cc | 58 | ||||
-rw-r--r-- | src/libstore/gc.cc | 40 | ||||
-rw-r--r-- | src/libstore/path.cc | 14 | ||||
-rw-r--r-- | src/libstore/store-api.cc | 8 | ||||
-rw-r--r-- | src/libstore/store-api.hh | 2 | ||||
-rw-r--r-- | tests/lang/eval-okay-foldlStrict.exp | 1 | ||||
-rw-r--r-- | tests/lang/eval-okay-foldlStrict.nix | 3 |
9 files changed, 89 insertions, 49 deletions
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index cabc92d15..34a212aa4 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -114,6 +114,9 @@ private: /* Cache used by checkSourcePath(). */ std::unordered_map<Path, Path> resolvedPaths; + /* Cache used by prim_match(). */ + std::unordered_map<std::string, std::regex> regexCache; + public: EvalState(const Strings & _searchPath, ref<Store> store); @@ -314,6 +317,7 @@ private: friend struct ExprOpConcatLists; friend struct ExprSelect; friend void prim_getAttr(EvalState & state, const Pos & pos, Value * * args, Value & v); + friend void prim_match(EvalState & state, const Pos & pos, Value * * args, Value & v); }; diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 29302c9b6..4cd28698c 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -1811,19 +1811,21 @@ static void prim_hashString(EvalState & state, const Pos & pos, Value * * args, /* Match a regular expression against a string and return either ‘null’ or a list containing substring matches. */ -static void prim_match(EvalState & state, const Pos & pos, Value * * args, Value & v) +void prim_match(EvalState & state, const Pos & pos, Value * * args, Value & v) { auto re = state.forceStringNoCtx(*args[0], pos); try { - std::regex regex(re, std::regex::extended); + auto regex = state.regexCache.find(re); + if (regex == state.regexCache.end()) + regex = state.regexCache.emplace(re, std::regex(re, std::regex::extended)).first; PathSet context; const std::string str = state.forceString(*args[1], context, pos); std::smatch match; - if (!std::regex_match(str, match, regex)) { + if (!std::regex_match(str, match, regex->second)) { mkNull(v); return; } diff --git a/src/libstore/derivations.cc b/src/libstore/derivations.cc index d9da8769c..205b90e55 100644 --- a/src/libstore/derivations.cc +++ b/src/libstore/derivations.cc @@ -213,15 +213,26 @@ Derivation Store::derivationFromPath(const StorePath & drvPath) } -static void printString(string & res, const string & s) +static void printString(string & res, std::string_view s) +{ + char buf[s.size() * 2 + 2]; + char * p = buf; + *p++ = '"'; + for (auto c : s) + if (c == '\"' || c == '\\') { *p++ = '\\'; *p++ = c; } + else if (c == '\n') { *p++ = '\\'; *p++ = 'n'; } + else if (c == '\r') { *p++ = '\\'; *p++ = 'r'; } + else if (c == '\t') { *p++ = '\\'; *p++ = 't'; } + else *p++ = c; + *p++ = '"'; + res.append(buf, p - buf); +} + + +static void printUnquotedString(string & res, std::string_view s) { res += '"'; - for (const char * i = s.c_str(); *i; i++) - if (*i == '\"' || *i == '\\') { res += "\\"; res += *i; } - else if (*i == '\n') res += "\\n"; - else if (*i == '\r') res += "\\r"; - else if (*i == '\t') res += "\\t"; - else res += *i; + res.append(s); res += '"'; } @@ -239,6 +250,19 @@ static void printStrings(string & res, ForwardIterator i, ForwardIterator j) } +template<class ForwardIterator> +static void printUnquotedStrings(string & res, ForwardIterator i, ForwardIterator j) +{ + res += '['; + bool first = true; + for ( ; i != j; ++i) { + if (first) first = false; else res += ','; + printUnquotedString(res, *i); + } + res += ']'; +} + + string Derivation::unparse(const Store & store, bool maskOutputs, std::map<std::string, StringSet> * actualInputs) const { @@ -249,10 +273,10 @@ string Derivation::unparse(const Store & store, bool maskOutputs, bool first = true; for (auto & i : outputs) { if (first) first = false; else s += ','; - s += '('; printString(s, i.first); - s += ','; printString(s, maskOutputs ? "" : store.printStorePath(i.second.path)); - s += ','; printString(s, i.second.hashAlgo); - s += ','; printString(s, i.second.hash); + s += '('; printUnquotedString(s, i.first); + s += ','; printUnquotedString(s, maskOutputs ? "" : store.printStorePath(i.second.path)); + s += ','; printUnquotedString(s, i.second.hashAlgo); + s += ','; printUnquotedString(s, i.second.hash); s += ')'; } @@ -261,24 +285,24 @@ string Derivation::unparse(const Store & store, bool maskOutputs, if (actualInputs) { for (auto & i : *actualInputs) { if (first) first = false; else s += ','; - s += '('; printString(s, i.first); - s += ','; printStrings(s, i.second.begin(), i.second.end()); + s += '('; printUnquotedString(s, i.first); + s += ','; printUnquotedStrings(s, i.second.begin(), i.second.end()); s += ')'; } } else { for (auto & i : inputDrvs) { if (first) first = false; else s += ','; - s += '('; printString(s, store.printStorePath(i.first)); - s += ','; printStrings(s, i.second.begin(), i.second.end()); + s += '('; printUnquotedString(s, store.printStorePath(i.first)); + s += ','; printUnquotedStrings(s, i.second.begin(), i.second.end()); s += ')'; } } s += "],"; auto paths = store.printStorePathSet(inputSrcs); // FIXME: slow - printStrings(s, paths.begin(), paths.end()); + printUnquotedStrings(s, paths.begin(), paths.end()); - s += ','; printString(s, platform); + s += ','; printUnquotedString(s, platform); s += ','; printString(s, builder); s += ','; printStrings(s, args.begin(), args.end()); diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc index 690febc5b..0c3d89611 100644 --- a/src/libstore/gc.cc +++ b/src/libstore/gc.cc @@ -255,12 +255,11 @@ void LocalStore::findTempRoots(FDs & fds, Roots & tempRoots, bool censor) void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots) { auto foundRoot = [&](const Path & path, const Path & target) { - Path storePath = toStorePath(target); - // FIXME - if (isStorePath(storePath) && isValidPath(parseStorePath(storePath))) - roots[parseStorePath(storePath)].emplace(path); + auto storePath = maybeParseStorePath(toStorePath(target)); + if (storePath && isValidPath(*storePath)) + roots[std::move(*storePath)].emplace(path); else - printInfo("skipping invalid root from '%1%' to '%2%'", path, storePath); + printInfo("skipping invalid root from '%1%' to '%2%'", path, target); }; try { @@ -296,10 +295,9 @@ void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots) } else if (type == DT_REG) { - Path storePath = storeDir + "/" + std::string(baseNameOf(path)); - // FIXME - if (isStorePath(storePath) && isValidPath(parseStorePath(storePath))) - roots[parseStorePath(storePath)].emplace(path); + auto storePath = maybeParseStorePath(storeDir + "/" + std::string(baseNameOf(path))); + if (storePath && isValidPath(*storePath)) + roots[std::move(*storePath)].emplace(path); } } @@ -523,14 +521,14 @@ void LocalStore::deletePathRecursive(GCState & state, const Path & path) unsigned long long size = 0; - // FIXME - if (isStorePath(path) && isValidPath(parseStorePath(path))) { + auto storePath = maybeParseStorePath(path); + if (storePath && isValidPath(*storePath)) { StorePathSet referrers; - queryReferrers(parseStorePath(path), referrers); + queryReferrers(*storePath, referrers); for (auto & i : referrers) if (printStorePath(i) != path) deletePathRecursive(state, printStorePath(i)); - size = queryPathInfo(parseStorePath(path))->narSize; - invalidatePathChecked(parseStorePath(path)); + size = queryPathInfo(*storePath)->narSize; + invalidatePathChecked(*storePath); } Path realPath = realStoreDir + "/" + std::string(baseNameOf(path)); @@ -593,8 +591,7 @@ bool LocalStore::canReachRoot(GCState & state, StorePathSet & visited, const Sto visited.insert(path.clone()); - //FIXME - if (!isStorePath(printStorePath(path)) || !isValidPath(path)) return false; + if (!isValidPath(path)) return false; StorePathSet incoming; @@ -637,8 +634,9 @@ void LocalStore::tryToDelete(GCState & state, const Path & path) //Activity act(*logger, lvlDebug, format("considering whether to delete '%1%'") % path); - // FIXME - if (!isStorePath(path) || !isValidPath(parseStorePath(path))) { + auto storePath = maybeParseStorePath(path); + + if (!storePath || !isValidPath(*storePath)) { /* A lock file belonging to a path that we're building right now isn't garbage. */ if (isActiveTempFile(state, path, ".lock")) return; @@ -655,7 +653,7 @@ void LocalStore::tryToDelete(GCState & state, const Path & path) StorePathSet visited; - if (canReachRoot(state, visited, parseStorePath(path))) { + if (storePath && canReachRoot(state, visited, *storePath)) { debug("cannot delete '%s' because it's still reachable", path); } else { /* No path we visited was a root, so everything is garbage. @@ -818,8 +816,8 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) string name = dirent->d_name; if (name == "." || name == "..") continue; Path path = storeDir + "/" + name; - // FIXME - if (isStorePath(path) && isValidPath(parseStorePath(path))) + auto storePath = maybeParseStorePath(path); + if (storePath && isValidPath(*storePath)) entries.push_back(path); else tryToDelete(state, path); diff --git a/src/libstore/path.cc b/src/libstore/path.cc index a33bec3ed..70b919adc 100644 --- a/src/libstore/path.cc +++ b/src/libstore/path.cc @@ -55,6 +55,20 @@ StorePath Store::parseStorePath(std::string_view path) const return StorePath::make(path, storeDir); } +std::optional<StorePath> Store::maybeParseStorePath(std::string_view path) const +{ + try { + return parseStorePath(path); + } catch (Error &) { + return {}; + } +} + +bool Store::isStorePath(const Path & path) const +{ + return (bool) maybeParseStorePath(path); +} + StorePathSet Store::parseStorePathSet(const PathSet & paths) const { StorePathSet res; diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc index d8f6c22bc..75fa5d1e6 100644 --- a/src/libstore/store-api.cc +++ b/src/libstore/store-api.cc @@ -19,14 +19,6 @@ bool Store::isInStore(const Path & path) const } -bool Store::isStorePath(const Path & path) const -{ - return isInStore(path) - && path.size() >= storeDir.size() + 1 + storePathHashLen - && path.find('/', storeDir.size() + 1) == Path::npos; -} - - Path Store::toStorePath(const Path & path) const { if (!isInStore(path)) diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh index 861b96930..a1cfb314a 100644 --- a/src/libstore/store-api.hh +++ b/src/libstore/store-api.hh @@ -281,6 +281,8 @@ public: StorePath parseStorePath(std::string_view path) const; + std::optional<StorePath> maybeParseStorePath(std::string_view path) const; + std::string printStorePath(const StorePath & path) const; // FIXME: remove diff --git a/tests/lang/eval-okay-foldlStrict.exp b/tests/lang/eval-okay-foldlStrict.exp new file mode 100644 index 000000000..837e12b40 --- /dev/null +++ b/tests/lang/eval-okay-foldlStrict.exp @@ -0,0 +1 @@ +500500 diff --git a/tests/lang/eval-okay-foldlStrict.nix b/tests/lang/eval-okay-foldlStrict.nix new file mode 100644 index 000000000..3b87188d2 --- /dev/null +++ b/tests/lang/eval-okay-foldlStrict.nix @@ -0,0 +1,3 @@ +with import ./lib.nix; + +builtins.foldl' (x: y: x + y) 0 (range 1 1000) |