diff options
author | Ronny Pfannschmidt <opensource@ronnypfannschmidt.de> | 2022-06-25 22:38:43 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-06-25 22:38:43 +0200 |
commit | 1c00405a0e5075a2330c60a69f72d4c7aad88203 (patch) | |
tree | 4ef1e1eb864821ff9a14916b9fa586debdc27729 | |
parent | 9f3bc380c8797fa677db269272a99af15a62bf20 (diff) | |
parent | 8a63dde177eaeaaf2ce6a4b0f9b5c7afc4eb9d10 (diff) | |
download | setuptools-scm-1c00405a0e5075a2330c60a69f72d4c7aad88203.tar.gz |
Merge pull request #729 from paugier/hg-pip-compat
Hg / pip compatibility
-rw-r--r-- | pyproject.toml | 1 | ||||
-rw-r--r-- | src/setuptools_scm/hg_git.py | 8 | ||||
-rw-r--r-- | src/setuptools_scm/utils.py | 50 |
3 files changed, 46 insertions, 13 deletions
diff --git a/pyproject.toml b/pyproject.toml index b2ee286..1d11e4c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,5 +2,6 @@ requires = [ "setuptools>=45", "packaging>=20.0", + "typing_extensions", ] build-backend = "setuptools.build_meta" diff --git a/src/setuptools_scm/hg_git.py b/src/setuptools_scm/hg_git.py index 1b48462..bde71ec 100644 --- a/src/setuptools_scm/hg_git.py +++ b/src/setuptools_scm/hg_git.py @@ -29,18 +29,18 @@ class GitWorkdirHgClient(GitWorkdir, HgWorkdir): return cls(root) def is_dirty(self) -> bool: - out, _, _ = self.do_ex("hg id -T '{dirty}'") + out, _, _ = self.do_ex('hg id -T "{dirty}"') return bool(out) def get_branch(self) -> str | None: - res = self.do_ex("hg id -T {bookmarks}") + res = self.do_ex('hg id -T "{bookmarks}"') if res.returncode: trace("branch err", res) return None return res.out def get_head_date(self) -> date | None: - date_part, err, ret = self.do_ex("hg log -r . -T {shortdate(date)}") + date_part, err, ret = self.do_ex('hg log -r . -T "{shortdate(date)}"') if ret: trace("head date err", date_part, err, ret) return None @@ -53,7 +53,7 @@ class GitWorkdirHgClient(GitWorkdir, HgWorkdir): pass def get_hg_node(self) -> str | None: - node, _, ret = self.do_ex("hg log -r . -T {node}") + node, _, ret = self.do_ex('hg log -r . -T "{node}"') if not ret: return node else: diff --git a/src/setuptools_scm/utils.py b/src/setuptools_scm/utils.py index 5cd0d66..7c690b8 100644 --- a/src/setuptools_scm/utils.py +++ b/src/setuptools_scm/utils.py @@ -8,6 +8,7 @@ import platform import shlex import subprocess import sys +import textwrap import warnings from types import CodeType from types import FunctionType @@ -51,8 +52,31 @@ def no_git_env(env: Mapping[str, str]) -> dict[str, str]: } -def trace(*k: object) -> None: +def avoid_pip_isolation(env: Mapping[str, str]) -> dict[str, str]: + """ + pip build isolation can break Mercurial + (see https://github.com/pypa/pip/issues/10635) + + pip uses PYTHONNOUSERSITE and a path in PYTHONPATH containing "pip-build-env-". + """ + new_env = {k: v for k, v in env.items() if k != "PYTHONNOUSERSITE"} + if "PYTHONPATH" not in new_env: + return new_env + + new_env["PYTHONPATH"] = os.pathsep.join( + [ + path + for path in new_env["PYTHONPATH"].split(os.pathsep) + if "pip-build-env-" not in path + ] + ) + return new_env + + +def trace(*k: object, indent: bool = False) -> None: if DEBUG: + if indent and len(k) > 1: + k = (k[0],) + tuple(textwrap.indent(str(s), " ") for s in k[1:]) print(*k, file=sys.stderr, flush=True) @@ -63,35 +87,43 @@ def ensure_stripped_str(str_or_bytes: str | bytes) -> str: return str_or_bytes.decode("utf-8", "surrogateescape").strip() -def _run(cmd: _t.CMD_TYPE, cwd: _t.PathT) -> subprocess.CompletedProcess[bytes]: +def _run(cmd: _t.CMD_TYPE, cwd: _t.PathT) -> subprocess.CompletedProcess[str]: return subprocess.run( cmd, capture_output=True, cwd=str(cwd), env=dict( - no_git_env(os.environ), + avoid_pip_isolation(no_git_env(os.environ)), # os.environ, # try to disable i18n LC_ALL="C", LANGUAGE="", HGPLAIN="1", ), + text=True, ) def do_ex(cmd: _t.CMD_TYPE, cwd: _t.PathT = ".") -> _CmdResult: - trace("cmd", repr(cmd)) - trace(" in", cwd) + if not DEBUG or not isinstance(cmd, list): + cmd_4_trace = cmd + else: + # give better results than shlex.join in our cases + cmd_4_trace = " ".join( + [s if all(c not in s for c in " {[:") else f'"{s}"' for s in cmd] + ) + trace("----\ncmd:\n", cmd_4_trace, indent=True) + trace(" in:", cwd) if os.name == "posix" and not isinstance(cmd, (list, tuple)): cmd = shlex.split(cmd) res = _run(cmd, cwd) if res.stdout: - trace("out", repr(res.stdout)) + trace("out:\n", res.stdout, indent=True) if res.stderr: - trace("err", repr(res.stderr)) + trace("err:\n", res.stderr, indent=True) if res.returncode: - trace("ret", res.returncode) + trace("ret:", res.returncode) return _CmdResult( ensure_stripped_str(res.stdout), ensure_stripped_str(res.stderr), res.returncode ) @@ -99,7 +131,7 @@ def do_ex(cmd: _t.CMD_TYPE, cwd: _t.PathT = ".") -> _CmdResult: def do(cmd: list[str] | str, cwd: str | _t.PathT = ".") -> str: out, err, ret = do_ex(cmd, cwd) - if ret: + if ret and not DEBUG: print(err) return out |