-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathpatches.py
119 lines (109 loc) · 4.57 KB
/
patches.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import logging
from patoolib.mime import *
from patoolib.util import *
def patched_run_checked(cmd, ret_ok=(0,), **kwargs):
"""Run command and raise PatoolError on error with an additional condition."""
retcode = patched_run(cmd, **kwargs)
# Original condition, with an added condition:
# Add a custom check, if retcode is not a specific value.
if retcode not in ret_ok and retcode != 255:
msg = f"Command `{cmd}' returned non-zero exit status {retcode}"
raise PatoolError(msg)
return retcode
def patched_guess_mime_file(filename: str) -> tuple[str | None, str | None]:
"""Determine MIME type of filename with file(1):
(a) using `file --brief --mime-type`
(b) using `file --brief` and look at the result string
(c) detect compressed archives (eg. .tar.gz) using
`file --brief --mime --uncompress --no-sandbox`
@return: tuple (mime, encoding)
"""
mime, encoding = None, None
base, ext = os.path.splitext(filename)
if ext.lower() in ('.alz',):
# let mimedb recognize these extensions
return mime, encoding
if os.path.isfile(filename):
file_prog = find_program("file")
if file_prog:
mime, encoding = guess_mime_file_mime(file_prog, filename)
if mime is None:
mime = guess_mime_file_text(file_prog, filename)
encoding = None
if mime in Mime2Encoding:
# try to look inside compressed archives
cmd = [file_prog, "--brief", "--mime", "--uncompress", "--no-sandbox", filename]
try:
outparts = backtick(cmd).strip().split(";")
mime2 = outparts[0].split(" ", 1)[0]
except (OSError, subprocess.CalledProcessError) as err:
log_warning(f"error executing {cmd}: {err}")
mime2 = None
# Some file(1) implementations return an empty or unknown mime type
# when the uncompressor program is not installed, other
# implementation return the original file type.
# The following detects both cases.
if (
mime2 in ('application/x-empty', 'application/octet-stream')
or mime2 in Mime2Encoding
or not mime2
):
# The uncompressor program file(1) uses is not installed
# or is not able to uncompress.
# Try to get mime information from the file extension.
mime2, encoding2 = guess_mime_mimedb(filename)
if mime2 in ArchiveMimetypes:
mime = mime2
encoding = encoding2
elif mime2 in ArchiveMimetypes:
mime = mime2
encoding = get_file_mime_encoding(outparts)
return mime, encoding
def patched_run(cmd: Sequence[str], verbosity: int = 0, **kwargs) -> int:
"""Run command without error checking.
@return: command return code
"""
# Note that shell_quote_nt() result is not suitable for copy-paste
# (especially on Unix systems), but it looks nicer than shell_quote().
if verbosity >= 0:
info = " ".join(map(shell_quote_nt, cmd))
log_info(f"running {info}")
if run_under_pythonw():
# prevent opening of additional consoles when running with pythonw.exe
kwargs["creationflags"] = (
subprocess.CREATE_NO_WINDOW # pytype: disable=module-attr
)
# try to prevent hangs for programs requiring input
kwargs["input"] = ""
if verbosity < 1:
# hide command output on stdout
kwargs['stdout'] = subprocess.DEVNULL
kwargs['stderr'] = subprocess.DEVNULL
if kwargs:
if verbosity > 0:
info = ", ".join(f"{k}={shell_quote(str(v))}" for k, v in kwargs.items())
log_info(f" with {info}")
kwargs['stdout'] = subprocess.PIPE
kwargs['stderr'] = subprocess.PIPE
if kwargs.get("shell"):
# for shell calls the command must be a string
cmd = " ".join(cmd)
kwargs["creationflags"] = (
subprocess.CREATE_NO_WINDOW # pytype: disable=module-attr
)
res = subprocess.run(cmd, text=True, **kwargs)
if res.stdout:
log_subprocess_output(res.stdout, level=logging.INFO)
if res.stderr:
pass
log_subprocess_output(res.stderr, level=logging.ERROR)
return res.returncode
def log_subprocess_output(output: str, level: int):
logger = logging.getLogger(__name__)
for line in output.splitlines():
logger.log(level, line)
# Apply the patch
import patoolib
patoolib.util.run = patched_run
patoolib.util.run_checked = patched_run_checked
patoolib.mime.guess_mime_file = patched_guess_mime_file