From 54bf5ba4227a234f8cd5102634b9a3b535e6fbdb Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 16 Dec 2019 19:11:47 +0100 Subject: [PATCH] nix-store -r: Handle symlinks to store paths Fixes #3270. --- src/libexpr/get-drvs.cc | 2 +- src/libstore/daemon.cc | 4 ++-- src/libstore/derivations.cc | 10 ---------- src/libstore/path.cc | 15 +++++++++++++++ src/libstore/path.hh | 24 ++++++++++++++++++++++++ src/libstore/store-api.cc | 13 ++++++++++--- src/libstore/store-api.hh | 25 +++++-------------------- src/libutil/util.cc | 8 ++++---- src/libutil/util.hh | 2 +- src/nix-store/nix-store.cc | 4 ++-- tests/nix-build.sh | 3 +++ 11 files changed, 67 insertions(+), 43 deletions(-) diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index a3412eab9..ca9c547fa 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -19,7 +19,7 @@ DrvInfo::DrvInfo(EvalState & state, const string & attrPath, Bindings * attrs) DrvInfo::DrvInfo(EvalState & state, ref store, const std::string & drvPathWithOutputs) : state(&state), attrs(nullptr), attrPath("") { - auto [drvPath, selectedOutputs] = store->parseDrvPathWithOutputs(drvPathWithOutputs); + auto [drvPath, selectedOutputs] = store->parsePathWithOutputs(drvPathWithOutputs); this->drvPath = store->printStorePath(drvPath); diff --git a/src/libstore/daemon.cc b/src/libstore/daemon.cc index c53dfdd56..8e9f9d71b 100644 --- a/src/libstore/daemon.cc +++ b/src/libstore/daemon.cc @@ -424,7 +424,7 @@ static void performOp(TunnelLogger * logger, ref store, case wopBuildPaths: { std::vector drvs; for (auto & s : readStrings(from)) - drvs.push_back(store->parseDrvPathWithOutputs(s)); + drvs.push_back(store->parsePathWithOutputs(s)); BuildMode mode = bmNormal; if (GET_PROTOCOL_MINOR(clientVersion) >= 15) { mode = (BuildMode) readInt(from); @@ -721,7 +721,7 @@ static void performOp(TunnelLogger * logger, ref store, case wopQueryMissing: { std::vector targets; for (auto & s : readStrings(from)) - targets.push_back(store->parseDrvPathWithOutputs(s)); + targets.push_back(store->parsePathWithOutputs(s)); logger->startWork(); StorePathSet willBuild, willSubstitute, unknown; unsigned long long downloadSize, narSize; diff --git a/src/libstore/derivations.cc b/src/libstore/derivations.cc index 726e34479..1a061149a 100644 --- a/src/libstore/derivations.cc +++ b/src/libstore/derivations.cc @@ -375,16 +375,6 @@ Hash hashDerivationModulo(Store & store, const Derivation & drv, bool maskOutput } -StorePathWithOutputs Store::parseDrvPathWithOutputs(const std::string & s) -{ - size_t n = s.find("!"); - return n == s.npos - ? StorePathWithOutputs{parseStorePath(s), std::set()} - : StorePathWithOutputs{parseStorePath(std::string_view(s.data(), n)), - tokenizeString>(string(s, n + 1), ",")}; -} - - std::string StorePathWithOutputs::to_string(const Store & store) const { return outputs.empty() diff --git a/src/libstore/path.cc b/src/libstore/path.cc index 81ae495a1..cda5f9968 100644 --- a/src/libstore/path.cc +++ b/src/libstore/path.cc @@ -96,4 +96,19 @@ StorePathSet singleton(const StorePath & path) return res; } +std::pair parsePathWithOutputs(std::string_view s) +{ + size_t n = s.find("!"); + return n == s.npos + ? std::make_pair(s, std::set()) + : std::make_pair(((std::string_view) s).substr(0, n), + tokenizeString>(((std::string_view) s).substr(n + 1), ",")); +} + +StorePathWithOutputs Store::parsePathWithOutputs(const std::string & s) +{ + auto [path, outputs] = nix::parsePathWithOutputs(s); + return {parseStorePath(path), std::move(outputs)}; +} + } diff --git a/src/libstore/path.hh b/src/libstore/path.hh index 273808f02..5ebb57480 100644 --- a/src/libstore/path.hh +++ b/src/libstore/path.hh @@ -7,6 +7,8 @@ namespace nix { /* See path.rs. */ struct StorePath; +struct Store; + extern "C" { void ffi_StorePath_drop(void *); bool ffi_StorePath_less_than(const StorePath & a, const StorePath & b); @@ -67,6 +69,28 @@ const size_t storePathHashLen = 32; // i.e. 160 bits /* Extension of derivations in the Nix store. */ const std::string drvExtension = ".drv"; +struct StorePathWithOutputs +{ + StorePath path; + std::set outputs; + + StorePathWithOutputs(const StorePath & path, const std::set & outputs = {}) + : path(path.clone()), outputs(outputs) + { } + + StorePathWithOutputs(StorePath && path, std::set && outputs) + : path(std::move(path)), outputs(std::move(outputs)) + { } + + StorePathWithOutputs(const StorePathWithOutputs & other) + : path(other.path.clone()), outputs(other.outputs) + { } + + std::string to_string(const Store & store) const; +}; + +std::pair parsePathWithOutputs(std::string_view s); + } namespace std { diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc index c98931885..1781e0c68 100644 --- a/src/libstore/store-api.cc +++ b/src/libstore/store-api.cc @@ -39,9 +39,9 @@ Path Store::toStorePath(const Path & path) const } -Path Store::followLinksToStore(const Path & _path) const +Path Store::followLinksToStore(std::string_view _path) const { - Path path = absPath(_path); + Path path = absPath(std::string(_path)); while (!isInStore(path)) { if (!isLink(path)) break; string target = readLink(path); @@ -53,12 +53,19 @@ Path Store::followLinksToStore(const Path & _path) const } -StorePath Store::followLinksToStorePath(const Path & path) const +StorePath Store::followLinksToStorePath(std::string_view path) const { return parseStorePath(toStorePath(followLinksToStore(path))); } +StorePathWithOutputs Store::followLinksToStorePathWithOutputs(std::string_view path) const +{ + auto [path2, outputs] = nix::parsePathWithOutputs(path); + return StorePathWithOutputs(followLinksToStorePath(path2), std::move(outputs)); +} + + string storePathToHash(const Path & path) { auto base = baseNameOf(path); diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh index 552bbd67d..d77d6bad8 100644 --- a/src/libstore/store-api.hh +++ b/src/libstore/store-api.hh @@ -241,23 +241,6 @@ struct BuildResult }; -struct StorePathWithOutputs -{ - StorePath path; - std::set outputs; - - StorePathWithOutputs(const StorePath & path, const std::set & outputs = {}) - : path(path.clone()), outputs(outputs) - { } - - StorePathWithOutputs(const StorePathWithOutputs & other) - : path(other.path.clone()), outputs(other.outputs) - { } - - std::string to_string(const Store & store) const; -}; - - class Store : public std::enable_shared_from_this, public Config { public: @@ -304,7 +287,7 @@ public: /* Split a string specifying a derivation and a set of outputs (/nix/store/hash-foo!out1,out2,...) into the derivation path and the outputs. */ - StorePathWithOutputs parseDrvPathWithOutputs(const string & s); + StorePathWithOutputs parsePathWithOutputs(const string & s); /* Display a set of paths in human-readable form (i.e., between quotes and separated by commas). */ @@ -323,11 +306,13 @@ public: Path toStorePath(const Path & path) const; /* Follow symlinks until we end up with a path in the Nix store. */ - Path followLinksToStore(const Path & path) const; + Path followLinksToStore(std::string_view path) const; /* Same as followLinksToStore(), but apply toStorePath() to the result. */ - StorePath followLinksToStorePath(const Path & path) const; + StorePath followLinksToStorePath(std::string_view path) const; + + StorePathWithOutputs followLinksToStorePathWithOutputs(std::string_view path) const; /* Constructs a unique store path name. */ StorePath makeStorePath(const string & type, diff --git a/src/libutil/util.cc b/src/libutil/util.cc index e67bdcdeb..012f1d071 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -1186,7 +1186,7 @@ void _interrupted() ////////////////////////////////////////////////////////////////////// -template C tokenizeString(const string & s, const string & separators) +template C tokenizeString(std::string_view s, const string & separators) { C result; string::size_type pos = s.find_first_not_of(separators, 0); @@ -1200,9 +1200,9 @@ template C tokenizeString(const string & s, const string & separators) return result; } -template Strings tokenizeString(const string & s, const string & separators); -template StringSet tokenizeString(const string & s, const string & separators); -template vector tokenizeString(const string & s, const string & separators); +template Strings tokenizeString(std::string_view s, const string & separators); +template StringSet tokenizeString(std::string_view s, const string & separators); +template vector tokenizeString(std::string_view s, const string & separators); string concatStringsSep(const string & sep, const Strings & ss) diff --git a/src/libutil/util.hh b/src/libutil/util.hh index abd91b81c..abf1c95d6 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -340,7 +340,7 @@ MakeError(FormatError, Error); /* String tokenizer. */ -template C tokenizeString(const string & s, const string & separators = " \t\n\r"); +template C tokenizeString(std::string_view s, const string & separators = " \t\n\r"); /* Concatenate the given strings with a separator between the diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc index e2e2939f4..45e152c47 100644 --- a/src/nix-store/nix-store.cc +++ b/src/nix-store/nix-store.cc @@ -128,7 +128,7 @@ static void opRealise(Strings opFlags, Strings opArgs) std::vector paths; for (auto & i : opArgs) - paths.push_back(store->parseDrvPathWithOutputs(i)); + paths.push_back(store->followLinksToStorePathWithOutputs(i)); unsigned long long downloadSize, narSize; StorePathSet willBuild, willSubstitute, unknown; @@ -893,7 +893,7 @@ static void opServe(Strings opFlags, Strings opArgs) std::vector paths; for (auto & s : readStrings(in)) - paths.emplace_back(store->parseDrvPathWithOutputs(s)); + paths.emplace_back(store->parsePathWithOutputs(s)); getBuildSettings(); diff --git a/tests/nix-build.sh b/tests/nix-build.sh index 395264863..0eb599608 100644 --- a/tests/nix-build.sh +++ b/tests/nix-build.sh @@ -23,3 +23,6 @@ outPath2=$(nix-build $(nix-instantiate dependencies.nix) --no-out-link) outPath2=$(nix-build $(nix-instantiate dependencies.nix)!out --no-out-link) [[ $outPath = $outPath2 ]] + +outPath2=$(nix-store -r $(nix-instantiate --indirect --add-root $TEST_ROOT/indirect dependencies.nix)!out) +[[ $outPath = $outPath2 ]]