nix-store -r: Handle symlinks to store paths

Fixes #3270.
This commit is contained in:
Eelco Dolstra 2019-12-16 19:11:47 +01:00
parent 14d82baba4
commit 54bf5ba422
11 changed files with 67 additions and 43 deletions

View file

@ -19,7 +19,7 @@ DrvInfo::DrvInfo(EvalState & state, const string & attrPath, Bindings * attrs)
DrvInfo::DrvInfo(EvalState & state, ref<Store> store, const std::string & drvPathWithOutputs) DrvInfo::DrvInfo(EvalState & state, ref<Store> store, const std::string & drvPathWithOutputs)
: state(&state), attrs(nullptr), attrPath("") : state(&state), attrs(nullptr), attrPath("")
{ {
auto [drvPath, selectedOutputs] = store->parseDrvPathWithOutputs(drvPathWithOutputs); auto [drvPath, selectedOutputs] = store->parsePathWithOutputs(drvPathWithOutputs);
this->drvPath = store->printStorePath(drvPath); this->drvPath = store->printStorePath(drvPath);

View file

@ -424,7 +424,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
case wopBuildPaths: { case wopBuildPaths: {
std::vector<StorePathWithOutputs> drvs; std::vector<StorePathWithOutputs> drvs;
for (auto & s : readStrings<Strings>(from)) for (auto & s : readStrings<Strings>(from))
drvs.push_back(store->parseDrvPathWithOutputs(s)); drvs.push_back(store->parsePathWithOutputs(s));
BuildMode mode = bmNormal; BuildMode mode = bmNormal;
if (GET_PROTOCOL_MINOR(clientVersion) >= 15) { if (GET_PROTOCOL_MINOR(clientVersion) >= 15) {
mode = (BuildMode) readInt(from); mode = (BuildMode) readInt(from);
@ -721,7 +721,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
case wopQueryMissing: { case wopQueryMissing: {
std::vector<StorePathWithOutputs> targets; std::vector<StorePathWithOutputs> targets;
for (auto & s : readStrings<Strings>(from)) for (auto & s : readStrings<Strings>(from))
targets.push_back(store->parseDrvPathWithOutputs(s)); targets.push_back(store->parsePathWithOutputs(s));
logger->startWork(); logger->startWork();
StorePathSet willBuild, willSubstitute, unknown; StorePathSet willBuild, willSubstitute, unknown;
unsigned long long downloadSize, narSize; unsigned long long downloadSize, narSize;

View file

@ -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<string>()}
: StorePathWithOutputs{parseStorePath(std::string_view(s.data(), n)),
tokenizeString<std::set<string>>(string(s, n + 1), ",")};
}
std::string StorePathWithOutputs::to_string(const Store & store) const std::string StorePathWithOutputs::to_string(const Store & store) const
{ {
return outputs.empty() return outputs.empty()

View file

@ -96,4 +96,19 @@ StorePathSet singleton(const StorePath & path)
return res; return res;
} }
std::pair<std::string_view, StringSet> parsePathWithOutputs(std::string_view s)
{
size_t n = s.find("!");
return n == s.npos
? std::make_pair(s, std::set<string>())
: std::make_pair(((std::string_view) s).substr(0, n),
tokenizeString<std::set<string>>(((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)};
}
} }

View file

@ -7,6 +7,8 @@ namespace nix {
/* See path.rs. */ /* See path.rs. */
struct StorePath; struct StorePath;
struct Store;
extern "C" { extern "C" {
void ffi_StorePath_drop(void *); void ffi_StorePath_drop(void *);
bool ffi_StorePath_less_than(const StorePath & a, const StorePath & b); 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. */ /* Extension of derivations in the Nix store. */
const std::string drvExtension = ".drv"; const std::string drvExtension = ".drv";
struct StorePathWithOutputs
{
StorePath path;
std::set<std::string> outputs;
StorePathWithOutputs(const StorePath & path, const std::set<std::string> & outputs = {})
: path(path.clone()), outputs(outputs)
{ }
StorePathWithOutputs(StorePath && path, std::set<std::string> && 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<std::string_view, StringSet> parsePathWithOutputs(std::string_view s);
} }
namespace std { namespace std {

View file

@ -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)) { while (!isInStore(path)) {
if (!isLink(path)) break; if (!isLink(path)) break;
string target = readLink(path); 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))); 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) string storePathToHash(const Path & path)
{ {
auto base = baseNameOf(path); auto base = baseNameOf(path);

View file

@ -241,23 +241,6 @@ struct BuildResult
}; };
struct StorePathWithOutputs
{
StorePath path;
std::set<std::string> outputs;
StorePathWithOutputs(const StorePath & path, const std::set<std::string> & 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<Store>, public Config class Store : public std::enable_shared_from_this<Store>, public Config
{ {
public: public:
@ -304,7 +287,7 @@ public:
/* Split a string specifying a derivation and a set of outputs /* Split a string specifying a derivation and a set of outputs
(/nix/store/hash-foo!out1,out2,...) into the derivation path (/nix/store/hash-foo!out1,out2,...) into the derivation path
and the outputs. */ 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 /* Display a set of paths in human-readable form (i.e., between quotes
and separated by commas). */ and separated by commas). */
@ -323,11 +306,13 @@ public:
Path toStorePath(const Path & path) const; Path toStorePath(const Path & path) const;
/* Follow symlinks until we end up with a path in the Nix store. */ /* 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 /* Same as followLinksToStore(), but apply toStorePath() to the
result. */ 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. */ /* Constructs a unique store path name. */
StorePath makeStorePath(const string & type, StorePath makeStorePath(const string & type,

View file

@ -1186,7 +1186,7 @@ void _interrupted()
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
template<class C> C tokenizeString(const string & s, const string & separators) template<class C> C tokenizeString(std::string_view s, const string & separators)
{ {
C result; C result;
string::size_type pos = s.find_first_not_of(separators, 0); string::size_type pos = s.find_first_not_of(separators, 0);
@ -1200,9 +1200,9 @@ template<class C> C tokenizeString(const string & s, const string & separators)
return result; return result;
} }
template Strings tokenizeString(const string & s, const string & separators); template Strings tokenizeString(std::string_view s, const string & separators);
template StringSet tokenizeString(const string & s, const string & separators); template StringSet tokenizeString(std::string_view s, const string & separators);
template vector<string> tokenizeString(const string & s, const string & separators); template vector<string> tokenizeString(std::string_view s, const string & separators);
string concatStringsSep(const string & sep, const Strings & ss) string concatStringsSep(const string & sep, const Strings & ss)

View file

@ -340,7 +340,7 @@ MakeError(FormatError, Error);
/* String tokenizer. */ /* String tokenizer. */
template<class C> C tokenizeString(const string & s, const string & separators = " \t\n\r"); template<class C> C tokenizeString(std::string_view s, const string & separators = " \t\n\r");
/* Concatenate the given strings with a separator between the /* Concatenate the given strings with a separator between the

View file

@ -128,7 +128,7 @@ static void opRealise(Strings opFlags, Strings opArgs)
std::vector<StorePathWithOutputs> paths; std::vector<StorePathWithOutputs> paths;
for (auto & i : opArgs) for (auto & i : opArgs)
paths.push_back(store->parseDrvPathWithOutputs(i)); paths.push_back(store->followLinksToStorePathWithOutputs(i));
unsigned long long downloadSize, narSize; unsigned long long downloadSize, narSize;
StorePathSet willBuild, willSubstitute, unknown; StorePathSet willBuild, willSubstitute, unknown;
@ -893,7 +893,7 @@ static void opServe(Strings opFlags, Strings opArgs)
std::vector<StorePathWithOutputs> paths; std::vector<StorePathWithOutputs> paths;
for (auto & s : readStrings<Strings>(in)) for (auto & s : readStrings<Strings>(in))
paths.emplace_back(store->parseDrvPathWithOutputs(s)); paths.emplace_back(store->parsePathWithOutputs(s));
getBuildSettings(); getBuildSettings();

View file

@ -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) outPath2=$(nix-build $(nix-instantiate dependencies.nix)!out --no-out-link)
[[ $outPath = $outPath2 ]] [[ $outPath = $outPath2 ]]
outPath2=$(nix-store -r $(nix-instantiate --indirect --add-root $TEST_ROOT/indirect dependencies.nix)!out)
[[ $outPath = $outPath2 ]]