gh-95285: py.exe launcher fails with short argv0 (GH-95295)

This commit is contained in:
Steve Dower 2022-07-26 21:24:44 +01:00 committed by GitHub
parent 51c56f8d72
commit 7ac5bb3e6a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 20 additions and 3 deletions

View File

@ -149,7 +149,7 @@ class RunPyMixin:
@classmethod @classmethod
def find_py(cls): def find_py(cls):
py_exe = None py_exe = None
if sysconfig.is_python_build(True): if sysconfig.is_python_build():
py_exe = Path(sys.executable).parent / PY_EXE py_exe = Path(sys.executable).parent / PY_EXE
else: else:
for p in os.getenv("PATH").split(";"): for p in os.getenv("PATH").split(";"):
@ -187,7 +187,7 @@ class RunPyMixin:
) )
return py_exe return py_exe
def run_py(self, args, env=None, allow_fail=False, expect_returncode=0): def run_py(self, args, env=None, allow_fail=False, expect_returncode=0, argv=None):
if not self.py_exe: if not self.py_exe:
self.py_exe = self.find_py() self.py_exe = self.find_py()
@ -198,9 +198,12 @@ class RunPyMixin:
"PYLAUNCHER_DEBUG": "1", "PYLAUNCHER_DEBUG": "1",
"PYLAUNCHER_DRYRUN": "1", "PYLAUNCHER_DRYRUN": "1",
} }
if not argv:
argv = [self.py_exe, *args]
with subprocess.Popen( with subprocess.Popen(
[self.py_exe, *args], argv,
env=env, env=env,
executable=self.py_exe,
stdin=subprocess.PIPE, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, stderr=subprocess.PIPE,
@ -539,6 +542,15 @@ class TestLauncher(unittest.TestCase, RunPyMixin):
self.assertEqual("3.100-arm64", data["SearchInfo.tag"]) self.assertEqual("3.100-arm64", data["SearchInfo.tag"])
self.assertEqual(f"X.Y-arm64.exe -X fake_arg_for_test -prearg {script} -postarg", data["stdout"].strip()) self.assertEqual(f"X.Y-arm64.exe -X fake_arg_for_test -prearg {script} -postarg", data["stdout"].strip())
def test_py_shebang_short_argv0(self):
with self.py_ini(TEST_PY_COMMANDS):
with self.script("#! /usr/bin/env python -prearg") as script:
# Override argv to only pass "py.exe" as the command
data = self.run_py([script, "-postarg"], argv=f'"py.exe" "{script}" -postarg')
self.assertEqual("PythonTestSuite", data["SearchInfo.company"])
self.assertEqual("3.100", data["SearchInfo.tag"])
self.assertEqual(f'X.Y.exe -prearg "{script}" -postarg', data["stdout"].strip())
def test_install(self): def test_install(self):
data = self.run_py(["-V:3.10"], env={"PYLAUNCHER_ALWAYS_INSTALL": "1"}, expect_returncode=111) data = self.run_py(["-V:3.10"], env={"PYLAUNCHER_ALWAYS_INSTALL": "1"}, expect_returncode=111)
cmd = data["stdout"].strip() cmd = data["stdout"].strip()

View File

@ -0,0 +1,2 @@
Fix :ref:`launcher` handling of command lines where it is only passed a
short executable name.

View File

@ -580,6 +580,9 @@ parseCommandLine(SearchInfo *search)
break; break;
} }
} }
if (tail == search->originalCmdLine && tail[0] == L'"') {
++tail;
}
// Without special cases, we can now fill in the search struct // Without special cases, we can now fill in the search struct
int tailLen = (int)(end ? (end - tail) : wcsnlen_s(tail, MAXLEN)); int tailLen = (int)(end ? (end - tail) : wcsnlen_s(tail, MAXLEN));
search->executableLength = -1; search->executableLength = -1;