diff options
Diffstat (limited to 'src/nix/run.cc')
-rw-r--r-- | src/nix/run.cc | 163 |
1 files changed, 89 insertions, 74 deletions
diff --git a/src/nix/run.cc b/src/nix/run.cc index f885c5e49..7fd9c4c7e 100644 --- a/src/nix/run.cc +++ b/src/nix/run.cc @@ -8,6 +8,7 @@ #include "fs-accessor.hh" #include "progress-bar.hh" #include "affinity.hh" +#include "eval.hh" #if __linux__ #include <sys/mount.h> @@ -19,11 +20,46 @@ using namespace nix; std::string chrootHelperName = "__run_in_chroot"; -struct CmdRun : InstallablesCommand +struct RunCommon : virtual Command +{ + void runProgram(ref<Store> store, + const std::string & program, + const Strings & args) + { + stopProgressBar(); + + restoreSignals(); + + restoreAffinity(); + + /* If this is a diverted store (i.e. its "logical" location + (typically /nix/store) differs from its "physical" location + (e.g. /home/eelco/nix/store), then run the command in a + chroot. For non-root users, this requires running it in new + mount and user namespaces. Unfortunately, + unshare(CLONE_NEWUSER) doesn't work in a multithreaded + program (which "nix" is), so we exec() a single-threaded + helper program (chrootHelper() below) to do the work. */ + auto store2 = store.dynamic_pointer_cast<LocalStore>(); + + if (store2 && store->storeDir != store2->realStoreDir) { + Strings helperArgs = { chrootHelperName, store->storeDir, store2->realStoreDir, program }; + for (auto & arg : args) helperArgs.push_back(arg); + + execv(readLink("/proc/self/exe").c_str(), stringsToCharPtrs(helperArgs).data()); + + throw SysError("could not execute chroot helper"); + } + + execvp(program.c_str(), stringsToCharPtrs(args).data()); + + throw SysError("unable to execute '%s'", program); + } +}; + +struct CmdRun : InstallablesCommand, RunCommon, MixEnvironment { std::vector<std::string> command = { "bash" }; - StringSet keep, unset; - bool ignoreEnvironment = false; CmdRun() { @@ -37,28 +73,6 @@ struct CmdRun : InstallablesCommand if (ss.empty()) throw UsageError("--command requires at least one argument"); command = ss; }); - - mkFlag() - .longName("ignore-environment") - .shortName('i') - .description("clear the entire environment (except those specified with --keep)") - .set(&ignoreEnvironment, true); - - mkFlag() - .longName("keep") - .shortName('k') - .description("keep specified environment variable") - .arity(1) - .labels({"name"}) - .handler([&](std::vector<std::string> ss) { keep.insert(ss.front()); }); - - mkFlag() - .longName("unset") - .shortName('u') - .description("unset specified environment variable") - .arity(1) - .labels({"name"}) - .handler([&](std::vector<std::string> ss) { unset.insert(ss.front()); }); } std::string description() override @@ -75,15 +89,15 @@ struct CmdRun : InstallablesCommand }, Example{ "To start a shell providing youtube-dl from your 'nixpkgs' channel:", - "nix run nixpkgs.youtube-dl" + "nix run nixpkgs#youtube-dl" }, Example{ "To run GNU Hello:", - "nix run nixpkgs.hello -c hello --greeting 'Hi everybody!'" + "nix run nixpkgs#hello -c hello --greeting 'Hi everybody!'" }, Example{ "To run GNU Hello in a chroot store:", - "nix run --store ~/my-nix nixpkgs.hello -c hello" + "nix run --store ~/my-nix nixpkgs#hello -c hello" }, }; } @@ -94,35 +108,13 @@ struct CmdRun : InstallablesCommand auto accessor = store->getFSAccessor(); - if (ignoreEnvironment) { - - if (!unset.empty()) - throw UsageError("--unset does not make sense with --ignore-environment"); - - std::map<std::string, std::string> kept; - for (auto & var : keep) { - auto s = getenv(var.c_str()); - if (s) kept[var] = s; - } - - clearEnv(); - - for (auto & var : kept) - setenv(var.first.c_str(), var.second.c_str(), 1); - - } else { - - if (!keep.empty()) - throw UsageError("--keep does not make sense without --ignore-environment"); - - for (auto & var : unset) - unsetenv(var.c_str()); - } std::unordered_set<StorePath> done; std::queue<StorePath> todo; for (auto & path : outPaths) todo.push(path.clone()); + setEnviron(); + auto unixPath = tokenizeString<Strings>(getEnv("PATH").value_or(""), ":"); while (!todo.empty()) { @@ -142,42 +134,65 @@ struct CmdRun : InstallablesCommand setenv("PATH", concatStringsSep(":", unixPath).c_str(), 1); - std::string cmd = *command.begin(); Strings args; for (auto & arg : command) args.push_back(arg); - stopProgressBar(); + runProgram(store, *command.begin(), args); + } +}; - restoreSignals(); +static auto r1 = registerCommand<CmdRun>("run"); - restoreAffinity(); +struct CmdApp : InstallableCommand, RunCommon +{ + std::vector<std::string> args; - /* If this is a diverted store (i.e. its "logical" location - (typically /nix/store) differs from its "physical" location - (e.g. /home/eelco/nix/store), then run the command in a - chroot. For non-root users, this requires running it in new - mount and user namespaces. Unfortunately, - unshare(CLONE_NEWUSER) doesn't work in a multithreaded - program (which "nix" is), so we exec() a single-threaded - helper program (chrootHelper() below) to do the work. */ - auto store2 = store.dynamic_pointer_cast<LocalStore>(); + CmdApp() + { + expectArgs("args", &args); + } - if (store2 && store->storeDir != store2->realStoreDir) { - Strings helperArgs = { chrootHelperName, store->storeDir, store2->realStoreDir, cmd }; - for (auto & arg : args) helperArgs.push_back(arg); + std::string description() override + { + return "run a Nix application"; + } - execv(readLink("/proc/self/exe").c_str(), stringsToCharPtrs(helperArgs).data()); + Examples examples() override + { + return { + Example{ + "To run Blender:", + "nix app blender-bin" + }, + }; + } - throw SysError("could not execute chroot helper"); - } + Strings getDefaultFlakeAttrPaths() override + { + return {"defaultApp." + settings.thisSystem.get()}; + } - execvp(cmd.c_str(), stringsToCharPtrs(args).data()); + Strings getDefaultFlakeAttrPathPrefixes() override + { + return {"apps." + settings.thisSystem.get() + "."}; + } - throw SysError("unable to exec '%s'", cmd); + void run(ref<Store> store) override + { + auto state = getEvalState(); + + auto app = installable->toApp(*state); + + state->realiseContext(app.context); + + Strings allArgs{app.program}; + for (auto & i : args) allArgs.push_back(i); + + runProgram(store, app.program, allArgs); } }; -static auto r1 = registerCommand<CmdRun>("run"); +static auto r2 = registerCommand<CmdApp>("app"); void chrootHelper(int argc, char * * argv) { |