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.