Remove lookupPathForProgram and implement initial runProgram test

Apparently, CreateProcessW already searches path, so manual path search
isn't really necessary.
This commit is contained in:
PoweredByPie 2024-06-18 00:55:47 -07:00
parent fcb92b4fa4
commit 8b81d083a7
2 changed files with 8 additions and 47 deletions

View File

@ -89,36 +89,6 @@ std::string runProgram(
return res.second; return res.second;
} }
// Looks at the $PATH environment variable to find the program.
// Adapted from https://github.com/nix-windows/nix/blob/windows/src/libutil/util.cc#L2276
Path lookupPathForProgram(const Path & program)
{
if (program.find('/') != program.npos || program.find('\\') != program.npos) {
throw UsageError("program '%1%' partially specifies its path", program);
}
// Possible extensions.
// TODO: This should actually be sourced from $PATHEXT, not hardcoded.
static constexpr const char * exts[] = {"", ".exe", ".cmd", ".bat"};
auto path = getEnv("PATH");
if (!path.has_value()) {
throw WinError("couldn't find PATH environment variable");
}
// Look through each directory listed in $PATH.
for (const std::string & dir : tokenizeString<Strings>(*path, ";")) {
// TODO: This should actually be canonPath(dir), but that ends up appending two drive paths
Path candidate = dir + "/" + program;
for (const auto ext : exts) {
if (pathExists(candidate + ext)) {
return candidate;
}
}
}
throw WinError("program '%1%' not found on PATH", program);
}
std::optional<Path> getProgramInterpreter(const Path & program) std::optional<Path> getProgramInterpreter(const Path & program)
{ {
@ -246,7 +216,7 @@ Pid spawnProcess(const Path & realProgram, const RunOptions & options, Pipe & ou
} }
} }
std::string cmdline = realProgram; std::string cmdline = windowsEscape(realProgram, false);
for (const auto & arg : options.args) { for (const auto & arg : options.args) {
// TODO: This isn't the right way to escape windows command // TODO: This isn't the right way to escape windows command
// See https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw // See https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw
@ -255,7 +225,8 @@ Pid spawnProcess(const Path & realProgram, const RunOptions & options, Pipe & ou
PROCESS_INFORMATION procInfo = {0}; PROCESS_INFORMATION procInfo = {0};
if (CreateProcessW( if (CreateProcessW(
string_to_os_string(realProgram).c_str(), // EXE path is provided in the cmdline
NULL,
string_to_os_string(cmdline).data(), string_to_os_string(cmdline).data(),
NULL, NULL,
NULL, NULL,
@ -335,9 +306,6 @@ void runProgram2(const RunOptions & options)
in.create(); in.create();
Path realProgram = options.program; Path realProgram = options.program;
if (options.lookupPath) {
realProgram = lookupPathForProgram(realProgram);
}
// TODO: Implement shebang / program interpreter lookup on Windows // TODO: Implement shebang / program interpreter lookup on Windows
auto interpreter = getProgramInterpreter(realProgram); auto interpreter = getProgramInterpreter(realProgram);

View File

@ -3,22 +3,15 @@
#include "processes.hh" #include "processes.hh"
namespace nix { namespace nix {
/*
TEST(SpawnTest, spawnEcho)
{
auto output = runProgram(RunOptions{.program = "cmd", .lookupPath = true, .args = {"/C", "echo \"hello world\""}});
std::cout << output.second << std::endl;
}
*/
#ifdef _WIN32 #ifdef _WIN32
Path lookupPathForProgram(const Path & program); TEST(SpawnTest, spawnEcho)
TEST(SpawnTest, pathSearch)
{ {
ASSERT_NO_THROW(lookupPathForProgram("cmd")); auto output = runProgram(RunOptions{.program = "cmd.exe", .args = {"/C", "echo", "hello world"}});
ASSERT_NO_THROW(lookupPathForProgram("cmd.exe")); ASSERT_EQ(output.first, 0);
ASSERT_THROW(lookupPathForProgram("C:/System32/cmd.exe"), UsageError); ASSERT_EQ(output.second, "\"hello world\"\r\n");
} }
std::string windowsEscape(const std::string & str, bool cmd); std::string windowsEscape(const std::string & str, bool cmd);
TEST(SpawnTest, windowsEscape) TEST(SpawnTest, windowsEscape)