nix shell: reflect command line order in PATH order

Prior to this change, Nix would prepend every installable to the PATH
list in order to ensure that installables appeared before the current
PATH from the ambient environment.

With this change, all the installables are still prepended to the PATH,
but in the same order as they appear on the command line. This means
that the first of two packages that expose an executable `hello` would
appear in the PATH first, and thus be executed first.

See the test in the prior commit for a more concrete example.
This commit is contained in:
Cole Helbling 2023-12-18 15:22:09 -08:00
parent 1fb43d1eee
commit f4454aac9f
3 changed files with 27 additions and 3 deletions

View file

@ -729,6 +729,20 @@ StorePathSet Installable::toStorePathSet(
return outPaths;
}
StorePaths Installable::toStorePaths(
ref<Store> evalStore,
ref<Store> store,
Realise mode, OperateOn operateOn,
const Installables & installables)
{
StorePaths outPaths;
for (auto & path : toBuiltPaths(evalStore, store, mode, operateOn, installables)) {
auto thisOutPaths = path.outPaths();
outPaths.insert(outPaths.end(), thisOutPaths.begin(), thisOutPaths.end());
}
return outPaths;
}
StorePath Installable::toStorePath(
ref<Store> evalStore,
ref<Store> store,

View file

@ -172,6 +172,13 @@ struct Installable
OperateOn operateOn,
const Installables & installables);
static std::vector<StorePath> toStorePaths(
ref<Store> evalStore,
ref<Store> store,
Realise mode,
OperateOn operateOn,
const Installables & installables);
static StorePath toStorePath(
ref<Store> evalStore,
ref<Store> store,

View file

@ -114,7 +114,7 @@ struct CmdShell : InstallablesCommand, MixEnvironment
setEnviron();
auto unixPath = tokenizeString<Strings>(getEnv("PATH").value_or(""), ":");
std::vector<std::string> pathAdditions;
while (!todo.empty()) {
auto path = todo.front();
@ -122,7 +122,7 @@ struct CmdShell : InstallablesCommand, MixEnvironment
if (!done.insert(path).second) continue;
if (true)
unixPath.push_front(store->printStorePath(path) + "/bin");
pathAdditions.push_back(store->printStorePath(path) + "/bin");
auto propPath = CanonPath(store->printStorePath(path)) + "nix-support" + "propagated-user-env-packages";
if (auto st = accessor->maybeLstat(propPath); st && st->type == SourceAccessor::tRegular) {
@ -131,7 +131,10 @@ struct CmdShell : InstallablesCommand, MixEnvironment
}
}
setenv("PATH", concatStringsSep(":", unixPath).c_str(), 1);
auto unixPath = tokenizeString<Strings>(getEnv("PATH").value_or(""), ":");
unixPath.insert(unixPath.begin(), pathAdditions.begin(), pathAdditions.end());
auto unixPathString = concatStringsSep(":", unixPath);
setenv("PATH", unixPathString.c_str(), 1);
Strings args;
for (auto & arg : command) args.push_back(arg);