diff options
-rwxr-xr-x | Master/bin/win32/tlmgr.bat | 55 | ||||
-rwxr-xr-x | Master/texmf/scripts/texlive/tlmgr.pl | 23 | ||||
-rw-r--r-- | Master/texmf/scripts/texlive/updater-w32.bat | 236 |
3 files changed, 193 insertions, 121 deletions
diff --git a/Master/bin/win32/tlmgr.bat b/Master/bin/win32/tlmgr.bat index eeb7a3bdf0b..efb1f4b2c69 100755 --- a/Master/bin/win32/tlmgr.bat +++ b/Master/bin/win32/tlmgr.bat @@ -1,27 +1,50 @@ @echo off
-rem Advanced starter for tlmgr with auto-update
+rem Advanced launcher for tlmgr with auto-update
+rem
rem Copyright 2009 by Tomasz M. Trzeciak <t.m.trzeciak@googlemail.com>
-rem Public Domain
+rem This file is licensed under the GNU General Public License version 2
+rem or any later version.
rem
-setlocal enableextensions
-rem TL installation root
-for %%P in ("%~dp0..\..") do set "tlroot=%%~fP"
+rem Check if we are running under NT based system
+rem (works for Vista too, extra check needed to exclude winNT4)
+if not [%OS%]==[Windows_NT] goto err_OS
+
+rem Make environment changes local & enable delayed expansion
+setlocal enabledelayedexpansion
+(set errorlevel=)
-rem not needed anymore
-rem path %TLdir%\tlpkg\installer;%path%
+rem Get TL installation root (it should be two levels up)
+for %%I in ("%~dp0..\..") do (set tlroot=%%~fI)
+
+rem Remove remains of previous update if any
+(set tlupdatername=run-updater-w32)
+(set tlupdater=%tlroot%\temp\%tlupdatername%)
+if exist "%tlupdater%*" del "%tlupdater%*"
+if exist "%tlupdater%*" goto :err_updater_exists
rem Start tlmgr
-set PERL5LIB=%tlroot%\tlpkg\tlperl\lib
+(set PERL5LIB=%tlroot%\tlpkg\tlperl\lib)
"%tlroot%\tlpkg\tlperl\bin\perl.exe" "%tlroot%\texmf\scripts\texlive\tlmgr.pl" %*
-rem Check for updater script
-set "updater=%tlroot%\temp\run-updater-w32"
-if not exist "%updater%" exit /b
-if exist "%updater%.bat" del "%updater%.bat"
-ren "%updater%" run-updater-w32.bat
-if errorlevel 1 exit /b 1
+rem Exit here if there are no updates to do
+if not exist "%tlupdater%" exit /b %errorlevel%
+rem Rename updater script before it is run
+ren "%tlupdater%" "%tlupdatername%.bat"
+if errorlevel 1 goto :err_rename_updater
+rem Run updater explicitly with cmd.exe, in case we are launched from 4NT
+rem Use delayed expansion for errorlevel, 4NT doesn't like: call exit /b %%errorlevel%%
+echo Starting update ...
+endlocal & call "%tlupdater%.bat" & exit /b !errorlevel!
+
+:err_updater_exists
+echo %~n0: cannot remove update script, infrastructure update might be in progress>&2
+exit /b 1
-rem Run updater script
-endlocal & call "%updater%.bat" & exit /b
+:err_rename_updater
+echo %~n0: cannot rename "%tlupdater%">&2
+exit /b 1
+:err_OS
+echo Unsupported operating system. Windows 2000 or later required.
+pause
diff --git a/Master/texmf/scripts/texlive/tlmgr.pl b/Master/texmf/scripts/texlive/tlmgr.pl index 4c7253fe2c6..29ce78d57f8 100755 --- a/Master/texmf/scripts/texlive/tlmgr.pl +++ b/Master/texmf/scripts/texlive/tlmgr.pl @@ -35,11 +35,8 @@ BEGIN { $^W = 1; # make subprograms (including kpsewhich) have the right path: $mydir = $0; - $mydir =~ s!\\!/!g if $^O =~ /^MSWin(32|64)$/i; $mydir =~ s,/[^/]*$,,; - if ($^O=~/^MSWin(32|64)$/i) { - $ENV{"PATH"} = "$mydir;$ENV{PATH}"; - } else { + if (!$^O=~/^MSWin(32|64)$/i) { $ENV{"PATH"} = "$mydir:$ENV{PATH}"; } # @@ -1198,15 +1195,19 @@ sub write_w32_updater { } return 0 if ($opts{"dry-run"}); # nothing else to do # write the updater script file - open UPDATER, ">$root/temp/run-updater-w32" - or die "Cannot create updater: $!"; - print UPDATER '@echo off + open UPDATER, ">$root/temp/run-updater-w32" or die "Cannot create updater: $!"; + print UPDATER ' +@echo off setlocal enableextensions (set errorlevel=) +(set guimode=' . $::gui_mode . ') >nul copy /y "%~dp0..\texmf\scripts\texlive\updater-w32.bat" "%~dp0updater-w32.bat" -call "%~dp0updater-w32" ' . join(' ',@updater_args) . ' -if errorlevel 1 call exit /b %%errorlevel%% -start /b cmd /c del "%~f0" "%~dp0updater-w32.bat"'; +rem Execute with cmd.exe to avoid problems if 4NT is used +rem Keep files write open during execution to signal running state +cmd.exe /c call "%~dp0updater-w32.bat" ' . join(' ',@updater_args) . ' 8^>^>"%~f0" 9^>^>"%~dp0updater-w32.bat" +rem Self-delete without error message about missing file +(if not errorlevel 1 start /b cmd.exe /c del "%~f0" "%~dp0updater-w32.bat") & exit /b %errorlevel% +'; close UPDATER; return 0; } @@ -1714,7 +1715,7 @@ sub action_update { tlwarn ("Aborting infrastructure update.\n") if ($ret); } - if (($nrupdated == 0) && ($tlmediasrc->media ne "NET") && $opts{"all"}) { + if (!(@new || @updated || @w32_updated) && ($tlmediasrc->media ne "NET") && $opts{"all"}) { # for all but net updates we warn if nothing is updated tlwarn("\nNothing to update.\n"); tlwarn("\nYour installation is set up to look on the disk for updates.\n"); diff --git a/Master/texmf/scripts/texlive/updater-w32.bat b/Master/texmf/scripts/texlive/updater-w32.bat index 0482f1d2d84..2984c0564c2 100644 --- a/Master/texmf/scripts/texlive/updater-w32.bat +++ b/Master/texmf/scripts/texlive/updater-w32.bat @@ -7,118 +7,151 @@ rem This file is licensed under the GNU General Public License version 2 rem or any later version. rem -rem This script makes some very specific assumptions. -rem Arguments are expected to be a package list passed in triples: -rem package-name old-revision-number new-revision-number -rem For each package-name a tar archive package-name.tar is -rem expected as well (also for .source and .doc pseudo packages - -rem - those are for distribution only and don't appear as separate -rem entries in tlpdb) and a corresponding backup archive -rem __BACKUP_package-name.rXXX.tar, where XXX is (old) -rem revision number (.source and .doc are included in them) - -rem The update logic is follows: -rem (1) untar all package archives -rem (2) include .tlpobj files into tlpdb -rem (3) print update info -rem Any error during (1) or (2) trigers a rollback action: -rem (1) print failed update info -rem (2) untar all package backups -rem (3) include .tlpobj files (from backup) into tlpdb -rem (4) print restore info and popup an error dialog -rem Any error during (1) or (2) and we go into panic mode. -rem At this point there is no guarantee that the installation is still -rem working. There is not much we can do but to print failed restore info -rem and popup a fatal error dialog with instructions to download and run -rem 'update-tlmgr-latest.exe' when everything else failed. - -rem make environment changes local & enable cmd extensions -setlocal enableextensions -rem get installation root -for /f "delims=" %%D in ('kpsewhich -var-value=SELFAUTOPARENT') do (set tlroot=%%~fD) -if exist "%tlroot%\" goto :foundtlroot ->&2 echo Could not locate installation root. -exit /b 1 - -:foundtlroot -rem get location of the log file -for /f "delims=" %%D in ('kpsewhich -var-value=TEXMFSYSVAR') do (set logdir=%%~fD\web2c) -if not exist "%logdir%\" (set logdir=temp) -rem cd to root -cd /d "%tlroot%" -rem create tar.exe backup ->nul copy /y tlpkg\installer\tar.exe temp\w32_tar.exe -rem set up perl environment -set "PERL5LIB=%tlroot%\tlpkg\tlperl\lib" -rem let's make sure that we can use dynamic variables +:: =================================================================== +:: INFRASTRUCTURE UPDATE ON WINDOWS +:: =================================================================== +:: Infrastructure files cannot be updated directly from the tlmgr.pl +:: script due to file locking problem on Windows - files that are in +:: use (either open or executing) cannot be removed or replaced. +:: Therefore the update process is performed by a batch script outside +:: of tlmgr.pl. +:: There are three pieces involved in the update: tlmgr.bat launcher, +:: write_w32_updater subroutine in tlmgr.pl and this script. Their +:: roles are as follows: +:: * tlmgr.bat is a watchdog - it launches tlmgr.pl and watches for +:: a trigger script that is to be executed. If trigger script exists +:: before tlmgr.pl is launched, it will be removed or tlmgr.bat will +:: abort if it fails to do so. This means that the trigger script +:: has to be created by the current invocation of tlmgr.pl +:: * write_w32_updater subroutine in tlmgr.pl prepares the update +:: and writes the trigger script. Packages in .lzma archives are +:: dowloaded/copied and uncompressed to .tar files. Also .tar +:: backups of the current packages are made. If everything is +:: successful, the trigger script is written, otherwise the update +:: is aborted. +:: * run-updater-w32.bat trigger script passes package list together +:: with revison numbers to the updater script. Additionally it locks +:: itself up write open (and the updater script as well) to prevent +:: tlmgr.bat from starting another instance of tlmgr and/or update. +:: * updater-w32.bat, which is this script, does the actual update. It +:: makes some very specific assumptions. Arguments are expected to +:: be a package list passed in triples: +:: package-name old-revision-number new-revision-number +:: For each package-name a .tar archive package-name.tar is expected +:: (also for .source and .doc pseudo packages---those are for +:: distribution only and don't appear separately in tlpdb). +:: Additionally a backup archive is expected: +:: __BACKUP_package-name.rXXX.tar, +:: where XXX is (old) revision number (.source and .doc are included +:: in the backup). +:: The update itself proceeds as follows: +:: (1) untar all package archives +:: (2) include .tlpobj files into tlpdb +:: (3) print update info +:: Any error during (1) or (2) triggers the rollback action: +:: (1) print failed update info +:: (2) untar all package backups +:: (3) include .tlpobj files (from backup) into tlpdb +:: (4) print restore info +:: Any error during (1) or (2) and we go into panic mode. At this +:: point there is no guarantee that the installation is still +:: working. There is not much we can do but to print failed restore +:: info and give instructions to download and run +:: 'update-tlmgr-latest.exe' to repair the installation. +:: =================================================================== + +rem Make environment changes local & enable cmd extensions +rem (we don't want delayed expansion becasue it's hard to echo bang !) +setlocal enableextensions disabledelayedexpansion +rem Make sure that we can use dynamic variables (set errorlevel=) (set date=) (set time=) -rem get package list from arguments +rem Get TL installation root +for /f "delims=" %%I in ('kpsewhich -var-value=SELFAUTOPARENT') do (set tlroot=%%~fI) +if not exist "%tlroot%\texmf\scripts\texlive\tlmgr.pl" ( + echo %~n0: cannot locate installation root.>&2 + exit /b 1 +) + +rem Get log file location +for /f "delims=" %%I in ('kpsewhich -var-value=TEXMFSYSVAR') do (set logdir=%%~fI\web2c) +if not exist "%logdir%\" (set logdir=%tlroot%\temp) + +rem Change to root +rem cd /d "%tlroot%" + +rem Make a private copy of tar.exe +copy /y "%tlroot%\tlpkg\installer\tar.exe" "%tlroot%\temp\tar-w32.exe" >nul +if errorlevel 1 ( + echo %~n0: cannot copy tar.exe.>&2 + exit /b 1 +) + +rem Set up perl environment +set PERL5LIB=%tlroot%\tlpkg\tlperl\lib + +rem Get package list from arguments (set pkgpartslist=%*) -if not defined pkgpartslist exit /b 0 -rem construct package list without .source and .doc packages -rem count the total number of packages while doing that +if not defined pkgpartslist ( + echo %~n0: no arguments given, how did you start me?>&2 + exit /b 1 +) + +rem Construct package list without .source and .doc packages +rem Count the total number of packages while doing that set pkgcount=0 (set pkglist=) -call :foreachpkg :remove_src_doc pkglist %pkgpartslist% +call :foreachpkg remove_src_doc pkglist %pkgpartslist% + +rem Set gui mode to console if not defined +if not defined guimode set guimode=0 echo DO NOT CLOSE THIS WINDOW! echo TeX Live infrastructure update in progress... -call :foreachpkg :untar "temp\" %pkgpartslist% || goto :rollback -call :foreachpkg :incltlpobj "tlpkg\tlpobj\" %pkgpartslist% || goto :rollback -call :foreachpkg :update_info "" %pkglist% -echo Update complete. +call :foreachpkg untar "%tlroot%\temp\" %pkgpartslist% +if errorlevel 1 goto :rollback +call :foreachpkg incltlpobj "%tlroot%\tlpkg\tlpobj\" %pkgpartslist% +if errorlevel 1 goto :rollback +call :foreachpkg updateinfo "update" %pkglist% +call :printmsg%guimode% "TeX Live infrastructure update complete." 0 "TeX Live Manager 2008" set exitcode=0 goto :finish :rollback -call :foreachpkg :update_info ">&2" %pkglist% ->&2 echo Update failed! Rolling back to previous version... -call :foreachpkg :untar "temp\__BACKUP_" %pkglist% || goto :panic -call :foreachpkg :incltlpobj "tlpkg\tlpobj\" %pkglist% || goto :panic -call :foreachpkg :restore_info "" %pkglist% -echo Recovery from backup successful. -call :errorpopup "ERROR: TeX Live" "TeX Live infrastructure update failed." +call :foreachpkg updateinfo "failed update" %pkglist% >&2 +echo Rolling back to previous version... +call :foreachpkg untar "%tlroot%\temp\__BACKUP_" %pkglist% +if errorlevel 1 goto :panic +call :foreachpkg incltlpobj "%tlroot%\tlpkg\tlpobj\" %pkglist% +if errorlevel 1 goto :panic +call :foreachpkg restoreinfo "restore" %pkglist% +call :printmsg%guimode% "TeX Live infrastructure update failed.\nPrevious version has been restored." 16 "ERROR: TeX Live Manager 2008" >&2 set exitcode=1 goto :finish :panic -call :foreachpkg :restore_info ">&2" %pkglist% ->&2 echo FATAL ERROR: recovery from backup failed! -echo Your TeX Live installation may be broken, to repair it download and run: -echo http://mirror.ctan.org/systems/texlive/tlnet/2008/update-tlmgr-latest.exe -call :errorpopup "FATAL ERROR: TeX Live" "TeX Live infrastructure update failed and so did recovery from backup.\nYour TeX Live installation may be broken, to repair it download and run:\nhttp://mirror.ctan.org/systems/texlive/tlnet/2008/update-tlmgr-latest.exe" +call :foreachpkg restoreinfo "failed restore" %pkglist% >&2 +call :printmsg%guimode% "TeX Live infrastructure update failed and backup recovery failed as well.\nYour TeX Live installation may be broken, to repair it download and run:\nhttp://mirror.ctan.org/systems/texlive/tlnet/2008/update-tlmgr-latest.exe" 16 "FATAL ERROR: TeX Live Manager 2008" >&2 rem Evil has taken over - emit adequate exit code exit /b 666 :finish -2>nul del temp\w32_tar.exe temp\__BACKUP_* +del "%tlroot%\temp\tar-w32.exe" "%tlroot%\temp\__BACKUP_*" >nul 2>&1 exit /b %exitcode% REM SUBROUTINES -:foreachpkg cmd prefix [pkg_name oldrev newrev [...]] -set pkgcurr=0 +:foreachpkg cmd prefix pkgname oldrev newrev ... +set pkgnr=0 :pkgloop if [%3]==[] exit /b 0 -set /a pkgcurr+=1 -call %~1 %2 %3 %4 %5 -if errorlevel 1 exit /b %errorlevel% +call :%1 %2 %3 %4 %5 +if errorlevel 1 exit /b 1 shift /3 & shift /3 & shift /3 goto :pkgloop -:untar temp\[__BACKUP_] pkg_name -set "ext=tar" -if %~n1_==__BACKUP__ set "ext=r%~3.tar" -temp\w32_tar.exe -x -f "%~1%~2.%ext%" && del "%~1%~2.%ext%" -exit /b %errorlevel% - -:incltlpobj tlpkg\tlpobj\ pkg_name -tlpkg\tlperl\bin\perl.exe texmf\scripts\texlive\tlmgr.pl _include_tlpobj "%~1%~2.tlpobj" -exit /b %errorlevel% - :remove_src_doc if /i %~x2.==.source. exit /b 0 if /i %~x2.==.doc. exit /b 0 @@ -126,19 +159,34 @@ set %1=%pkglist% %2 %3 %4 set /a pkgcount+=1 exit /b 0 -:update_info redir pkg_name oldrev newrev -set "infomsg=update: %~2 (%~3 -^> %~4)" -goto :continue_info -:restore_info redir pkg_name oldrev newrev -set "infomsg=restore: %~2 (%~3)" -:continue_info -if "%~1"==">&2" set "infomsg=failed %infomsg%" ->>"%logdir%\tlmgr.log" echo [%date% %time%] %infomsg% -%~1 echo [%pkgcurr%/%pkgcount%] %infomsg% +:untar %tlroot%\temp\[__BACKUP_] pkgname +set "suffix=tar" +if %~n1_==__BACKUP__ set "suffix=r%~3.tar" +"%tlroot%\temp\tar-w32.exe" -C "%tlroot%" -f "%~1%~2.%suffix%" -x && del "%~1%~2.%suffix%" +exit /b %errorlevel% + +:incltlpobj %tlroot%\tlpkg\tlpobj\ pkgname +"%tlroot%\tlpkg\tlperl\bin\perl.exe" "%tlroot%\texmf\scripts\texlive\tlmgr.pl" _include_tlpobj "%~1%~2.tlpobj" +exit /b %errorlevel% + +:updateinfo header pkgname oldrev newrev +set "infomsg= -> %~4" +:restoreinfo header pkgname oldrev newrev +set "infomsg=%~1: %~2 (%~3%infomsg%)" +set "infomsg=%infomsg:>=^>%" +set /a pkgnr+=1 +echo [%pkgnr%/%pkgcount%] %infomsg% +echo [%date% %time%] %infomsg%>>"%logdir%\tlmgr.log" +set "infomsg=" exit /b 0 -:errorpopup "title string" "message text" ->temp\errorpopup.vbs echo CreateObject("Scripting.FileSystemObject").DeleteFile(WScript.ScriptFullName) : MsgBox Replace("%~2","\n",Chr(10)), 16, "%~1" -wscript temp\errorpopup.vbs -rem del temp\errorpopup.vbs +:printmsg0 "message text" +set infomsg=%~1 +for %%I in ("%infomsg:\n=" "%") do echo.%%~I exit /b 0 + +:printmsg1 "message text" icon "title string" +echo MsgBox Replace("%~1", "\n", Chr(10)), %2, "%~3" >"%tlroot%\temp\dialogpopup.vbs" +cscript -nologo "%tlroot%\temp\dialogpopup.vbs" +del "%tlroot%\temp\dialogpopup.vbs" +exit /b %errorlevel% |