-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathenv.cc
More file actions
123 lines (96 loc) · 3.66 KB
/
Copy pathenv.cc
File metadata and controls
123 lines (96 loc) · 3.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include <queue>
#include <boost/unordered/unordered_flat_set.hpp>
#include "nix/cmd/command.hh"
#include "nix/expr/eval.hh"
#include "run.hh"
#include "nix/util/strings.hh"
#include "nix/util/executable-path.hh"
#include "nix/util/environment-variables.hh"
#include "nix/util/mounted-source-accessor.hh"
using namespace nix;
struct CmdEnv : NixMultiCommand
{
CmdEnv()
: NixMultiCommand("env", RegisterCommand::getCommandsFor({"env"}))
{
}
std::string description() override
{
return "manipulate the process environment";
}
Category category() override
{
return catUtility;
}
};
static auto rCmdEnv = registerCommand<CmdEnv>("env");
struct CmdShell : InstallablesCommand, MixEnvironment
{
using InstallablesCommand::run;
std::vector<std::string> command = {getEnv("SHELL").value_or("bash")};
CmdShell()
{
addFlag({
.longName = "command",
.shortName = 'c',
.description = "Command and arguments to be executed, defaulting to `$SHELL`",
.labels = {"command", "args"},
.handler = {[&](std::vector<std::string> ss) {
if (ss.empty())
throw UsageError("--command requires at least one argument");
command = ss;
}},
});
}
std::string description() override
{
return "run a shell in which the specified packages are available";
}
std::string doc() override
{
return
#include "shell.md"
;
}
void run(ref<Store> store, Installables && installables) override
{
auto state = getEvalState();
auto outPaths =
Installable::toStorePaths(getEvalStore(), store, Realise::Outputs, OperateOn::Output, installables);
boost::unordered_flat_set<StorePath, std::hash<StorePath>> done;
std::queue<StorePath> todo;
for (auto & path : outPaths)
todo.push(path);
setEnviron();
std::vector<std::string> pathAdditions;
while (!todo.empty()) {
auto path = todo.front();
todo.pop();
if (!done.insert(path).second)
continue;
auto binDir = state->storeFS->resolveSymlinks(CanonPath(store->printStorePath(path)) / "bin");
if (!store->isInStore(binDir.abs()))
throw Error("path '%s' is not in the Nix store", binDir);
pathAdditions.push_back(binDir.abs());
auto propPath = state->storeFS->resolveSymlinks(
CanonPath(store->printStorePath(path)) / "nix-support" / "propagated-user-env-packages");
if (auto st = state->storeFS->maybeLstat(propPath); st && st->type == SourceAccessor::tRegular) {
for (auto & p : tokenizeString<Paths>(state->storeFS->readFile(propPath)))
todo.push(store->parseStorePath(p));
}
}
// TODO: split losslessly; empty means .
auto unixPath = ExecutablePath::load();
unixPath.directories.insert(unixPath.directories.begin(), pathAdditions.begin(), pathAdditions.end());
auto unixPathString = unixPath.render();
setEnvOs(OS_STR("PATH"), unixPathString.c_str());
Strings args;
for (auto & arg : command)
args.push_back(arg);
// Release our references to eval caches to ensure they are persisted to disk, because
// we are about to exec out of this process without running C++ destructors.
state->evalCaches.clear();
execProgramInStore(store, UseLookupPath::Use, *command.begin(), args);
}
};
static auto rCmdShell = registerCommand2<CmdShell>({"env", "shell"});