Skip to content

Commit a69b18c

Browse files
committed
Fix --python venvs.
Restore re-written script permissions and improve error output when the requested `--python` can't be found.
1 parent b79f808 commit a69b18c

File tree

1 file changed

+27
-9
lines changed

1 file changed

+27
-9
lines changed

dev_cmd/venv.py

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import json
1010
import os
1111
import shutil
12+
import stat
1213
import subprocess
1314
import sys
1415
from contextlib import contextmanager
@@ -20,6 +21,7 @@
2021
from typing import IO, Any, Dict, Iterator, cast
2122

2223
from dev_cmd import color
24+
from dev_cmd.errors import DevCmdError
2325
from dev_cmd.model import Command, PythonConfig, Venv
2426

2527
AVAILABLE = False
@@ -35,7 +37,7 @@ def _fingerprint(data: bytes) -> str:
3537

3638

3739
@contextmanager
38-
def named_temporary_file(
40+
def _named_temporary_file(
3941
tmp_dir: str | None = None, prefix: str | None = None
4042
) -> Iterator[IO[bytes]]:
4143
# Work around Windows issue with auto-delete: https://bugs.python.org/issue14243
@@ -55,21 +57,21 @@ def _ensure_cache_dir() -> Path:
5557
gitignore = cache_dir / ".gitignore"
5658
if not gitignore.exists():
5759
cache_dir.mkdir(parents=True, exist_ok=True)
58-
with named_temporary_file(tmp_dir=fspath(cache_dir), prefix=".gitignore.") as gitignore_fp:
60+
with _named_temporary_file(tmp_dir=fspath(cache_dir), prefix=".gitignore.") as gitignore_fp:
5961
gitignore_fp.write(b"*\n")
6062
gitignore_fp.close()
6163
os.rename(gitignore_fp.name, gitignore)
6264
return cache_dir
6365

6466

6567
@dataclass(frozen=True)
66-
class VenvLayout:
68+
class _VenvLayout:
6769
python: str
6870
site_packages_dir: str
6971

7072

71-
def _create_venv(python: str, venv_dir: str) -> VenvLayout:
72-
subprocess.run(
73+
def _create_venv(python: str, venv_dir: str) -> _VenvLayout:
74+
result = subprocess.run(
7375
args=[
7476
"pex3",
7577
"venv",
@@ -81,8 +83,11 @@ def _create_venv(python: str, venv_dir: str) -> VenvLayout:
8183
"--dest-dir",
8284
venv_dir,
8385
],
84-
check=True,
86+
capture_output=True,
87+
text=True,
8588
)
89+
if result.returncode != 0:
90+
raise DevCmdError(result.stderr)
8691

8792
result = subprocess.run(
8893
args=["pex3", "venv", "inspect", venv_dir],
@@ -94,7 +99,7 @@ def _create_venv(python: str, venv_dir: str) -> VenvLayout:
9499
python_exe = venv_data["interpreter"]["binary"]
95100
site_packages_dir = venv_data["site_packages"]
96101

97-
return VenvLayout(python=python_exe, site_packages_dir=site_packages_dir)
102+
return _VenvLayout(python=python_exe, site_packages_dir=site_packages_dir)
98103

99104

100105
def marker_environment(python: str) -> dict[str, str]:
@@ -202,6 +207,18 @@ def extract_command_fingerprint_data(command: Command | None) -> dict[str, Any]
202207
)
203208

204209

210+
def _chmod_plus_x(path: str) -> None:
211+
path_mode = os.stat(path).st_mode
212+
path_mode &= 0o777
213+
if path_mode & stat.S_IRUSR:
214+
path_mode |= stat.S_IXUSR
215+
if path_mode & stat.S_IRGRP:
216+
path_mode |= stat.S_IXGRP
217+
if path_mode & stat.S_IROTH:
218+
path_mode |= stat.S_IXOTH
219+
os.chmod(path, path_mode)
220+
221+
205222
def ensure(python: str, config: PythonConfig, rebuild_if_needed: bool = True) -> Venv:
206223
fingerprint = _fingerprint_python_config(python=python, config=config)
207224
venv_dir = _ensure_cache_dir() / "venvs" / fingerprint
@@ -214,7 +231,7 @@ def ensure(python: str, config: PythonConfig, rebuild_if_needed: bool = True) ->
214231
)
215232
work_dir = Path(f"{venv_dir}.work")
216233
venv_layout = _create_venv(python, venv_dir=fspath(work_dir))
217-
with named_temporary_file(
234+
with _named_temporary_file(
218235
tmp_dir=fspath(work_dir), prefix="3rdparty-reqs."
219236
) as reqs_fp:
220237
reqs_fp.close()
@@ -257,7 +274,7 @@ def ensure(python: str, config: PythonConfig, rebuild_if_needed: bool = True) ->
257274
@contextmanager
258275
def _extra_requirements_args() -> Iterator[list[str]]:
259276
if isinstance(config.extra_requirements, str):
260-
with named_temporary_file(
277+
with _named_temporary_file(
261278
tmp_dir=fspath(work_dir), prefix="extra-reqs."
262279
) as fp:
263280
fp.write(config.extra_requirements.encode())
@@ -313,6 +330,7 @@ def _extra_requirements_args() -> Iterator[list[str]]:
313330
)
314331
shutil.copyfileobj(candidate_fp, rewrite_fp)
315332
os.rename(rewrite_fp.name, candidate_console_script)
333+
_chmod_plus_x(candidate_console_script)
316334

317335
with (work_dir / layout_file.name).open("w") as out_fp:
318336
json.dump(

0 commit comments

Comments
 (0)