forked from lix-project/lix
libutil: add which() and whichAll(); migrate usage
Adds two util API functions: which(), and whichAll(), which look for
matching file(s) in every directory in PATH, and migrates the few uses
of this pattern that currently exist in the codebase to use these
functions. This will also be used in future commits.
WIP TODO: tests, search path as PATH default argument?
Change-Id: I2bf80d09196b5c84891043e09b23e012fe6cfc4c
This commit is contained in:
parent
dd7b11e496
commit
a9f0c5faad
|
@ -1299,6 +1299,32 @@ void runProgram2(const RunOptions & options)
|
|||
throw ExecError(status, "program '%1%' %2%", options.program, statusToString(status));
|
||||
}
|
||||
|
||||
std::optional<Path> which(std::string_view cmdName)
|
||||
{
|
||||
for (auto const & dir : tokenizeString<StringSet>(getEnv("PATH").value_or(""), ":")) {
|
||||
auto supposedExe = dir + "/" + cmdName;
|
||||
if (pathExists(supposedExe)) {
|
||||
return std::move(supposedExe);
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::vector<Path> whichAll(std::string_view cmdName)
|
||||
{
|
||||
std::vector<Path> results;
|
||||
|
||||
for (auto const & dir : tokenizeString<StringSet>(getEnv("PATH").value_or(""), ":")) {
|
||||
auto supposedExe = dir + "/" + cmdName;
|
||||
if (pathExists(supposedExe)) {
|
||||
results.push_back(std::move(supposedExe));
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
void closeMostFDs(const std::set<int> & exceptions)
|
||||
{
|
||||
|
|
|
@ -521,6 +521,31 @@ public:
|
|||
*/
|
||||
std::vector<char *> stringsToCharPtrs(const Strings & ss);
|
||||
|
||||
/** Gets the first file called `cmdName` in colon-separated PATH.
|
||||
*
|
||||
* @param cmdName The name of the file to look for in PATH.
|
||||
*
|
||||
* @return std::nullopt if the specified filename was not found.
|
||||
*
|
||||
* @note This does *not* check if the found file is executable or not.
|
||||
*
|
||||
* @see whichAll()
|
||||
*/
|
||||
std::optional<Path> which(std::string_view cmdName);
|
||||
|
||||
/** Gets all files called `cmdName` in colon-separated PATH.
|
||||
*
|
||||
* @param cmdName The name of the file to look for in PATH.
|
||||
*
|
||||
* @return an std::vector of @ref Path "Paths", which will be empty if
|
||||
* none were found.
|
||||
*
|
||||
* @note This does *not* check if the found files are executable or not.
|
||||
*
|
||||
* @see which()
|
||||
*/
|
||||
std::vector<Path> whichAll(std::string_view cmdName);
|
||||
|
||||
/**
|
||||
* Close all file descriptors except those listed in the given set.
|
||||
* Good practice in child processes.
|
||||
|
|
|
@ -77,9 +77,9 @@ struct CmdDoctor : StoreCommand
|
|||
{
|
||||
PathSet dirs;
|
||||
|
||||
for (auto & dir : tokenizeString<Strings>(getEnv("PATH").value_or(""), ":"))
|
||||
if (pathExists(dir + "/nix-env"))
|
||||
dirs.insert(dirOf(canonPath(dir + "/nix-env", true)));
|
||||
for (auto const & nixExeInPath : whichAll("nix-env")) {
|
||||
dirs.insert(canonPath(dirOf(nixExeInPath), true));
|
||||
}
|
||||
|
||||
if (dirs.size() != 1) {
|
||||
std::stringstream ss;
|
||||
|
|
|
@ -104,11 +104,9 @@ struct CmdUpgradeNix : MixDryRun, StoreCommand
|
|||
{
|
||||
Path where;
|
||||
|
||||
for (auto & dir : tokenizeString<Strings>(getEnv("PATH").value_or(""), ":"))
|
||||
if (pathExists(dir + "/nix-env")) {
|
||||
where = dir;
|
||||
break;
|
||||
}
|
||||
if (auto nixEnvPath = which("nix-env")) {
|
||||
where = dirOf(*nixEnvPath);
|
||||
}
|
||||
|
||||
if (where == "")
|
||||
throw Error("couldn't figure out how Nix is installed, so I can't upgrade it");
|
||||
|
|
Loading…
Reference in a new issue