Coverage for src / dotbot / util / common.py: 89%
18 statements
« prev ^ index » next coverage.py v7.12.0, created at 2025-11-29 10:55 -0800
« prev ^ index » next coverage.py v7.12.0, created at 2025-11-29 10:55 -0800
1import os
2import platform
3import subprocess
4import sys
5from typing import Optional
8def shell_command(
9 command: str,
10 cwd: Optional[str] = None,
11 *,
12 enable_stdin: bool = False,
13 enable_stdout: bool = False,
14 enable_stderr: bool = False,
15) -> int:
16 with open(os.devnull, "w") as devnull_w, open(os.devnull) as devnull_r:
17 stdin = None if enable_stdin else devnull_r
18 stdout = None if enable_stdout else devnull_w
19 stderr = None if enable_stderr else devnull_w
20 executable = os.environ.get("SHELL")
21 if platform.system() == "Windows":
22 # We avoid setting the executable kwarg on Windows because it does
23 # not have the desired effect when combined with shell=True. It
24 # will result in the correct program being run (e.g. bash), but it
25 # will be invoked with a '/c' argument instead of a '-c' argument,
26 # which it won't understand.
27 #
28 # See https://github.com/anishathalye/dotbot/issues/219 and
29 # https://bugs.python.org/issue40467.
30 #
31 # This means that complex commands that require Bash's parsing
32 # won't work; a workaround for this is to write the command as
33 # `bash -c "..."`.
34 executable = None
35 return subprocess.call( # noqa: S602
36 command,
37 shell=True,
38 executable=executable,
39 stdin=stdin,
40 stdout=stdout,
41 stderr=stderr,
42 cwd=cwd,
43 )
46def normslash(path: str) -> str:
47 if sys.platform == "win32":
48 # this is how normcase in cpython/Lib/ntpath.py does it; we don't use normcase
49 # because we don't want to make all characters lowercase
50 return path.replace("/", "\\")
51 return path