diff --git a/lix/legacy/nix-channel.cc b/lix/legacy/nix-channel.cc index e6a2eb3ca..26055d4c0 100644 --- a/lix/legacy/nix-channel.cc +++ b/lix/legacy/nix-channel.cc @@ -9,6 +9,7 @@ #include "lix/libstore/temporary-dir.hh" #include "lix/libutil/async.hh" #include "lix/libutil/regex.hh" +#include "lix/libutil/result.hh" #include "lix/libutil/users.hh" #include "nix-channel.hh" @@ -65,13 +66,18 @@ static void addChannel(const std::string & url, const std::string & name) static Path profile; // Remove a channel. -static void removeChannel(const std::string & name) -{ +static kj::Promise> removeChannel(const std::string & name) +try { readChannels(); channels.erase(name); writeChannels(); - runProgram(settings.nixBinDir + "/nix-env", true, { "--profile", profile, "--uninstall", name }); + TRY_AWAIT(runProgram( + settings.nixBinDir + "/nix-env", true, {"--profile", profile, "--uninstall", name} + )); + co_return result::success(); +} catch (...) { + co_return result::current_exception(); } static Path nixDefExpr; @@ -127,8 +133,14 @@ static void update(AsyncIoRoot & aio, const StringSet & channelNames) bool unpacked = false; if (std::regex_search(filename, regex::parse("\\.tar\\.(gz|bz2|xz)$"))) { - runProgram(settings.nixBinDir + "/nix-build", false, { "--no-out-link", "--expr", "import " + unpackChannelPath + - "{ name = \"" + cname + "\"; channelName = \"" + name + "\"; src = builtins.storePath \"" + filename + "\"; }" }); + aio.blockOn(runProgram( + settings.nixBinDir + "/nix-build", + false, + {"--no-out-link", + "--expr", + "import " + unpackChannelPath + "{ name = \"" + cname + "\"; channelName = \"" + + name + "\"; src = builtins.storePath \"" + filename + "\"; }"} + )); unpacked = true; } @@ -158,7 +170,7 @@ static void update(AsyncIoRoot & aio, const StringSet & channelNames) for (auto & expr : exprs) envArgs.push_back(std::move(expr)); envArgs.push_back("--quiet"); - runProgram(settings.nixBinDir + "/nix-env", false, envArgs); + aio.blockOn(runProgram(settings.nixBinDir + "/nix-env", false, envArgs)); // Make the channels appear in nix-env. struct stat st; @@ -244,7 +256,7 @@ static int main_nix_channel(AsyncIoRoot & aio, std::string programName, Strings case cRemove: if (args.size() != 1) throw UsageError("'--remove' requires one argument"); - removeChannel(args[0]); + aio.blockOn(removeChannel(args[0])); break; case cList: if (!args.empty()) @@ -259,7 +271,11 @@ static int main_nix_channel(AsyncIoRoot & aio, std::string programName, Strings case cListGenerations: if (!args.empty()) throw UsageError("'--list-generations' expects no arguments"); - std::cout << runProgram(settings.nixBinDir + "/nix-env", false, {"--profile", profile, "--list-generations"}) << std::flush; + std::cout << aio.blockOn(runProgram( + settings.nixBinDir + "/nix-env", + false, + {"--profile", profile, "--list-generations"} + )) << std::flush; break; case cRollback: if (args.size() > 1) @@ -271,7 +287,7 @@ static int main_nix_channel(AsyncIoRoot & aio, std::string programName, Strings } else { envArgs.push_back("--rollback"); } - runProgram(settings.nixBinDir + "/nix-env", false, envArgs); + aio.blockOn(runProgram(settings.nixBinDir + "/nix-env", false, envArgs)); break; } diff --git a/lix/libexpr/primops.cc b/lix/libexpr/primops.cc index 6782c4664..580346bd9 100644 --- a/lix/libexpr/primops.cc +++ b/lix/libexpr/primops.cc @@ -321,7 +321,7 @@ void prim_exec(EvalState & state, Value * * args, Value & v) throw; } - auto output = runProgram(program, true, commandArgs); + auto output = state.aio.blockOn(runProgram(program, true, commandArgs)); Expr * parsed; try { parsed = &state.ctx.parseExprFromString(std::move(output), CanonPath::root); diff --git a/lix/libfetchers/git.cc b/lix/libfetchers/git.cc index 67f0b3fd4..92d29afd9 100644 --- a/lix/libfetchers/git.cc +++ b/lix/libfetchers/git.cc @@ -69,12 +69,12 @@ Path getCachePath(std::string_view key) // ... static kj::Promise>> readHead(const Path & path) try { - auto [status, output] = runProgram(RunOptions { + auto [status, output] = TRY_AWAIT(runProgram(RunOptions{ .program = "git", // FIXME: use 'HEAD' to avoid returning all refs .args = {"ls-remote", "--symref", path}, .isInteractive = true, - }); + })); if (status != 0) { co_return std::nullopt; } @@ -103,9 +103,13 @@ storeCachedHead(const std::string & actualUrl, const std::string & headRef) try { Path cacheDir = getCachePath(actualUrl); try { - runProgram("git", true, { "-C", cacheDir, "--git-dir", ".", "symbolic-ref", "--", "HEAD", headRef }); - } catch (ExecError &e) { - if (!WIFEXITED(e.status)) throw; + TRY_AWAIT(runProgram( + "git", true, {"-C", cacheDir, "--git-dir", ".", "symbolic-ref", "--", "HEAD", headRef} + )); + } catch (ExecError & e) { + if (!WIFEXITED(e.status)) { + throw; + } co_return false; } /* No need to touch refs/HEAD, because `git symbolic-ref` updates the mtime. */ @@ -182,7 +186,7 @@ try { /* Check whether HEAD points to something that looks like a commit, since that is the refrence we want to use later on. */ - auto result = runProgram(RunOptions{ + auto result = TRY_AWAIT(runProgram(RunOptions{ .program = "git", .args = {"-C", @@ -195,7 +199,7 @@ try { "HEAD^{commit}"}, .environment = env, .redirections = {{.dup = STDERR_FILENO, .from = STDOUT_FILENO}}, - }); + })); auto exitCode = WEXITSTATUS(result.first); auto errorMessage = result.second; @@ -223,7 +227,7 @@ try { gitDiffOpts.emplace_back("--ignore-submodules"); } gitDiffOpts.emplace_back("--"); - runProgram("git", true, gitDiffOpts); + TRY_AWAIT(runProgram("git", true, gitDiffOpts)); clean = true; } @@ -252,8 +256,8 @@ try { if (submodules) gitOpts.emplace_back("--recurse-submodules"); - auto files = tokenizeString>( - runProgram("git", true, gitOpts), "\0"s); + auto files = + tokenizeString>(TRY_AWAIT(runProgram("git", true, gitOpts)), "\0"s); Path actualPath(absPath(workdir)); @@ -280,13 +284,39 @@ try { // modified dirty file? input.attrs.insert_or_assign( "lastModified", - workdirInfo.hasHead ? std::stoull(runProgram("git", true, { "-C", actualPath, "--git-dir", gitDir, "log", "-1", "--format=%ct", "--no-show-signature", "HEAD" })) : 0); + workdirInfo.hasHead ? std::stoull(TRY_AWAIT(runProgram( + "git", + true, + {"-C", + actualPath, + "--git-dir", + gitDir, + "log", + "-1", + "--format=%ct", + "--no-show-signature", + "HEAD"} + ))) + : 0 + ); if (workdirInfo.hasHead) { - input.attrs.insert_or_assign("dirtyRev", chomp( - runProgram("git", true, { "-C", actualPath, "--git-dir", gitDir, "rev-parse", "--verify", "HEAD" })) + "-dirty"); - input.attrs.insert_or_assign("dirtyShortRev", chomp( - runProgram("git", true, { "-C", actualPath, "--git-dir", gitDir, "rev-parse", "--verify", "--short", "HEAD" })) + "-dirty"); + input.attrs.insert_or_assign( + "dirtyRev", + chomp(TRY_AWAIT(runProgram( + "git", + true, + {"-C", actualPath, "--git-dir", gitDir, "rev-parse", "--verify", "HEAD"} + ))) + "-dirty" + ); + input.attrs.insert_or_assign( + "dirtyShortRev", + chomp(TRY_AWAIT(runProgram( + "git", + true, + {"-C", actualPath, "--git-dir", gitDir, "rev-parse", "--verify", "--short", "HEAD"} + ))) + "-dirty" + ); } co_return {std::move(storePath), input}; @@ -429,7 +459,7 @@ struct GitInputScheme : InputScheme args.push_back(destDir); - runProgram("git", true, args, true); + TRY_AWAIT(runProgram("git", true, args, true)); co_return result::success(); } catch (...) { co_return result::current_exception(); @@ -458,25 +488,52 @@ struct GitInputScheme : InputScheme auto gitDir = ".git"; - auto result = runProgram(RunOptions { + auto result = TRY_AWAIT(runProgram(RunOptions{ .program = "git", - .args = {"-C", *root, "--git-dir", gitDir, "check-ignore", "--quiet", std::string(path.rel())}, - }); + .args = + {"-C", + *root, + "--git-dir", + gitDir, + "check-ignore", + "--quiet", + std::string(path.rel())}, + })); auto exitCode = WEXITSTATUS(result.first); if (exitCode != 0) { // The path is not `.gitignore`d, we can add the file. - runProgram("git", true, - { "-C", *root, "--git-dir", gitDir, "add", "--intent-to-add", "--", std::string(path.rel()) }); - + TRY_AWAIT(runProgram( + "git", + true, + {"-C", + *root, + "--git-dir", + gitDir, + "add", + "--intent-to-add", + "--", + std::string(path.rel())} + )); if (commitMsg) { auto [_fd, msgPath] = createTempFile("nix-msg"); AutoDelete const _delete{msgPath}; writeFile(msgPath, *commitMsg); - runProgram("git", true, - { "-C", *root, "--git-dir", gitDir, "commit", std::string(path.rel()), "-F", msgPath }, true); + TRY_AWAIT(runProgram( + "git", + true, + {"-C", + *root, + "--git-dir", + gitDir, + "commit", + std::string(path.rel()), + "-F", + msgPath}, + true + )); } } @@ -582,8 +639,18 @@ struct GitInputScheme : InputScheme } if (!input.getRev()) - input.attrs.insert_or_assign("rev", - Hash::parseAny(chomp(runProgram("git", true, { "-C", actualUrl, "--git-dir", gitDir, "rev-parse", *input.getRef() })), HashType::SHA1).gitRev()); + input.attrs.insert_or_assign( + "rev", + Hash::parseAny( + chomp(TRY_AWAIT(runProgram( + "git", + true, + {"-C", actualUrl, "--git-dir", gitDir, "rev-parse", *input.getRef()} + ))), + HashType::SHA1 + ) + .gitRev() + ); repoDir = actualUrl; } else { @@ -620,7 +687,11 @@ struct GitInputScheme : InputScheme PathLock cacheDirLock = TRY_AWAIT(lockPathAsync(cacheDir + ".lock")); if (!pathExists(cacheDir)) { - runProgram("git", true, { "-c", "init.defaultBranch=" + gitInitialBranch, "init", "--bare", repoDir }); + TRY_AWAIT(runProgram( + "git", + true, + {"-c", "init.defaultBranch=" + gitInitialBranch, "init", "--bare", repoDir} + )); } std::vector gitRefFileCandidates; @@ -638,7 +709,17 @@ struct GitInputScheme : InputScheme repo. */ if (input.getRev()) { try { - runProgram("git", true, { "-C", repoDir, "--git-dir", gitDir, "cat-file", "-e", input.getRev()->gitRev() }); + TRY_AWAIT(runProgram( + "git", + true, + {"-C", + repoDir, + "--git-dir", + gitDir, + "cat-file", + "-e", + input.getRev()->gitRev()} + )); doFetch = false; } catch (ExecError & e) { if (WIFEXITED(e.status)) { @@ -707,14 +788,21 @@ struct GitInputScheme : InputScheme // FIXME: git stderr messes up our progress indicator, so // we're using --quiet for now. Should process its stderr. - runProgram("git", true, { - "-C", repoDir, - "--git-dir", gitDir, - "fetch", - "--quiet", - "--force", - "--", actualUrl, fmt("%s:%s", fetchRef, fetchRef) - }, true); + TRY_AWAIT(runProgram( + "git", + true, + {"-C", + repoDir, + "--git-dir", + gitDir, + "fetch", + "--quiet", + "--force", + "--", + actualUrl, + fmt("%s:%s", fetchRef, fetchRef)}, + true + )); } catch (Error & e) { if (!pathExists(localRefFile)) throw; printTaggedWarning( @@ -741,7 +829,13 @@ struct GitInputScheme : InputScheme // cache dir lock is removed at scope end; we will only use read-only operations on specific revisions in the remainder } - bool isShallow = chomp(runProgram("git", true, { "-C", repoDir, "--git-dir", gitDir, "rev-parse", "--is-shallow-repository" })) == "true"; + bool isShallow = + chomp(TRY_AWAIT(runProgram( + "git", + true, + {"-C", repoDir, "--git-dir", gitDir, "rev-parse", "--is-shallow-repository"} + ))) + == "true"; if (isShallow && !shallow) throw Error("'%s' is a shallow Git repository, but shallow repositories are only allowed when `shallow = true;` is specified.", actualUrl); @@ -759,13 +853,13 @@ struct GitInputScheme : InputScheme AutoDelete delTmpDir(tmpDir, true); PathFilter filter = defaultPathFilter; - auto result = runProgram(RunOptions{ + auto result = TRY_AWAIT(runProgram(RunOptions{ .program = "git", .args = {"-C", repoDir, "--git-dir", gitDir, "cat-file", "commit", input.getRev()->gitRev() }, .redirections = {{.dup = STDERR_FILENO, .from = STDOUT_FILENO}}, - }); + })); if (WEXITSTATUS(result.first) == 128 && result.second.find("bad file") != std::string::npos) { @@ -784,18 +878,41 @@ struct GitInputScheme : InputScheme Path tmpGitDir = createTempDir(); AutoDelete delTmpGitDir(tmpGitDir, true); - runProgram("git", true, { "-c", "init.defaultBranch=" + gitInitialBranch, "init", tmpDir, "--separate-git-dir", tmpGitDir }); + TRY_AWAIT(runProgram( + "git", + true, + {"-c", + "init.defaultBranch=" + gitInitialBranch, + "init", + tmpDir, + "--separate-git-dir", + tmpGitDir} + )); { // TODO: repoDir might lack the ref (it only checks if rev // exists, see FIXME above) so use a big hammer and fetch // everything to ensure we get the rev. Activity act(*logger, lvlTalkative, actUnknown, fmt("making temporary clone of '%s'", repoDir)); - runProgram("git", true, { "-C", tmpDir, "fetch", "--quiet", "--force", - "--update-head-ok", "--", repoDir, "refs/*:refs/*" }, true); + TRY_AWAIT(runProgram( + "git", + true, + {"-C", + tmpDir, + "fetch", + "--quiet", + "--force", + "--update-head-ok", + "--", + repoDir, + "refs/*:refs/*"}, + true + )); } - runProgram("git", true, { "-C", tmpDir, "checkout", "--quiet", input.getRev()->gitRev() }); + TRY_AWAIT(runProgram( + "git", true, {"-C", tmpDir, "checkout", "--quiet", input.getRev()->gitRev()} + )); /* Ensure that we use the correct origin for fetching submodules. This matters for submodules with relative @@ -805,21 +922,29 @@ struct GitInputScheme : InputScheme /* Restore the config.bare setting we may have just copied erroneously from the user's repo. */ - runProgram("git", true, { "-C", tmpDir, "config", "core.bare", "false" }); + TRY_AWAIT(runProgram("git", true, {"-C", tmpDir, "config", "core.bare", "false"})); } else - runProgram("git", true, { "-C", tmpDir, "config", "remote.origin.url", actualUrl }); + TRY_AWAIT(runProgram( + "git", true, {"-C", tmpDir, "config", "remote.origin.url", actualUrl} + )); /* As an optimisation, copy the modules directory of the source repo if it exists. */ auto modulesPath = repoDir + "/" + gitDir + "/modules"; if (pathExists(modulesPath)) { Activity act(*logger, lvlTalkative, actUnknown, fmt("copying submodules of '%s'", actualUrl)); - runProgram("cp", true, { "-R", "--", modulesPath, tmpGitDir + "/modules" }); + TRY_AWAIT(runProgram("cp", true, {"-R", "--", modulesPath, tmpGitDir + "/modules"}) + ); } { Activity act(*logger, lvlTalkative, actUnknown, fmt("fetching submodules of '%s'", actualUrl)); - runProgram("git", true, { "-C", tmpDir, "submodule", "--quiet", "update", "--init", "--recursive" }, true); + TRY_AWAIT(runProgram( + "git", + true, + {"-C", tmpDir, "submodule", "--quiet", "update", "--init", "--recursive"}, + true + )); } filter = isNotDotGitDirectory; @@ -839,7 +964,19 @@ struct GitInputScheme : InputScheme store->addToStoreRecursive(name, *prepareDump(tmpDir, filter), HashType::SHA256) ); - auto lastModified = std::stoull(runProgram("git", true, { "-C", repoDir, "--git-dir", gitDir, "log", "-1", "--format=%ct", "--no-show-signature", input.getRev()->gitRev() })); + auto lastModified = std::stoull(TRY_AWAIT(runProgram( + "git", + true, + {"-C", + repoDir, + "--git-dir", + gitDir, + "log", + "-1", + "--format=%ct", + "--no-show-signature", + input.getRev()->gitRev()} + ))); Attrs infoAttrs({ {"rev", input.getRev()->gitRev()}, @@ -847,8 +984,20 @@ struct GitInputScheme : InputScheme }); if (!shallow) - infoAttrs.insert_or_assign("revCount", - std::stoull(runProgram("git", true, { "-C", repoDir, "--git-dir", gitDir, "rev-list", "--count", input.getRev()->gitRev() }))); + infoAttrs.insert_or_assign( + "revCount", + std::stoull(TRY_AWAIT(runProgram( + "git", + true, + {"-C", + repoDir, + "--git-dir", + gitDir, + "rev-list", + "--count", + input.getRev()->gitRev()} + ))) + ); if (!_input.getRev()) getCache()->add( diff --git a/lix/libfetchers/mercurial.cc b/lix/libfetchers/mercurial.cc index 92a427317..5472c1639 100644 --- a/lix/libfetchers/mercurial.cc +++ b/lix/libfetchers/mercurial.cc @@ -37,7 +37,7 @@ static kj::Promise> runHg(const Strings & args) try { RunOptions opts = hgOptions(args); - auto res = runProgram(std::move(opts)); + auto res = TRY_AWAIT(runProgram(std::move(opts))); if (!statusOk(res.first)) throw ExecError(res.first, "hg %1%", statusToString(res.first)); @@ -300,9 +300,12 @@ struct MercurialInputScheme : InputScheme /* If this is a commit hash that we already have, we don't have to pull again. */ - if (!(input.getRev() - && pathExists(cacheDir) - && runProgram(hgOptions({ "identify", "-R", cacheDir, "-r", revOrRef, "--template", "1" })).second == "1")) + if (!(input.getRev() && pathExists(cacheDir) + && TRY_AWAIT(runProgram(hgOptions( + {"identify", "-R", cacheDir, "-r", revOrRef, "--template", "1"} + ))) + .second + == "1")) { Activity act(*logger, lvlTalkative, actUnknown, fmt("fetching Mercurial repository '%s'", actualUrl)); diff --git a/lix/libstore/build/local-derivation-goal.cc b/lix/libstore/build/local-derivation-goal.cc index a9ac614d5..58988b563 100644 --- a/lix/libstore/build/local-derivation-goal.cc +++ b/lix/libstore/build/local-derivation-goal.cc @@ -74,23 +74,27 @@ extern "C" int sandbox_init_with_parameters(const char *profile, uint64_t flags, namespace nix { -void handleDiffHook( - uid_t uid, uid_t gid, - const Path & tryA, const Path & tryB, - const Path & drvPath, const Path & tmpDir) -{ +static kj::Promise> handleDiffHook( + uid_t uid, + uid_t gid, + const Path & tryA, + const Path & tryB, + const Path & drvPath, + const Path & tmpDir +) +try { auto & diffHookOpt = settings.diffHook.get(); if (diffHookOpt && settings.runDiffHook) { auto & diffHook = *diffHookOpt; try { - auto diffRes = runProgram(RunOptions { + auto diffRes = TRY_AWAIT(runProgram(RunOptions{ .program = diffHook, .searchPath = true, .args = {tryA, tryB, drvPath, tmpDir}, .uid = uid, .gid = gid, .chdir = "/" - }); + })); if (!statusOk(diffRes.first)) throw ExecError(diffRes.first, "diff-hook program '%1%' %2%", @@ -107,6 +111,9 @@ void handleDiffHook( logError(ei); } } + co_return result::success(); +} catch (...) { + co_return result::current_exception(); } const Path LocalDerivationGoal::homeDir = "/homeless-shelter"; @@ -724,7 +731,7 @@ try { auto state = stBegin; std::string lines; try { - runProgram(settings.preBuildHook, false, args); + TRY_AWAIT(runProgram(settings.preBuildHook, false, args)); } catch (nix::Error & e) { e.addTrace(nullptr, "while running pre-build-hook %s for derivation %s", @@ -2151,10 +2158,14 @@ try { deletePath(dst); movePath(actualPath, dst); - handleDiffHook( + TRY_AWAIT(handleDiffHook( buildUser ? buildUser->getUID() : getuid(), buildUser ? buildUser->getGID() : getgid(), - finalDestPath, dst, worker.store.printStorePath(drvPath), tmpDir); + finalDestPath, + dst, + worker.store.printStorePath(drvPath), + tmpDir + )); nondeterministic.push_back(std::make_pair(worker.store.toRealPath(finalDestPath), dst)); } else diff --git a/lix/libstore/gc.cc b/lix/libstore/gc.cc index 5590f446c..659750eff 100644 --- a/lix/libstore/gc.cc +++ b/lix/libstore/gc.cc @@ -366,8 +366,9 @@ try { // platform-specific code in lix/libstore/platform/ try { std::regex lsofRegex = regex::parse(R"(^n(/.*)$)"); - auto lsofLines = - tokenizeString>(runProgram(LSOF, true, { "-n", "-w", "-F", "n" }), "\n"); + auto lsofLines = tokenizeString>( + TRY_AWAIT(runProgram(LSOF, true, {"-n", "-w", "-F", "n"})), "\n" + ); for (const auto & line : lsofLines) { std::smatch match; if (std::regex_match(line, match, lsofRegex)) diff --git a/lix/libstore/globals.cc b/lix/libstore/globals.cc index ad9c7435e..72ad0316d 100644 --- a/lix/libstore/globals.cc +++ b/lix/libstore/globals.cc @@ -243,16 +243,23 @@ StringSet Settings::getDefaultExtraPlatforms() // machines. Note that we can’t force processes from executing // x86_64 in aarch64 environments or vice versa since they can // always exec with their own binary preferences. - if (std::string{SYSTEM} == "aarch64-darwin" - && runProgram(RunOptions{ - .program = "arch", - .args = {"-arch", "x86_64", "/usr/bin/true"}, - .redirections = {{.dup = STDERR_FILENO, .from = STDOUT_FILENO}} - } - ).first + if (std::string{SYSTEM} == "aarch64-darwin") { + AutoCloseFD null(open("/dev/null", O_RDWR | O_CLOEXEC)); + if (!null) { + throw Error("could not open /dev/null"); + } + if (runProgram2(RunOptions{ + .program = "arch", + .args = {"-arch", "x86_64", "/usr/bin/true"}, + .redirections = + {{.dup = STDOUT_FILENO, .from = null.get()}, + {.dup = STDERR_FILENO, .from = null.get()}} + } + ).wait() == 0) - { - extraPlatforms.insert("x86_64-darwin"); + { + extraPlatforms.insert("x86_64-darwin"); + } } #endif diff --git a/lix/libutil/processes.cc b/lix/libutil/processes.cc index 25f40eb5e..dd04fdfd1 100644 --- a/lix/libutil/processes.cc +++ b/lix/libutil/processes.cc @@ -1,3 +1,4 @@ +#include "async-io.hh" #include "lix/libutil/current-process.hh" #include "lix/libutil/environment-variables.hh" #include "lix/libutil/finally.hh" @@ -228,19 +229,25 @@ Pid startProcess(std::function fun, const ProcessOptions & options) return Pid{pid}; } -std::string runProgram(Path program, bool searchPath, const Strings & args, bool isInteractive) -{ - auto res = runProgram(RunOptions {.program = program, .searchPath = searchPath, .args = args, .isInteractive = isInteractive}); +kj::Promise> +runProgram(Path program, bool searchPath, const Strings args, bool isInteractive) +try { + auto res = TRY_AWAIT(runProgram(RunOptions{ + .program = program, .searchPath = searchPath, .args = args, .isInteractive = isInteractive + })); - if (!statusOk(res.first)) + if (!statusOk(res.first)) { throw ExecError(res.first, "program '%1%' %2%", program, statusToString(res.first)); + } - return res.second; + co_return res.second; +} catch (...) { + co_return result::current_exception(); } // Output = error code + "standard out" output stream -std::pair runProgram(RunOptions && options) -{ +kj::Promise>> runProgram(RunOptions options) +try { options.captureStdout = true; int status = 0; @@ -254,7 +261,9 @@ std::pair runProgram(RunOptions && options) status = e.status; } - return {status, std::move(stdout)}; + co_return {status, std::move(stdout)}; +} catch (...) { + co_return result::current_exception(); } RunningProgram::RunningProgram(PathView program, Pid pid, AutoCloseFD stdout) diff --git a/lix/libutil/processes.hh b/lix/libutil/processes.hh index afd302f2a..11beda0d1 100644 --- a/lix/libutil/processes.hh +++ b/lix/libutil/processes.hh @@ -1,10 +1,12 @@ #pragma once ///@file +#include "lix/libutil/result.hh" #include "lix/libutil/types.hh" #include "lix/libutil/error.hh" #include "lix/libutil/file-descriptor.hh" +#include #include #include #include @@ -69,8 +71,12 @@ Pid startProcess(std::function fun, const ProcessOptions & options = Pro * Run a program and return its stdout in a string (i.e., like the * shell backtick operator). */ -std::string runProgram(Path program, bool searchPath = false, - const Strings & args = Strings(), bool isInteractive = false); +kj::Promise> runProgram( + Path program, + bool searchPath = false, + const Strings args = Strings(), + bool isInteractive = false +); struct RunOptions { @@ -130,7 +136,7 @@ public: Source * getStdout() const { return stdoutSource.get(); }; }; -std::pair runProgram(RunOptions && options); +kj::Promise>> runProgram(RunOptions options); RunningProgram runProgram2(const RunOptions & options); diff --git a/lix/nix/flake.cc b/lix/nix/flake.cc index 6e135b276..191cb696f 100644 --- a/lix/nix/flake.cc +++ b/lix/nix/flake.cc @@ -950,7 +950,7 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand if (!changedFiles.empty() && pathExists(flakeDir + "/.git")) { Strings args = { "-C", flakeDir, "add", "--intent-to-add", "--force", "--" }; for (auto & s : changedFiles) args.push_back(s); - runProgram("git", true, args); + aio().blockOn(runProgram("git", true, args)); } auto welcomeText = cursor->maybeGetAttr(*evalState, "welcomeText"); if (welcomeText) { diff --git a/lix/nix/upgrade-nix.cc b/lix/nix/upgrade-nix.cc index 5ad8ab84a..723bc9578 100644 --- a/lix/nix/upgrade-nix.cc +++ b/lix/nix/upgrade-nix.cc @@ -108,7 +108,7 @@ struct CmdUpgradeNix : MixDryRun, EvalCommand { Activity act(*logger, lvlInfo, actUnknown, fmt("verifying that '%s' works...", store->printStorePath(storePath))); - auto s = runProgram(newNixEnv, false, {"--version"}); + auto s = aio().blockOn(runProgram(newNixEnv, false, {"--version"})); if (s.find("Nix") == std::string::npos) throw Error("could not verify that '%s' works", newNixEnv); } @@ -128,7 +128,7 @@ struct CmdUpgradeNix : MixDryRun, EvalCommand this->profileDir, }; printTalkative("running %s %s", newNixEnv, concatStringsSep(" ", removeArgs)); - runProgram(newNixEnv, false, removeArgs); + aio().blockOn(runProgram(newNixEnv, false, removeArgs)); Strings upgradeArgs = { "--profile", @@ -139,7 +139,7 @@ struct CmdUpgradeNix : MixDryRun, EvalCommand }; printTalkative("running %s %s", newNixEnv, concatStringsSep(" ", upgradeArgs)); - runProgram(newNixEnv, false, upgradeArgs); + aio().blockOn(runProgram(newNixEnv, false, upgradeArgs)); } else if (pathExists(canonProfileDir + "/manifest.json")) { this->upgradeNewStyleProfile(store, storePath); } else {