From 964620929cf5bde4bdc779ce1ec5aeb618895552 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Fri, 24 Jul 2020 21:59:43 +0000 Subject: spix (24jul20) git-svn-id: svn://tug.org/texlive/trunk@55933 c570f23f-e606-0410-a88d-b1316a301751 --- .../source/texk/texlive/linked_scripts/Makefile.am | 1 + .../source/texk/texlive/linked_scripts/Makefile.in | 1 + .../source/texk/texlive/linked_scripts/scripts.lst | 1 + .../texk/texlive/linked_scripts/spix/spix.py | 145 +++++++++++++++++++++ 4 files changed, 148 insertions(+) create mode 100755 Build/source/texk/texlive/linked_scripts/spix/spix.py (limited to 'Build/source') diff --git a/Build/source/texk/texlive/linked_scripts/Makefile.am b/Build/source/texk/texlive/linked_scripts/Makefile.am index 17f0218f2ab..e645c612f4a 100644 --- a/Build/source/texk/texlive/linked_scripts/Makefile.am +++ b/Build/source/texk/texlive/linked_scripts/Makefile.am @@ -198,6 +198,7 @@ texmf_other_scripts = \ pythontex/depythontex.py \ pythontex/pythontex.py \ rubik/rubikrotation.pl \ + spix/spix.py \ splitindex/splitindex.pl \ srcredact/srcredact.pl \ sty2dtx/sty2dtx.pl \ diff --git a/Build/source/texk/texlive/linked_scripts/Makefile.in b/Build/source/texk/texlive/linked_scripts/Makefile.in index 2b1e2ad3761..76ba9f64465 100644 --- a/Build/source/texk/texlive/linked_scripts/Makefile.in +++ b/Build/source/texk/texlive/linked_scripts/Makefile.in @@ -411,6 +411,7 @@ texmf_other_scripts = \ pythontex/depythontex.py \ pythontex/pythontex.py \ rubik/rubikrotation.pl \ + spix/spix.py \ splitindex/splitindex.pl \ srcredact/srcredact.pl \ sty2dtx/sty2dtx.pl \ diff --git a/Build/source/texk/texlive/linked_scripts/scripts.lst b/Build/source/texk/texlive/linked_scripts/scripts.lst index b9925bdbfb1..01bf79d494e 100644 --- a/Build/source/texk/texlive/linked_scripts/scripts.lst +++ b/Build/source/texk/texlive/linked_scripts/scripts.lst @@ -140,6 +140,7 @@ pygmentex/pygmentex.py pythontex/depythontex.py pythontex/pythontex.py rubik/rubikrotation.pl +spix/spix.py splitindex/splitindex.pl srcredact/srcredact.pl sty2dtx/sty2dtx.pl diff --git a/Build/source/texk/texlive/linked_scripts/spix/spix.py b/Build/source/texk/texlive/linked_scripts/spix/spix.py new file mode 100755 index 00000000000..1369703a7aa --- /dev/null +++ b/Build/source/texk/texlive/linked_scripts/spix/spix.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python3 + +# Copyright 2020 Louis Paternault +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +"""Compile a `.tex` file, executing commands that are set inside the file itself.""" + +import argparse +import logging +import os +import pathlib +import re +import subprocess +import sys + +NAME = "SpiX" +VERSION = "1.1.0" + +RE_EMPTY = re.compile("^ *$") +RE_COMMENT = re.compile("^ *%") +RE_COMMAND = re.compile(r"^%\$ ?(.*)$") + + +class SpixError(Exception): + """Exception that should be catched and nicely displayed to user.""" + + +def parse_lines(lines): + """Parse line to find code snippets. + + :param iterable lines: Lines to parte (typically ``open("foo.tex").readlines()``. + :return: Iterator over snippets (as strings). + """ + snippet = None + for line in lines: + line = line.rstrip("\n") + if RE_COMMAND.match(line): + match = RE_COMMAND.match(line) + if snippet is None: + snippet = "" + else: + snippet += "\n" + snippet += match.groups()[0] + elif RE_EMPTY.match(line) or RE_COMMENT.match(line): + if snippet is not None: + yield snippet + snippet = None + else: + break + if snippet is not None: + yield snippet + + +def compiletex(filename, *, dryrun=False): + """Read commands from file, and execute them. + + :param str filename: File to process. + :param bool dryrun: If ``True``, print commands to run, but do not execute them. + """ + env = os.environ + filename = pathlib.Path(filename) + env["texname"] = filename.name + env["basename"] = filename.stem + + try: + with open(filename, errors="ignore") as file: + for snippet in parse_lines(file.readlines()): + print(snippet) + if dryrun: + continue + + subprocess.check_call( + ["sh", "-c", snippet, NAME, filename.name], + cwd=(pathlib.Path.cwd() / filename).parent, + env=env, + ) + except subprocess.CalledProcessError: + raise SpixError() + except IsADirectoryError as error: + raise SpixError(str(error)) + + +def commandline_parser(): + """Return a command line parser. + + :rtype: argparse.ArgumentParser + """ + parser = argparse.ArgumentParser( + prog="spix", + description=( + "Compile a `.tex` file, " + "executing commands that are set inside the file itself." + ), + ) + parser.add_argument( + "-n", + "--dry-run", + action="store_true", + help="Print the commands that would be executed, but do not execute them.", + ) + parser.add_argument( + "--version", + help="Show version and exit.", + action="version", + version=f"{NAME} {VERSION}", + ) + parser.add_argument("FILE", nargs=1, help="File to process.") + + return parser + + +def main(): + """Main function.""" + arguments = commandline_parser().parse_args() + + if os.path.exists(arguments.FILE[0]): + arguments.FILE = arguments.FILE[0] + elif os.path.exists(f"{arguments.FILE[0]}.tex"): + arguments.FILE = f"{arguments.FILE[0]}.tex" + else: + logging.error("""File not found: "%s".""", arguments.FILE[0]) + sys.exit(1) + + try: + compiletex(arguments.FILE, dryrun=arguments.dry_run) + except SpixError as error: + if str(error): + logging.error(error) + sys.exit(1) + + +if __name__ == "__main__": + main() -- cgit v1.2.3