diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 3b02e8815..b5376caf3 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -500,6 +500,7 @@ EvalState::EvalState( , valueAllocCache(std::make_shared(nullptr)) , env1AllocCache(std::make_shared(nullptr)) #endif + , virtualPathMarker(settings.nixStore + "/virtual00000000000000000") , baseEnv(allocEnv(128)) , staticBaseEnv{std::make_shared(false, nullptr)} { diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 34ad3d1cb..bb20f2641 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -227,14 +227,16 @@ public: void registerAccessor(ref accessor); /* Convert a path to a string representation of the format - `/__nix_virtual__//`. */ + `/nix/store/virtual000.../`. */ std::string encodePath(const SourcePath & path); /* Decode a path encoded by `encodePath()`. */ SourcePath decodePath(std::string_view s, PosIdx pos = noPos); + const std::string virtualPathMarker; + /* Decode all virtual paths in a string, i.e. all - /__nix_virtual__/... substrings are replaced by the + /nix/store/virtual000... substrings are replaced by the corresponding input accessor. */ std::string decodePaths(std::string_view s); diff --git a/src/libexpr/paths.cc b/src/libexpr/paths.cc index 235f8a933..e2101858d 100644 --- a/src/libexpr/paths.cc +++ b/src/libexpr/paths.cc @@ -14,18 +14,16 @@ void EvalState::registerAccessor(ref accessor) inputAccessors.emplace(accessor->number, accessor); } -static constexpr std::string_view marker = "/__nix_virtual__/"; - std::string EvalState::encodePath(const SourcePath & path) { /* For backward compatibility, return paths in the root FS normally. Encoding any other path is not very reproducible (due - to /__nix_virtual__/) and we should depreceate it + to /nix/store/virtual000...) and we should deprecate it eventually. So print a warning about use of an encoded path in decodePath(). */ return path.accessor == rootFS ? path.path.abs() - : std::string(marker) + std::to_string(path.accessor->number) + path.path.abs(); + : fmt("%s%08x-source%s", virtualPathMarker, path.accessor->number, path.path.absOrEmpty()); } SourcePath EvalState::decodePath(std::string_view s, PosIdx pos) @@ -33,17 +31,17 @@ SourcePath EvalState::decodePath(std::string_view s, PosIdx pos) if (!hasPrefix(s, "/")) throwEvalError(pos, "string '%1%' doesn't represent an absolute path", s); - if (hasPrefix(s, marker)) { + if (hasPrefix(s, virtualPathMarker)) { auto fail = [s]() { throw Error("cannot decode virtual path '%s'", s); }; - s = s.substr(marker.size()); + s = s.substr(virtualPathMarker.size()); try { auto slash = s.find('/'); if (slash == std::string::npos) fail(); - size_t number = std::stoi(std::string(s, 0, slash)); + size_t number = std::stoi(std::string(s, 0, slash), nullptr, 16); s = s.substr(slash); auto accessor = inputAccessors.find(number); @@ -70,7 +68,7 @@ std::string EvalState::decodePaths(std::string_view s) size_t pos = 0; while (true) { - auto m = s.find(marker, pos); + auto m = s.find(virtualPathMarker, pos); if (m == s.npos) { res.append(s.substr(pos)); return res; diff --git a/src/libutil/canon-path.hh b/src/libutil/canon-path.hh index b1be0341e..c5e7f0596 100644 --- a/src/libutil/canon-path.hh +++ b/src/libutil/canon-path.hh @@ -58,6 +58,14 @@ public: const std::string & abs() const { return path; } + /* Like abs(), but return an empty string if this path is + '/'. Thus the returned string never ends in a slash. */ + const std::string & absOrEmpty() const + { + const static std::string epsilon; + return isRoot() ? epsilon : path; + } + const char * c_str() const { return path.c_str(); }