Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 3 additions & 34 deletions pytinytex/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,9 @@ def compile(
continue
logger.info("Auto-installing missing package: %s", pkg)
try:
# Try to find the correct TeX Live package name
pkg_name = _resolve_package_name(pkg)
install(pkg_name)
newly_installed.append(pkg_name)
all_installed.append(pkg_name)
install(pkg)
newly_installed.append(pkg)
all_installed.append(pkg)
except RuntimeError as e:
logger.warning("Failed to install '%s': %s", pkg, e)

Expand All @@ -171,32 +169,3 @@ def compile(
return result


def _resolve_package_name(sty_name):
"""Try to resolve a .sty file name to a TeX Live package name.

For most packages, the .sty name matches the package name.
Falls back to the sty_name itself if tlmgr search fails.
"""
from . import get_tinytex_path
from .tlmgr import _run_tlmgr_command

try:
path = get_tinytex_path()
_, output = _run_tlmgr_command(
["search", "--file", sty_name + ".sty"],
path,
machine_readable=False,
)
# Parse tlmgr search output for package names
# Lines look like: "texmf-dist/tex/latex/booktabs/booktabs.sty"
# or "<package>:" header lines
for line in output.splitlines():
line = line.strip()
if line.endswith(":") and not line.startswith(" "):
# This is a package name header
return line.rstrip(":")
except RuntimeError:
pass

# Fallback: assume sty name == package name
return sty_name
67 changes: 63 additions & 4 deletions pytinytex/tlmgr.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,35 @@ def _needs_self_update(error_message):
def install(package):
"""Install a TeX Live package via tlmgr.

If the direct install fails, attempts to resolve the package name
(e.g. mapping a .sty file name to the correct TeX Live package)
and retries.

Args:
package: Package name (e.g. "booktabs", "amsmath").
package: Package name (e.g. "booktabs", "amsmath") or a .sty
file stem that will be resolved to the correct package.

Returns:
Tuple of (exit_code, output).
"""
from . import get_tinytex_path

path = get_tinytex_path()
result = _run_tlmgr_command(["install", package], path, False)
_refresh_filename_db(path)
return result
try:
result = _run_tlmgr_command(["install", package], path, False)
_refresh_filename_db(path)
return result
except RuntimeError:
# Try resolving the name (e.g. .sty name -> tlmgr package name)
resolved = _resolve_package_name(package, path)
if resolved != package:
logger.info(
"Resolved '%s' to package '%s', retrying install", package, resolved
)
result = _run_tlmgr_command(["install", resolved], path, False)
_refresh_filename_db(path)
return result
raise


def remove(package):
Expand Down Expand Up @@ -208,6 +225,48 @@ def uninstall(path=None):
clear_path_cache()


# --- Package name resolution ---


def _resolve_package_name(sty_name, path=None):
"""Try to resolve a .sty file name to a TeX Live package name.

For most packages, the .sty name matches the package name.
Falls back to the sty_name itself if tlmgr search fails.

Args:
sty_name: The stem of a .sty file (e.g. "booktabs").
path: TinyTeX bin path. Resolved automatically if None.

Returns:
The TeX Live package name, or sty_name as a fallback.
"""
if path is None:
from . import get_tinytex_path

path = get_tinytex_path()

try:
_, output = _run_tlmgr_command(
["search", "--file", sty_name + ".sty"],
path,
machine_readable=False,
)
# Parse tlmgr search output for package names
# Lines look like: "texmf-dist/tex/latex/booktabs/booktabs.sty"
# or "<package>:" header lines
for line in output.splitlines():
line = line.strip()
if line.endswith(":") and not line.startswith(" "):
# This is a package name header
return line.rstrip(":")
except RuntimeError:
pass

# Fallback: assume sty name == package name
return sty_name


# --- Machine-readable output parsing ---


Expand Down
Loading