diff --git a/jupyterlab_latex/build.py b/jupyterlab_latex/build.py index 2d2f69c..1fe62a3 100644 --- a/jupyterlab_latex/build.py +++ b/jupyterlab_latex/build.py @@ -1,7 +1,6 @@ """ JupyterLab LaTex : live LaTeX editing for JupyterLab """ import glob, json, re, os -from contextlib import contextmanager import shutil from tornado import gen, web @@ -11,53 +10,6 @@ from .config import LatexConfig from .util import run_command -@contextmanager -def latex_cleanup(cleanup=True, workdir='.', whitelist=None, greylist=None): - """Context manager for changing directory and removing files when done. - - By default it works in the current directory, and removes all files that - were not present in the working directory. - - Parameters - ---------- - - workdir = string, optional - This represents a path to the working directory for running LaTeX (the - default is '.'). - whitelist = list or None, optional - This is the set of files not present before running the LaTeX commands - that are not to be removed when cleaning up. Defaults to None. - greylist = list or None, optional - This is the set of files that need to be removed before running LaTeX - commands but which, if present, will not by removed when cleaning up. - Defaults to None. - """ - orig_work_dir = os.getcwd() - os.chdir(os.path.abspath(workdir)) - - keep_files = set() - for fp in greylist: - try: - os.remove(fp) - keep_files.add(fp) - except FileNotFoundError: - pass - - before = set(glob.glob("*")) - keep_files = keep_files.union(before, - set(whitelist if whitelist else []) - ) - yield - if cleanup: - after = set(glob.glob("*")) - for fn in set(after-keep_files): - if not os.path.isdir(fn): - os.remove(fn) - else: - shutil.rmtree(fn) - os.chdir(orig_work_dir) - - class LatexBuildHandler(APIHandler): """ @@ -245,7 +197,7 @@ def filter_output(self, latex_output): return '\n'.join(filtered_output) @gen.coroutine - def run_latex(self, command_sequence): + def run_latex(self, command_sequence, working_directory): """Run commands sequentially, returning a 500 code on an error. Parameters @@ -269,9 +221,9 @@ def run_latex(self, command_sequence): """ for cmd in command_sequence: - self.log.debug(f'jupyterlab-latex: run: {" ".join(cmd)} (CWD: {os.getcwd()})') + self.log.debug(f'jupyterlab-latex: run: {" ".join(cmd)} (CWD: {working_directory})') - code, output = yield run_command(cmd) + code, output = yield run_command(cmd, working_directory) if code != 0: self.set_status(500) self.log.error((f'LaTeX command `{" ".join(cmd)}` ' @@ -290,6 +242,7 @@ def get(self, path = ''): # Parse the path into the base name and extension of the file tex_file_path = os.path.join(self.root_dir, path.strip('/')) tex_base_name, ext = os.path.splitext(os.path.basename(tex_file_path)) + working_directory = os.path.abspath(os.path.dirname(tex_file_path)) c = LatexConfig(config=self.config) self.log.debug((f"jupyterlab-latex: get: path=({path}), " @@ -303,12 +256,33 @@ def get(self, path = ''): out = (f"The file at `{tex_file_path}` does not end with .tex. " "You can only run LaTeX on a file ending with .tex.") else: - with latex_cleanup( - cleanup=c.cleanup, - workdir=os.path.dirname(tex_file_path), - whitelist=[tex_base_name+'.pdf', tex_base_name+'.synctex.gz'], - greylist=[tex_base_name+'.aux'] - ): - cmd_sequence = self.build_tex_cmd_sequence(tex_base_name) - out = yield self.run_latex(cmd_sequence) + whitelist = [tex_base_name+'.pdf', tex_base_name+'.synctex.gz'] + greylist = [tex_base_name+'.aux'] + + keep_files = set() + for fp in greylist: + try: + os.remove(os.path.join(working_directory, fp)) + keep_files.add(fp) + except FileNotFoundError: + pass + + before = set(glob.glob("*", root_dir=working_directory)) + keep_files = keep_files.union(before, + set(whitelist if whitelist else []) + ) + + + cmd_sequence = self.build_tex_cmd_sequence(tex_base_name) + out = yield self.run_latex(cmd_sequence, working_directory) + + if c.cleanup: + after = set(glob.glob("*", root_dir=working_directory)) + for fn in set(after-keep_files): + abs_fn = os.path.join(working_directory, fn) + if not os.path.isdir(abs_fn): + os.remove(abs_fn) + else: + shutil.rmtree(abs_fn) + self.finish(out) diff --git a/jupyterlab_latex/synctex.py b/jupyterlab_latex/synctex.py index 72f62e8..1cb98e4 100644 --- a/jupyterlab_latex/synctex.py +++ b/jupyterlab_latex/synctex.py @@ -123,7 +123,7 @@ def build_synctex_view_cmd(self, tex_name, pos): @gen.coroutine - def run_synctex(self, cmd): + def run_synctex(self, cmd, working_directory): """Run commands sequentially, returning a 500 code on an error. Parameters @@ -145,8 +145,8 @@ def run_synctex(self, cmd): there. """ - self.log.debug(f'jupyterlab-latex: run: {" ".join(cmd)} (CWD: {os.getcwd()})') - code, output = yield run_command(cmd) + self.log.debug(f'jupyterlab-latex: run: {" ".join(cmd)} (CWD: {working_directory})') + code, output = yield run_command(cmd, working_directory) if code != 0: self.set_status(500) self.log.error((f'SyncTex command `{" ".join(cmd)}` ' @@ -194,7 +194,7 @@ def get(self, path = ''): else: cmd, pos = self.build_synctex_cmd(relative_base_path, ext) - out = yield self.run_synctex(cmd) + out = yield self.run_synctex(cmd, workdir) out = json.dumps(parse_synctex_response(out, pos)) self.finish(out) diff --git a/jupyterlab_latex/util.py b/jupyterlab_latex/util.py index 0e74161..6945634 100644 --- a/jupyterlab_latex/util.py +++ b/jupyterlab_latex/util.py @@ -6,7 +6,7 @@ from tornado.process import Subprocess, CalledProcessError @gen.coroutine -def run_command_sync(cmd): +def run_command_sync(cmd, working_directory): """ Run a command using the synchronous `subprocess.run`. The asynchronous `run_command_async` should be preferred, @@ -22,7 +22,7 @@ def run_command_sync(cmd): A tuple containing the (return code, stdout) """ try: - process = subprocess.run(cmd, stdout=subprocess.PIPE) + process = subprocess.run(cmd, stdout=subprocess.PIPE, cwd=working_directory) except subprocess.CalledProcessError as err: pass code = process.returncode @@ -30,7 +30,7 @@ def run_command_sync(cmd): return (code, out) @gen.coroutine -def run_command_async(cmd): +def run_command_async(cmd, working_directory): """ Run a command using the asynchronous `tornado.process.Subprocess`. @@ -45,7 +45,8 @@ def run_command_async(cmd): """ process = Subprocess(cmd, stdout=Subprocess.STREAM, - stderr=Subprocess.STREAM) + stderr=Subprocess.STREAM, + cwd=working_directory) try: yield process.wait_for_exit() except CalledProcessError as err: