From 3c340975f8f48bfe5469aa89a524f4d74468bfb6 Mon Sep 17 00:00:00 2001 From: Yihui Xie Date: Thu, 16 Nov 2023 21:56:16 -0600 Subject: [PATCH] Fix #420: install TinyTeX to `ProgramData` on Windows if `APPDATA` contains special characters (#429) --- R/install.R | 48 +++++++++++++++++++++++++++++------ man/copy_tinytex.Rd | 6 ++++- tools/install-bin-windows.bat | 15 ++++++++--- 3 files changed, 56 insertions(+), 13 deletions(-) diff --git a/R/install.R b/R/install.R index 1ad6f800f..abf0d45f6 100644 --- a/R/install.R +++ b/R/install.R @@ -200,13 +200,29 @@ auto_repo = function() { if (length(x) == 1) x else 'ctan' } -win_app_dir = function(..., error = TRUE) { +# use %APPDATA%/TinyTeX if it exists or doesn't contain spaces or non-ASCII +# chars, otherwise use %ProgramData%, because TeX Live doesn't work when the +# installation path contains non-ASCII chars +win_app_dir = function(s) { + d = Sys.getenv('TINYTEX_DIR') + if (d != '') return(file.path(d, s)) d = Sys.getenv('APPDATA') - if (d == '') { - if (error) stop('Environment variable "APPDATA" not set.') - return(d) + if (d != '') { + d2 = file.path(d, s) + if (dir_exists(d2)) { + if (getOption('tinytex.warn.appdata', TRUE) && !xfun::is_ascii(d2)) warning( + "You are recommended to move TinyTeX to another location via\n\n", + " tinytex::copy_tinytex(to = Sys.getenv('ProgramData'), move = TRUE)\n\n", + "otherwise TinyTeX will not work because its current installation path '", + normalizePath(d2), "' contains non-ASCII characters.", call. = FALSE + ) + return(d2) + } + if (grepl('^[!-~]+$', d)) return(d2) # path is pure ASCII and has no spaces } - file.path(d, ...) + d = Sys.getenv('ProgramData') + if (d == '') stop("The environment variable 'ProgramData' is not set.") + file.path(d, s) } # check if /usr/local/bin on macOS is writable @@ -472,7 +488,7 @@ install_prebuilt = function( } # post-install configurations -post_install_config = function(add_path, extra_packages, repo, hash = FALSE) { +post_install_config = function(add_path = TRUE, extra_packages = NULL, repo = 'ctan', hash = FALSE) { if (os_index == 2) { if (!dir_exists(bin_dir <- '~/.local/bin')) dir.create(bin_dir <- '~/bin', FALSE, TRUE) tlmgr(c('option', 'sys_bin', bin_dir)) @@ -516,14 +532,28 @@ download_installer = function(file, version) { #' @param to The destination directory where you want to make a copy of TinyTeX. #' Like \code{from} in \code{use_tinytex()}, a dialog will pop up if \code{to} #' is not provided in \code{copy_tinytex()}. +#' @param move Whether to use the new copy and delete the original copy of +#' TinyTeX after copying it. #' @note You can only copy TinyTeX and use it in the same system, e.g., the #' Windows version of TinyTeX only works on Windows. #' @export -copy_tinytex = function(from = tinytex_root(), to = select_dir('Select Destination Directory')) { +copy_tinytex = function( + from = tinytex_root(), to = select_dir('Select Destination Directory'), move = FALSE +) { + op = options(tinytex.warn.appdata = FALSE); on.exit(options(op), add = TRUE) if (!dir_exists(from)) stop('TinyTeX does not seem to be installed.') if (length(to) != 1 || !dir_exists(to)) stop("The destination directory '", to, "' does not exist.") - file.copy(from, to, recursive = TRUE) + target = file.path(to, basename(from)) + if (!move || !{tlmgr_path('remove'); res <- file.rename(from, target)}) { + res = file.copy(from, to, recursive = TRUE) + if (res && move) { + tlmgr_path('remove') + unlink(from, recursive = TRUE) + } + } + if (res && move) use_tinytex(target) + res } #' @rdname copy_tinytex @@ -539,6 +569,8 @@ use_tinytex = function(from = select_dir('Select TinyTeX Directory')) { "Failed to add '", d, "' to your system's environment variable PATH. You may ", "consider the fallback approach, i.e., set options(tinytex.tlmgr.path = '", p, "')." ) + op = options(tinytex.tlmgr.path = p); on.exit(options(op), add = TRUE) + post_install_config(FALSE) message('Restart R and your editor and check if tinytex::tinytex_root() points to ', from) } diff --git a/man/copy_tinytex.Rd b/man/copy_tinytex.Rd index 63c6c49f3..96eca0b78 100644 --- a/man/copy_tinytex.Rd +++ b/man/copy_tinytex.Rd @@ -7,7 +7,8 @@ \usage{ copy_tinytex( from = tinytex_root(), - to = select_dir("Select Destination Directory") + to = select_dir("Select Destination Directory"), + move = FALSE ) use_tinytex(from = select_dir("Select TinyTeX Directory")) @@ -22,6 +23,9 @@ the directory interactively will pop up.} \item{to}{The destination directory where you want to make a copy of TinyTeX. Like \code{from} in \code{use_tinytex()}, a dialog will pop up if \code{to} is not provided in \code{copy_tinytex()}.} + +\item{move}{Whether to use the new copy and delete the original copy of +TinyTeX after copying it.} } \description{ The function \code{copy_tinytex()} copies the existing TinyTeX installation diff --git a/tools/install-bin-windows.bat b/tools/install-bin-windows.bat index ae3d9ed35..792d49509 100644 --- a/tools/install-bin-windows.bat +++ b/tools/install-bin-windows.bat @@ -9,6 +9,11 @@ for /d %%G in ("TinyTeX*") do rd /s /q "%%~G" if not defined TINYTEX_INSTALLER set TINYTEX_INSTALLER=TinyTeX-1 +rem install to APPDATA by default if it doesn't contain spaces or non-ASCII chars, otherwise use ProgramData +if not defined TINYTEX_DIR ( + set TINYTEX_DIR=%APPDATA% + powershell -Command "if ($Env:APPDATA -match '^[!-~]+$') {exit 0} else {exit 1}" || set TINYTEX_DIR=%ProgramData% +) set BUNDLE_EXT=zip if "%TINYTEX_INSTALLER%" == "TinyTeX-2" set BUNDLE_EXT=exe @@ -45,13 +50,15 @@ if %BUNDLE_EXT% == exe ( ) del %DOWNLOADED_FILE% -echo Move to APPDATA folder -rd /s /q "%APPDATA%\TinyTeX" +rem in case it was installed to APPDATA previously rd /s /q "%APPDATA%\TinyTeX" -move /y TinyTeX "%APPDATA%" + +rd /s /q "%TINYTEX_DIR%\TinyTeX" +rd /s /q "%TINYTEX_DIR%\TinyTeX" +move /y TinyTeX "%TINYTEX_DIR%" echo add tlmgr to PATH -cd /d "%APPDATA%\TinyTeX\bin\win*" +cd /d "%TINYTEX_DIR%\TinyTeX\bin\win*" call tlmgr path add if /i not "%CI%"=="true" call tlmgr option repository ctan call tlmgr postaction install script xetex