diff options
-rw-r--r-- | src/libexpr/primops.cc | 2 | ||||
-rw-r--r-- | src/libstore/build.cc | 10 | ||||
-rw-r--r-- | src/libstore/daemon.cc | 4 | ||||
-rw-r--r-- | src/libstore/derivations.cc | 8 | ||||
-rw-r--r-- | src/libstore/derivations.hh | 2 | ||||
-rw-r--r-- | src/libstore/local-store.cc | 12 | ||||
-rw-r--r-- | src/libstore/local-store.hh | 2 | ||||
-rw-r--r-- | src/libstore/remote-store.cc | 48 | ||||
-rw-r--r-- | src/libstore/remote-store.hh | 2 | ||||
-rw-r--r-- | src/libstore/store-api.cc | 11 | ||||
-rw-r--r-- | src/libstore/store-api.hh | 12 | ||||
-rw-r--r-- | src/libstore/worker-protocol.hh | 78 | ||||
-rw-r--r-- | src/nix/develop.cc | 2 |
13 files changed, 149 insertions, 44 deletions
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 30f4c3529..dcc34407b 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -839,7 +839,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * } /* Write the resulting term into the Nix store directory. */ - auto drvPath = writeDerivation(state.store, drv, state.repair); + auto drvPath = writeDerivation(*state.store, drv, state.repair); auto drvPathS = state.store->printStorePath(drvPath); printMsg(lvlChatty, "instantiated '%1%' -> '%2%'", drvName, drvPathS); diff --git a/src/libstore/build.cc b/src/libstore/build.cc index afb2bb096..dd932cee9 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -2756,8 +2756,12 @@ struct RestrictedStore : public LocalFSStore void queryReferrers(const StorePath & path, StorePathSet & referrers) override { } - OutputPathMap queryDerivationOutputMap(const StorePath & path) override - { throw Error("queryDerivationOutputMap"); } + std::map<std::string, std::optional<StorePath>> queryPartialDerivationOutputMap(const StorePath & path) override + { + if (!goal.isAllowed(path)) + throw InvalidPath("cannot query output map for unknown path '%s' in recursive Nix", printStorePath(path)); + return next->queryPartialDerivationOutputMap(path); + } std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override { throw Error("queryPathFromHashPart"); } @@ -4983,7 +4987,7 @@ void Worker::waitForInput() std::vector<unsigned char> buffer(4096); for (auto & k : fds2) { if (pollStatus.at(fdToPollStatus.at(k)).revents) { - ssize_t rd = read(k, buffer.data(), buffer.size()); + ssize_t rd = ::read(k, buffer.data(), buffer.size()); // FIXME: is there a cleaner way to handle pt close // than EIO? Is this even standard? if (rd == 0 || (rd == -1 && errno == EIO)) { diff --git a/src/libstore/daemon.cc b/src/libstore/daemon.cc index ad3fe1847..f35ddb522 100644 --- a/src/libstore/daemon.cc +++ b/src/libstore/daemon.cc @@ -325,9 +325,9 @@ static void performOp(TunnelLogger * logger, ref<Store> store, case wopQueryDerivationOutputMap: { auto path = store->parseStorePath(readString(from)); logger->startWork(); - OutputPathMap outputs = store->queryDerivationOutputMap(path); + auto outputs = store->queryPartialDerivationOutputMap(path); logger->stopWork(); - writeOutputPathMap(*store, to, outputs); + worker_proto::write(*store, to, outputs); break; } diff --git a/src/libstore/derivations.cc b/src/libstore/derivations.cc index a9fed2564..43bc61e55 100644 --- a/src/libstore/derivations.cc +++ b/src/libstore/derivations.cc @@ -61,7 +61,7 @@ bool BasicDerivation::isBuiltin() const } -StorePath writeDerivation(ref<Store> store, +StorePath writeDerivation(Store & store, const Derivation & drv, RepairFlag repair) { auto references = drv.inputSrcs; @@ -71,10 +71,10 @@ StorePath writeDerivation(ref<Store> store, (that can be missing (of course) and should not necessarily be held during a garbage collection). */ auto suffix = std::string(drv.name) + drvExtension; - auto contents = drv.unparse(*store, false); + auto contents = drv.unparse(store, false); return settings.readOnlyMode - ? store->computeStorePathForText(suffix, contents, references) - : store->addTextToStore(suffix, contents, references, repair); + ? store.computeStorePathForText(suffix, contents, references) + : store.addTextToStore(suffix, contents, references, repair); } diff --git a/src/libstore/derivations.hh b/src/libstore/derivations.hh index 3aae30ab2..9656a32f2 100644 --- a/src/libstore/derivations.hh +++ b/src/libstore/derivations.hh @@ -146,7 +146,7 @@ class Store; enum RepairFlag : bool { NoRepair = false, Repair = true }; /* Write a derivation to the Nix store, and return its path. */ -StorePath writeDerivation(ref<Store> store, +StorePath writeDerivation(Store & store, const Derivation & drv, RepairFlag repair = NoRepair); /* Read a derivation from a file. */ diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index bccd77b68..a79b2da44 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -785,17 +785,21 @@ StorePathSet LocalStore::queryValidDerivers(const StorePath & path) } -OutputPathMap LocalStore::queryDerivationOutputMap(const StorePath & path) +std::map<std::string, std::optional<StorePath>> LocalStore::queryPartialDerivationOutputMap(const StorePath & path) { - return retrySQLite<OutputPathMap>([&]() { + std::map<std::string, std::optional<StorePath>> outputs; + BasicDerivation drv = readDerivation(path); + for (auto & [outName, _] : drv.outputs) { + outputs.insert_or_assign(outName, std::nullopt); + } + return retrySQLite<std::map<std::string, std::optional<StorePath>>>([&]() { auto state(_state.lock()); auto useQueryDerivationOutputs(state->stmtQueryDerivationOutputs.use() (queryValidPathId(*state, path))); - OutputPathMap outputs; while (useQueryDerivationOutputs.next()) - outputs.emplace( + outputs.insert_or_assign( useQueryDerivationOutputs.getStr(0), parseStorePath(useQueryDerivationOutputs.getStr(1)) ); diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh index 31e6587ac..5af12c2b2 100644 --- a/src/libstore/local-store.hh +++ b/src/libstore/local-store.hh @@ -133,7 +133,7 @@ public: StorePathSet queryValidDerivers(const StorePath & path) override; - OutputPathMap queryDerivationOutputMap(const StorePath & path) override; + std::map<std::string, std::optional<StorePath>> queryPartialDerivationOutputMap(const StorePath & path) override; std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override; diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc index 8dcc1d710..adba17c5e 100644 --- a/src/libstore/remote-store.cc +++ b/src/libstore/remote-store.cc @@ -31,7 +31,6 @@ template<> StorePathSet readStorePaths(const Store & store, Source & from) return paths; } - void writeStorePaths(const Store & store, Sink & out, const StorePathSet & paths) { out << paths.size(); @@ -39,6 +38,7 @@ void writeStorePaths(const Store & store, Sink & out, const StorePathSet & paths out << store.printStorePath(i); } + StorePathCAMap readStorePathCAMap(const Store & store, Source & from) { StorePathCAMap paths; @@ -57,30 +57,36 @@ void writeStorePathCAMap(const Store & store, Sink & out, const StorePathCAMap & } } -std::map<string, StorePath> readOutputPathMap(const Store & store, Source & from) + +namespace worker_proto { + +StorePath read(const Store & store, Source & from, Phantom<StorePath> _) { - std::map<string, StorePath> pathMap; - auto rawInput = readStrings<Strings>(from); - if (rawInput.size() % 2) - throw Error("got an odd number of elements from the daemon when trying to read a output path map"); - auto curInput = rawInput.begin(); - while (curInput != rawInput.end()) { - auto thisKey = *curInput++; - auto thisValue = *curInput++; - pathMap.emplace(thisKey, store.parseStorePath(thisValue)); - } - return pathMap; + return store.parseStorePath(readString(from)); } -void writeOutputPathMap(const Store & store, Sink & out, const std::map<string, StorePath> & pathMap) +void write(const Store & store, Sink & out, const StorePath & storePath) { - out << 2*pathMap.size(); - for (auto & i : pathMap) { - out << i.first; - out << store.printStorePath(i.second); - } + out << store.printStorePath(storePath); +} + + +template<> +std::optional<StorePath> read(const Store & store, Source & from, Phantom<std::optional<StorePath>> _) +{ + auto s = readString(from); + return s == "" ? std::optional<StorePath> {} : store.parseStorePath(s); +} + +template<> +void write(const Store & store, Sink & out, const std::optional<StorePath> & storePathOpt) +{ + out << (storePathOpt ? store.printStorePath(*storePathOpt) : ""); +} + } + /* TODO: Separate these store impls into different files, give them better names */ RemoteStore::RemoteStore(const Params & params) : Store(params) @@ -468,12 +474,12 @@ StorePathSet RemoteStore::queryDerivationOutputs(const StorePath & path) } -OutputPathMap RemoteStore::queryDerivationOutputMap(const StorePath & path) +std::map<std::string, std::optional<StorePath>> RemoteStore::queryPartialDerivationOutputMap(const StorePath & path) { auto conn(getConnection()); conn->to << wopQueryDerivationOutputMap << printStorePath(path); conn.processStderr(); - return readOutputPathMap(*this, conn->from); + return worker_proto::read(*this, conn->from, Phantom<std::map<std::string, std::optional<StorePath>>> {}); } diff --git a/src/libstore/remote-store.hh b/src/libstore/remote-store.hh index 72d2a6689..b319e774b 100644 --- a/src/libstore/remote-store.hh +++ b/src/libstore/remote-store.hh @@ -51,7 +51,7 @@ public: StorePathSet queryDerivationOutputs(const StorePath & path) override; - OutputPathMap queryDerivationOutputMap(const StorePath & path) override; + std::map<std::string, std::optional<StorePath>> queryPartialDerivationOutputMap(const StorePath & path) override; std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override; StorePathSet querySubstitutablePaths(const StorePathSet & paths) override; diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc index 539a66c98..b8ce71f3c 100644 --- a/src/libstore/store-api.cc +++ b/src/libstore/store-api.cc @@ -359,6 +359,17 @@ bool Store::PathInfoCacheValue::isKnownNow() return std::chrono::steady_clock::now() < time_point + ttl; } +OutputPathMap Store::queryDerivationOutputMap(const StorePath & path) { + auto resp = queryPartialDerivationOutputMap(path); + OutputPathMap result; + for (auto & [outName, optOutPath] : resp) { + if (!optOutPath) + throw Error("output '%s' has no store path mapped to it", outName); + result.insert_or_assign(outName, *optOutPath); + } + return result; +} + StorePathSet Store::queryDerivationOutputs(const StorePath & path) { auto outputMap = this->queryDerivationOutputMap(path); diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh index 128682e7a..0ec14b5f2 100644 --- a/src/libstore/store-api.hh +++ b/src/libstore/store-api.hh @@ -343,9 +343,15 @@ public: /* Query the outputs of the derivation denoted by `path'. */ virtual StorePathSet queryDerivationOutputs(const StorePath & path); - /* Query the mapping outputName=>outputPath for the given derivation */ - virtual OutputPathMap queryDerivationOutputMap(const StorePath & path) - { unsupported("queryDerivationOutputMap"); } + /* Query the mapping outputName => outputPath for the given derivation. All + outputs are mentioned so ones mising the mapping are mapped to + `std::nullopt`. */ + virtual std::map<std::string, std::optional<StorePath>> queryPartialDerivationOutputMap(const StorePath & path) + { unsupported("queryPartialDerivationOutputMap"); } + + /* Query the mapping outputName=>outputPath for the given derivation. + Assume every output has a mapping and throw an exception otherwise. */ + OutputPathMap queryDerivationOutputMap(const StorePath & path); /* Query the full store path given the hash part of a valid store path, or empty if the path doesn't exist. */ diff --git a/src/libstore/worker-protocol.hh b/src/libstore/worker-protocol.hh index 5eddaff56..13cf8d4ab 100644 --- a/src/libstore/worker-protocol.hh +++ b/src/libstore/worker-protocol.hh @@ -70,10 +70,84 @@ template<class T> T readStorePaths(const Store & store, Source & from); void writeStorePaths(const Store & store, Sink & out, const StorePathSet & paths); +/* To guide overloading */ +template<typename T> +struct Phantom {}; + + +namespace worker_proto { +/* FIXME maybe move more stuff inside here */ + +StorePath read(const Store & store, Source & from, Phantom<StorePath> _); +void write(const Store & store, Sink & out, const StorePath & storePath); + +template<typename T> +std::map<std::string, T> read(const Store & store, Source & from, Phantom<std::map<std::string, T>> _); +template<typename T> +void write(const Store & store, Sink & out, const std::map<string, T> & resMap); +template<typename T> +std::optional<T> read(const Store & store, Source & from, Phantom<std::optional<T>> _); +template<typename T> +void write(const Store & store, Sink & out, const std::optional<T> & optVal); + +/* Specialization which uses and empty string for the empty case, taking + advantage of the fact StorePaths always serialize to a non-empty string. + This is done primarily for backwards compatability, so that StorePath <= + std::optional<StorePath>, where <= is the compatability partial order. + */ +template<> +void write(const Store & store, Sink & out, const std::optional<StorePath> & optVal); + +template<typename T> +std::map<std::string, T> read(const Store & store, Source & from, Phantom<std::map<std::string, T>> _) +{ + std::map<string, T> resMap; + auto size = (size_t)readInt(from); + while (size--) { + auto thisKey = readString(from); + resMap.insert_or_assign(std::move(thisKey), nix::worker_proto::read(store, from, Phantom<T> {})); + } + return resMap; +} + +template<typename T> +void write(const Store & store, Sink & out, const std::map<string, T> & resMap) +{ + out << resMap.size(); + for (auto & i : resMap) { + out << i.first; + nix::worker_proto::write(store, out, i.second); + } +} + +template<typename T> +std::optional<T> read(const Store & store, Source & from, Phantom<std::optional<T>> _) +{ + auto tag = readNum<uint8_t>(from); + switch (tag) { + case 0: + return std::nullopt; + case 1: + return nix::worker_proto::read(store, from, Phantom<T> {}); + default: + throw Error("got an invalid tag bit for std::optional: %#04x", tag); + } +} + +template<typename T> +void write(const Store & store, Sink & out, const std::optional<T> & optVal) +{ + out << (optVal ? 1 : 0); + if (optVal) + nix::worker_proto::write(store, out, *optVal); +} + + +} + + StorePathCAMap readStorePathCAMap(const Store & store, Source & from); void writeStorePathCAMap(const Store & store, Sink & out, const StorePathCAMap & paths); -void writeOutputPathMap(const Store & store, Sink & out, const OutputPathMap & paths); - } diff --git a/src/nix/develop.cc b/src/nix/develop.cc index 9aaa80822..8a14e45c9 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -138,7 +138,7 @@ StorePath getDerivationEnvironment(ref<Store> store, const StorePath & drvPath) .path = shellOutPath } }); drv.env["out"] = store->printStorePath(shellOutPath); - auto shellDrvPath2 = writeDerivation(store, drv); + auto shellDrvPath2 = writeDerivation(*store, drv); /* Build the derivation. */ store->buildPaths({{shellDrvPath2}}); |