#include "environment-variables.hh" #include "executable-path.hh" #include "strings-inline.hh" #include "util.hh" #include "file-path-impl.hh" namespace nix { namespace fs { using namespace std::filesystem; } constexpr static const OsStringView path_var_separator{ &ExecutablePath::separator, 1, }; ExecutablePath ExecutablePath::load() { // "If PATH is unset or is set to null, the path search is // implementation-defined." // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03 return ExecutablePath::parse(getEnvOs(OS_STR("PATH")).value_or(OS_STR(""))); } ExecutablePath ExecutablePath::parse(const OsString & path) { auto strings = path.empty() ? (std::list{}) : basicSplitString, OsChar>(path, path_var_separator); std::vector ret; ret.reserve(strings.size()); std::transform( std::make_move_iterator(strings.begin()), std::make_move_iterator(strings.end()), std::back_inserter(ret), [](auto && str) { return fs::path{ str.empty() // "A zero-length prefix is a legacy feature that // indicates the current working directory. It // appears as two adjacent characters // ("::"), as an initial preceding the rest // of the list, or as a trailing following // the rest of the list." // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03 ? OS_STR(".") : std::move(str), }; }); return {ret}; } OsString ExecutablePath::render() const { std::vector path2; path2.reserve(directories.size()); for (auto & p : directories) path2.push_back(p.native()); return basicConcatStringsSep(path_var_separator, path2); } std::optional ExecutablePath::findName(const OsString & exe, std::function isExecutable) const { // "If the pathname being sought contains a , the search // through the path prefixes shall not be performed." // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03 assert(OsPathTrait::rfindPathSep(exe) == exe.npos); for (auto & dir : directories) { auto candidate = dir / exe; if (isExecutable(candidate)) return std::filesystem::canonical(candidate); } return std::nullopt; } fs::path ExecutablePath::findPath(const fs::path & exe, std::function isExecutable) const { // "If the pathname being sought contains a , the search // through the path prefixes shall not be performed." // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03 if (exe.filename() == exe) { auto resOpt = findName(exe, isExecutable); if (resOpt) return *resOpt; else throw ExecutableLookupError("Could not find executable '%s'", exe.string()); } else { return exe; } } } // namespace nix