aboutsummaryrefslogtreecommitdiff
path: root/src/nix/run.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/nix/run.cc')
-rw-r--r--src/nix/run.cc112
1 files changed, 84 insertions, 28 deletions
diff --git a/src/nix/run.cc b/src/nix/run.cc
index 35b763345..9c15b6749 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,7 +20,44 @@ 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
{
std::vector<std::string> command = { "bash" };
StringSet keep, unset;
@@ -61,11 +99,6 @@ struct CmdRun : InstallablesCommand
.handler([&](std::vector<std::string> ss) { unset.insert(ss.front()); });
}
- std::string name() override
- {
- return "run";
- }
-
std::string description() override
{
return "run a shell in which the specified packages are available";
@@ -147,42 +180,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"};
+ }
+
+ Strings getDefaultFlakeAttrPathPrefixes() override
+ {
+ return {"apps."};
+ }
+
+ void run(ref<Store> store) override
+ {
+ auto state = getEvalState();
+
+ auto app = installable->toApp(*state);
+
+ state->realiseContext(app.context);
- execvp(cmd.c_str(), stringsToCharPtrs(args).data());
+ Strings allArgs{app.program};
+ for (auto & i : args) allArgs.push_back(i);
- throw SysError("unable to exec '%s'", cmd);
+ runProgram(store, app.program, allArgs);
}
};
-static RegisterCommand r1(make_ref<CmdRun>());
+static auto r2 = registerCommand<CmdApp>("app");
void chrootHelper(int argc, char * * argv)
{