diff options
author | Norbert Preining <preining@logic.at> | 2009-02-09 07:16:35 +0000 |
---|---|---|
committer | Norbert Preining <preining@logic.at> | 2009-02-09 07:16:35 +0000 |
commit | c92f1ff98e4fc53d91cec289ca90cfd8ab6b15f1 (patch) | |
tree | 770e96de7b4a8ba54ec83fca43d1f4166d1fb4f4 | |
parent | ade7ca0899ec126ca5c34413ec4e23d3a09a7732 (diff) |
new patch from Tomek for tmgr/w32_updater
git-svn-id: svn://tug.org/texlive/trunk@12122 c570f23f-e606-0410-a88d-b1316a301751
-rwxr-xr-x | Master/texmf/scripts/texlive/tlmgr.pl | 251 | ||||
-rw-r--r-- | Master/tlpkg/installer/w32_updater.cmd | 123 |
2 files changed, 209 insertions, 165 deletions
diff --git a/Master/texmf/scripts/texlive/tlmgr.pl b/Master/texmf/scripts/texlive/tlmgr.pl index 2643505f519..c60cf2199fe 100755 --- a/Master/texmf/scripts/texlive/tlmgr.pl +++ b/Master/texmf/scripts/texlive/tlmgr.pl @@ -1124,28 +1124,31 @@ sub action_backup { # sub write_w32_updater { - my ($opt_dry, @w32_updates) = @_; + my @w32_updated = @_; my $media = $tlmediasrc->media; my $mediatlpdb = $tlmediasrc->tlpdb; # we have to download/copy also the src/doc files if necessary! my $container_src_split = $mediatlpdb->config_src_container; my $container_doc_split = $mediatlpdb->config_doc_container; # get options about src/doc splitting from $totlpdb - # TT: should we local options to decide about install of doc & src? + # TT: should we use local options to decide about install of doc & src? my $opt_src = $localtlpdb->option_install_srcfiles; my $opt_doc = $localtlpdb->option_install_docfiles; my $root = $localtlpdb->root; my $temp = "$root/temp"; my $repo = $mediatlpdb->root . "/$Archive"; TeXLive::TLUtils::mkdirhier($temp); + tlwarn("Backup option not implemented for infrastructure update.\n") if ($opts{"backup"}); if ($media eq 'DVD') { - tlwarn ("Creating updater from DVD currently not implemented!\n"); - tlwarn ("But it should not be necessary!\n"); + tlwarn("Creating updater from DVD currently not implemented!\n"); + tlwarn("But it should not be necessary!\n"); return 1; # abort } my ($mediatlp, $localtlp, $opt_real_doc, $sysret, $size, $md5, $fullname, $oldrev, $newrev, $pkg_part, @pkg_parts, @updater_args); - foreach my $pkg (@w32_updates) { + my $totalnr = $#w32_updated + 1; + my $currnr = 0; + foreach my $pkg (@w32_updated) { $mediatlp = $mediatlpdb->get_package($pkg); $localtlp = $localtlpdb->get_package($pkg); $oldrev = $localtlp->revision; @@ -1155,10 +1158,17 @@ sub write_w32_updater { @pkg_parts = ($pkg); push(@pkg_parts, "$pkg.source") if ($container_src_split && $opt_src && $mediatlp->srcfiles); push(@pkg_parts, "$pkg.doc") if ($container_doc_split && $opt_real_doc && $mediatlp->docfiles); - if ($opt_dry) { - info("update: $pkg ($oldrev -> $newrev)\n"); + $currnr++; + if ($opts{"dry-run"}) { + info("[$currnr/$totalnr] update: $pkg ($oldrev -> $newrev)\n"); next; } + # create backup; make_container expects file name in a format: some-name.r[0-9]+ + ($size, $md5, $fullname) = $localtlp->make_container("tar", $root, $temp, "__BACKUP_$pkg.r$oldrev"); + if ($size <= 0) { + tlwarn("Creation of backup container of $pkg failed.\n"); + return 1; # backup failed? abort + } foreach $pkg_part (@pkg_parts) { if ($media eq 'CD') { copy("$repo/$pkg_part.tar.lzma", "$temp"); @@ -1167,26 +1177,27 @@ sub write_w32_updater { } # now we should have the file present if (!-r "$temp/$pkg_part.tar.lzma") { - tlwarn ("Couldn't get $pkg_part.tar.lzma, that is bad\n"); + tlwarn("Couldn't get $pkg_part.tar.lzma, that is bad\n"); return 1; # abort } # unpack lzma archive - $sysret = system("$root/tlpkg/installer/lzma/lzmadec.win32.exe < \"$temp/$pkg_part.tar.lzma\" > \"$temp/$pkg_part.tar\""); - return 1 if $sysret; # unpack failed? abort + $sysret = system("$::progs{'lzmadec'} < \"$temp/$pkg_part.tar.lzma\" > \"$temp/$pkg_part.tar\""); + if ($sysret) { + tlwarn("Couldn't unpack $pkg_part.tar.lzma\n"); + return 1; # unpack failed? abort + } unlink("$temp/$pkg_part.tar.lzma"); # we don't need that archive anymore push @updater_args, $pkg_part, $oldrev, $newrev; } - # create backup - ($size, $md5, $fullname) = $localtlp->make_container("tar", $root, $temp, "__BACKUP_$pkg.r$oldrev"); - if ($size <= 0) { - tlwarn("Creation of backup container of $pkg failed.\n"); - return 1; # backup failed? abort - } } - return 0 if ($opt_dry); # nothing else to do + return 0 if ($opts{"dry-run"}); # nothing else to do # write the updater script file open UPDATER, ">$root/tlpkg/installer/updater" or die "Cannot create updater: $!"; - print UPDATER 'call %~dp0w32_updater ' . join(' ',@updater_args); + print UPDATER '@echo off +setlocal enableextensions +(set errorlevel=) +call "%~dp0w32_updater" ' . join(' ',@updater_args) . ' +start /b cmd /c del "%~f0" & exit /b %errorlevel%'; close UPDATER; return 0; } @@ -1422,6 +1433,7 @@ sub action_update { # # we first collect the list of packages to be actually updated or installed my @updated; + my @w32_updated; # win32 special packages that need the updater batch script my @new; my @addlines; @@ -1476,7 +1488,12 @@ sub action_update { } my $mediarev = $mediatlp->revision; if ($rev < $mediarev) { - push @updated, $pkg; + if (win32() && !$opts{"list"} && ($pkg =~ m/$WinSpecialUpdatePackagesRegexp/)) { + # w32 specials are treated as other packages for --list + push @w32_updated, $pkg; + } else { + push @updated, $pkg; + } } elsif ($rev > $mediarev) { if ($::machinereadable) { push @addlines, @@ -1495,18 +1512,20 @@ sub action_update { } # number calculation - my $totalnr = $#new + $#updated + 2; + # without w32 special packages, those are dealt with in the updater batch script + my $totalnr = $#new + $#updated + 2; my $nrupdated = 0; my $currnr = 1; # sizes_of_packages returns the sizes of *all* packages if nothing # is passed over, so if @new and @updated both are empty we will # get something wrong back, namely the total size of all packages my %sizes; - if ($totalnr > 0) { + # for size calculation we also want w32 special packages + if (@new || @updated || @w32_updated) { %sizes = %{$mediatlpdb->sizes_of_packages( $localtlpdb->option_install_srcfiles, $localtlpdb->option_install_docfiles, - @new, @updated )}; + @new, @updated, @w32_updated)}; } else { $sizes{'__TOTAL__'} = 0; } @@ -1567,7 +1586,6 @@ sub action_update { } # - my @w32_updates if win32(); foreach my $pkg (sort @updated) { next if ($pkg =~ m/^00texlive/); my $tlp = $localtlpdb->get_package($pkg); @@ -1588,110 +1606,107 @@ sub action_update { } else { info("$pkg: local: $rev, source: $mediarev\n"); } - } else { - if ($opts{"backup"} && !$opts{"dry-run"}) { - $tlp->make_container("lzma", $root, - $opts{"backupdir"}, "${pkg}.r" . $tlp->revision); - $unwind_package = - "$opts{'backupdir'}/${pkg}.r" . $tlp->revision . ".tar.lzma"; + next; + } + + if ($opts{"backup"} && !$opts{"dry-run"}) { + $tlp->make_container("lzma", $root, + $opts{"backupdir"}, "${pkg}.r" . $tlp->revision); + $unwind_package = + "$opts{'backupdir'}/${pkg}.r" . $tlp->revision . ".tar.lzma"; - if ($autobackup) { - # in case we do auto backups we remove older backups - clear_old_backups($pkg, $opts{"backupdir"}, $autobackup); - } + if ($autobackup) { + # in case we do auto backups we remove older backups + clear_old_backups($pkg, $opts{"backupdir"}, $autobackup); } + } - if (win32() && ($pkg =~ m/$WinSpecialUpdatePackagesRegexp/)) { - # collect all infrastructure packages for later processing - push @w32_updates, $pkg; - } else { - if ($::machinereadable) { - machine_line($pkg, $FLAG_UPDATE, $rev, $mediarev, $sizes{$pkg}); - } else { - info("[$currnr/$totalnr] update: $pkg ($rev -> $mediarev)"); - } - $currnr++; - if ($opts{"dry-run"}) { - info("\n") unless $::machinereadable; - next; - } else { - info(" ... ") unless $::machinereadable; # more to come - } + if ($::machinereadable) { + machine_line($pkg, $FLAG_UPDATE, $rev, $mediarev, $sizes{$pkg}); + } else { + info("[$currnr/$totalnr] update: $pkg ($rev -> $mediarev)"); + } + $currnr++; + if ($opts{"dry-run"}) { + info("\n") unless $::machinereadable; + next; + } else { + info(" ... ") unless $::machinereadable; # more to come + } - if (!$unwind_package) { - # no backup was made, so let us create a temporary .tar file - # of the package - my $tlp = $localtlpdb->get_package($pkg); - my ($s, $m, $fullname) = $tlp->make_container("tar", $root, $temp, - "__BACKUP_${pkg}.r" . $tlp->revision); - if ($s <= 0) { - tlwarn("\n$0: Creation of backup container of $pkg failed.\n"); - tlwarn("Continuing to update other packages, please retry...\n"); - # we should try to update other packages at least - next; - } - $remove_unwind_container = 1; - $unwind_package = "$fullname"; - } - # first remove the package, then reinstall it - # this way we get rid of useless files - # force the deinstallation since we will reinstall it - # - # the remove_package should also remove empty dirs in case - # a dir is changed into a file - merge_into(\%ret, &remove_package($pkg, $localtlpdb)); - my $foo = $tlmediasrc->install_package($pkg, $localtlpdb); - if (ref $foo) { - # installation succeeded because we got a reference - merge_into (\%ret, $foo); - logpackage("update: $pkg ($rev -> $mediarev)"); - unlink($unwind_package) if $remove_unwind_container; - } else { - # install_package returned a scalar, so error. - # now in fact we should do some cleanup, removing files and - # dirs from the new package before re-installing the old one. - # TODO - logpackage("failed update: $pkg ($rev -> $mediarev)"); - tlwarn("\n\nInstallation of new version of $pkg did fail, trying to unwind.\n"); - if (win32()) { - # w32 is notorious for not releasing a file immediately - # we experienced permission denied errors - my $newname = $unwind_package; - $newname =~ s/__BACKUP/___BACKUP/; - copy ("-f", $unwind_package, $newname); - # try to remove the file if has been created by us - unlink($unwind_package) if $remove_unwind_container; - # and make sure that the temporary file is removed in any case - $remove_unwind_container = 1; - $unwind_package = $newname; - } - my $instret = TeXLive::TLMedia->_install_package("$unwind_package", - [], $localtlpdb); - if ($instret) { - # now we have to include the tlpobj - my $tlpobj = TeXLive::TLPOBJ->new; - $tlpobj->from_file($root . "/tlpkg/tlpobj/$pkg.tlpobj"); - $localtlpdb->add_tlpobj($tlpobj); - $localtlpdb->save; - logpackage("restore: $pkg ($rev)"); - tlwarn("Restoring old package state succeeded.\n"); - } else { - logpackage("restore failed: $pkg ($rev)"); - tlwarn("Restoring of old package did NOT succeed.\n"); - tlwarn("Most likely repair: run tlmgr install $pkg and hope.\n"); - } - unlink($unwind_package) if $remove_unwind_container; - } - info("done\n") unless $::machinereadable; + if (!$unwind_package) { + # no backup was made, so let us create a temporary .tar file + # of the package + my $tlp = $localtlpdb->get_package($pkg); + my ($s, $m, $fullname) = $tlp->make_container("tar", $root, $temp, + "__BACKUP_${pkg}.r" . $tlp->revision); + if ($s <= 0) { + tlwarn("\n$0: Creation of backup container of $pkg failed.\n"); + tlwarn("Continuing to update other packages, please retry...\n"); + # we should try to update other packages at least + next; } + $remove_unwind_container = 1; + $unwind_package = "$fullname"; } + # first remove the package, then reinstall it + # this way we get rid of useless files + # force the deinstallation since we will reinstall it + # + # the remove_package should also remove empty dirs in case + # a dir is changed into a file + merge_into(\%ret, &remove_package($pkg, $localtlpdb)); + my $foo = $tlmediasrc->install_package($pkg, $localtlpdb); + if (ref $foo) { + # installation succeeded because we got a reference + merge_into (\%ret, $foo); + logpackage("update: $pkg ($rev -> $mediarev)"); + unlink($unwind_package) if $remove_unwind_container; + } else { + # install_package returned a scalar, so error. + # now in fact we should do some cleanup, removing files and + # dirs from the new package before re-installing the old one. + # TODO + logpackage("failed update: $pkg ($rev -> $mediarev)"); + tlwarn("\n\nInstallation of new version of $pkg did fail, trying to unwind.\n"); + if (win32()) { + # w32 is notorious for not releasing a file immediately + # we experienced permission denied errors + my $newname = $unwind_package; + $newname =~ s/__BACKUP/___BACKUP/; + copy ("-f", $unwind_package, $newname); + # try to remove the file if has been created by us + unlink($unwind_package) if $remove_unwind_container; + # and make sure that the temporary file is removed in any case + $remove_unwind_container = 1; + $unwind_package = $newname; + } + my $instret = TeXLive::TLMedia->_install_package("$unwind_package", + [], $localtlpdb); + if ($instret) { + # now we have to include the tlpobj + my $tlpobj = TeXLive::TLPOBJ->new; + $tlpobj->from_file($root . "/tlpkg/tlpobj/$pkg.tlpobj"); + $localtlpdb->add_tlpobj($tlpobj); + $localtlpdb->save; + logpackage("restore: $pkg ($rev)"); + tlwarn("Restoring old package state succeeded.\n"); + } else { + logpackage("failed restore: $pkg ($rev)"); + tlwarn("Restoring of old package did NOT succeed.\n"); + tlwarn("Most likely repair: run tlmgr install $pkg and hope.\n"); + } + unlink($unwind_package) if $remove_unwind_container; + } + info("done\n") unless $::machinereadable; } - - # that already checks whether we actually have to do something - if (win32()) { - my $ret = write_w32_updater($opts{"dry-run"} || $opts{"list"}, @w32_updates); + + if (win32() && !$opts{"list"} && @w32_updated) { + info("Preparing TeX Live infrastructure update...\n"); + my $ret = write_w32_updater(@w32_updated); tlwarn ("Aborting infrastructure update.\n") if ($ret); } + if (($nrupdated == 0) && ($tlmediasrc->media ne "NET") && $opts{"all"}) { # for all but net updates we warn if nothing is updated tlwarn("\nNothing to update.\n"); diff --git a/Master/tlpkg/installer/w32_updater.cmd b/Master/tlpkg/installer/w32_updater.cmd index b92a8d4a5bf..df0d84acf92 100644 --- a/Master/tlpkg/installer/w32_updater.cmd +++ b/Master/tlpkg/installer/w32_updater.cmd @@ -1,106 +1,130 @@ @echo off rem Update script for TeX Live infrastructure -rem called automatically if detected by tlmgr launcher +rem called automatically if there are any infrastructure updates rem rem Copyright 2009 by Tomasz M. Trzeciak <t.m.trzeciak@googlemail.com> 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 -2>nul verify nonzero_errorlevel setlocal enableextensions -if not errorlevel 1 goto :begin ->&2 echo CMD.EXE extensions not available. Aborting... +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 -:begin -rem let's make sure that we can use dynamic variables -set "errorlevel=" -set "date=" -set "time=" -rem get root location -for /f "delims=" %%D in ('kpsewhich -var-value=SELFAUTOPARENT') do set "TLROOT=%%~fD" +:foundtlroot rem get location of the log file -for /f "delims=" %%D in ('kpsewhich -var-value=TEXMFSYSVAR') do set "logdir=%%~fD\web2c\" +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%" +cd /d "%tlroot%" rem create tar.exe backup >nul copy /y "%~dp0tar.exe" "%~dp0tarsave.exe" rem set up perl environment -set "PERL5LIB=%TLROOT%\tlpkg\tlperl\lib" +set "PERL5LIB=%tlroot%\tlpkg\tlperl\lib" +rem let's make sure that we can use dynamic variables +(set errorlevel=) +(set date=) +(set time=) + rem get package list from arguments -set pkglist=%* -if not defined pkglist goto :finish +(set pkgpartslist=%*) +if not defined pkgpartslist exit /b 0 +rem construct package list without .src 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% echo DO NOT CLOSE THIS WINDOW! echo TeX Live infrastructure update in progress... -call :foreachpkg :untar "temp\" %pkglist% || goto :rollback -call :foreachpkg :tlobj "tlpkg\tlpobj\" %pkglist% || goto :rollback -set pkglist=& call :foreachpkg :filter_src_doc "" %pkglist% +call :foreachpkg :untar "temp\" %pkgpartslist% || goto :rollback +call :foreachpkg :incltlpobj "tlpkg\tlpobj\" %pkgpartslist% || goto :rollback call :foreachpkg :update_info "" %pkglist% echo Update complete. set exitcode=0 goto :finish :rollback -set pkglist=& call :foreachpkg :filter_src_doc "" %pkglist% 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 :tlobj "tlpkg\tlpobj\" %pkglist% || goto :panic +call :foreachpkg :incltlpobj "tlpkg\tlpobj\" %pkglist% || goto :panic call :foreachpkg :restore_info "" %pkglist% echo Recovery from backup successful. - >temp\popup.vbs echo MsgBox "TeX Live infrastructure update failed." ^& Chr(10) ^& _ ->>temp\popup.vbs echo "Recovery from backup succeeded.", _ ->>temp\popup.vbs echo 48, "TeX Live update" -start /wait wscript temp\popup.vbs -del temp\popup.vbs +call :errorpopup "ERROR: TeX Live" "TeX Live infrastructure update failed." set exitcode=1 goto :finish -:finish -del tlpkg\installer\tarsave.exe temp\__BACKUP_* -rem start /b cmd /c del "%~f0" & exit /b 0 -exit /b %exitcode% - :panic call :foreachpkg :restore_info ">&2" %pkglist% >&2 echo FATAL ERROR: recovery from backup failed! -echo To repair your TeX Live installation download and run: +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 - >temp\popup.vbs echo MsgBox "TeX Live infrastructure update failed and so did recovery from backup." ^& Chr(10) ^& _ ->>temp\popup.vbs echo "To repair your TeX Live installation download and run:" ^& Chr(10) ^& _ ->>temp\popup.vbs echo "http://mirror.ctan.org/systems/texlive/tlnet/2008/update-tlmgr-latest.exe", _ ->>temp\popup.vbs echo 16, "FATAL ERROR: TeX Live update" -start /wait wscript temp\popup.vbs -del temp\popup.vbs +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" rem Evil has taken over - emit adequate exit code exit /b 666 +:finish +2>nul del tlpkg\installer\tarsave.exe temp\__BACKUP_* +exit /b %exitcode% + REM SUBROUTINES :foreachpkg cmd prefix [pkg_name oldrev newrev [...]] +set pkgcurr=0 +:pkgloop if [%3]==[] exit /b 0 +set /a pkgcurr+=1 call %~1 %2 %3 %4 %5 if errorlevel 1 exit /b %errorlevel% shift /3 & shift /3 & shift /3 -goto :foreachpkg +goto :pkgloop :untar temp\[__BACKUP_] pkg_name set "ext=tar" +if "%~x2"==".src" (set type=.source) else (set type=%~x2) if %~n1_==__BACKUP__ set "ext=r%~3.tar" -tlpkg\installer\tarsave.exe -x -f "%~1%~2.%ext%" && del "%~1%~2.%ext%" +tlpkg\installer\tarsave.exe -x -f "%~1%~n2%type%.%ext%" && del "%~1%~n2%type%.%ext%" exit /b %errorlevel% -:tlobj tlpkg\tlpobj\ pkg_name +:incltlpobj tlpkg\tlpobj\ pkg_name tlpkg\tlperl\bin\perl.exe texmf\scripts\texlive\tlmgr.pl _include_tlpobj "%~1%~2.tlpobj" exit /b %errorlevel% -:filter_src_doc +:remove_src_doc if /i %~x2.==.src. exit /b 0 if /i %~x2.==.doc. exit /b 0 -set pkglist=%pkglist% %2 %3 %4 +set %1=%pkglist% %2 %3 %4 +set /a pkgcount+=1 exit /b 0 :update_info redir pkg_name oldrev newrev @@ -109,8 +133,13 @@ goto :continue_info :restore_info redir pkg_name oldrev newrev set "infomsg=restore: %~2 (%~3)" :continue_info -rem exit /b 0 -if "%~1"==">&2" set "infomsg=failed %infomsg% -rem >>%logdir%tlmgr.log echo [%date% %time%] %infomsg% -%~1 echo %infomsg% +if "%~1"==">&2" set "infomsg=failed %infomsg%" +>>"%logdir%\tlmgr.log" echo [%date% %time%] %infomsg% +%~1 echo [%pkgcurr%/%pkgcount%] %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 +exit /b 0
\ No newline at end of file |