diff --git a/lix/libstore/fs-accessor.hh b/lix/libstore/fs-accessor.hh index b32ac4e72..63d80ceb8 100644 --- a/lix/libstore/fs-accessor.hh +++ b/lix/libstore/fs-accessor.hh @@ -1,7 +1,9 @@ #pragma once ///@file +#include "lix/libutil/result.hh" #include "lix/libutil/types.hh" +#include namespace nix { @@ -33,9 +35,9 @@ public: virtual ~FSAccessor() { } - virtual Stat stat(const Path & path) = 0; + virtual kj::Promise> stat(const Path & path) = 0; - virtual StringSet readDirectory(const Path & path) = 0; + virtual kj::Promise> readDirectory(const Path & path) = 0; /** * Read a file inside the store. @@ -44,9 +46,10 @@ public: * inside a valid store path, otherwise it just needs to be physically * present (but not necessarily properly registered) */ - virtual std::string readFile(const Path & path, bool requireValidPath = true) = 0; + virtual kj::Promise> + readFile(const Path & path, bool requireValidPath = true) = 0; - virtual std::string readLink(const Path & path) = 0; + virtual kj::Promise> readLink(const Path & path) = 0; }; } diff --git a/lix/libstore/local-fs-store.cc b/lix/libstore/local-fs-store.cc index 9428a3cbc..e8df9e0ea 100644 --- a/lix/libstore/local-fs-store.cc +++ b/lix/libstore/local-fs-store.cc @@ -14,38 +14,42 @@ struct LocalStoreAccessor : public FSAccessor LocalStoreAccessor(ref store) : store(store) { } - Path toRealPath(const Path & path, bool requireValidPath = true) - { + kj::Promise> toRealPath(const Path & path, bool requireValidPath = true) + try { auto storePath = store->toStorePath(path).first; if (requireValidPath && !store->isValidPath(storePath)) throw InvalidPath("path '%1%' does not exist in the store", store->printStorePath(storePath)); - return store->getRealStoreDir() + std::string(path, store->config().storeDir.size()); + co_return store->getRealStoreDir() + std::string(path, store->config().storeDir.size()); + } catch (...) { + co_return result::current_exception(); } - FSAccessor::Stat stat(const Path & path) override - { - auto realPath = toRealPath(path); + kj::Promise> stat(const Path & path) override + try { + auto realPath = TRY_AWAIT(toRealPath(path)); struct stat st; if (lstat(realPath.c_str(), &st)) { - if (errno == ENOENT || errno == ENOTDIR) return {Type::tMissing, 0, false}; + if (errno == ENOENT || errno == ENOTDIR) co_return {Type::tMissing, 0, false}; throw SysError("getting status of '%1%'", path); } if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode)) throw Error("file '%1%' has unsupported type", path); - return { + co_return { S_ISREG(st.st_mode) ? Type::tRegular : S_ISLNK(st.st_mode) ? Type::tSymlink : Type::tDirectory, S_ISREG(st.st_mode) ? (uint64_t) st.st_size : 0, S_ISREG(st.st_mode) && st.st_mode & S_IXUSR}; + } catch (...) { + co_return result::current_exception(); } - StringSet readDirectory(const Path & path) override - { - auto realPath = toRealPath(path); + kj::Promise> readDirectory(const Path & path) override + try { + auto realPath = TRY_AWAIT(toRealPath(path)); auto entries = nix::readDirectory(realPath); @@ -53,17 +57,24 @@ struct LocalStoreAccessor : public FSAccessor for (auto & entry : entries) res.insert(entry.name); - return res; + co_return res; + } catch (...) { + co_return result::current_exception(); } - std::string readFile(const Path & path, bool requireValidPath = true) override - { - return nix::readFile(toRealPath(path, requireValidPath)); + kj::Promise> + readFile(const Path & path, bool requireValidPath = true) override + try { + co_return nix::readFile(TRY_AWAIT(toRealPath(path, requireValidPath))); + } catch (...) { + co_return result::current_exception(); } - std::string readLink(const Path & path) override - { - return nix::readLink(toRealPath(path)); + kj::Promise> readLink(const Path & path) override + try { + co_return nix::readLink(TRY_AWAIT(toRealPath(path))); + } catch (...) { + co_return result::current_exception(); } }; diff --git a/lix/libstore/nar-accessor.cc b/lix/libstore/nar-accessor.cc index 3f935f5c7..53037c117 100644 --- a/lix/libstore/nar-accessor.cc +++ b/lix/libstore/nar-accessor.cc @@ -1,5 +1,6 @@ #include "lix/libstore/nar-accessor.hh" #include "lix/libutil/archive.hh" +#include "lix/libutil/async.hh" #include #include @@ -87,11 +88,11 @@ struct NarAccessor : public FSAccessor return *result; } - Stat stat(const Path & path) override - { + kj::Promise> stat(const Path & path) override + try { auto i = find(path); if (i == nullptr) - return {FSAccessor::Type::tMissing, 0, false}; + co_return {FSAccessor::Type::tMissing, 0, false}; auto handlers = overloaded{ [](const nar_index::File & f) { return Stat{tRegular, f.size, f.executable, f.offset}; @@ -99,11 +100,13 @@ struct NarAccessor : public FSAccessor [](const nar_index::Symlink &) { return Stat{tSymlink}; }, [](const nar_index::Directory &) { return Stat{tDirectory}; }, }; - return std::visit(handlers, *i); + co_return std::visit(handlers, *i); + } catch (...) { + co_return result::current_exception(); } - StringSet readDirectory(const Path & path) override - { + kj::Promise> readDirectory(const Path & path) override + try { auto & i = get(path); auto dir = std::get_if(&i); @@ -114,29 +117,36 @@ struct NarAccessor : public FSAccessor for (auto & child : dir->contents) res.insert(child.first); - return res; + co_return res; + } catch (...) { + co_return result::current_exception(); } - std::string readFile(const Path & path, bool requireValidPath = true) override - { + kj::Promise> + readFile(const Path & path, bool requireValidPath = true) override + try { auto & i = get(path); auto file = std::get_if(&i); if (!file) throw Error("path '%1%' inside NAR file is not a regular file", path); - if (getNarBytes) return getNarBytes(file->offset, file->size); + if (getNarBytes) co_return getNarBytes(file->offset, file->size); assert(nar); - return std::string(*nar, file->offset, file->size); + co_return std::string(*nar, file->offset, file->size); + } catch (...) { + co_return result::current_exception(); } - std::string readLink(const Path & path) override - { + kj::Promise> readLink(const Path & path) override + try { auto & i = get(path); auto link = std::get_if(&i); if (!link) throw Error("path '%1%' inside NAR file is not a symlink", path); - return link->target; + co_return link->target; + } catch (...) { + co_return result::current_exception(); } }; @@ -157,9 +167,9 @@ ref makeLazyNarAccessor(const std::string & listing, } using nlohmann::json; -json listNar(ref accessor, const Path & path, bool recurse) -{ - auto st = accessor->stat(path); +kj::Promise> listNar(ref accessor, const Path & path, bool recurse) +try { + auto st = TRY_AWAIT(accessor->stat(path)); json obj = json::object(); @@ -177,9 +187,9 @@ json listNar(ref accessor, const Path & path, bool recurse) { obj["entries"] = json::object(); json &res2 = obj["entries"]; - for (auto & name : accessor->readDirectory(path)) { + for (auto & name : TRY_AWAIT(accessor->readDirectory(path))) { if (recurse) { - res2[name] = listNar(accessor, path + "/" + name, true); + res2[name] = TRY_AWAIT(listNar(accessor, path + "/" + name, true)); } else res2[name] = json::object(); } @@ -187,13 +197,15 @@ json listNar(ref accessor, const Path & path, bool recurse) break; case FSAccessor::Type::tSymlink: obj["type"] = "symlink"; - obj["target"] = accessor->readLink(path); + obj["target"] = TRY_AWAIT(accessor->readLink(path)); break; case FSAccessor::Type::tMissing: default: throw Error("path '%s' does not exist in NAR", path); } - return obj; + co_return obj; +} catch (...) { + co_return result::current_exception(); } static nlohmann::json listNar(const nar_index::Entry & e, Path path) diff --git a/lix/libstore/nar-accessor.hh b/lix/libstore/nar-accessor.hh index 20154bf16..e86031cee 100644 --- a/lix/libstore/nar-accessor.hh +++ b/lix/libstore/nar-accessor.hh @@ -37,7 +37,8 @@ ref makeLazyNarAccessor( * Write a JSON representation of the contents of a NAR (except file * contents). */ -nlohmann::json listNar(ref accessor, const Path & path, bool recurse); +kj::Promise> +listNar(ref accessor, const Path & path, bool recurse); nlohmann::json listNar(const nar_index::Entry & nar); } diff --git a/lix/libstore/remote-fs-accessor.cc b/lix/libstore/remote-fs-accessor.cc index af6d0a4a3..9da86795b 100644 --- a/lix/libstore/remote-fs-accessor.cc +++ b/lix/libstore/remote-fs-accessor.cc @@ -22,8 +22,9 @@ Path RemoteFSAccessor::makeCacheFile(std::string_view hashPart, const std::strin return fmt("%s/%s.%s", cacheDir, hashPart, ext); } -ref RemoteFSAccessor::addToCache(std::string_view hashPart, std::string && nar) -{ +kj::Promise>> +RemoteFSAccessor::addToCache(std::string_view hashPart, std::string && nar) +try { if (cacheDir != "") { try { /* FIXME: do this asynchronously. */ @@ -38,18 +39,21 @@ ref RemoteFSAccessor::addToCache(std::string_view hashPart, std::str if (cacheDir != "") { try { - nlohmann::json j = listNar(narAccessor, "", true); + nlohmann::json j = TRY_AWAIT(listNar(narAccessor, "", true)); writeFile(makeCacheFile(hashPart, "ls"), j.dump()); } catch (...) { ignoreExceptionExceptInterrupt(); } } - return narAccessor; + co_return narAccessor; +} catch (...) { + co_return result::current_exception(); } -std::pair, Path> RemoteFSAccessor::fetch(const Path & path_, bool requireValidPath) -{ +kj::Promise, Path>>> +RemoteFSAccessor::fetch(const Path & path_, bool requireValidPath) +try { auto path = canonPath(path_); auto [storePath, restPath] = store->toStorePath(path); @@ -58,7 +62,7 @@ std::pair, Path> RemoteFSAccessor::fetch(const Path & path_, boo throw InvalidPath("path '%1%' does not exist in remote store", store->printStorePath(storePath)); auto i = nars.find(std::string(storePath.hashPart())); - if (i != nars.end()) return {i->second, restPath}; + if (i != nars.end()) co_return {i->second, restPath}; std::string listing; Path cacheFile; @@ -85,44 +89,55 @@ std::pair, Path> RemoteFSAccessor::fetch(const Path & path_, boo }); nars.emplace(storePath.hashPart(), narAccessor); - return {narAccessor, restPath}; + co_return {narAccessor, restPath}; } catch (SysError &) { } try { auto narAccessor = makeNarAccessor(nix::readFile(cacheFile)); nars.emplace(storePath.hashPart(), narAccessor); - return {narAccessor, restPath}; + co_return {narAccessor, restPath}; } catch (SysError &) { } } StringSink sink; store->narFromPath(storePath)->drainInto(sink); - return {addToCache(storePath.hashPart(), std::move(sink.s)), restPath}; + co_return {TRY_AWAIT(addToCache(storePath.hashPart(), std::move(sink.s))), restPath}; +} catch (...) { + co_return result::current_exception(); } -FSAccessor::Stat RemoteFSAccessor::stat(const Path & path) -{ - auto res = fetch(path); - return res.first->stat(res.second); +kj::Promise> RemoteFSAccessor::stat(const Path & path) +try { + auto res = TRY_AWAIT(fetch(path)); + co_return TRY_AWAIT(res.first->stat(res.second)); +} catch (...) { + co_return result::current_exception(); } -StringSet RemoteFSAccessor::readDirectory(const Path & path) -{ - auto res = fetch(path); - return res.first->readDirectory(res.second); +kj::Promise> RemoteFSAccessor::readDirectory(const Path & path) +try { + auto res = TRY_AWAIT(fetch(path)); + co_return TRY_AWAIT(res.first->readDirectory(res.second)); +} catch (...) { + co_return result::current_exception(); } -std::string RemoteFSAccessor::readFile(const Path & path, bool requireValidPath) -{ - auto res = fetch(path, requireValidPath); - return res.first->readFile(res.second); +kj::Promise> +RemoteFSAccessor::readFile(const Path & path, bool requireValidPath) +try { + auto res = TRY_AWAIT(fetch(path, requireValidPath)); + co_return TRY_AWAIT(res.first->readFile(res.second)); +} catch (...) { + co_return result::current_exception(); } -std::string RemoteFSAccessor::readLink(const Path & path) -{ - auto res = fetch(path); - return res.first->readLink(res.second); +kj::Promise> RemoteFSAccessor::readLink(const Path & path) +try { + auto res = TRY_AWAIT(fetch(path)); + co_return TRY_AWAIT(res.first->readLink(res.second)); +} catch (...) { + co_return result::current_exception(); } } diff --git a/lix/libstore/remote-fs-accessor.hh b/lix/libstore/remote-fs-accessor.hh index b6e5c567f..11b0e3d91 100644 --- a/lix/libstore/remote-fs-accessor.hh +++ b/lix/libstore/remote-fs-accessor.hh @@ -15,26 +15,28 @@ class RemoteFSAccessor : public FSAccessor Path cacheDir; - std::pair, Path> fetch(const Path & path_, bool requireValidPath = true); + kj::Promise, Path>>> + fetch(const Path & path_, bool requireValidPath = true); friend class BinaryCacheStore; Path makeCacheFile(std::string_view hashPart, const std::string & ext); - ref addToCache(std::string_view hashPart, std::string && nar); + kj::Promise>> addToCache(std::string_view hashPart, std::string && nar); public: RemoteFSAccessor(ref store, const /* FIXME: use std::optional */ Path & cacheDir = ""); - Stat stat(const Path & path) override; + kj::Promise> stat(const Path & path) override; - StringSet readDirectory(const Path & path) override; + kj::Promise> readDirectory(const Path & path) override; - std::string readFile(const Path & path, bool requireValidPath = true) override; + kj::Promise> + readFile(const Path & path, bool requireValidPath = true) override; - std::string readLink(const Path & path) override; + kj::Promise> readLink(const Path & path) override; }; } diff --git a/lix/libstore/store-api.cc b/lix/libstore/store-api.cc index c70e9ddaa..b78147f00 100644 --- a/lix/libstore/store-api.cc +++ b/lix/libstore/store-api.cc @@ -1392,9 +1392,11 @@ readDerivationCommon(Store& store, const StorePath& drvPath, bool requireValidPa try { auto accessor = store.getFSAccessor(); try { - co_return parseDerivation(store, - accessor->readFile(store.printStorePath(drvPath), requireValidPath), - Derivation::nameFromPath(drvPath)); + co_return parseDerivation( + store, + TRY_AWAIT(accessor->readFile(store.printStorePath(drvPath), requireValidPath)), + Derivation::nameFromPath(drvPath) + ); } catch (FormatError & e) { throw Error("error parsing derivation '%s': %s", store.printStorePath(drvPath), e.msg()); } diff --git a/lix/nix/cat.cc b/lix/nix/cat.cc index 8dddb847c..032bd23c4 100644 --- a/lix/nix/cat.cc +++ b/lix/nix/cat.cc @@ -11,13 +11,13 @@ struct MixCat : virtual Args void cat(ref accessor) { - auto st = accessor->stat(path); + auto st = aio().blockOn(accessor->stat(path)); if (st.type == FSAccessor::Type::tMissing) throw Error("path '%1%' does not exist", path); if (st.type != FSAccessor::Type::tRegular) throw Error("path '%1%' is not a regular file", path); - auto file = accessor->readFile(path); + auto file = aio().blockOn(accessor->readFile(path)); logger->pause(); writeFull(STDOUT_FILENO, file); diff --git a/lix/nix/ls.cc b/lix/nix/ls.cc index 34c3decf8..a748a6ce8 100644 --- a/lix/nix/ls.cc +++ b/lix/nix/ls.cc @@ -45,7 +45,7 @@ struct MixLs : virtual Args, MixJSON auto showFile = [&](const Path & curPath, const std::string & relPath) { if (verbose) { - auto st = accessor->stat(curPath); + auto st = aio().blockOn(accessor->stat(curPath)); std::string tp = st.type == FSAccessor::Type::tRegular ? (st.isExecutable ? "-r-xr-xr-x" : "-r--r--r--") : @@ -53,14 +53,14 @@ struct MixLs : virtual Args, MixJSON "dr-xr-xr-x"; auto line = fmt("%s %20d %s", tp, st.fileSize, relPath); if (st.type == FSAccessor::Type::tSymlink) - line += " -> " + accessor->readLink(curPath); + line += " -> " + aio().blockOn(accessor->readLink(curPath)); logger->cout(line); if (recursive && st.type == FSAccessor::Type::tDirectory) doPath(st, curPath, relPath, false); } else { logger->cout(relPath); if (recursive) { - auto st = accessor->stat(curPath); + auto st = aio().blockOn(accessor->stat(curPath)); if (st.type == FSAccessor::Type::tDirectory) doPath(st, curPath, relPath, false); } @@ -71,14 +71,14 @@ struct MixLs : virtual Args, MixJSON const std::string & relPath, bool showDirectory) { if (st.type == FSAccessor::Type::tDirectory && !showDirectory) { - auto names = accessor->readDirectory(curPath); + auto names = aio().blockOn(accessor->readDirectory(curPath)); for (auto & name : names) showFile(curPath + "/" + name, relPath + "/" + name); } else showFile(curPath, relPath); }; - auto st = accessor->stat(path); + auto st = aio().blockOn(accessor->stat(path)); if (st.type == FSAccessor::Type::tMissing) throw Error("path '%1%' does not exist", path); doPath(st, path, @@ -93,7 +93,7 @@ struct MixLs : virtual Args, MixJSON if (json) { if (showDirectory) throw UsageError("'--directory' is useless with '--json'"); - logger->cout("%s", listNar(accessor, path, recursive)); + logger->cout("%s", aio().blockOn(listNar(accessor, path, recursive))); } else listText(accessor); } diff --git a/lix/nix/run.cc b/lix/nix/run.cc index dcd81037b..e24f9f554 100644 --- a/lix/nix/run.cc +++ b/lix/nix/run.cc @@ -139,7 +139,7 @@ struct CmdShell : InstallablesCommand, MixEnvironment pathAdditions.push_back(store->printStorePath(path) + "/bin"); auto propPath = store->printStorePath(path) + "/nix-support/propagated-user-env-packages"; - if (accessor->stat(propPath).type == FSAccessor::tRegular) { + if (aio().blockOn(accessor->stat(propPath)).type == FSAccessor::tRegular) { for (auto & p : tokenizeString(readFile(propPath))) todo.push(store->parseStorePath(p)); } diff --git a/lix/nix/why-depends.cc b/lix/nix/why-depends.cc index fb2923d23..d5fa6cdea 100644 --- a/lix/nix/why-depends.cc +++ b/lix/nix/why-depends.cc @@ -213,7 +213,7 @@ struct CmdWhyDepends : SourceExprCommand, MixOperateOnOptions std::function visitPath; visitPath = [&](const Path & p) { - auto st = accessor->stat(p); + auto st = aio().blockOn(accessor->stat(p)); auto p2 = p == pathS ? "/" : std::string(p, pathS.size() + 1); @@ -222,13 +222,13 @@ struct CmdWhyDepends : SourceExprCommand, MixOperateOnOptions }; if (st.type == FSAccessor::Type::tDirectory) { - auto names = accessor->readDirectory(p); + auto names = aio().blockOn(accessor->readDirectory(p)); for (auto & name : names) visitPath(p + "/" + name); } else if (st.type == FSAccessor::Type::tRegular) { - auto contents = accessor->readFile(p); + auto contents = aio().blockOn(accessor->readFile(p)); for (auto & hash : hashes) { auto pos = contents.find(hash); @@ -246,7 +246,7 @@ struct CmdWhyDepends : SourceExprCommand, MixOperateOnOptions } else if (st.type == FSAccessor::Type::tSymlink) { - auto target = accessor->readLink(p); + auto target = aio().blockOn(accessor->readLink(p)); for (auto & hash : hashes) { auto pos = target.find(hash);