Skip to content

Commit 30387c9

Browse files
committed
Use modern python subprocess timeout to run system check
1 parent 3d30fcd commit 30387c9

File tree

1 file changed

+25
-114
lines changed

1 file changed

+25
-114
lines changed

latextools/system_check.py

Lines changed: 25 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
from .latextools_plugin import NoSuchPluginException
2121
from .utils.activity_indicator import ActivityIndicator
2222
from .utils.distro_utils import using_miktex
23-
from .utils.external_command import check_output
2423
from .utils.external_command import get_texpath
2524
from .utils.logging import logger
2625
from .utils.output_directory import get_aux_directory
@@ -41,73 +40,22 @@
4140
__all__ = ["LatextoolsSystemCheckCommand", "LatextoolsInsertTextCommand"]
4241

4342

44-
class SubprocessTimeoutThread(threading.Thread):
45-
"""
46-
A thread for monitoring a subprocess to kill the subprocess after a fixed
47-
period of time
48-
"""
49-
50-
def __init__(self, timeout, *args, **kwargs):
51-
super(SubprocessTimeoutThread, self).__init__()
52-
self.args = args
53-
self.kwargs = kwargs
54-
# ignore the preexec_fn if specified
55-
if "preexec_fn" in kwargs:
56-
del self.kwargs["preexec_fn"]
57-
58-
if "startupinfo" in kwargs:
59-
del self.kwargs["startupinfo"]
60-
61-
if sublime.platform() == "windows":
62-
# ensure console window doesn't show
63-
self.kwargs["startupinfo"] = startupinfo = subprocess.STARTUPINFO()
64-
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
65-
self.kwargs["shell"] = True
43+
def check_output(cmd, env=None):
44+
startupinfo = None
45+
if sublime.platform() == "windows":
46+
# ensure console window doesn't show
47+
startupinfo = subprocess.STARTUPINFO()
48+
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
6649

67-
self.timeout = timeout
68-
69-
self.returncode = None
70-
self.stdout = None
71-
self.stderr = None
72-
73-
def run(self):
74-
if sublime.platform() != "windows":
75-
preexec_fn = os.setsid
76-
else:
77-
preexec_fn = None
78-
79-
try:
80-
self._p = p = subprocess.Popen(*self.args, preexec_fn=preexec_fn, **self.kwargs)
81-
82-
self.stdout, self.stderr = p.communicate()
83-
self.returncode = p.returncode
84-
except Exception as e:
85-
# just in case...
86-
self.kill_process()
87-
raise e
88-
89-
def start(self):
90-
super(SubprocessTimeoutThread, self).start()
91-
self.join(self.timeout)
92-
93-
# if the timeout occurred, kill the entire process chain
94-
if self.isAlive():
95-
self.kill_process()
96-
97-
def kill_process(self):
98-
try:
99-
if sublime.platform == "windows":
100-
startupinfo = subprocess.STARTUPINFO()
101-
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
102-
subprocess.call(
103-
f"taskkill /t /f /pid {self._p.pid}",
104-
startupinfo=startupinfo,
105-
shell=True,
106-
)
107-
else:
108-
os.killpg(self._p.pid, signal.SIGKILL)
109-
except Exception:
110-
traceback.print_exc()
50+
return subprocess.check_output(
51+
cmd,
52+
env=env,
53+
timeout=30,
54+
encoding="utf-8",
55+
errors="ignore",
56+
universal_newlines=True,
57+
startupinfo=startupinfo
58+
)
11159

11260

11361
def get_version_info(executable, env=None):
@@ -123,24 +71,11 @@ def get_version_info(executable, env=None):
12371
version = "-version"
12472

12573
try:
126-
t = SubprocessTimeoutThread(
127-
30, # wait 30 seconds
128-
[executable, version],
129-
stdout=subprocess.PIPE,
130-
stderr=subprocess.STDOUT,
131-
shell=False,
132-
env=env,
133-
)
134-
135-
t.start()
136-
137-
stdout = t.stdout
74+
stdout = check_output([executable, version], env=env)
13875
if stdout is None:
13976
return None
14077

141-
return re.split(r"\r?\n", stdout.decode(encoding="utf-8", errors="ignore").strip(), 1)[
142-
0
143-
].lstrip("Version: ")
78+
return stdout.split("\n", 1)[0].lstrip("Version: ")
14479
except Exception:
14580
return None
14681

@@ -153,22 +88,11 @@ def get_tex_path_variable_texlive(variable, env=None):
15388
logger.info(f"Reading path for {variable}...")
15489

15590
try:
156-
t = SubprocessTimeoutThread(
157-
30, # wait up to 30 seconds
158-
["kpsewhich", "--expand-path=$" + variable],
159-
stdout=subprocess.PIPE,
160-
stderr=subprocess.STDOUT,
161-
shell=False,
162-
env=env,
163-
)
164-
165-
t.start()
166-
167-
stdout = t.stdout
91+
stdout = check_output(["kpsewhich", f"--expand-path=${variable}"], env=env)
16892
if stdout is None:
16993
return None
17094

171-
return "\n".join(re.split(r"\r?\n", stdout.decode("utf-8").strip()))
95+
return stdout.strip()
17296
except Exception:
17397
return None
17498

@@ -180,30 +104,17 @@ def get_tex_path_variable_miktex(variable, env=None):
180104
"""
181105
logger.info(f"Reading path for {variable}...")
182106

183-
try:
184-
command = ["findtexmf", "-alias=latex"]
185-
command.append(
186-
("-show-path={" + variable + "}").format(
187-
TEXINPUTS="tex", BIBINPUTS="bib", BSTINPUTS="bst"
188-
)
189-
)
107+
arg = {"TEXINPUTS": "tex", "BIBINPUTS": "bib", "BSTINPUTS": "bst"}
190108

191-
t = SubprocessTimeoutThread(
192-
30, # wait up to 30 seconds
193-
command,
194-
stdout=subprocess.PIPE,
195-
stderr=subprocess.STDOUT,
196-
shell=False,
197-
env=env,
109+
try:
110+
stdout = check_output(
111+
["findtexmf", "-alias=latex", f"-show-path={arg['variable']}"],
112+
env=env
198113
)
199-
200-
t.start()
201-
202-
stdout = t.stdout
203114
if stdout is None:
204115
return None
205116

206-
output = "\n".join(re.split(r"\r?\n", stdout.decode("utf-8").strip()))
117+
output = stdout.strip()
207118
return os.pathsep.join([os.path.normpath(p) for p in output.split(os.pathsep)])
208119
except Exception:
209120
return None

0 commit comments

Comments
 (0)