texlive[72375] trunk: minted 3.0: latexminted user-level executable,
commits+karl at tug.org
commits+karl at tug.org
Wed Sep 25 00:39:08 CEST 2024
Revision: 72375
https://tug.org/svn/texlive?view=revision&revision=72375
Author: karl
Date: 2024-09-25 00:39:08 +0200 (Wed, 25 Sep 2024)
Log Message:
-----------
minted 3.0: latexminted user-level executable, .whl files under /scripts/
Modified Paths:
--------------
trunk/Build/source/texk/texlive/linked_scripts/Makefile.am
trunk/Build/source/texk/texlive/linked_scripts/Makefile.in
trunk/Build/source/texk/texlive/linked_scripts/scripts.lst
trunk/Master/tlpkg/libexec/ctan2tds
trunk/Master/tlpkg/tlpsrc/minted.tlpsrc
Added Paths:
-----------
trunk/Build/source/texk/texlive/linked_scripts/minted/
trunk/Build/source/texk/texlive/linked_scripts/minted/latexminted.py
trunk/Master/bin/aarch64-linux/latexminted
trunk/Master/bin/amd64-freebsd/latexminted
trunk/Master/bin/amd64-netbsd/latexminted
trunk/Master/bin/armhf-linux/latexminted
trunk/Master/bin/i386-freebsd/latexminted
trunk/Master/bin/i386-linux/latexminted
trunk/Master/bin/i386-netbsd/latexminted
trunk/Master/bin/i386-solaris/latexminted
trunk/Master/bin/universal-darwin/latexminted
trunk/Master/bin/windows/latexminted.exe
trunk/Master/bin/x86_64-cygwin/latexminted
trunk/Master/bin/x86_64-darwinlegacy/latexminted
trunk/Master/bin/x86_64-linux/latexminted
trunk/Master/bin/x86_64-linuxmusl/latexminted
trunk/Master/bin/x86_64-solaris/latexminted
trunk/Master/texmf-dist/scripts/minted/
trunk/Master/texmf-dist/scripts/minted/latex2pydata-0.4.0-py3-none-any.whl
trunk/Master/texmf-dist/scripts/minted/latexminted-0.1.0-py3-none-any.whl
trunk/Master/texmf-dist/scripts/minted/latexminted.py
trunk/Master/texmf-dist/scripts/minted/latexrestricted-0.4.0-py3-none-any.whl
trunk/Master/texmf-dist/scripts/minted/pygments-2.18.0-py3-none-any.whl
Removed Paths:
-------------
trunk/Master/texmf-dist/doc/latex/minted/latex2pydata-0.4.0-py3-none-any.whl
trunk/Master/texmf-dist/doc/latex/minted/latexminted-0.1.0-py3-none-any.whl
trunk/Master/texmf-dist/doc/latex/minted/latexrestricted-0.4.0-py3-none-any.whl
trunk/Master/texmf-dist/doc/latex/minted/pygments-2.18.0-py3-none-any.whl
trunk/Master/texmf-dist/tex/latex/minted/latexminted.py
Modified: trunk/Build/source/texk/texlive/linked_scripts/Makefile.am
===================================================================
--- trunk/Build/source/texk/texlive/linked_scripts/Makefile.am 2024-09-24 20:32:58 UTC (rev 72374)
+++ trunk/Build/source/texk/texlive/linked_scripts/Makefile.am 2024-09-24 22:39:08 UTC (rev 72375)
@@ -191,6 +191,7 @@
memoize/memoize-extract.pl \
memoize/memoize-extract.py \
mf2pt1/mf2pt1.pl \
+ minted/latexminted.py \
mkgrkindex/mkgrkindex \
mkjobtexmf/mkjobtexmf.pl \
mkpic/mkpic \
Modified: trunk/Build/source/texk/texlive/linked_scripts/Makefile.in
===================================================================
--- trunk/Build/source/texk/texlive/linked_scripts/Makefile.in 2024-09-24 20:32:58 UTC (rev 72374)
+++ trunk/Build/source/texk/texlive/linked_scripts/Makefile.in 2024-09-24 22:39:08 UTC (rev 72375)
@@ -411,6 +411,7 @@
memoize/memoize-extract.pl \
memoize/memoize-extract.py \
mf2pt1/mf2pt1.pl \
+ minted/latexminted.py \
mkgrkindex/mkgrkindex \
mkjobtexmf/mkjobtexmf.pl \
mkpic/mkpic \
Added: trunk/Build/source/texk/texlive/linked_scripts/minted/latexminted.py
===================================================================
--- trunk/Build/source/texk/texlive/linked_scripts/minted/latexminted.py (rev 0)
+++ trunk/Build/source/texk/texlive/linked_scripts/minted/latexminted.py 2024-09-24 22:39:08 UTC (rev 72375)
@@ -0,0 +1,359 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2024, Geoffrey M. Poore
+# All rights reserved.
+#
+# Licensed under the LaTeX Project Public License version 1.3c:
+# https://www.latex-project.org/lppl.txt
+#
+
+
+'''
+This Python executable is intended for installation within a TeX distribution,
+along with Python wheels for the following Python packages:
+
+ * latexminted: https://pypi.org/project/latexminted/
+
+ * latexrestricted: https://pypi.org/project/latexrestricted/
+
+ * latex2pydata: https://pypi.org/project/latex2pydata/
+
+ * Pygments: https://pypi.org/project/Pygments/
+
+The combined executable plus wheels provide everything that is needed for the
+Python side of the minted LaTeX package. No additional Python libraries are
+required.
+
+The wheels require Python >= 3.8. If this executable is launched with an
+earlier Python version, then it will attempt to locate a more recent Python
+installation and run itself with that Python version in a subprocess. The
+search for more recent Python versions looks for executables of the form
+`python3.x` on PATH.
+
+If the latexminted Python package is installed separately, outside TeX, then
+it will create a separate `latexminted` executable as part of the installation
+process. That makes it possible to install latexminted and dependencies
+separately and then customize Pygments with additional packages that provide
+plugins. However, running that separate `latexminted` executable is not
+straightforward under Windows. Under Windows, if this executable finds a
+suitable `latexminted` executable elsewhere, outside a TeX installation, then
+this executable will run that separate `latexminted` executable in a
+subprocess and exit. There are two reasons for this approach:
+
+ 1. Under Windows with TeX Live, the default restricted shell escape can only
+ run executables such as `latexminted` that are part of the TeX
+ installation; the executable that runs is not the first executable on
+ PATH. That is part of TeX Live's security measures to prevent running
+ executables in the current working directory, which is typically writable
+ by LaTeX and is the first place Windows checks when searching for
+ executables. This script and the latexrestricted Python package enforce
+ equivalent security, but do so in a less restrictive manner by expanding
+ executable names into executable paths with Python's `shutil.which()` and
+ then comparing the result with locations writable by LaTeX.
+
+ 2. Under non-Windows operating systems, it is possible to modify PATH so that
+ the desired `latexminted` executable is first. Under Windows, the system
+ PATH is prepended to the user PATH, so a system-wide TeX installation will
+ prevent a user-installed `latexminted` executable from being accessible.
+
+Requirements for locating and running a separate `latexminted` executable
+under Windows:
+
+ * The separate executable must be the first `latexminted.exe` found on PATH,
+ or it must be the first `latexminted.exe` on PATH that is located under
+ the user home directory.
+
+ * The separate executable must be outside a TeX installation. There is a
+ check for a `tex.exe` executable in the same directory as
+ `latexminted.exe`. There is a check for the case-insensitive strings
+ "texlive", "miktex", and "tinytex" in the path to the `latexminted`
+ executable. With TeX Live, the path to the `latexminted` executable is
+ also compared to the environment variable `SELFAUTOLOC`.
+
+ * The separate executable must be outside the current working directory,
+ TEXMFOUTPUT, and TEXMF_OUTPUT_DIRECTORY.
+
+ * The current directory, TEXMFOUTPUT, and TEXMF_OUTPUT_DIRECTORY cannot be
+ subdirectories of the directory in which the executable is located.
+'''
+
+
+__version__ = '0.1.0'
+
+
+import os
+import pathlib
+import platform
+import shutil
+import subprocess
+import sys
+
+
+
+
+# This is an abbreviated variant of `AnyPath` from latexrestricted:
+# https://github.com/gpoore/latexrestricted/blob/main/latexrestricted/_anypath.py
+class Path(type(pathlib.Path())):
+ __slots__ = (
+ '_cache_key',
+ )
+
+ if sys.version_info[:2] < (3, 9):
+ def is_relative_to(self, other):
+ try:
+ self.relative_to(other)
+ return True
+ except ValueError:
+ return False
+
+ @property
+ def cache_key(self):
+ try:
+ return self._cache_key
+ except AttributeError:
+ self._cache_key = (type(self), self)
+ return self._cache_key
+
+ _resolved_set = set()
+
+ def resolve(self):
+ resolved = super().resolve()
+ self._resolved_set.add(resolved.cache_key)
+ return resolved
+
+ def is_resolved(self) -> bool:
+ return self.cache_key in self._resolved_set
+
+
+
+
+# Define function that determines whether subprocess executable paths are
+# permitted.
+prohibited_path_roots = set()
+prohibited_path_roots.add(Path.cwd())
+env_TEXMFOUTPUT = os.getenv('TEXMFOUTPUT')
+env_TEXMF_OUTPUT_DIRECTORY = os.getenv('TEXMF_OUTPUT_DIRECTORY')
+for env_var in (env_TEXMFOUTPUT, env_TEXMF_OUTPUT_DIRECTORY):
+ if env_var:
+ env_var_path = Path(env_var)
+ prohibited_path_roots.add(env_var_path)
+ prohibited_path_roots.add(env_var_path.resolve())
+
+def is_permitted_executable_path(executable_path, executable_path_resolved):
+ if not executable_path_resolved.is_resolved():
+ raise Exception('Second argument must be resolved path')
+ if any(e.is_relative_to(p) or p.is_relative_to(e)
+ for e in set([executable_path.parent, executable_path_resolved.parent])
+ for p in prohibited_path_roots):
+ return False
+ return True
+
+# TeX Live allows setting `TEXMFOUTPUT` in LaTeX configuration.
+# Retrieving that value with kpsewhich follows the approach in latexrestricted:
+# https://github.com/gpoore/latexrestricted/blob/main/latexrestricted/_latex_config.py
+env_SELFAUTOLOC = os.getenv('SELFAUTOLOC')
+env_TEXSYSTEM = os.getenv('TEXSYSTEM')
+if not env_TEXMFOUTPUT and env_SELFAUTOLOC and (not env_TEXSYSTEM or env_TEXSYSTEM.lower() != 'miktex'):
+ if platform.system() == 'Windows':
+ # Under Windows, shell escape executables will often be launched with
+ # the TeX Live `runscript.exe` executable wrapper. This overwrites
+ # `SELFAUTOLOC` from TeX with the location of the wrapper, so
+ # `SELFAUTOLOC` may not be correct.
+ which_tlmgr = shutil.which('tlmgr') # No `.exe`; likely `.bat`
+ if not which_tlmgr:
+ sys.exit('Failed to find TeX Live "tlmgr" executable on PATH')
+ which_tlmgr_resolved = Path(which_tlmgr).resolve()
+ texlive_bin_path = which_tlmgr_resolved.parent
+ # Make sure executable is *.exe, not *.bat or *.cmd:
+ # https://docs.python.org/3/library/subprocess.html#security-considerations
+ which_kpsewhich = shutil.which('kpsewhich.exe', path=str(texlive_bin_path))
+ if not which_kpsewhich:
+ sys.exit('Failed to find a TeX Live "tlmgr" executable with accompanying "kpsewhich" executable on PATH')
+ which_kpsewhich_path = Path(which_kpsewhich)
+ which_kpsewhich_resolved = which_kpsewhich_path.resolve()
+ if not texlive_bin_path == which_kpsewhich_resolved.parent:
+ sys.exit(' '.join([
+ '"tlmgr" executable from PATH resolved to "{}" '.format(which_tlmgr_resolved.as_posix()),
+ 'while "kpsewhich" resolved to "{}";'.format(which_kpsewhich_resolved.as_posix()),
+ '"tlmgr" and "kpsewhich" should be in the same location',
+ ]))
+ if not which_kpsewhich_resolved.name.lower().endswith('.exe'):
+ sys.exit(' '.join([
+ 'Executable "kpsewhich" resolved to "{}",'.format(which_kpsewhich_resolved.as_posix()),
+ 'but *.exe is required',
+ ]))
+ else:
+ which_kpsewhich = shutil.which('kpsewhich', path=env_SELFAUTOLOC)
+ if not which_kpsewhich:
+ sys.exit(' '.join([
+ 'Environment variable SELFAUTOLOC has value "{}",'.format(env_SELFAUTOLOC),
+ 'but a "kpsewhich" executable was not found at that location',
+ ]))
+ which_kpsewhich_path = Path(which_kpsewhich)
+ which_kpsewhich_resolved = which_kpsewhich_path.resolve()
+ if not is_permitted_executable_path(which_kpsewhich_path, which_kpsewhich_resolved):
+ # As in the latexrestricted case, this doesn't initially check for the
+ # TeX Live scenario where `TEXMFOUTPUT` is set in a `texmf.cnf` config
+ # file to a location that includes the `kpsewhich` executable. There
+ # isn't a good way to get the value of `TEXMFOUTPUT` without running
+ # `kpsewhich` in that case.
+ sys.exit(
+ 'Executable "kpsewhich" is located under the current directory, TEXMFOUTPUT, or '
+ 'TEXMF_OUTPUT_DIRECTORY, or one of these locations is under the same directory as the executable'
+ )
+ kpsewhich_cmd = [which_kpsewhich_resolved.as_posix(), '--var-value', 'TEXMFOUTPUT']
+ try:
+ kpsewhich_proc = subprocess.run(kpsewhich_cmd, shell=False, capture_output=True)
+ except PermissionError:
+ sys.exit('Insufficient permission to run "{}"'.format(which_kpsewhich_resolved.as_posix()))
+ kpsewhich_TEXMFOUTPUT = kpsewhich_proc.stdout.decode(sys.stdout.encoding) or None
+ if kpsewhich_TEXMFOUTPUT:
+ kpsewhich_TEXMFOUTPUT_path = Path(kpsewhich_TEXMFOUTPUT)
+ prohibited_path_roots.add(kpsewhich_TEXMFOUTPUT_path)
+ prohibited_path_roots.add(kpsewhich_TEXMFOUTPUT_path.resolve())
+ if not is_permitted_executable_path(which_kpsewhich_path, which_kpsewhich_resolved):
+ # It is now possible to check for the TeX Live scenario where
+ # `TEXMFOUTPUT` is set in a `texmf.cnf` config file to a location that
+ # includes the `kpsewhich` executable. Giving an error message after
+ # already running `kpsewhich` isn't ideal, but there isn't a good
+ # alternative. As in the latexrestricted case, the impact on overall
+ # security is negligible because an unsafe value of `TEXMFOUTPUT`
+ # means that all TeX-related executables are potentially compromised.
+ sys.exit(
+ 'Executable "kpsewhich" is located under the current directory, TEXMFOUTPUT, or '
+ 'TEXMF_OUTPUT_DIRECTORY, or one of these locations is under the same directory as the executable'
+ )
+
+
+
+
+# If Python version is < 3.8, try to locate a more recent version and then
+# relaunch this script with that Python version in a subprocess.
+if sys.version_info[:2] < (3, 8):
+ for minor_version in range(13, 7, -1):
+ if platform.system() == 'Windows':
+ # Batch files must be prohibited:
+ # https://docs.python.org/3/library/subprocess.html#security-considerations
+ which_python = shutil.which('python3.{}.exe'.format(minor_version))
+ else:
+ which_python = shutil.which('python3.{}'.format(minor_version))
+ if which_python:
+ which_python_path = Path(which_python)
+ which_python_resolved = which_python_path.resolve()
+ if platform.system() == 'Windows' and not which_python_resolved.name.lower().endswith('.exe'):
+ continue
+ if is_permitted_executable_path(which_python_path, which_python_resolved):
+ python_cmd = [which_python_resolved.as_posix(), __file__] + sys.argv[1:]
+ python_proc = subprocess.run(python_cmd, shell=False, capture_output=True)
+ sys.stderr.buffer.write(python_proc.stderr)
+ sys.stdout.buffer.write(python_proc.stdout)
+ sys.exit(python_proc.returncode)
+ sys.exit('latexminted requires Python >= 3.8, but a compatible Python executable was not found on PATH')
+
+
+
+
+# Check for required wheel dependencies and add them to Python's `sys.path`.
+script_resolved = Path(__file__).resolve()
+required_wheel_packages = (
+ 'latexminted',
+ 'latexrestricted',
+ 'latex2pydata',
+ 'pygments',
+)
+wheel_paths = [p for p in script_resolved.parent.glob('*.whl') if p.name.startswith(required_wheel_packages)]
+if not wheel_paths:
+ sys.exit('latexminted failed to find bundled wheels *.whl')
+for pkg in required_wheel_packages:
+ if not any(whl.name.startswith(pkg) for whl in wheel_paths):
+ sys.exit('latexminted failed to find all required bundled wheels *.whl')
+for wheel_path in wheel_paths:
+ sys.path.insert(0, wheel_path.as_posix())
+
+
+
+
+# Under Windows, check PATH for a `latexminted` executable outside a TeX
+# installation. If a `latexminted` executable is found in a suitable location
+# with sufficient precedence, run it in a subprocess and exit.
+#
+# The environment variable `LATEXMINTED_SUBPROCESS` is used to prevent an
+# endless recursion of subprocesses in the event that a `latexminted`
+# executable *inside* a TeX installation somehow manages to pass the tests for
+# an executable *outside* a TeX installation.
+if platform.system() == 'Windows' and not os.getenv('LATEXMINTED_SUBPROCESS'):
+ os.environ['LATEXMINTED_SUBPROCESS'] = '1'
+ fallback_path_search = True
+ if env_SELFAUTOLOC:
+ env_SELFAUTOLOC_resolved = Path(env_SELFAUTOLOC).resolve()
+ else:
+ env_SELFAUTOLOC_resolved = None
+ which_latexminted = shutil.which('latexminted.exe')
+ if which_latexminted:
+ which_latexminted_path = Path(which_latexminted)
+ which_latexminted_resolved = which_latexminted_path.resolve()
+ if not which_latexminted_resolved.name.lower().endswith('.exe'):
+ sys.exit(' '.join([
+ 'Executable "latexminted" resolved to "{}",'.format(which_latexminted_resolved.as_posix()),
+ 'but *.exe is required',
+ ]))
+ if which_latexminted_resolved == script_resolved:
+ pass
+ elif (which_latexminted_resolved.parent / 'tex.exe').exists():
+ pass
+ elif any(x in which_latexminted_resolved.as_posix().lower() for x in ('texlive', 'miktex', 'tinytex')):
+ pass
+ elif env_SELFAUTOLOC_resolved and which_latexminted_resolved.is_relative_to(env_SELFAUTOLOC_resolved):
+ pass
+ elif is_permitted_executable_path(which_latexminted_path, which_latexminted_resolved):
+ latexminted_cmd = [which_latexminted_resolved.as_posix()] + sys.argv[1:]
+ latexminted_proc = subprocess.run(latexminted_cmd, shell=False, capture_output=True)
+ sys.stderr.buffer.write(latexminted_proc.stderr)
+ sys.stdout.buffer.write(latexminted_proc.stdout)
+ sys.exit(latexminted_proc.returncode)
+ else:
+ # If there was a `latexminted` executable on PATH outside a TeX
+ # installation, but it wasn't permitted due to its location, don't
+ # perform fallback search.
+ fallback_path_search = False
+ if fallback_path_search:
+ # Windows appends user PATH to system PATH, so the system PATH may
+ # prevent finding a user installation of `latexminted`. Search
+ # through PATH elements under user home directory to check for
+ # `latexminted.exe` outside a TeX installation.
+ home_path = Path.home()
+ env_PATH = os.environ.get('PATH', '')
+ for path_elem in env_PATH.split(os.pathsep):
+ if not path_elem or not Path(path_elem).is_relative_to(home_path):
+ continue
+ which_latexminted = shutil.which('latexminted.exe', path=path_elem)
+ if not which_latexminted:
+ continue
+ which_latexminted_path = Path(which_latexminted)
+ which_latexminted_resolved = which_latexminted_path.resolve()
+ if which_latexminted_resolved == script_resolved:
+ break
+ elif (which_latexminted_resolved.parent / 'tex.exe').exists():
+ break
+ elif any(x in which_latexminted_resolved.as_posix().lower() for x in ('texlive', 'miktex', 'tinytex')):
+ break
+ elif env_SELFAUTOLOC_resolved and which_latexminted_resolved.is_relative_to(env_SELFAUTOLOC_resolved):
+ break
+ elif is_permitted_executable_path(which_latexminted_path, which_latexminted_resolved):
+ latexminted_cmd = [which_latexminted_resolved.as_posix()] + sys.argv[1:]
+ try:
+ latexminted_proc = subprocess.run(latexminted_cmd, shell=False, capture_output=True)
+ except PermissionError:
+ break
+ sys.stderr.buffer.write(latexminted_proc.stderr)
+ sys.stdout.buffer.write(latexminted_proc.stdout)
+ sys.exit(latexminted_proc.returncode)
+ else:
+ break
+
+
+
+
+from latexminted.cmdline import main
+main()
Property changes on: trunk/Build/source/texk/texlive/linked_scripts/minted/latexminted.py
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Modified: trunk/Build/source/texk/texlive/linked_scripts/scripts.lst
===================================================================
--- trunk/Build/source/texk/texlive/linked_scripts/scripts.lst 2024-09-24 20:32:58 UTC (rev 72374)
+++ trunk/Build/source/texk/texlive/linked_scripts/scripts.lst 2024-09-24 22:39:08 UTC (rev 72375)
@@ -132,6 +132,7 @@
memoize/memoize-extract.pl
memoize/memoize-extract.py
mf2pt1/mf2pt1.pl
+minted/latexminted.py
mkgrkindex/mkgrkindex
mkjobtexmf/mkjobtexmf.pl
mkpic/mkpic
Added: trunk/Master/bin/aarch64-linux/latexminted
===================================================================
--- trunk/Master/bin/aarch64-linux/latexminted (rev 0)
+++ trunk/Master/bin/aarch64-linux/latexminted 2024-09-24 22:39:08 UTC (rev 72375)
@@ -0,0 +1 @@
+link ../../texmf-dist/scripts/minted/latexminted.py
\ No newline at end of file
Property changes on: trunk/Master/bin/aarch64-linux/latexminted
___________________________________________________________________
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Added: trunk/Master/bin/amd64-freebsd/latexminted
===================================================================
--- trunk/Master/bin/amd64-freebsd/latexminted (rev 0)
+++ trunk/Master/bin/amd64-freebsd/latexminted 2024-09-24 22:39:08 UTC (rev 72375)
@@ -0,0 +1 @@
+link ../../texmf-dist/scripts/minted/latexminted.py
\ No newline at end of file
Property changes on: trunk/Master/bin/amd64-freebsd/latexminted
___________________________________________________________________
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Added: trunk/Master/bin/amd64-netbsd/latexminted
===================================================================
--- trunk/Master/bin/amd64-netbsd/latexminted (rev 0)
+++ trunk/Master/bin/amd64-netbsd/latexminted 2024-09-24 22:39:08 UTC (rev 72375)
@@ -0,0 +1 @@
+link ../../texmf-dist/scripts/minted/latexminted.py
\ No newline at end of file
Property changes on: trunk/Master/bin/amd64-netbsd/latexminted
___________________________________________________________________
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Added: trunk/Master/bin/armhf-linux/latexminted
===================================================================
--- trunk/Master/bin/armhf-linux/latexminted (rev 0)
+++ trunk/Master/bin/armhf-linux/latexminted 2024-09-24 22:39:08 UTC (rev 72375)
@@ -0,0 +1 @@
+link ../../texmf-dist/scripts/minted/latexminted.py
\ No newline at end of file
Property changes on: trunk/Master/bin/armhf-linux/latexminted
___________________________________________________________________
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Added: trunk/Master/bin/i386-freebsd/latexminted
===================================================================
--- trunk/Master/bin/i386-freebsd/latexminted (rev 0)
+++ trunk/Master/bin/i386-freebsd/latexminted 2024-09-24 22:39:08 UTC (rev 72375)
@@ -0,0 +1 @@
+link ../../texmf-dist/scripts/minted/latexminted.py
\ No newline at end of file
Property changes on: trunk/Master/bin/i386-freebsd/latexminted
___________________________________________________________________
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Added: trunk/Master/bin/i386-linux/latexminted
===================================================================
--- trunk/Master/bin/i386-linux/latexminted (rev 0)
+++ trunk/Master/bin/i386-linux/latexminted 2024-09-24 22:39:08 UTC (rev 72375)
@@ -0,0 +1 @@
+link ../../texmf-dist/scripts/minted/latexminted.py
\ No newline at end of file
Property changes on: trunk/Master/bin/i386-linux/latexminted
___________________________________________________________________
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Added: trunk/Master/bin/i386-netbsd/latexminted
===================================================================
--- trunk/Master/bin/i386-netbsd/latexminted (rev 0)
+++ trunk/Master/bin/i386-netbsd/latexminted 2024-09-24 22:39:08 UTC (rev 72375)
@@ -0,0 +1 @@
+link ../../texmf-dist/scripts/minted/latexminted.py
\ No newline at end of file
Property changes on: trunk/Master/bin/i386-netbsd/latexminted
___________________________________________________________________
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Added: trunk/Master/bin/i386-solaris/latexminted
===================================================================
--- trunk/Master/bin/i386-solaris/latexminted (rev 0)
+++ trunk/Master/bin/i386-solaris/latexminted 2024-09-24 22:39:08 UTC (rev 72375)
@@ -0,0 +1 @@
+link ../../texmf-dist/scripts/minted/latexminted.py
\ No newline at end of file
Property changes on: trunk/Master/bin/i386-solaris/latexminted
___________________________________________________________________
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Added: trunk/Master/bin/universal-darwin/latexminted
===================================================================
--- trunk/Master/bin/universal-darwin/latexminted (rev 0)
+++ trunk/Master/bin/universal-darwin/latexminted 2024-09-24 22:39:08 UTC (rev 72375)
@@ -0,0 +1 @@
+link ../../texmf-dist/scripts/minted/latexminted.py
\ No newline at end of file
Property changes on: trunk/Master/bin/universal-darwin/latexminted
___________________________________________________________________
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Added: trunk/Master/bin/windows/latexminted.exe
===================================================================
(Binary files differ)
Index: trunk/Master/bin/windows/latexminted.exe
===================================================================
--- trunk/Master/bin/windows/latexminted.exe 2024-09-24 20:32:58 UTC (rev 72374)
+++ trunk/Master/bin/windows/latexminted.exe 2024-09-24 22:39:08 UTC (rev 72375)
Property changes on: trunk/Master/bin/windows/latexminted.exe
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: trunk/Master/bin/x86_64-cygwin/latexminted
===================================================================
--- trunk/Master/bin/x86_64-cygwin/latexminted (rev 0)
+++ trunk/Master/bin/x86_64-cygwin/latexminted 2024-09-24 22:39:08 UTC (rev 72375)
@@ -0,0 +1 @@
+link ../../texmf-dist/scripts/minted/latexminted.py
\ No newline at end of file
Property changes on: trunk/Master/bin/x86_64-cygwin/latexminted
___________________________________________________________________
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Added: trunk/Master/bin/x86_64-darwinlegacy/latexminted
===================================================================
--- trunk/Master/bin/x86_64-darwinlegacy/latexminted (rev 0)
+++ trunk/Master/bin/x86_64-darwinlegacy/latexminted 2024-09-24 22:39:08 UTC (rev 72375)
@@ -0,0 +1 @@
+link ../../texmf-dist/scripts/minted/latexminted.py
\ No newline at end of file
Property changes on: trunk/Master/bin/x86_64-darwinlegacy/latexminted
___________________________________________________________________
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Added: trunk/Master/bin/x86_64-linux/latexminted
===================================================================
--- trunk/Master/bin/x86_64-linux/latexminted (rev 0)
+++ trunk/Master/bin/x86_64-linux/latexminted 2024-09-24 22:39:08 UTC (rev 72375)
@@ -0,0 +1 @@
+link ../../texmf-dist/scripts/minted/latexminted.py
\ No newline at end of file
Property changes on: trunk/Master/bin/x86_64-linux/latexminted
___________________________________________________________________
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Added: trunk/Master/bin/x86_64-linuxmusl/latexminted
===================================================================
--- trunk/Master/bin/x86_64-linuxmusl/latexminted (rev 0)
+++ trunk/Master/bin/x86_64-linuxmusl/latexminted 2024-09-24 22:39:08 UTC (rev 72375)
@@ -0,0 +1 @@
+link ../../texmf-dist/scripts/minted/latexminted.py
\ No newline at end of file
Property changes on: trunk/Master/bin/x86_64-linuxmusl/latexminted
___________________________________________________________________
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Added: trunk/Master/bin/x86_64-solaris/latexminted
===================================================================
--- trunk/Master/bin/x86_64-solaris/latexminted (rev 0)
+++ trunk/Master/bin/x86_64-solaris/latexminted 2024-09-24 22:39:08 UTC (rev 72375)
@@ -0,0 +1 @@
+link ../../texmf-dist/scripts/minted/latexminted.py
\ No newline at end of file
Property changes on: trunk/Master/bin/x86_64-solaris/latexminted
___________________________________________________________________
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Deleted: trunk/Master/texmf-dist/doc/latex/minted/latex2pydata-0.4.0-py3-none-any.whl
===================================================================
(Binary files differ)
Deleted: trunk/Master/texmf-dist/doc/latex/minted/latexminted-0.1.0-py3-none-any.whl
===================================================================
(Binary files differ)
Deleted: trunk/Master/texmf-dist/doc/latex/minted/latexrestricted-0.4.0-py3-none-any.whl
===================================================================
(Binary files differ)
Deleted: trunk/Master/texmf-dist/doc/latex/minted/pygments-2.18.0-py3-none-any.whl
===================================================================
(Binary files differ)
Added: trunk/Master/texmf-dist/scripts/minted/latex2pydata-0.4.0-py3-none-any.whl
===================================================================
(Binary files differ)
Index: trunk/Master/texmf-dist/scripts/minted/latex2pydata-0.4.0-py3-none-any.whl
===================================================================
--- trunk/Master/texmf-dist/scripts/minted/latex2pydata-0.4.0-py3-none-any.whl 2024-09-24 20:32:58 UTC (rev 72374)
+++ trunk/Master/texmf-dist/scripts/minted/latex2pydata-0.4.0-py3-none-any.whl 2024-09-24 22:39:08 UTC (rev 72375)
Property changes on: trunk/Master/texmf-dist/scripts/minted/latex2pydata-0.4.0-py3-none-any.whl
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: trunk/Master/texmf-dist/scripts/minted/latexminted-0.1.0-py3-none-any.whl
===================================================================
(Binary files differ)
Index: trunk/Master/texmf-dist/scripts/minted/latexminted-0.1.0-py3-none-any.whl
===================================================================
--- trunk/Master/texmf-dist/scripts/minted/latexminted-0.1.0-py3-none-any.whl 2024-09-24 20:32:58 UTC (rev 72374)
+++ trunk/Master/texmf-dist/scripts/minted/latexminted-0.1.0-py3-none-any.whl 2024-09-24 22:39:08 UTC (rev 72375)
Property changes on: trunk/Master/texmf-dist/scripts/minted/latexminted-0.1.0-py3-none-any.whl
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: trunk/Master/texmf-dist/scripts/minted/latexminted.py
===================================================================
--- trunk/Master/texmf-dist/scripts/minted/latexminted.py (rev 0)
+++ trunk/Master/texmf-dist/scripts/minted/latexminted.py 2024-09-24 22:39:08 UTC (rev 72375)
@@ -0,0 +1,359 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2024, Geoffrey M. Poore
+# All rights reserved.
+#
+# Licensed under the LaTeX Project Public License version 1.3c:
+# https://www.latex-project.org/lppl.txt
+#
+
+
+'''
+This Python executable is intended for installation within a TeX distribution,
+along with Python wheels for the following Python packages:
+
+ * latexminted: https://pypi.org/project/latexminted/
+
+ * latexrestricted: https://pypi.org/project/latexrestricted/
+
+ * latex2pydata: https://pypi.org/project/latex2pydata/
+
+ * Pygments: https://pypi.org/project/Pygments/
+
+The combined executable plus wheels provide everything that is needed for the
+Python side of the minted LaTeX package. No additional Python libraries are
+required.
+
+The wheels require Python >= 3.8. If this executable is launched with an
+earlier Python version, then it will attempt to locate a more recent Python
+installation and run itself with that Python version in a subprocess. The
+search for more recent Python versions looks for executables of the form
+`python3.x` on PATH.
+
+If the latexminted Python package is installed separately, outside TeX, then
+it will create a separate `latexminted` executable as part of the installation
+process. That makes it possible to install latexminted and dependencies
+separately and then customize Pygments with additional packages that provide
+plugins. However, running that separate `latexminted` executable is not
+straightforward under Windows. Under Windows, if this executable finds a
+suitable `latexminted` executable elsewhere, outside a TeX installation, then
+this executable will run that separate `latexminted` executable in a
+subprocess and exit. There are two reasons for this approach:
+
+ 1. Under Windows with TeX Live, the default restricted shell escape can only
+ run executables such as `latexminted` that are part of the TeX
+ installation; the executable that runs is not the first executable on
+ PATH. That is part of TeX Live's security measures to prevent running
+ executables in the current working directory, which is typically writable
+ by LaTeX and is the first place Windows checks when searching for
+ executables. This script and the latexrestricted Python package enforce
+ equivalent security, but do so in a less restrictive manner by expanding
+ executable names into executable paths with Python's `shutil.which()` and
+ then comparing the result with locations writable by LaTeX.
+
+ 2. Under non-Windows operating systems, it is possible to modify PATH so that
+ the desired `latexminted` executable is first. Under Windows, the system
+ PATH is prepended to the user PATH, so a system-wide TeX installation will
+ prevent a user-installed `latexminted` executable from being accessible.
+
+Requirements for locating and running a separate `latexminted` executable
+under Windows:
+
+ * The separate executable must be the first `latexminted.exe` found on PATH,
+ or it must be the first `latexminted.exe` on PATH that is located under
+ the user home directory.
+
+ * The separate executable must be outside a TeX installation. There is a
+ check for a `tex.exe` executable in the same directory as
+ `latexminted.exe`. There is a check for the case-insensitive strings
+ "texlive", "miktex", and "tinytex" in the path to the `latexminted`
+ executable. With TeX Live, the path to the `latexminted` executable is
+ also compared to the environment variable `SELFAUTOLOC`.
+
+ * The separate executable must be outside the current working directory,
+ TEXMFOUTPUT, and TEXMF_OUTPUT_DIRECTORY.
+
+ * The current directory, TEXMFOUTPUT, and TEXMF_OUTPUT_DIRECTORY cannot be
+ subdirectories of the directory in which the executable is located.
+'''
+
+
+__version__ = '0.1.0'
+
+
+import os
+import pathlib
+import platform
+import shutil
+import subprocess
+import sys
+
+
+
+
+# This is an abbreviated variant of `AnyPath` from latexrestricted:
+# https://github.com/gpoore/latexrestricted/blob/main/latexrestricted/_anypath.py
+class Path(type(pathlib.Path())):
+ __slots__ = (
+ '_cache_key',
+ )
+
+ if sys.version_info[:2] < (3, 9):
+ def is_relative_to(self, other):
+ try:
+ self.relative_to(other)
+ return True
+ except ValueError:
+ return False
+
+ @property
+ def cache_key(self):
+ try:
+ return self._cache_key
+ except AttributeError:
+ self._cache_key = (type(self), self)
+ return self._cache_key
+
+ _resolved_set = set()
+
+ def resolve(self):
+ resolved = super().resolve()
+ self._resolved_set.add(resolved.cache_key)
+ return resolved
+
+ def is_resolved(self) -> bool:
+ return self.cache_key in self._resolved_set
+
+
+
+
+# Define function that determines whether subprocess executable paths are
+# permitted.
+prohibited_path_roots = set()
+prohibited_path_roots.add(Path.cwd())
+env_TEXMFOUTPUT = os.getenv('TEXMFOUTPUT')
+env_TEXMF_OUTPUT_DIRECTORY = os.getenv('TEXMF_OUTPUT_DIRECTORY')
+for env_var in (env_TEXMFOUTPUT, env_TEXMF_OUTPUT_DIRECTORY):
+ if env_var:
+ env_var_path = Path(env_var)
+ prohibited_path_roots.add(env_var_path)
+ prohibited_path_roots.add(env_var_path.resolve())
+
+def is_permitted_executable_path(executable_path, executable_path_resolved):
+ if not executable_path_resolved.is_resolved():
+ raise Exception('Second argument must be resolved path')
+ if any(e.is_relative_to(p) or p.is_relative_to(e)
+ for e in set([executable_path.parent, executable_path_resolved.parent])
+ for p in prohibited_path_roots):
+ return False
+ return True
+
+# TeX Live allows setting `TEXMFOUTPUT` in LaTeX configuration.
+# Retrieving that value with kpsewhich follows the approach in latexrestricted:
+# https://github.com/gpoore/latexrestricted/blob/main/latexrestricted/_latex_config.py
+env_SELFAUTOLOC = os.getenv('SELFAUTOLOC')
+env_TEXSYSTEM = os.getenv('TEXSYSTEM')
+if not env_TEXMFOUTPUT and env_SELFAUTOLOC and (not env_TEXSYSTEM or env_TEXSYSTEM.lower() != 'miktex'):
+ if platform.system() == 'Windows':
+ # Under Windows, shell escape executables will often be launched with
+ # the TeX Live `runscript.exe` executable wrapper. This overwrites
+ # `SELFAUTOLOC` from TeX with the location of the wrapper, so
+ # `SELFAUTOLOC` may not be correct.
+ which_tlmgr = shutil.which('tlmgr') # No `.exe`; likely `.bat`
+ if not which_tlmgr:
+ sys.exit('Failed to find TeX Live "tlmgr" executable on PATH')
+ which_tlmgr_resolved = Path(which_tlmgr).resolve()
+ texlive_bin_path = which_tlmgr_resolved.parent
+ # Make sure executable is *.exe, not *.bat or *.cmd:
+ # https://docs.python.org/3/library/subprocess.html#security-considerations
+ which_kpsewhich = shutil.which('kpsewhich.exe', path=str(texlive_bin_path))
+ if not which_kpsewhich:
+ sys.exit('Failed to find a TeX Live "tlmgr" executable with accompanying "kpsewhich" executable on PATH')
+ which_kpsewhich_path = Path(which_kpsewhich)
+ which_kpsewhich_resolved = which_kpsewhich_path.resolve()
+ if not texlive_bin_path == which_kpsewhich_resolved.parent:
+ sys.exit(' '.join([
+ '"tlmgr" executable from PATH resolved to "{}" '.format(which_tlmgr_resolved.as_posix()),
+ 'while "kpsewhich" resolved to "{}";'.format(which_kpsewhich_resolved.as_posix()),
+ '"tlmgr" and "kpsewhich" should be in the same location',
+ ]))
+ if not which_kpsewhich_resolved.name.lower().endswith('.exe'):
+ sys.exit(' '.join([
+ 'Executable "kpsewhich" resolved to "{}",'.format(which_kpsewhich_resolved.as_posix()),
+ 'but *.exe is required',
+ ]))
+ else:
+ which_kpsewhich = shutil.which('kpsewhich', path=env_SELFAUTOLOC)
+ if not which_kpsewhich:
+ sys.exit(' '.join([
+ 'Environment variable SELFAUTOLOC has value "{}",'.format(env_SELFAUTOLOC),
+ 'but a "kpsewhich" executable was not found at that location',
+ ]))
+ which_kpsewhich_path = Path(which_kpsewhich)
+ which_kpsewhich_resolved = which_kpsewhich_path.resolve()
+ if not is_permitted_executable_path(which_kpsewhich_path, which_kpsewhich_resolved):
+ # As in the latexrestricted case, this doesn't initially check for the
+ # TeX Live scenario where `TEXMFOUTPUT` is set in a `texmf.cnf` config
+ # file to a location that includes the `kpsewhich` executable. There
+ # isn't a good way to get the value of `TEXMFOUTPUT` without running
+ # `kpsewhich` in that case.
+ sys.exit(
+ 'Executable "kpsewhich" is located under the current directory, TEXMFOUTPUT, or '
+ 'TEXMF_OUTPUT_DIRECTORY, or one of these locations is under the same directory as the executable'
+ )
+ kpsewhich_cmd = [which_kpsewhich_resolved.as_posix(), '--var-value', 'TEXMFOUTPUT']
+ try:
+ kpsewhich_proc = subprocess.run(kpsewhich_cmd, shell=False, capture_output=True)
+ except PermissionError:
+ sys.exit('Insufficient permission to run "{}"'.format(which_kpsewhich_resolved.as_posix()))
+ kpsewhich_TEXMFOUTPUT = kpsewhich_proc.stdout.decode(sys.stdout.encoding) or None
+ if kpsewhich_TEXMFOUTPUT:
+ kpsewhich_TEXMFOUTPUT_path = Path(kpsewhich_TEXMFOUTPUT)
+ prohibited_path_roots.add(kpsewhich_TEXMFOUTPUT_path)
+ prohibited_path_roots.add(kpsewhich_TEXMFOUTPUT_path.resolve())
+ if not is_permitted_executable_path(which_kpsewhich_path, which_kpsewhich_resolved):
+ # It is now possible to check for the TeX Live scenario where
+ # `TEXMFOUTPUT` is set in a `texmf.cnf` config file to a location that
+ # includes the `kpsewhich` executable. Giving an error message after
+ # already running `kpsewhich` isn't ideal, but there isn't a good
+ # alternative. As in the latexrestricted case, the impact on overall
+ # security is negligible because an unsafe value of `TEXMFOUTPUT`
+ # means that all TeX-related executables are potentially compromised.
+ sys.exit(
+ 'Executable "kpsewhich" is located under the current directory, TEXMFOUTPUT, or '
+ 'TEXMF_OUTPUT_DIRECTORY, or one of these locations is under the same directory as the executable'
+ )
+
+
+
+
+# If Python version is < 3.8, try to locate a more recent version and then
+# relaunch this script with that Python version in a subprocess.
+if sys.version_info[:2] < (3, 8):
+ for minor_version in range(13, 7, -1):
+ if platform.system() == 'Windows':
+ # Batch files must be prohibited:
+ # https://docs.python.org/3/library/subprocess.html#security-considerations
+ which_python = shutil.which('python3.{}.exe'.format(minor_version))
+ else:
+ which_python = shutil.which('python3.{}'.format(minor_version))
+ if which_python:
+ which_python_path = Path(which_python)
+ which_python_resolved = which_python_path.resolve()
+ if platform.system() == 'Windows' and not which_python_resolved.name.lower().endswith('.exe'):
+ continue
+ if is_permitted_executable_path(which_python_path, which_python_resolved):
+ python_cmd = [which_python_resolved.as_posix(), __file__] + sys.argv[1:]
+ python_proc = subprocess.run(python_cmd, shell=False, capture_output=True)
+ sys.stderr.buffer.write(python_proc.stderr)
+ sys.stdout.buffer.write(python_proc.stdout)
+ sys.exit(python_proc.returncode)
+ sys.exit('latexminted requires Python >= 3.8, but a compatible Python executable was not found on PATH')
+
+
+
+
+# Check for required wheel dependencies and add them to Python's `sys.path`.
+script_resolved = Path(__file__).resolve()
+required_wheel_packages = (
+ 'latexminted',
+ 'latexrestricted',
+ 'latex2pydata',
+ 'pygments',
+)
+wheel_paths = [p for p in script_resolved.parent.glob('*.whl') if p.name.startswith(required_wheel_packages)]
+if not wheel_paths:
+ sys.exit('latexminted failed to find bundled wheels *.whl')
+for pkg in required_wheel_packages:
+ if not any(whl.name.startswith(pkg) for whl in wheel_paths):
+ sys.exit('latexminted failed to find all required bundled wheels *.whl')
+for wheel_path in wheel_paths:
+ sys.path.insert(0, wheel_path.as_posix())
+
+
+
+
+# Under Windows, check PATH for a `latexminted` executable outside a TeX
+# installation. If a `latexminted` executable is found in a suitable location
+# with sufficient precedence, run it in a subprocess and exit.
+#
+# The environment variable `LATEXMINTED_SUBPROCESS` is used to prevent an
+# endless recursion of subprocesses in the event that a `latexminted`
+# executable *inside* a TeX installation somehow manages to pass the tests for
+# an executable *outside* a TeX installation.
+if platform.system() == 'Windows' and not os.getenv('LATEXMINTED_SUBPROCESS'):
+ os.environ['LATEXMINTED_SUBPROCESS'] = '1'
+ fallback_path_search = True
+ if env_SELFAUTOLOC:
+ env_SELFAUTOLOC_resolved = Path(env_SELFAUTOLOC).resolve()
+ else:
+ env_SELFAUTOLOC_resolved = None
+ which_latexminted = shutil.which('latexminted.exe')
+ if which_latexminted:
+ which_latexminted_path = Path(which_latexminted)
+ which_latexminted_resolved = which_latexminted_path.resolve()
+ if not which_latexminted_resolved.name.lower().endswith('.exe'):
+ sys.exit(' '.join([
+ 'Executable "latexminted" resolved to "{}",'.format(which_latexminted_resolved.as_posix()),
+ 'but *.exe is required',
+ ]))
+ if which_latexminted_resolved == script_resolved:
+ pass
+ elif (which_latexminted_resolved.parent / 'tex.exe').exists():
+ pass
+ elif any(x in which_latexminted_resolved.as_posix().lower() for x in ('texlive', 'miktex', 'tinytex')):
+ pass
+ elif env_SELFAUTOLOC_resolved and which_latexminted_resolved.is_relative_to(env_SELFAUTOLOC_resolved):
+ pass
+ elif is_permitted_executable_path(which_latexminted_path, which_latexminted_resolved):
+ latexminted_cmd = [which_latexminted_resolved.as_posix()] + sys.argv[1:]
+ latexminted_proc = subprocess.run(latexminted_cmd, shell=False, capture_output=True)
+ sys.stderr.buffer.write(latexminted_proc.stderr)
+ sys.stdout.buffer.write(latexminted_proc.stdout)
+ sys.exit(latexminted_proc.returncode)
+ else:
+ # If there was a `latexminted` executable on PATH outside a TeX
+ # installation, but it wasn't permitted due to its location, don't
+ # perform fallback search.
+ fallback_path_search = False
+ if fallback_path_search:
+ # Windows appends user PATH to system PATH, so the system PATH may
+ # prevent finding a user installation of `latexminted`. Search
+ # through PATH elements under user home directory to check for
+ # `latexminted.exe` outside a TeX installation.
+ home_path = Path.home()
+ env_PATH = os.environ.get('PATH', '')
+ for path_elem in env_PATH.split(os.pathsep):
+ if not path_elem or not Path(path_elem).is_relative_to(home_path):
+ continue
+ which_latexminted = shutil.which('latexminted.exe', path=path_elem)
+ if not which_latexminted:
+ continue
+ which_latexminted_path = Path(which_latexminted)
+ which_latexminted_resolved = which_latexminted_path.resolve()
+ if which_latexminted_resolved == script_resolved:
+ break
+ elif (which_latexminted_resolved.parent / 'tex.exe').exists():
+ break
+ elif any(x in which_latexminted_resolved.as_posix().lower() for x in ('texlive', 'miktex', 'tinytex')):
+ break
+ elif env_SELFAUTOLOC_resolved and which_latexminted_resolved.is_relative_to(env_SELFAUTOLOC_resolved):
+ break
+ elif is_permitted_executable_path(which_latexminted_path, which_latexminted_resolved):
+ latexminted_cmd = [which_latexminted_resolved.as_posix()] + sys.argv[1:]
+ try:
+ latexminted_proc = subprocess.run(latexminted_cmd, shell=False, capture_output=True)
+ except PermissionError:
+ break
+ sys.stderr.buffer.write(latexminted_proc.stderr)
+ sys.stdout.buffer.write(latexminted_proc.stdout)
+ sys.exit(latexminted_proc.returncode)
+ else:
+ break
+
+
+
+
+from latexminted.cmdline import main
+main()
Property changes on: trunk/Master/texmf-dist/scripts/minted/latexminted.py
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: trunk/Master/texmf-dist/scripts/minted/latexrestricted-0.4.0-py3-none-any.whl
===================================================================
(Binary files differ)
Index: trunk/Master/texmf-dist/scripts/minted/latexrestricted-0.4.0-py3-none-any.whl
===================================================================
--- trunk/Master/texmf-dist/scripts/minted/latexrestricted-0.4.0-py3-none-any.whl 2024-09-24 20:32:58 UTC (rev 72374)
+++ trunk/Master/texmf-dist/scripts/minted/latexrestricted-0.4.0-py3-none-any.whl 2024-09-24 22:39:08 UTC (rev 72375)
Property changes on: trunk/Master/texmf-dist/scripts/minted/latexrestricted-0.4.0-py3-none-any.whl
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: trunk/Master/texmf-dist/scripts/minted/pygments-2.18.0-py3-none-any.whl
===================================================================
(Binary files differ)
Index: trunk/Master/texmf-dist/scripts/minted/pygments-2.18.0-py3-none-any.whl
===================================================================
--- trunk/Master/texmf-dist/scripts/minted/pygments-2.18.0-py3-none-any.whl 2024-09-24 20:32:58 UTC (rev 72374)
+++ trunk/Master/texmf-dist/scripts/minted/pygments-2.18.0-py3-none-any.whl 2024-09-24 22:39:08 UTC (rev 72375)
Property changes on: trunk/Master/texmf-dist/scripts/minted/pygments-2.18.0-py3-none-any.whl
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Deleted: trunk/Master/texmf-dist/tex/latex/minted/latexminted.py
===================================================================
--- trunk/Master/texmf-dist/tex/latex/minted/latexminted.py 2024-09-24 20:32:58 UTC (rev 72374)
+++ trunk/Master/texmf-dist/tex/latex/minted/latexminted.py 2024-09-24 22:39:08 UTC (rev 72375)
@@ -1,359 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2024, Geoffrey M. Poore
-# All rights reserved.
-#
-# Licensed under the LaTeX Project Public License version 1.3c:
-# https://www.latex-project.org/lppl.txt
-#
-
-
-'''
-This Python executable is intended for installation within a TeX distribution,
-along with Python wheels for the following Python packages:
-
- * latexminted: https://pypi.org/project/latexminted/
-
- * latexrestricted: https://pypi.org/project/latexrestricted/
-
- * latex2pydata: https://pypi.org/project/latex2pydata/
-
- * Pygments: https://pypi.org/project/Pygments/
-
-The combined executable plus wheels provide everything that is needed for the
-Python side of the minted LaTeX package. No additional Python libraries are
-required.
-
-The wheels require Python >= 3.8. If this executable is launched with an
-earlier Python version, then it will attempt to locate a more recent Python
-installation and run itself with that Python version in a subprocess. The
-search for more recent Python versions looks for executables of the form
-`python3.x` on PATH.
-
-If the latexminted Python package is installed separately, outside TeX, then
-it will create a separate `latexminted` executable as part of the installation
-process. That makes it possible to install latexminted and dependencies
-separately and then customize Pygments with additional packages that provide
-plugins. However, running that separate `latexminted` executable is not
-straightforward under Windows. Under Windows, if this executable finds a
-suitable `latexminted` executable elsewhere, outside a TeX installation, then
-this executable will run that separate `latexminted` executable in a
-subprocess and exit. There are two reasons for this approach:
-
- 1. Under Windows with TeX Live, the default restricted shell escape can only
- run executables such as `latexminted` that are part of the TeX
- installation; the executable that runs is not the first executable on
- PATH. That is part of TeX Live's security measures to prevent running
- executables in the current working directory, which is typically writable
- by LaTeX and is the first place Windows checks when searching for
- executables. This script and the latexrestricted Python package enforce
- equivalent security, but do so in a less restrictive manner by expanding
- executable names into executable paths with Python's `shutil.which()` and
- then comparing the result with locations writable by LaTeX.
-
- 2. Under non-Windows operating systems, it is possible to modify PATH so that
- the desired `latexminted` executable is first. Under Windows, the system
- PATH is prepended to the user PATH, so a system-wide TeX installation will
- prevent a user-installed `latexminted` executable from being accessible.
-
-Requirements for locating and running a separate `latexminted` executable
-under Windows:
-
- * The separate executable must be the first `latexminted.exe` found on PATH,
- or it must be the first `latexminted.exe` on PATH that is located under
- the user home directory.
-
- * The separate executable must be outside a TeX installation. There is a
- check for a `tex.exe` executable in the same directory as
- `latexminted.exe`. There is a check for the case-insensitive strings
- "texlive", "miktex", and "tinytex" in the path to the `latexminted`
- executable. With TeX Live, the path to the `latexminted` executable is
- also compared to the environment variable `SELFAUTOLOC`.
-
- * The separate executable must be outside the current working directory,
- TEXMFOUTPUT, and TEXMF_OUTPUT_DIRECTORY.
-
- * The current directory, TEXMFOUTPUT, and TEXMF_OUTPUT_DIRECTORY cannot be
- subdirectories of the directory in which the executable is located.
-'''
-
-
-__version__ = '0.1.0'
-
-
-import os
-import pathlib
-import platform
-import shutil
-import subprocess
-import sys
-
-
-
-
-# This is an abbreviated variant of `AnyPath` from latexrestricted:
-# https://github.com/gpoore/latexrestricted/blob/main/latexrestricted/_anypath.py
-class Path(type(pathlib.Path())):
- __slots__ = (
- '_cache_key',
- )
-
- if sys.version_info[:2] < (3, 9):
- def is_relative_to(self, other):
- try:
- self.relative_to(other)
- return True
- except ValueError:
- return False
-
- @property
- def cache_key(self):
- try:
- return self._cache_key
- except AttributeError:
- self._cache_key = (type(self), self)
- return self._cache_key
-
- _resolved_set = set()
-
- def resolve(self):
- resolved = super().resolve()
- self._resolved_set.add(resolved.cache_key)
- return resolved
-
- def is_resolved(self) -> bool:
- return self.cache_key in self._resolved_set
-
-
-
-
-# Define function that determines whether subprocess executable paths are
-# permitted.
-prohibited_path_roots = set()
-prohibited_path_roots.add(Path.cwd())
-env_TEXMFOUTPUT = os.getenv('TEXMFOUTPUT')
-env_TEXMF_OUTPUT_DIRECTORY = os.getenv('TEXMF_OUTPUT_DIRECTORY')
-for env_var in (env_TEXMFOUTPUT, env_TEXMF_OUTPUT_DIRECTORY):
- if env_var:
- env_var_path = Path(env_var)
- prohibited_path_roots.add(env_var_path)
- prohibited_path_roots.add(env_var_path.resolve())
-
-def is_permitted_executable_path(executable_path, executable_path_resolved):
- if not executable_path_resolved.is_resolved():
- raise Exception('Second argument must be resolved path')
- if any(e.is_relative_to(p) or p.is_relative_to(e)
- for e in set([executable_path.parent, executable_path_resolved.parent])
- for p in prohibited_path_roots):
- return False
- return True
-
-# TeX Live allows setting `TEXMFOUTPUT` in LaTeX configuration.
-# Retrieving that value with kpsewhich follows the approach in latexrestricted:
-# https://github.com/gpoore/latexrestricted/blob/main/latexrestricted/_latex_config.py
-env_SELFAUTOLOC = os.getenv('SELFAUTOLOC')
-env_TEXSYSTEM = os.getenv('TEXSYSTEM')
-if not env_TEXMFOUTPUT and env_SELFAUTOLOC and (not env_TEXSYSTEM or env_TEXSYSTEM.lower() != 'miktex'):
- if platform.system() == 'Windows':
- # Under Windows, shell escape executables will often be launched with
- # the TeX Live `runscript.exe` executable wrapper. This overwrites
- # `SELFAUTOLOC` from TeX with the location of the wrapper, so
- # `SELFAUTOLOC` may not be correct.
- which_tlmgr = shutil.which('tlmgr') # No `.exe`; likely `.bat`
- if not which_tlmgr:
- sys.exit('Failed to find TeX Live "tlmgr" executable on PATH')
- which_tlmgr_resolved = Path(which_tlmgr).resolve()
- texlive_bin_path = which_tlmgr_resolved.parent
- # Make sure executable is *.exe, not *.bat or *.cmd:
- # https://docs.python.org/3/library/subprocess.html#security-considerations
- which_kpsewhich = shutil.which('kpsewhich.exe', path=str(texlive_bin_path))
- if not which_kpsewhich:
- sys.exit('Failed to find a TeX Live "tlmgr" executable with accompanying "kpsewhich" executable on PATH')
- which_kpsewhich_path = Path(which_kpsewhich)
- which_kpsewhich_resolved = which_kpsewhich_path.resolve()
- if not texlive_bin_path == which_kpsewhich_resolved.parent:
- sys.exit(' '.join([
- '"tlmgr" executable from PATH resolved to "{}" '.format(which_tlmgr_resolved.as_posix()),
- 'while "kpsewhich" resolved to "{}";'.format(which_kpsewhich_resolved.as_posix()),
- '"tlmgr" and "kpsewhich" should be in the same location',
- ]))
- if not which_kpsewhich_resolved.name.lower().endswith('.exe'):
- sys.exit(' '.join([
- 'Executable "kpsewhich" resolved to "{}",'.format(which_kpsewhich_resolved.as_posix()),
- 'but *.exe is required',
- ]))
- else:
- which_kpsewhich = shutil.which('kpsewhich', path=env_SELFAUTOLOC)
- if not which_kpsewhich:
- sys.exit(' '.join([
- 'Environment variable SELFAUTOLOC has value "{}",'.format(env_SELFAUTOLOC),
- 'but a "kpsewhich" executable was not found at that location',
- ]))
- which_kpsewhich_path = Path(which_kpsewhich)
- which_kpsewhich_resolved = which_kpsewhich_path.resolve()
- if not is_permitted_executable_path(which_kpsewhich_path, which_kpsewhich_resolved):
- # As in the latexrestricted case, this doesn't initially check for the
- # TeX Live scenario where `TEXMFOUTPUT` is set in a `texmf.cnf` config
- # file to a location that includes the `kpsewhich` executable. There
- # isn't a good way to get the value of `TEXMFOUTPUT` without running
- # `kpsewhich` in that case.
- sys.exit(
- 'Executable "kpsewhich" is located under the current directory, TEXMFOUTPUT, or '
- 'TEXMF_OUTPUT_DIRECTORY, or one of these locations is under the same directory as the executable'
- )
- kpsewhich_cmd = [which_kpsewhich_resolved.as_posix(), '--var-value', 'TEXMFOUTPUT']
- try:
- kpsewhich_proc = subprocess.run(kpsewhich_cmd, shell=False, capture_output=True)
- except PermissionError:
- sys.exit('Insufficient permission to run "{}"'.format(which_kpsewhich_resolved.as_posix()))
- kpsewhich_TEXMFOUTPUT = kpsewhich_proc.stdout.decode(sys.stdout.encoding) or None
- if kpsewhich_TEXMFOUTPUT:
- kpsewhich_TEXMFOUTPUT_path = Path(kpsewhich_TEXMFOUTPUT)
- prohibited_path_roots.add(kpsewhich_TEXMFOUTPUT_path)
- prohibited_path_roots.add(kpsewhich_TEXMFOUTPUT_path.resolve())
- if not is_permitted_executable_path(which_kpsewhich_path, which_kpsewhich_resolved):
- # It is now possible to check for the TeX Live scenario where
- # `TEXMFOUTPUT` is set in a `texmf.cnf` config file to a location that
- # includes the `kpsewhich` executable. Giving an error message after
- # already running `kpsewhich` isn't ideal, but there isn't a good
- # alternative. As in the latexrestricted case, the impact on overall
- # security is negligible because an unsafe value of `TEXMFOUTPUT`
- # means that all TeX-related executables are potentially compromised.
- sys.exit(
- 'Executable "kpsewhich" is located under the current directory, TEXMFOUTPUT, or '
- 'TEXMF_OUTPUT_DIRECTORY, or one of these locations is under the same directory as the executable'
- )
-
-
-
-
-# If Python version is < 3.8, try to locate a more recent version and then
-# relaunch this script with that Python version in a subprocess.
-if sys.version_info[:2] < (3, 8):
- for minor_version in range(13, 7, -1):
- if platform.system() == 'Windows':
- # Batch files must be prohibited:
- # https://docs.python.org/3/library/subprocess.html#security-considerations
- which_python = shutil.which('python3.{}.exe'.format(minor_version))
- else:
- which_python = shutil.which('python3.{}'.format(minor_version))
- if which_python:
- which_python_path = Path(which_python)
- which_python_resolved = which_python_path.resolve()
- if platform.system() == 'Windows' and not which_python_resolved.name.lower().endswith('.exe'):
- continue
- if is_permitted_executable_path(which_python_path, which_python_resolved):
- python_cmd = [which_python_resolved.as_posix(), __file__] + sys.argv[1:]
- python_proc = subprocess.run(python_cmd, shell=False, capture_output=True)
- sys.stderr.buffer.write(python_proc.stderr)
- sys.stdout.buffer.write(python_proc.stdout)
- sys.exit(python_proc.returncode)
- sys.exit('latexminted requires Python >= 3.8, but a compatible Python executable was not found on PATH')
-
-
-
-
-# Check for required wheel dependencies and add them to Python's `sys.path`.
-script_resolved = Path(__file__).resolve()
-required_wheel_packages = (
- 'latexminted',
- 'latexrestricted',
- 'latex2pydata',
- 'pygments',
-)
-wheel_paths = [p for p in script_resolved.parent.glob('*.whl') if p.name.startswith(required_wheel_packages)]
-if not wheel_paths:
- sys.exit('latexminted failed to find bundled wheels *.whl')
-for pkg in required_wheel_packages:
- if not any(whl.name.startswith(pkg) for whl in wheel_paths):
- sys.exit('latexminted failed to find all required bundled wheels *.whl')
-for wheel_path in wheel_paths:
- sys.path.insert(0, wheel_path.as_posix())
-
-
-
-
-# Under Windows, check PATH for a `latexminted` executable outside a TeX
-# installation. If a `latexminted` executable is found in a suitable location
-# with sufficient precedence, run it in a subprocess and exit.
-#
-# The environment variable `LATEXMINTED_SUBPROCESS` is used to prevent an
-# endless recursion of subprocesses in the event that a `latexminted`
-# executable *inside* a TeX installation somehow manages to pass the tests for
-# an executable *outside* a TeX installation.
-if platform.system() == 'Windows' and not os.getenv('LATEXMINTED_SUBPROCESS'):
- os.environ['LATEXMINTED_SUBPROCESS'] = '1'
- fallback_path_search = True
- if env_SELFAUTOLOC:
- env_SELFAUTOLOC_resolved = Path(env_SELFAUTOLOC).resolve()
- else:
- env_SELFAUTOLOC_resolved = None
- which_latexminted = shutil.which('latexminted.exe')
- if which_latexminted:
- which_latexminted_path = Path(which_latexminted)
- which_latexminted_resolved = which_latexminted_path.resolve()
- if not which_latexminted_resolved.name.lower().endswith('.exe'):
- sys.exit(' '.join([
- 'Executable "latexminted" resolved to "{}",'.format(which_latexminted_resolved.as_posix()),
- 'but *.exe is required',
- ]))
- if which_latexminted_resolved == script_resolved:
- pass
- elif (which_latexminted_resolved.parent / 'tex.exe').exists():
- pass
- elif any(x in which_latexminted_resolved.as_posix().lower() for x in ('texlive', 'miktex', 'tinytex')):
- pass
- elif env_SELFAUTOLOC_resolved and which_latexminted_resolved.is_relative_to(env_SELFAUTOLOC_resolved):
- pass
- elif is_permitted_executable_path(which_latexminted_path, which_latexminted_resolved):
- latexminted_cmd = [which_latexminted_resolved.as_posix()] + sys.argv[1:]
- latexminted_proc = subprocess.run(latexminted_cmd, shell=False, capture_output=True)
- sys.stderr.buffer.write(latexminted_proc.stderr)
- sys.stdout.buffer.write(latexminted_proc.stdout)
- sys.exit(latexminted_proc.returncode)
- else:
- # If there was a `latexminted` executable on PATH outside a TeX
- # installation, but it wasn't permitted due to its location, don't
- # perform fallback search.
- fallback_path_search = False
- if fallback_path_search:
- # Windows appends user PATH to system PATH, so the system PATH may
- # prevent finding a user installation of `latexminted`. Search
- # through PATH elements under user home directory to check for
- # `latexminted.exe` outside a TeX installation.
- home_path = Path.home()
- env_PATH = os.environ.get('PATH', '')
- for path_elem in env_PATH.split(os.pathsep):
- if not path_elem or not Path(path_elem).is_relative_to(home_path):
- continue
- which_latexminted = shutil.which('latexminted.exe', path=path_elem)
- if not which_latexminted:
- continue
- which_latexminted_path = Path(which_latexminted)
- which_latexminted_resolved = which_latexminted_path.resolve()
- if which_latexminted_resolved == script_resolved:
- break
- elif (which_latexminted_resolved.parent / 'tex.exe').exists():
- break
- elif any(x in which_latexminted_resolved.as_posix().lower() for x in ('texlive', 'miktex', 'tinytex')):
- break
- elif env_SELFAUTOLOC_resolved and which_latexminted_resolved.is_relative_to(env_SELFAUTOLOC_resolved):
- break
- elif is_permitted_executable_path(which_latexminted_path, which_latexminted_resolved):
- latexminted_cmd = [which_latexminted_resolved.as_posix()] + sys.argv[1:]
- try:
- latexminted_proc = subprocess.run(latexminted_cmd, shell=False, capture_output=True)
- except PermissionError:
- break
- sys.stderr.buffer.write(latexminted_proc.stderr)
- sys.stdout.buffer.write(latexminted_proc.stdout)
- sys.exit(latexminted_proc.returncode)
- else:
- break
-
-
-
-
-from latexminted.cmdline import main
-main()
Modified: trunk/Master/tlpkg/libexec/ctan2tds
===================================================================
--- trunk/Master/tlpkg/libexec/ctan2tds 2024-09-24 20:32:58 UTC (rev 72374)
+++ trunk/Master/tlpkg/libexec/ctan2tds 2024-09-24 22:39:08 UTC (rev 72375)
@@ -3751,6 +3751,7 @@
'luasseq' => '\.lua$',
'lyluatex' => '\.lua$',
'make4ht' => '(extensions|filters|formats|\.lua)$',
+ 'minted' => '\.whl$',
'mycv' => 'mycv_split_contents\.pl$',
'pgfmolbio' => '\.lua$',
'pax' => 'pax.jar$',
@@ -3847,6 +3848,7 @@
'match_parens' => '^match_parens$',
'mathspic' => '^mathspic\.pl$',
'memoize' => '\.p[ly]$',
+ 'minted' => 'latexminted.py$',
'multibibliography' => '\.pl$',
'mf2pt1' => '\.pl$',
'mkgrkindex' => 'mkgrkindex$',
Modified: trunk/Master/tlpkg/tlpsrc/minted.tlpsrc
===================================================================
--- trunk/Master/tlpkg/tlpsrc/minted.tlpsrc 2024-09-24 20:32:58 UTC (rev 72374)
+++ trunk/Master/tlpkg/tlpsrc/minted.tlpsrc 2024-09-24 22:39:08 UTC (rev 72375)
@@ -1,20 +1,13 @@
-# dependencies per
-# https://raw.githubusercontent.com/gpoore/minted/master/source/minted.pdf
-# report on tex-live, 31 Jul 2022 14:11:20 +0200.
-# 12sep23 DEPENDS.txt added to package.
+binpattern f bin/${ARCH}/latexminted
+
depend catchfile
depend etoolbox
depend float
-depend framed
depend fvextra
-depend ifplatform
-#base depend ifthen
-depend graphics # keyval
-depend kvoptions
-depend lineno
+depend latex2pydata
depend newfloat
depend pdftexcmds
-depend tools # shellesc
-depend upquote
+depend pgf #pgfkeys
+depend pgfopts
+depend tools #shellesc
depend xcolor
-depend xstring
More information about the tex-live-commits
mailing list.