summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xMaster/bin/win32/tlmgr.bat15
-rwxr-xr-xMaster/texmf/scripts/texlive/tlmgr.pl220
-rw-r--r--Master/texmf/scripts/texlive/updater-w32228
-rw-r--r--Master/tlpkg/tlpsrc/texlive.infra.tlpsrc2
4 files changed, 345 insertions, 120 deletions
diff --git a/Master/bin/win32/tlmgr.bat b/Master/bin/win32/tlmgr.bat
index 8f72641d00b..03536cb9c88 100755
--- a/Master/bin/win32/tlmgr.bat
+++ b/Master/bin/win32/tlmgr.bat
@@ -1,8 +1,8 @@
@echo off
rem Advanced launcher for tlmgr with auto-update
rem
-rem Copyright 2009 by Tomasz M. Trzeciak
rem Public Domain
+rem Originally written 2009 by Tomasz M. Trzeciak
rem Make environment changes local
setlocal enableextensions
@@ -11,7 +11,7 @@ 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 tlupdatername=updater-w32)
(set tlupdater=%tlroot%\temp\%tlupdatername%)
if exist "%tlupdater%*" del "%tlupdater%*"
if exist "%tlupdater%*" goto :err_updater_exists
@@ -24,20 +24,15 @@ perl "%tlroot%\texmf\scripts\texlive\tlmgr.pl" %*
rem Finish if there are no updates to do; the last error code will be returned
if not exist "%tlupdater%" goto :eof
rem Rename updater script before it is run
-ren "%tlupdater%" "%tlupdatername%.bat"
+ren "%tlupdater%" "%tlupdatername%.bat">nul
if errorlevel 1 goto :err_rename_updater
rem Run updater
-echo Starting update ...
endlocal & call "%tlupdater%.bat" & goto :eof
:err_updater_exists
-echo %~n0: cannot remove update script, infrastructure update might be in progress>&2
+echo %~nx0: updater script detected, infrastructure update might be running>&2
exit /b 1
:err_rename_updater
-echo %~n0: cannot rename "%tlupdater%">&2
+echo %~nx0: cannot rename "%tlupdater%" to "%tlupdatername%.bat">&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 82f7a72c531..e138e649496 100755
--- a/Master/texmf/scripts/texlive/tlmgr.pl
+++ b/Master/texmf/scripts/texlive/tlmgr.pl
@@ -1289,22 +1289,20 @@ 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: $!";
- # TODO: respawn tlmgr if $restart_tlmgr is set
- # TODO: using @::SAVEDARGV
- print UPDATER '
-@echo off
-setlocal enableextensions
-(set guimode=' . $::gui_mode . ')
->nul copy /y "%~dp0..\texmf\scripts\texlive\updater-w32.bat" "%~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
-rem For gui mode console window might be hidden, so open a new one
-' . ($::gui_mode ? 'start /wait ' : '') . 'cmd.exe /c title TeX Live Manager 2009^& 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") & goto :eof
-';
+ my @rerun_tlmgr_args;
+ # quote all arguments in case of manes with spaces
+ @rerun_tlmgr_args = map ("\"$_\"", @::SAVEDARGV) if $restart_tlmgr;
+ # prepare updater script
+ copy("$root/texmf/scripts/texlive/updater-w32", "$temp");
+ open UPDATER, ">>$temp/updater-w32" or die "Cannot open updater script: $!";
+ print UPDATER "
+:setupenv
+set w32upd_gui_mode=$::gui_mode
+set w32upd_title=TeX Live Manager $TeXLive::TLConfig::ReleaseYear Update
+set w32upd_debug=$::opt_verbosity
+set w32upd_args=@updater_args
+set w32upd_rerun_args=@rerun_tlmgr_args
+";
close UPDATER;
return 0;
}
@@ -1355,43 +1353,22 @@ sub action_update {
init_tlmedia();
info("update: dry run, no changes will be made\n") if $opts{"dry-run"};
- # if the update is not for one of the critical packages then do
# check for updates to tlmgr and die unless either --force or --list or --self
# is given
- my @pretodo = @ARGV;
- push (@pretodo, @CriticalPackagesList) if $opts{"self"};
- my $other_updates_asked_for = 0;
- if ($opts{"all"}) {
- $other_updates_asked_for = 1;
- } else {
- for my $p (@pretodo) {
- my $matched = 0;
- for my $cp (@CriticalPackagesList) {
- # we match for initial package name, that shold be fine
- if ($p =~ m/^$cp/) {
- $matched = 1;
- last;
- }
- }
- if (!$matched) {
- $other_updates_asked_for = 1;
- last;
- }
- }
- }
- if ($other_updates_asked_for && !$opts{"self"}) {
- if (check_for_critical_updates($localtlpdb, $tlmediatlpdb)) {
- if ($opts{"force"}) {
- tlwarn("$0: Continuing due to --force.\n");
- } elsif ($opts{"list"} || $opts{"self"}) {
- # do not warn here
+ my @critical = check_for_critical_updates($localtlpdb, $tlmediatlpdb);
+ my $dry_run_cont = $opts{"dry-run"} && ($opts{"dry-run"} < 0);
+ if ( !$dry_run_cont && !$opts{"self"} && @critical) {
+ critical_updates_warning();
+ if ($opts{"force"}) {
+ tlwarn("$0: Continuing due to --force.\n");
+ } elsif ($opts{"list"}) {
+ # do not warn here
+ } else {
+ if ($::gui_mode) {
+ # return here and don't do any updates
+ return;
} else {
- if ($::gui_mode) {
- # return here and don't do any updates
- return;
- } else {
- die "$0: Exiting, please read above warning.\n";
- }
+ die "$0: Exiting, please read above warning.\n";
}
}
}
@@ -1523,31 +1500,33 @@ sub action_update {
my @todo;
if ($opts{"list"}) {
- # for --list we treat all packages the same
@todo = $localtlpdb->list_packages;
} elsif ($opts{"self"}) {
- # do only critical packages, if others are asked for, do them after tlmgr restart
- @todo = @CriticalPackagesList;
+ @todo = @critical;
+ } elsif ($opts{"all"}) {
+ @todo = $localtlpdb->list_packages;
} else {
- @pretodo = $localtlpdb->list_packages if ($opts{"all"});
- # filter out win32 special packages
- for my $p (@pretodo) {
- push(@todo, $p) if ($p !~ m/$CriticalPackagesRegexp/);
- }
+ @todo = @ARGV;
}
# don't do anything if we have been invoced in a strange way
if (!@todo) {
tlwarn("tlmgr update: please specify a list of packages or --all.\n");
}
- # update all .ARCH dependencies, too, unless $opts{"no-depends-at-all"}:
- @todo = $tlmediatlpdb->expand_dependencies("-only-arch", $localtlpdb, @todo)
- unless $opts{"no-depends-at-all"};
- #
- # update general deps unless $opts{"no-depends"}:
- @todo = $tlmediatlpdb->expand_dependencies("-no-collections",$localtlpdb,@todo)
- unless $opts{"no-depends"};
-
+ if (!$opts{"self"}) {
+ # update all .ARCH dependencies, too, unless $opts{"no-depends-at-all"}:
+ @todo = $tlmediatlpdb->expand_dependencies("-only-arch", $localtlpdb, @todo)
+ unless $opts{"no-depends-at-all"};
+ #
+ # update general deps unless $opts{"no-depends"}:
+ @todo = $tlmediatlpdb->expand_dependencies("-no-collections",$localtlpdb,@todo)
+ unless $opts{"no-depends"};
+ #
+ # filter out critical packages
+ @todo = grep (!m/$CriticalPackagesRegexp/, @todo)
+ unless $opts{"list"};
+ }
+
#
# we first collect the list of packages to be actually updated or installed
my %updated;
@@ -1905,39 +1884,61 @@ sub action_update {
#
# check that if updates to the critical packages are present all of
# them have been successfully updated
- my $infra_update_present = 0;
my $infra_update_done = 1;
- for my $pkg (@CriticalPackagesList) {
- if (defined($updated{$pkg})) {
- $infra_update_present = 1;
- $infra_update_done &&= $updated{$pkg};
+ for my $pkg (@critical) {
+ $infra_update_done &&= $updated{$pkg} if (defined($updated{$pkg}));
+ }
+
+ # check if any additional updates are asked for
+ my $other_updates_asked_for = 0;
+ if ($opts{"all"}) {
+ $other_updates_asked_for = 1;
+ } else {
+ foreach my $p (@ARGV) {
+ if ($p !~ m/$CriticalPackagesRegexp/) {
+ $other_updates_asked_for = 1;
+ last;
+ }
}
}
my $restart_tlmgr = 0;
- # only when we are not dry-running we restart the program
- if ($infra_update_present && $infra_update_done &&
- $other_updates_asked_for && !$opts{"dry-run"}) {
+ if ($opts{"self"} && $infra_update_done && $other_updates_asked_for) {
# weed out the --self argument from the saved arguments
- @::SAVEDARGV = grep {!m;^--self$;} @::SAVEDARGV;;
- @::SAVEDARGV = grep {!m;^-self$;} @::SAVEDARGV;;
+ @::SAVEDARGV = grep (!m/^-?-self$/, @::SAVEDARGV);
$restart_tlmgr = 1;
}
+ # infra update and tlmgr restart on win32 is done by the updater batch script
if (win32() && !$opts{"list"} && @w32_updated) {
info("Preparing TeX Live infrastructure update...\n");
my $ret = write_w32_updater($restart_tlmgr, @w32_updated);
- tlwarn ("Aborting infrastructure update.\n") if ($ret);
+ if ($ret) {
+ tlwarn ("Aborting infrastructure update.\n");
+ $restart_tlmgr = 0 if ($opts{"dry-run"});
+ }
}
- # temporarily disable tlmgr restart after infra update (needs more work)
- if (!win32() && $restart_tlmgr) {
+ # only when we are not dry-running we restart the program
+ if (!win32() && $restart_tlmgr && !$opts{"dry-run"}) {
info ("Restarting tlmgr to complete update ...\n");
debug("restarting tlmgr @::SAVEDARGV\n");
exec("tlmgr", @::SAVEDARGV);
die "Cannot restart tlmgr, please retry updating.";
}
+ # for --dry-run we cannot restart tlmgr (no way to fake successful infra update)
+ # instead we call action_update() again and signal this by $opts{"dry-run"} = -1
+ if ($opts{"dry-run"} && !$opts{"list"} && $restart_tlmgr) {
+ $opts{"self"} = 0;
+ $opts{"dry-run"} = -1;
+ $localtlmedia = undef;
+ $tlmediatlpdb = undef;
+ info ("Restarting tlmgr to complete update ...\n");
+ action_update();
+ return;
+ }
+
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");
@@ -1990,6 +1991,7 @@ sub action_install {
# check for updates to tlmgr itself, and die unless --force is given
if (check_for_critical_updates( $localtlpdb, $tlmediatlpdb)) {
+ critical_updates_warning();
if ($opts{"force"}) {
tlwarn("Continuing due to --force\n");
} else {
@@ -3414,6 +3416,7 @@ sub check_for_critical_updates
my $criticalupdate = 0;
my @critical = $localtlpdb->expand_dependencies("-no-collections",
$localtlpdb, @CriticalPackagesList);
+ my @critical_upd;
for my $pkg (sort @critical) {
my $tlp = $localtlpdb->get_package($pkg);
if (!defined($tlp)) {
@@ -3430,24 +3433,23 @@ sub check_for_critical_updates
next;
}
my $remoterev = $mtlp->revision;
- if ($remoterev > $localrev) {
- $criticalupdate = 1;
- last;
- }
- }
- if ($criticalupdate) {
- tlwarn("Updates for tlmgr itself are present.\n");
- tlwarn("=" x 79, "\n");
- tlwarn("Please update the package manager first, via either\n");
- tlwarn(" tlmgr update --self\n");
- tlwarn("or by getting the latest updater for Unix-ish systems:\n");
- tlwarn(" $TeXLiveURL/update-tlmgr-latest.sh\n");
- tlwarn("and/or Windows systems:\n");
- tlwarn(" $TeXLiveURL/update-tlmgr-latest.exe\n");
- tlwarn("Then continue with other updates.\n");
- tlwarn("=" x 79, "\n");
+ push (@critical_upd, $pkg) if ($remoterev > $localrev);
}
- return($criticalupdate);
+ return(@critical_upd);
+}
+
+sub critical_updates_warning
+{
+ tlwarn("Updates for tlmgr itself are present.\n");
+ tlwarn("=" x 79, "\n");
+ tlwarn("Please update the package manager first, via either\n");
+ tlwarn(" tlmgr update --self\n");
+ tlwarn("or by getting the latest updater for Unix-ish systems:\n");
+ tlwarn(" $TeXLiveURL/update-tlmgr-latest.sh\n");
+ tlwarn("and/or Windows systems:\n");
+ tlwarn(" $TeXLiveURL/update-tlmgr-latest.exe\n");
+ tlwarn("Then continue with other updates.\n");
+ tlwarn("=" x 79, "\n");
}
1;
@@ -3602,11 +3604,10 @@ must be specified. Options:
=item B<--all>
-Update all installed packages but the tlmgr itself.
-For packages contained in an installed
-collection, also install new packages and remove deleted packages in
-those collections. Packages not contained in an installed collection
-are not considered for addition or removal.
+Update all installed packages except for tlmgr itself. For packages
+contained in an installed collection, also install new packages and
+remove deleted packages in those collections. Packages not contained
+in an installed collection are not considered for addition or removal.
More precisely, if both the server and the local installation have a
collection C, and C on the server contains a package A that is not
@@ -3615,16 +3616,17 @@ contains a package B, but B is no longer in the server's C, then B will
be deleted.
In case that updates to tlmgr itself are present this will not work
-unless also the option B<--self> is given.
+unless also the option B<--force> or B<--self> is given.
=item B<--self>
-Updates tlmgr itself if updates are present. On Windows this includes
-updates to the perl interpreter shipped by TeX Live.
+Update tlmgr itself (that is, the infrastructure packages) if updates
+are present. On Windows this includes updates to the perl interpreter
+shipped by TeX Live.
-If this option is given together with B<--all> then first tlmgr will
-be updated, and after that tlmgr restarted to complete with the rest
-of the updates.
+If this option is given together with B<--all> or a list of packages
+then tlmgr will be updated first and, if this update succeeds, it will
+be restarted to complete the rest of the updates.
=item B<--list>
@@ -3638,8 +3640,8 @@ written to the terminal. This is a more detailed report than C<--list>.
=item B<--force>
-If updates to tlmgr itself (that is, the infrastructure packages) are
-present, tlmgr will not perform the update unless this option is given.
+Force update of packages even if updates to tlmgr itself are present.
+Updates to tlmgr are not performed unless B<--self> option is also given.
(C<--list> is still performed regardless of this option.)
=item B<--no-remove>
diff --git a/Master/texmf/scripts/texlive/updater-w32 b/Master/texmf/scripts/texlive/updater-w32
new file mode 100644
index 00000000000..59f6788bf3e
--- /dev/null
+++ b/Master/texmf/scripts/texlive/updater-w32
@@ -0,0 +1,228 @@
+@echo off
+rem Update script for TeX Live infrastructure
+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
+
+:: ===================================================================
+:: 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 .xz 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 created from the template
+:: appended with evironment settings needed for the update.
+:: Otherwise the update is aborted.
+:: * updater-w32.bat, which is this script, triggers and executes
+:: the actual update. During the execution of an update it locks
+:: itself up write open to prevent tlmgr.bat from starting another
+:: instance of tlmgr and/or update. The list of packages to update
+:: and any additional information is passed through evironment,
+:: including agrmuments for tlmgr restart needed to complete the
+:: update of remaining packages.
+:: The list of infrastructure packages consists of 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
+:: (4) optionally restart tlmgr to complete the update
+:: 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 (2) or (3) 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 the environment is clean and that we can use dynamic variables
+for %%I in (errorlevel date time w32upd_args) do (set %%I=)
+
+rem Set up the evironment for update
+call :setupenv
+if not defined w32upd_args (
+ echo updater-w32: update arguments not defined, please report this to: tex-live@tug.org>&2
+ exit /b 1
+)
+set dbg=rem
+if /i %w32upd_debug%0 GTR 0 set dbg=echo D:updater-w32:
+
+if "%~1"=="main" goto :main
+
+rem Restart in cmd.exe to avoid problems if 4NT is used
+set respawn=cmd.exe /c call
+rem For gui mode console window might be hidden, so open a new one
+if /i %w32upd_gui_mode%0==10 set respawn=start /wait %respawn%
+rem Lock this file write-open during execution to signal running state
+call %dbg% respawning in cmd.exe ...
+%respawn% "%~f0" main 9^>^>"%~f0"
+set exitcode=%errorlevel%
+if /i %exitcode%0 NEQ 0 (
+ call %dbg% update script left for inspection at: %~f0.txt
+ copy /y "%~f0" "%~f0.txt" >nul
+ exit /b %exitcode%
+)
+rem Self-delete without error message about missing file
+start /b cmd.exe /c del "%~f0" & exit /b %exitcode%
+
+:main
+title %w32upd_title%
+
+rem Get TL installation root and log file location
+for /f "tokens=1-2 delims=;" %%I in (
+ 'kpsewhich -expand-var=$SELFAUTOPARENT/.;$TEXMFSYSVAR/web2c'
+) do (
+ set tlroot=%%~fI
+ set logdir=%%~fJ
+)
+if not exist "%tlroot%\texmf\scripts\texlive\tlmgr.pl" (
+ echo updater-w32: cannot locate installation root.>&2
+ exit /b 1
+)
+call %dbg% TL root: %tlroot%
+if not exist "%logdir%\" (set logdir=%tlroot%\temp)
+call %dbg% log dir: %logdir%
+
+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 updater-w32: cannot copy tar.exe>&2
+ exit /b 1
+)
+
+rem Set up perl environment
+set PERL5LIB=%tlroot%\tlpkg\tlperl\lib
+
+rem Get package list
+set pkgpartslist=%w32upd_args%
+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%
+
+rem Begin update
+set exitcode=0
+echo DO NOT CLOSE THIS WINDOW!
+echo TeX Live infrastructure update in progress...
+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%
+if not defined w32upd_rerun_args goto :finishmsg
+echo Restarting tlmgr to complete update ...
+call %dbg% tlmgr %w32upd_rerun_args%
+"%tlroot%\tlpkg\tlperl\bin\perl.exe" "%tlroot%\texmf\scripts\texlive\tlmgr.pl" %w32upd_rerun_args%
+set exitcode=%errorlevel%
+goto :finishmsg
+
+:rollback
+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%w32upd_gui_mode% "TeX Live infrastructure update failed.\nPrevious version has been restored." 16 "ERROR: %w32upd_title%" >&2
+set exitcode=1
+goto :finish
+
+:panic
+call :foreachpkg restoreinfo "failed restore" %pkglist% >&2
+call :printmsg%w32upd_gui_mode% "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/update-tlmgr-latest.exe" 16 "FATAL ERROR: %w32upd_title%" >&2
+rem Evil has taken over - emit adequate exit code
+exit /b 666
+
+:finishmsg
+call :printmsg%w32upd_gui_mode% "TeX Live infrastructure update complete." 0 "%w32upd_title%"
+:finish
+del "%tlroot%\temp\tar-w32.exe" "%tlroot%\temp\__BACKUP_*" >nul 2>&1
+exit /b %exitcode%
+
+REM SUBROUTINES
+
+:foreachpkg cmd prefix pkgname oldrev newrev ...
+set pkgnr=0
+:pkgloop
+if [%3]==[] exit /b 0
+call :%1 %2 %3 %4 %5
+if errorlevel 1 exit /b 1
+shift /3 & shift /3 & shift /3
+goto :pkgloop
+
+:remove_src_doc
+if /i %~x2.==.source. exit /b 0
+if /i %~x2.==.doc. exit /b 0
+set %1=%pkglist% %2 %3 %4
+set /a pkgcount+=1
+exit /b 0
+
+:untar %tlroot%\temp\[__BACKUP_] pkgname
+set "suffix=tar"
+if %~n1_==__BACKUP__ set "suffix=r%~3.tar"
+call %dbg% untar: "%~1%~2.%suffix%"
+"%tlroot%\temp\tar-w32.exe" -C "%tlroot%" -f "%~1%~2.%suffix%" -x && del "%~1%~2.%suffix%"
+exit /b %errorlevel%
+
+:incltlpobj %tlroot%\tlpkg\tlpobj\ pkgname
+call %dbg% merge into tlpdb: "%~1%~2.tlpobj"
+"%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
+
+: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%
+
+rem Everything below is generated automatically by tlmgr on each infrastructure update
diff --git a/Master/tlpkg/tlpsrc/texlive.infra.tlpsrc b/Master/tlpkg/tlpsrc/texlive.infra.tlpsrc
index 36d0580889f..1462025b44c 100644
--- a/Master/tlpkg/tlpsrc/texlive.infra.tlpsrc
+++ b/Master/tlpkg/tlpsrc/texlive.infra.tlpsrc
@@ -28,7 +28,7 @@ runpattern f tlpkg/installer/config.guess
binpattern f bin/${ARCH}/tlmgr
binpattern f/win32 bin/win32/tl-w32-wrapper.texlua
binpattern f/win32 bin/win32/tlmgr-gui.vbs
-binpattern f/win32 texmf/scripts/texlive/updater-w32.bat
+binpattern f/win32 texmf/scripts/texlive/updater-w32
binpattern f/win32 tl-portable.bat
binpattern f/win32 tlpkg/installer/tar.exe
binpattern f/win32 tlpkg/installer/xz/xzdec.exe