From e913e5b3ecbd7fb2a524c8f33a73143b357e3c7a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Mar 2026 20:52:43 +0000 Subject: [PATCH 1/2] refactor: install_tinytex() calls install-bin-unix.sh and install-bin-windows.ps1 Agent-Logs-Url: https://github.com/rstudio/tinytex/sessions/be1d7fad-94aa-4aa6-86f7-46b65d175692 Co-authored-by: yihui <163582+yihui@users.noreply.github.com> --- R/install.R | 43 ++++++++++++++++++++++++++++++++++- tools/install-bin-unix.sh | 33 +++++++++++++++++++++++---- tools/install-bin-windows.ps1 | 40 ++++++++++++++++++++++++++------ 3 files changed, 104 insertions(+), 12 deletions(-) diff --git a/R/install.R b/R/install.R index 9c6b0c8a1..1775591ce 100644 --- a/R/install.R +++ b/R/install.R @@ -143,7 +143,7 @@ install_tinytex = function( if (src_install) { install_tinytex_source(repository, ...) } else { - install_prebuilt(bundle, ..., repo = repository) + install_via_script(bundle, ..., repo = repository) } } user_dir = install(user_dir, version, add_path, extra_packages) @@ -328,6 +328,47 @@ macos_path = function(dir = NULL, action = 'add') { ret } +install_via_script = function(pkg = '', dir = '', version = 'daily', add_path = TRUE, extra_packages = NULL, repo = 'ctan') { + # Set env vars consumed by the install-bin-*.sh / install-bin-*.ps1 scripts + env_vars = c(TINYTEX_INSTALLER = pkg) + if (version != 'daily') env_vars['TINYTEX_VERSION'] = version + + # Determine the final TinyTeX directory so we can find tlmgr afterwards + target = if (dir == '') default_inst() else xfun::normalize_path(dir) + # Pass the full target path to the script only when using a custom directory + if (dir != '') env_vars['TINYTEX_TEXDIR'] = target + + old_vars = xfun::set_envvar(env_vars) + on.exit(xfun::set_envvar(old_vars), add = TRUE) + + if (is_windows()) { + script = 'install-bin-windows.ps1' + download_file('https://tinytex.yihui.org/install-bin-windows.ps1', script) + on.exit(unlink(script), add = TRUE) + script_args = c('-NonInteractive', '-File', script, if (!add_path) '--no-path') + res = system2('powershell', script_args) + } else { + script = 'install-bin-unix.sh' + download_file('https://tinytex.yihui.org/install-bin-unix.sh', script) + on.exit(unlink(script), add = TRUE) + res = system2('sh', c(script, if (!add_path) '--no-path')) + } + if (res != 0) stop('Failed to install TinyTeX', call. = FALSE) + if (!dir_exists(target)) stop('Failed to install TinyTeX.') + target = normalizePath(target) + + opts = options(tinytex.tlmgr.path = find_tlmgr(target)) + on.exit(options(opts), add = TRUE) + + r_texmf(.quiet = TRUE) + # don't use the default random ctan mirror when installing on CI servers + if (repo != 'ctan' || tolower(Sys.getenv('CI')) != 'true') + tlmgr_repo(repo, stdout = FALSE, .quiet = TRUE) + tlmgr_install(setdiff(extra_packages, tl_pkgs())) + + target +} + install_tinytex_source = function(repo = '', dir, version, add_path, extra_packages) { if (version != 'daily') stop( 'tinytex::install_tinytex() does not support installing a specific version of ', diff --git a/tools/install-bin-unix.sh b/tools/install-bin-unix.sh index a7be1830f..b3b5b0d1d 100755 --- a/tools/install-bin-unix.sh +++ b/tools/install-bin-unix.sh @@ -2,6 +2,10 @@ set -e +# abort installation if TINYTEX_PREVENT_INSTALL=true +[ "$(echo "${TINYTEX_PREVENT_INSTALL}" | tr '[:upper:]' '[:lower:]')" != 'true' ] || + (echo "The environment variable 'TINYTEX_PREVENT_INSTALL' was set to 'true', so the installation is aborted." && exit 1) + perl -mFile::Find /dev/null || (echo "perl is required but not found (https://github.com/rstudio/tinytex/issues/419)" && exit 1) @@ -41,9 +45,12 @@ is_musl() { } if [ $OSNAME = 'Darwin' ]; then - TEXDIR=${TINYTEX_DIR:-~/Library}/TinyTeX + # default name in the archive; used to compute TEXDIR and rename after extraction + TEXDIR_DEFAULT_BASENAME="TinyTeX" + TEXDIR_DEFAULT_PARENT=${TINYTEX_DIR:-~/Library} else - TEXDIR=${TINYTEX_DIR:-~}/.TinyTeX + TEXDIR_DEFAULT_BASENAME=".TinyTeX" + TEXDIR_DEFAULT_PARENT=${TINYTEX_DIR:-~} if [ $OSNAME != 'Linux' ]; then TINYTEX_INSTALLER="installer-unix" elif is_musl; then @@ -58,7 +65,18 @@ else fi fi -rm -rf $TEXDIR +# TINYTEX_TEXDIR allows callers (e.g. the R package) to specify the full +# installation path directly; fall back to the traditional TINYTEX_DIR-based default +TEXDIR=${TINYTEX_TEXDIR:-${TEXDIR_DEFAULT_PARENT}/${TEXDIR_DEFAULT_BASENAME}} + +# the path where the archive will be extracted (always the standard basename under the +# same parent as TEXDIR, regardless of whether a custom name was requested) +TEXDIR_EXTRACTED="$(dirname $TEXDIR)/$TEXDIR_DEFAULT_BASENAME" + +rm -rf "$TEXDIR" +# also remove the standard extraction target when a custom path is requested, +# so the rename step below has a clean destination +[ "$TEXDIR" = "$TEXDIR_EXTRACTED" ] || rm -rf "$TEXDIR_EXTRACTED" # determine the OS/arch suffix and file extension based on the naming scheme if [ "$USE_NEW_NAMES" = true ] && [ "${TINYTEX_INSTALLER#"TinyTeX"}" != "$TINYTEX_INSTALLER" ]; then @@ -102,7 +120,12 @@ if [ "${TINYTEX_INSTALLER#"TinyTeX"}" != "$TINYTEX_INSTALLER" ]; then wget --retry-connrefused --progress=dot:giga -O "${INSTALLER_FILE}" ${TINYTEX_URL} fi tar xf "${INSTALLER_FILE}" -C $(dirname $TEXDIR) - if [ -n "$1" ]; then mv "${INSTALLER_FILE}" "$1/"; else rm "${INSTALLER_FILE}"; fi + # rename to TEXDIR if a custom path (TINYTEX_TEXDIR) was requested and the + # archive extracted to a different name (e.g. .TinyTeX or TinyTeX) + [ "$TEXDIR" = "$TEXDIR_EXTRACTED" ] || mv "$TEXDIR_EXTRACTED" "$TEXDIR" + # the first positional arg may be a directory to move the installer to (used by + # build scripts); ignore it if it looks like a flag (e.g. --no-path) + if [ -n "$1" ] && [ "${1#--}" = "$1" ]; then mv "${INSTALLER_FILE}" "$1/"; else rm "${INSTALLER_FILE}"; fi else echo "We do not have a prebuilt TinyTeX package for this operating system ($(uname -s) $(uname -m))." echo "I will try to install from source for you instead." @@ -123,6 +146,8 @@ fi [ $OSNAME != "Darwin" ] && ./tlmgr option sys_bin $BINDIR ./tlmgr postaction install script xetex # GH issue #313 +# do not wrap lines in latex log (https://github.com/rstudio/tinytex/issues/322) +./tlmgr conf texmf max_print_line 10000 NO_PATH=0 for arg in "$@"; do diff --git a/tools/install-bin-windows.ps1 b/tools/install-bin-windows.ps1 index bc6a57697..0d494e01a 100644 --- a/tools/install-bin-windows.ps1 +++ b/tools/install-bin-windows.ps1 @@ -1,5 +1,12 @@ $ErrorActionPreference = 'Stop' +if ($env:TINYTEX_PREVENT_INSTALL -eq 'true') { + throw "The environment variable 'TINYTEX_PREVENT_INSTALL' was set to 'true', so the installation is aborted." +} + +# parse --no-path argument +$AddPath = -not ($args -contains '--no-path') + # switch to a temp directory cd $env:TEMP [Environment]::CurrentDirectory = $PWD.Path @@ -15,6 +22,10 @@ if (-not $env:TINYTEX_DIR) { $env:TINYTEX_DIR = if ($env:APPDATA -match '^[!-~]+$') { $env:APPDATA } else { $env:ProgramData } } +# TINYTEX_TEXDIR allows callers (e.g. the R package) to specify the full installation +# path directly; fall back to the traditional TINYTEX_DIR\TinyTeX default +$TargetDir = if ($env:TINYTEX_TEXDIR) { $env:TINYTEX_TEXDIR } else { "$($env:TINYTEX_DIR)\TinyTeX" } + # new naming scheme: TinyTeX-{N}-windows.exe for daily and versions after v2026.03.02 $UseNewNames = $true if ($env:TINYTEX_VERSION) { @@ -52,7 +63,7 @@ if ($BundleExt -eq 'exe') { } # save the downloaded file to the output dir (for build-tinytex-2.ps1) -if ($args[0]) { +if ($args[0] -and $args[0] -ne '--no-path') { move $DownloadedFile "$($args[0])\$DownloadedFile" } else { del $DownloadedFile @@ -61,12 +72,27 @@ if ($args[0]) { # in case it was installed to APPDATA previously rd $env:APPDATA\TinyTeX -r -fo -ErrorAction SilentlyContinue -rd $env:TINYTEX_DIR\TinyTeX -r -fo -ErrorAction SilentlyContinue -rd $env:TINYTEX_DIR\TinyTeX -r -fo -ErrorAction SilentlyContinue -move TinyTeX $env:TINYTEX_DIR +# remove any existing installation at the target directory +rd $TargetDir -r -fo -ErrorAction SilentlyContinue + +# the bundle always extracts to a 'TinyTeX' directory in the current dir (TEMP); +# move it to the parent of TargetDir, then rename if a custom leaf name was requested +$TargetParent = Split-Path $TargetDir -Parent +$TargetLeaf = Split-Path $TargetDir -Leaf +if (-not (Test-Path $TargetParent)) { mkdir $TargetParent -Force | Out-Null } +# remove an existing TinyTeX dir in the target parent that may conflict with the move +rd (Join-Path $TargetParent 'TinyTeX') -r -fo -ErrorAction SilentlyContinue +move TinyTeX $TargetParent +if ($TargetLeaf -ne 'TinyTeX') { + rename-item (Join-Path $TargetParent 'TinyTeX') $TargetLeaf +} # add tlmgr to PATH -Write-Host 'add tlmgr to PATH' -$tlmgr = "$env:TINYTEX_DIR\TinyTeX\bin\windows\tlmgr.bat" -& $tlmgr path add +$tlmgr = "$TargetDir\bin\windows\tlmgr.bat" & $tlmgr postaction install script xetex +# do not wrap lines in latex log (https://github.com/rstudio/tinytex/issues/322) +& $tlmgr conf texmf max_print_line 10000 +if ($AddPath) { + Write-Host 'add tlmgr to PATH' + & $tlmgr path add +} From d5159fea2be19531dc832e6b80b55f8b4758a437 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Mar 2026 20:53:51 +0000 Subject: [PATCH 2/2] fix: quote dirname in shell, clarify normalizePath usage in R Agent-Logs-Url: https://github.com/rstudio/tinytex/sessions/be1d7fad-94aa-4aa6-86f7-46b65d175692 Co-authored-by: yihui <163582+yihui@users.noreply.github.com> --- R/install.R | 3 ++- tools/install-bin-unix.sh | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/R/install.R b/R/install.R index 1775591ce..eec3ef6e9 100644 --- a/R/install.R +++ b/R/install.R @@ -333,7 +333,8 @@ install_via_script = function(pkg = '', dir = '', version = 'daily', add_path = env_vars = c(TINYTEX_INSTALLER = pkg) if (version != 'daily') env_vars['TINYTEX_VERSION'] = version - # Determine the final TinyTeX directory so we can find tlmgr afterwards + # xfun::normalize_path() expands ~ so we can pass TINYTEX_TEXDIR to the script; + # normalizePath() below (after install) resolves symlinks for the canonical path target = if (dir == '') default_inst() else xfun::normalize_path(dir) # Pass the full target path to the script only when using a custom directory if (dir != '') env_vars['TINYTEX_TEXDIR'] = target diff --git a/tools/install-bin-unix.sh b/tools/install-bin-unix.sh index b3b5b0d1d..21da62037 100755 --- a/tools/install-bin-unix.sh +++ b/tools/install-bin-unix.sh @@ -71,7 +71,7 @@ TEXDIR=${TINYTEX_TEXDIR:-${TEXDIR_DEFAULT_PARENT}/${TEXDIR_DEFAULT_BASENAME}} # the path where the archive will be extracted (always the standard basename under the # same parent as TEXDIR, regardless of whether a custom name was requested) -TEXDIR_EXTRACTED="$(dirname $TEXDIR)/$TEXDIR_DEFAULT_BASENAME" +TEXDIR_EXTRACTED="$(dirname "$TEXDIR")/$TEXDIR_DEFAULT_BASENAME" rm -rf "$TEXDIR" # also remove the standard extraction target when a custom path is requested, @@ -119,7 +119,7 @@ if [ "${TINYTEX_INSTALLER#"TinyTeX"}" != "$TINYTEX_INSTALLER" ]; then else wget --retry-connrefused --progress=dot:giga -O "${INSTALLER_FILE}" ${TINYTEX_URL} fi - tar xf "${INSTALLER_FILE}" -C $(dirname $TEXDIR) + tar xf "${INSTALLER_FILE}" -C "$(dirname "$TEXDIR")" # rename to TEXDIR if a custom path (TINYTEX_TEXDIR) was requested and the # archive extracted to a different name (e.g. .TinyTeX or TinyTeX) [ "$TEXDIR" = "$TEXDIR_EXTRACTED" ] || mv "$TEXDIR_EXTRACTED" "$TEXDIR"