1#!/usr/bin/env perl
2# $Id: tlmgr.pl 37289 2015-05-09 02:43:37Z preining $
3#
4# Copyright 2008-2015 Norbert Preining
5# This file is licensed under the GNU General Public License version 2
6# or any later version.
7#
8
9my $svnrev = '$Revision: 37289 $';
10my $datrev = '$Date: 2015-05-09 04:43:37 +0200 (Sat, 09 May 2015) $';
11my $tlmgrrevision;
12my $prg;
13if ($svnrev =~ m/: ([0-9]+) /) {
14  $tlmgrrevision = $1;
15} else {
16  $tlmgrrevision = "unknown";
17}
18$datrev =~ s/^.*Date: //;
19$datrev =~ s/ \(.*$//;
20$tlmgrrevision .= " ($datrev)";
21
22our $Master;
23our $ismain;
24our $loadmediasrcerror;
25our $packagelogfile;
26our $packagelogged;
27our $tlmgr_config_file;
28our $pinfile;
29our $action; # for the pod2usage -sections call
30our %opts;
31
32END {
33  if ($opts{"pause"}) {
34    print "Press Enter to exit the program.\n";
35    <STDIN>;
36  }
37}
38
39BEGIN {
40  $^W = 1;
41  $ismain = (__FILE__ eq $0);
42  # WARNING
43  # The only use anticipated for tlmgr.pl as library for the 2009 release
44  # is the Windows w32client prototype script.
45  # Unix-specific problems with use as library will probably go undetected.
46
47  # make subprograms (including kpsewhich) have the right path:
48  my ($bindir, $kpsewhichname);
49  if ($^O =~ /^MSWin/i) {
50    # on w32 $0 and __FILE__ point directly to tlmgr.pl; they can be relative
51    $Master = __FILE__;
52    $Master =~ s!\\!/!g;
53    $Master =~ s![^/]*$!../../..!
54      unless ($Master =~ s!/texmf-dist/scripts/texlive/tlmgr\.pl$!!i);
55    $bindir = "$Master/bin/win32";
56    $kpsewhichname = "kpsewhich.exe";
57    # path already set by wrapper batchfile
58  } else {
59    $Master = __FILE__;
60    $Master =~ s,/*[^/]*$,,;
61    if ($ismain) {
62      $bindir = $Master;
63      $Master = "$Master/../..";
64    } else {
65      # for the time being, this code will not be used or tested
66      $Master = "$Master/../../..";
67      # no code yet for $bindir; would have to detect platform
68    }
69    # make subprograms (including kpsewhich) have the right path:
70    $ENV{"PATH"} = "$bindir:$ENV{PATH}";
71    $kpsewhichname = "kpsewhich";
72  }
73  if (-r "$bindir/$kpsewhichname") {
74    # if not in bootstrapping mode => kpsewhich exists, so use it to get $Master
75    chomp($Master = `kpsewhich -var-value=SELFAUTOPARENT`);
76  }
77  $::installerdir = $Master;
78
79  #
80  # make Perl find our packages first:
81  unshift (@INC, "$Master/tlpkg");
82  unshift (@INC, "$Master/texmf-dist/scripts/texlive");
83}
84
85use Cwd qw/abs_path/;
86use File::Spec;
87use Digest::MD5;
88use Pod::Usage;
89use Getopt::Long qw(:config no_autoabbrev permute);
90use strict;
91
92use TeXLive::TLConfig;
93use TeXLive::TLPDB;
94use TeXLive::TLPOBJ;
95use TeXLive::TLUtils;
96use TeXLive::TLWinGoo;
97use TeXLive::TLDownload;
98use TeXLive::TLConfFile;
99TeXLive::TLUtils->import(qw(member info give_ctan_mirror win32 dirname
100                            mkdirhier copy log debug tlcmp));
101use TeXLive::TLPaper;
102
103#
104# set up $prg for warning messages
105$prg = TeXLive::TLUtils::basename($0);
106
107binmode(STDOUT, ":utf8");
108binmode(STDERR, ":utf8");
109
110our %config;       # hash of config settings from config file
111our $remotetlpdb;
112our $location;     # location from which the new packages come
113our $localtlpdb;   # local installation which we are munging
114
115# flags for machine-readable form
116our $FLAG_REMOVE = "d";
117our $FLAG_FORCIBLE_REMOVED = "f";
118our $FLAG_UPDATE = "u";
119our $FLAG_REVERSED_UPDATE = "r";
120our $FLAG_AUTOINSTALL = "a";
121our $FLAG_INSTALL = "i";
122our $FLAG_REINSTALL = "I";
123
124# keep in sync with install-tl.
125our $common_fmtutil_args =
126  "--no-error-if-no-engine=$TeXLive::TLConfig::PartialEngineSupport";
127
128# return flags for error handling
129#
130# all fine
131our $F_OK = 0;
132#
133# some warnings, but we still try to run post actions
134our $F_WARNING = 1;
135#
136# error, terminating
137our $F_ERROR = 2;
138#
139# all fine, but no need to run post actions
140our $F_NOPOSTACTION = 4;
141
142# option variables
143$::gui_mode = 0;
144$::machinereadable = 0;
145
146my %globaloptions = (
147  "gui" => 1,
148  "gui-lang" => "=s",
149  "debug-translation" => 1,
150  "location|repository|repo" => "=s",
151  "machine-readable" => 1,
152  "package-logfile" => "=s",
153  "persistent-downloads" => "!",
154  "no-execute-actions" => 1,
155  "pin-file" => "=s",
156  "pause" => 1,
157  "print-platform|print-arch" => 1,
158  "version" => 1,
159  "help" => 1,
160  "h|?" => 1);
161
162my %action_specification = (
163  '_include_tlpobj' => {
164    "run-post" => 0,
165    "function" => \&action_include_tlpobj
166  },
167  "backup" => {
168    "options" => {
169      "backupdir" => "=s",
170      "clean" => ":-99",
171      "all" => 1,
172      "dry-run|n" => 1
173    },
174    "run-post" => 1,
175    "function" => \&action_backup
176  },
177  "candidates" => {
178    "run-post" => 0,
179    "function" => \&action_candidates
180  },
181  "check" => {
182    "options"  => { "use-svn" => 1 },
183    "run-post" => 1,
184    "function" => \&action_check
185  },
186  "conf" => {
187    "options"  => {
188      "conffile" => "=s",
189      "delete" => 1,
190    },
191    "run-post" => 0,
192    "function" => \&action_conf
193  },
194  "dump-tlpdb" => {
195    "options"  => { "local" => 1, remote => 1 },
196    "run-post" => 0,
197    "function" => \&action_dumptlpdb
198  },
199  "generate" => {
200    "options"  => {
201      "localcfg" => "=s",
202      "dest" => "=s",
203      "rebuild-sys" => 1
204    },
205    "run-post" => 1,
206    "function" => \&action_generate
207  },
208  "get-mirror" => {
209    "run-post" => 0,
210    "function" => \&action_get_mirror
211  },
212  "gui" => {
213    "options"  => { "load" => 1 },
214    "run-post" => 1,
215    "function" => \&action_gui
216  },
217  "info" => {
218    "options"  => { "list" => 1, "only-installed" => 1 },
219    "run-post" => 0,
220    "function" => \&action_info
221  },
222  "init-usertree" => {
223    "run-post" => 0,
224    "function" => \&action_init_usertree
225  },
226  "install" => {
227    "options"  => {
228      "no-depends"        => 1,
229      "no-depends-at-all" => 1,
230      "file" => 1,
231      "reinstall" => 1,
232      "force" => 1,
233      "dry-run|n" => 1,
234      "with-doc" => 1,
235      "with-src" => 1,
236    },
237    "run-post" => 1,
238    "function" => \&action_install
239  },
240  "option" => {
241    "run-post" => 1,
242    "function" => \&action_option
243  },
244  "paper" => {
245    "options"  => { "list" => 1 },
246    "run-post" => 1,
247    "function" => \&action_paper
248  },
249  "path" => {
250    "options"  => { "w32mode" => "=s" },
251    "run-post" => 0,
252    "function" => \&action_path
253  },
254  "pinning" => {
255    "options"  => { "all" => 1 },
256    "run-post" => 1,
257    "function" => \&action_pinning
258  },
259  "platform" => {
260    "options"  => { "dry-run|n" => 1 },
261    "run-post" => 1,
262    "function" => \&action_platform
263  },
264  "postaction" => {
265    "options" => {
266      "w32mode" => "=s",
267      "all" => 1,
268      "fileassocmode" => "=i"
269    },
270    "run-post" => 0,
271    "function" => \&action_postaction
272  },
273  "recreate-tlpdb" => {
274    "options"  => { "platform|arch" => "=s" },
275    "run-post" => 0,
276    "function" => \&action_recreate_tlpdb
277  },
278  "remove" => {
279    "options"  => {
280      "no-depends"        => 1,
281      "no-depends-at-all" => 1,
282      "force" => 1,
283      "dry-run|n" => 1
284    },
285    "run-post" => 1,
286    "function" => \&action_remove
287  },
288  repository => {
289    "options"  => { "with-platforms" => 1 },
290    "run-post" => 1,
291    "function" => \&action_repository
292  },
293  "restore" => {
294    "options"  => {
295      "backupdir" => "=s",
296      "dry-run|n" => 1,
297      "all" => 1,
298      "force" => 1
299    },
300    "run-post" => 1,
301    "function" => \&action_restore
302  },
303  "search" => {
304    "options"  => {
305      "global" => 1,
306      "word" => 1,
307      "file" => 1,
308      "all" => 1,
309    },
310    "run-post" => 1,
311    "function" => \&action_search
312  },
313  "uninstall" => {
314    "options"  => { "force" => 1 },
315    "run-post" => 0,
316    "function" => \&action_uninstall
317  },
318  "update" => {
319    "options"  => {
320      "no-depends"                 => 1,
321      "no-depends-at-all"          => 1,
322      "all" => 1,
323      "self" => 1,
324      "list" => 1,
325      "no-auto-remove"             => 1,
326      "no-auto-install"            => 1,
327      "reinstall-forcibly-removed" => 1,
328      "force" => 1,
329      "backupdir" => "=s",
330      "backup" => 1,
331      "exclude" => "=s@",
332      "dry-run|n" => 1
333    },
334    "run-post" => 1,
335    "function" => \&action_update
336  },
337  "version" => { }, # handled separately
338);
339
340main() if $ismain;
341
342#####################################################################
343
344
345sub main {
346  my %options;       # TL options from local tlpdb
347
348  my %globaloptions = (
349    "gui" => 1,
350    "gui-lang" => "=s",
351    "debug-translation" => 1,
352    "h|?" => 1,
353    "help" => 1,
354    "location|repository|repo" => "=s",
355    "machine-readable" => 1,
356    "no-execute-actions" => 1,
357    "package-logfile" => "=s",
358    "persistent-downloads" => "!",
359    "pause" => 1,
360    "pin-file" => "=s",
361    "print-platform|print-arch" => 1,
362    "usermode|user-mode" => 1,
363    "usertree|user-tree" => "=s",
364    "version" => 1,
365  );
366
367  my %optarg;
368  for my $k (keys %globaloptions) {
369    if ($globaloptions{$k} eq "1") {
370      $optarg{$k} = 1;
371    } else {
372      $optarg{"$k" . $globaloptions{$k}} = 1;
373    }
374  }
375  for my $v (values %action_specification) {
376    if (defined($v->{'options'})) {
377      my %opts = %{$v->{'options'}};
378      for my $k (keys %opts) {
379        if ($opts{$k} eq "1") {
380          $optarg{$k} = 1;
381        } else {
382          $optarg{"$k" . $opts{$k}} = 1;
383        }
384      }
385    }
386  }
387
388  # save command line options for later restart, if necessary
389  @::SAVEDARGV = @ARGV;
390
391  TeXLive::TLUtils::process_logging_options();
392
393  GetOptions(\%opts, keys(%optarg)) or pod2usage(2);
394
395  $::debug_translation = 0;
396  $::debug_translation = 1 if $opts{"debug-translation"};
397
398  $::machinereadable = $opts{"machine-readable"}
399    if (defined($opts{"machine-readable"}));
400
401  $action = shift @ARGV;
402  if (!defined($action)) {
403    if ($opts{"gui"}) {			# -gui = gui
404      $action = "gui";
405    } elsif ($opts{"print-platform"}) {	# -print-arch = print-arch
406      $action = "print-platform";
407    } else {
408      $action = "";
409    }
410  }
411  $action = lc($action);
412
413  $action = "platform" if ($action eq "arch");
414
415  ddebug("action = $action\n");
416  for my $k (keys %opts) {
417    ddebug("$k => $opts{$k}\n");
418  }
419  ddebug("arguments: @ARGV\n") if @ARGV;
420
421  if ($opts{"version"} || (defined $action && $action eq "version")) {
422    info(give_version());
423    exit(0);
424  }
425
426  if (defined($action) && $action eq "help") {
427    $opts{"help"} = 1;
428  }
429
430  if (defined($action) && $action eq "print-platform") {
431    print TeXLive::TLUtils::platform(), "\n";
432    exit 0;
433  }
434
435  #
436  # ACTION massaging
437  # for backward compatibility and usability
438
439  # unify arguments so that the $action contains paper in all cases
440  # and push the first arg back to @ARGV for action_paper processing
441  if ($action =~ /^(paper|xdvi|psutils|pdftex|dvips|dvipdfmx?|context)$/) {
442    unshift(@ARGV, $action);
443    $action = "paper";
444  }
445
446  # backward compatibility with action "show" and "list" from before
447  if ($action =~ /^(show|list)$/) {
448    $action = "info";
449  }
450
451  # now $action should be part of %actionoptions, otherwise this is
452  # an error
453  if (defined($action) && $action && !exists $action_specification{$action}) {
454    die "$prg: unknown action: $action; try --help if you need it.\n";
455  }
456
457  if ((!defined($action) || !$action) && !$opts{"help"} && !$opts{"h"}) {
458    die "$prg: missing action; try --help if you need it.\n";
459  }
460
461  if ($opts{"help"} || $opts{"h"}) {
462    # perldoc does ASCII emphasis on the output, and runs it through
463    # $PAGER, so people want it.  But not all Unix platforms have it,
464    # and on Windows our Config.pm can apparently interfere, so always
465    # skip it there.  Or if users have NOPERLDOC set in the environment.
466    my @noperldoc = ();
467    if (win32() || $ENV{"NOPERLDOC"}) {
468      @noperldoc = ("-noperldoc", "1");
469    } else {
470      if (!TeXLive::TLUtils::which("perldoc")) {
471        @noperldoc = ("-noperldoc", "1");
472      } else {
473        # checking only for the existence of perldoc is not enough
474        # because Debian/Ubuntu unfortunately ship a stub that does nothing;
475        # try to check for that, too.
476        my $ret = system("perldoc -V >/dev/null 2>&1");
477        if ($ret == 0) {
478          debug("working perldoc found, using it\n");
479        } else {
480          tlwarn("$prg: perldoc seems to be non-functional, not using it.\n");
481          @noperldoc = ("-noperldoc", "1");
482        }
483      }
484    }
485    # less can break control characters and thus the output of pod2usage
486    # is broken.  We add/set LESS=-R in the environment and unset
487    # LESSPIPE and LESSOPEN to try to help.
488    #
489    if (defined($ENV{'LESS'})) {
490      $ENV{'LESS'} .= " -R";
491    } else {
492      $ENV{'LESS'} = "-R";
493    }
494    delete $ENV{'LESSPIPE'};
495    delete $ENV{'LESSOPEN'};
496    if ($action && ($action ne "help")) {
497      # 1) Must use [...] form for -sections arg because otherwise the
498      #    /$action subsection selector applies to all sections.
499      #    https://rt.cpan.org/Public/Bug/Display.html?id=102116
500      # 2) Must use "..." for that so the $action value is interpolated.
501      pod2usage(-exitstatus => 0, -verbose => 99,
502                -sections => [ 'NAME', 'SYNOPSIS', "ACTIONS/$::action.*" ],
503                @noperldoc);
504    } else {
505      if ($opts{"help"}) {
506        pod2usage(-exitstatus => 0, -verbose => 2, @noperldoc);
507      } else {
508        # give a short message about usage
509        print "
510tlmgr revision $tlmgrrevision
511usage: tlmgr  OPTION...  ACTION  ARGUMENT...
512where ACTION is one of:\n";
513        for my $k (sort keys %action_specification) {
514          # don't print internal options
515          next if ($k =~ m/^_/);
516          print " $k\n";
517        }
518        print "\nUse\n tlmgr ACTION --help
519for more details on a specific option, and
520 tlmgr --help
521for the full story.\n";
522        exit 0;
523      }
524    }
525  }
526
527  # --machine-readable is only supported by update.
528  if ($::machinereadable &&
529    $action ne "update" && $action ne "install" && $action ne "option") {
530    tlwarn("$prg: --machine-readable output not supported for $action\n");
531  }
532
533  #
534  # bail out of it is unknown action
535  if (!defined($action_specification{$action})) {
536    tlwarn("$prg: action unknown: $action\n");
537    exit ($F_ERROR);
538  }
539
540  # check on supported arguments
541  #
542  my %suppargs;
543  %suppargs = %{$action_specification{$action}{'options'}}
544    if defined($action_specification{$action}{'options'});
545  my @notvalidargs;
546  for my $k (keys %opts) {
547    my @allargs = keys %suppargs;
548    push @allargs, keys %globaloptions;
549    my $found = 0;
550    for my $ok (@allargs) {
551      my @variants = split '\|', $ok;
552      if (TeXLive::TLUtils::member($k, @variants)) {
553        $found = 1;
554        last;
555      }
556    }
557    push @notvalidargs, $k if !$found;
558  }
559  if (@notvalidargs) {
560    my $msg = "The action $action does not support the following option(s):\n";
561    for my $c (@notvalidargs) {
562      $msg .= " $c";
563    }
564    tlwarn("$prg: $msg\n");
565    tldie("$prg: Try --help if you need it.\n");
566  }
567
568  #
569  # the main tree we will be working on
570  $::maintree = $Master;
571  if ($opts{"usermode"}) {
572    # we could also try to detect that we don't have write permissions
573    # and switch to user mode automatically
574    if (defined($opts{"usertree"})) {
575      $::maintree = $opts{"usertree"};
576    } else {
577      chomp($::maintree = `kpsewhich -var-value TEXMFHOME`);
578    }
579  }
580
581  # besides doing normal logging if -logfile is specified, we try to log
582  # package related actions (install, remove, update) to
583  # the package-log file TEXMFSYSVAR/web2c/tlmgr.log
584  $packagelogged = 0;  # how many msgs we logged
585  chomp (my $texmfsysvar = `kpsewhich -var-value=TEXMFSYSVAR`);
586  $packagelogfile = $opts{"package-logfile"};
587  if ($opts{"usermode"}) {
588    $packagelogfile ||= "$::maintree/web2c/tlmgr.log";
589  } else {
590    $packagelogfile ||= "$texmfsysvar/web2c/tlmgr.log";
591  }
592  #
593  # Try to open the packagelog file, but do NOT die when that does not work
594  if (!open(PACKAGELOG, ">>$packagelogfile")) {
595    debug("Cannot open package log file $packagelogfile for appending\n");
596    debug("Will not log package installation/removal/update for that run\n");
597    $packagelogfile = "";
598  }
599
600  $loadmediasrcerror = "Cannot load TeX Live database from ";
601
602  # load the config file and set the config options
603  # load it BEFORE starting downloads as we set persistent-downloads there!
604  load_config_file();
605
606  # set global variable if execute actions should be suppressed
607  $::no_execute_actions = 1 if (defined($opts{'no-execute-actions'}));
608
609
610  # if we are asked to use persistent connections try to start it here
611  {
612    my $do_persistent;
613    if (defined($opts{'persistent-downloads'})) {
614      # a command line argument for persistent-downloads has been given,
615      # either with --no-... or --... that overrides any other setting
616      $do_persistent = $opts{'persistent-downloads'};
617    } else {
618      # check if it is set in the config file
619      if (defined($config{'persistent-downloads'})) {
620        $do_persistent = $config{'persistent-downloads'};
621      }
622    }
623    # default method is doing persistent downloads:
624    if (!defined($do_persistent)) {
625      $do_persistent = 1;
626    }
627    ddebug("tlmgr:main: do persistent downloads = $do_persistent\n");
628    if ($do_persistent) {
629      TeXLive::TLUtils::setup_persistent_downloads() ;
630    }
631    if (!defined($::tldownload_server)) {
632      debug("tlmgr:main: ::tldownload_server not defined\n");
633    } else {
634      debug("tlmgr:main: ::tldownload_server defined\n");
635    }
636  }
637
638  my $ret = execute_action($action, @ARGV);
639
640  if ($ret & $F_ERROR) {
641    tlwarn("$prg: An error has occurred. See above messages. Exiting.\n");
642  }
643
644  # end of main program, returns also error codes
645  exit ($ret);
646
647} # end main
648
649sub give_version {
650  if (!defined($::version_string)) {
651    $::version_string = "";
652    $::version_string .= "tlmgr revision $tlmgrrevision\n";
653    $::version_string .= "tlmgr using installation: $Master\n";
654    if (open (REL_TL, "$Master/release-texlive.txt")) {
655      # print first and last lines, which have the TL version info.
656      my @rel_tl = <REL_TL>;
657      $::version_string .= $rel_tl[0];
658      $::version_string .= $rel_tl[$#rel_tl];
659      close (REL_TL);
660    }
661  }
662  #
663  # add the list of revisions
664  if ($::opt_verbosity > 0) {
665    $::version_string .= "Revisions of TeXLive:: modules:";
666    $::version_string .= "\nTLConfig: " . TeXLive::TLConfig->module_revision();
667    $::version_string .= "\nTLUtils:  " . TeXLive::TLUtils->module_revision();
668    $::version_string .= "\nTLPOBJ:   " . TeXLive::TLPOBJ->module_revision();
669    $::version_string .= "\nTLPDB:    " . TeXLive::TLPDB->module_revision();
670    $::version_string .= "\nTLPaper:  " . TeXLive::TLPaper->module_revision();
671    $::version_string .= "\nTLWinGoo: " . TeXLive::TLWinGoo->module_revision();
672    $::version_string .= "\n";
673  }
674  return $::version_string;
675}
676
677
678sub execute_action {
679  my ($action, @argv) = @_;
680
681  # we have to set @ARGV to the @argv since many of the action_* subs
682  # use GetOption
683  @ARGV = @argv;
684
685  # actions which shouldn't have any lasting effects, such as search or
686  # list, end by calling finish(0), which skips postinstall actions.
687  if (!defined($action_specification{$action})) {
688    tlwarn ("$prg: unknown action: $action; try --help if you need it.\n");
689    return ($F_ERROR);
690  }
691
692  if (!defined($action_specification{$action}{"function"})) {
693    tlwarn ("$prg: action $action defined, but no way to execute it.\n");
694    return ($F_ERROR);
695  }
696
697  my $ret = $F_OK;
698  my $foo = &{$action_specification{$action}{"function"}}();
699  if (defined($foo)) {
700    if ($foo & $F_ERROR) {
701      # warnings etc are given at the highest level, i.e., in main
702      return($foo);
703    }
704    if ($foo & $F_WARNING) {
705      tlwarn("$prg: action $action returned a warning.\n");
706      $ret = $foo;
707    }
708  } else {
709    $ret = $F_OK;
710    tlwarn("$prg: didn't get return value from action $action, assuming ok.\n");
711  }
712  my $run_post = 1;
713  if ($ret & $F_NOPOSTACTION) {
714    # clear the postaction bit
715    $ret ^= $F_NOPOSTACTION;
716    $run_post = 0;
717  }
718  if (!$action_specification{$action}{"run-post"}) {
719    $run_post = 0;
720  }
721
722  # close the special log file
723  if ($packagelogfile && !$::gui_mode) {
724    info("$prg: package log updated: $packagelogfile\n") if $packagelogged;
725    close(PACKAGELOG);
726  }
727
728  return ($ret) if (!$run_post);
729
730  # run external programs.
731  $ret |= &handle_execute_actions();
732
733  return $ret;
734}
735
736
737
738# run CMD with notice to the user and if exit status is nonzero, complain.
739# return exit status.
740#
741sub do_cmd_and_check
742{
743  my $cmd = shift;
744  # we output the pre-running notice on a separate line so that
745  # tlmgr front ends (MacOSX's TeX Live Utility) can read it
746  # and show it to the user before the possibly long delay.
747  info("running $cmd ...\n");
748  my ($out, $ret);
749  if ($opts{"dry-run"}) {
750    $ret = $F_OK;
751    $out = "";
752  } else {
753    ($out, $ret) = TeXLive::TLUtils::run_cmd("$cmd 2>&1");
754  }
755  if ($ret == 0) {
756    info("done running $cmd.\n");
757    log("--output of $cmd:\n$out\n--end of output of $cmd.");
758    return ($F_OK);
759  } else {
760    info("\n");
761    tlwarn("$cmd failed (status $ret), output:\n$out\n");
762    return ($F_ERROR);
763  }
764}
765
766# run external programs (mktexlsr, updmap-sys, etc.) as specified by the
767# keys in the RET hash.  We return the number of unsuccessful runs, zero
768# if all ok.
769#
770# If the "map" key is specified, the value may be a reference to a list
771# of map command strings to pass to updmap, e.g., "enable Map=ascii.map".
772#
773sub handle_execute_actions {
774  my $errors = 0;
775
776  my $sysmode = ($opts{"usermode"} ? "" : "-sys");
777  my $invoke_fmtutil = "fmtutil$sysmode $common_fmtutil_args";
778
779  if ($::files_changed) {
780    $errors += do_cmd_and_check("mktexlsr");
781    if (defined($localtlpdb->get_package('context'))) {
782      $errors += do_cmd_and_check("mtxrun --generate");
783    }
784    $::files_changed = 0;
785  }
786
787  chomp(my $TEXMFSYSVAR = `kpsewhich -var-value=TEXMFSYSVAR`);
788  chomp(my $TEXMFSYSCONFIG = `kpsewhich -var-value=TEXMFSYSCONFIG`);
789  chomp(my $TEXMFLOCAL = `kpsewhich -var-value=TEXMFLOCAL`);
790  chomp(my $TEXMFDIST = `kpsewhich -var-value=TEXMFDIST`);
791
792  # maps handling
793  {
794    my $updmap_run_needed = 0;
795    for my $m (keys %{$::execute_actions{'enable'}{'maps'}}) {
796      $updmap_run_needed = 1;
797    }
798    for my $m (keys %{$::execute_actions{'disable'}{'maps'}}) {
799      $updmap_run_needed = 1;
800    }
801    my $dest = $opts{"usermode"} ? "$::maintree/web2c/updmap.cfg"
802               : "$TEXMFDIST/web2c/updmap.cfg";
803    if ($updmap_run_needed) {
804      TeXLive::TLUtils::create_updmap($localtlpdb, $dest);
805    }
806    $errors += do_cmd_and_check("updmap$sysmode") if $updmap_run_needed;
807  }
808
809  # format relevant things
810  # we first have to check if the config files, that is fmtutil.cnf
811  # or one of the language* files have changed, regenerate them
812  # if necessary, and then run the necessary fmtutil calls.
813  {
814    # first check for language* files
815    my $regenerate_language = 0;
816    for my $m (keys %{$::execute_actions{'enable'}{'hyphens'}}) {
817      $regenerate_language = 1;
818      last;
819    }
820    for my $m (keys %{$::execute_actions{'disable'}{'hyphens'}}) {
821      $regenerate_language = 1;
822      last;
823    }
824    if ($regenerate_language) {
825      for my $ext ("dat", "def", "dat.lua") {
826        my $lang = "language.$ext";
827        info("regenerating $lang\n");
828        my $arg1 = "$TEXMFSYSVAR/tex/generic/config/language.$ext";
829        my $arg2 = "$TEXMFLOCAL/tex/generic/config/language-local.$ext";
830        if ($ext eq "dat") {
831          TeXLive::TLUtils::create_language_dat($localtlpdb, $arg1, $arg2);
832        } elsif ($ext eq "def") {
833          TeXLive::TLUtils::create_language_def($localtlpdb, $arg1, $arg2);
834        } else {
835          TeXLive::TLUtils::create_language_lua($localtlpdb, $arg1, $arg2);
836        }
837      }
838    }
839
840    #
841    # check if *depending* formats have been changed
842    # we are currently only caring for package "latex" and "tex". If
843    # one of these has changed, we search for all packages *depending*
844    # on latex/tex and regenerate all formats in these packages.
845    #
846    # do this only if we are not in --list or --dry-run mode
847    if (!$opts{"list"}) {
848      my @check_indirect_formats;
849      # TODO:
850      # in case that hyphenation patterns are changed, ie $regenerate_language
851      # then maybe we don't need to update latex based ones?
852      push @check_indirect_formats, $localtlpdb->needed_by("latex")
853        if ($::latex_updated);
854      push @check_indirect_formats, $localtlpdb->needed_by("tex")
855        if ($::tex_updated);
856      for my $p (@check_indirect_formats) {
857          my $tlp = $localtlpdb->get_package($p);
858          if (!defined($tlp)) {
859            tlwarn("$p mentioned but not found in local tlpdb, strange!\n");
860            next;
861          }
862          TeXLive::TLUtils::announce_execute_actions("enable", $tlp, "format");
863      }
864    }
865
866    # format-regenerate is used when the paper size changes.  In that
867    # case, if option("create_formats") is set, we simply want to generate
868    # all formats
869    #
870    my %done_formats;
871    my %updated_engines;
872    my %format_to_engine;
873    my %do_enable;
874    my $do_full = 0;
875    for my $m (keys %{$::execute_actions{'enable'}{'formats'}}) {
876      $do_full = 1;
877      $do_enable{$m} = 1;
878      # here we check whether an engine is updated
879      my %foo = %{$::execute_actions{'enable'}{'formats'}{$m}};
880      if (!defined($foo{'name'}) || !defined($foo{'engine'})) {
881        tlwarn("$prg: Very strange error, please report ", %foo);
882      } else {
883        $format_to_engine{$m} = $foo{'engine'};
884        if ($foo{'name'} eq $foo{'engine'}) {
885          $updated_engines{$m} = 1;
886        }
887      }
888    }
889    for my $m (keys %{$::execute_actions{'disable'}{'formats'}}) {
890      $do_full = 1;
891    }
892    my $opt_fmt = $localtlpdb->option("create_formats");
893    if ($do_full) {
894      info("regenerating fmtutil.cnf in $TEXMFDIST\n");
895      TeXLive::TLUtils::create_fmtutil($localtlpdb,
896                                       "$TEXMFDIST/web2c/fmtutil.cnf");
897    }
898    if ($opt_fmt && !$::regenerate_all_formats) {
899      # first regenerate all formats --byengine
900      for my $e (keys %updated_engines) {
901        log ("updating formats based on $e\n");
902        $errors += do_cmd_and_check
903                    ("$invoke_fmtutil --no-error-if-no-format --byengine $e");
904      }
905      # now rebuild all other formats
906      for my $f (keys %do_enable) {
907        next if defined($updated_engines{$format_to_engine{$f}});
908        # ignore disabled formats
909        next if !$::execute_actions{'enable'}{'formats'}{$f}{'mode'};
910        log ("(re)creating format dump $f\n");
911        $errors += do_cmd_and_check ("$invoke_fmtutil --byfmt $f");
912        $done_formats{$f} = 1;
913      }
914    }
915
916    # now go back to the hyphenation patterns and regenerate formats
917    # based on the various language files
918    # this of course will in some cases duplicate fmtutil calls,
919    # but it is much easier than actually checking which formats
920    # don't need to be updated
921
922    if ($regenerate_language) {
923      for my $ext ("dat", "def", "dat.lua") {
924        my $lang = "language.$ext";
925        if (! TeXLive::TLUtils::win32()) {
926          # Use full path for external command, except on Windows.
927          $lang = "$TEXMFSYSVAR/tex/generic/config/$lang";
928        }
929        if ($localtlpdb->option("create_formats")
930            && !$::regenerate_all_formats) {
931          $errors += do_cmd_and_check ("$invoke_fmtutil --byhyphen \"$lang\"");
932        }
933      }
934    }
935  }
936
937  #
938  if ($::regenerate_all_formats) {
939    info("Regenerating all formats, this may take some time ...");
940    $errors += do_cmd_and_check("$invoke_fmtutil --all");
941    info("done\n");
942    $::regenerate_all_formats = 0;
943  }
944
945  # undefine the global var, otherwise in GUI mode the actions
946  # are accumulating
947  undef %::execute_actions;
948
949  if ($errors > 0) {
950    # should we return warning here?
951    return $F_ERROR;
952  } else {
953    return $F_OK;
954  }
955}
956
957
958#  GET_MIRROR
959#
960# just return a mirror
961sub action_get_mirror {
962  my $loc = give_ctan_mirror();
963  print "$loc\n";
964  return ($F_OK | $F_NOPOSTACTION);
965}
966
967#
968# includes a .tlpobj in the db, also searchers for sub-tlpobj
969# for doc and source files
970#
971
972#  _INCLUDE_TLPOBJ
973#
974# includes a .tlpobj in the db, also searchers for sub-tlpobj
975# for doc and source files
976#
977sub action_include_tlpobj {
978  # this is an internal function that should not be used outside
979  init_local_db();
980  for my $f (@ARGV) {
981    my $tlpobj = TeXLive::TLPOBJ->new;
982    $tlpobj->from_file($f);
983    # we now have to check whether that is a .doc or .src package, so shipping
984    # src or doc files from a different package.
985    # We should have that package already installed ...
986    my $pkg = $tlpobj->name;
987    if ($pkg =~ m/^(.*)\.(source|doc)$/) {
988      # got a .src or .doc package
989      my $type = $2;
990      my $mothership = $1;
991      my $mothertlp = $localtlpdb->get_package($mothership);
992      if (!defined($mothertlp)) {
993        tlwarn("We are trying to add ${type} files to a nonexistent package $mothership!\n");
994        tlwarn("Trying to continue!\n");
995        # the best we can do is rename that package to $mothername and add it!
996        $tlpobj->name($mothership);
997        # add the src/docfiles tlpobj under the mothership name
998        $localtlpdb->add_tlpobj($tlpobj);
999      } else {
1000        if ($type eq "source") {
1001          $mothertlp->srcfiles($tlpobj->srcfiles);
1002          $mothertlp->srcsize($tlpobj->srcsize);
1003        } else {
1004          # must be "doc"
1005          $mothertlp->docfiles($tlpobj->docfiles);
1006          $mothertlp->docsize($tlpobj->docsize);
1007        }
1008        # that make sure that the original entry is overwritten
1009        $localtlpdb->add_tlpobj($mothertlp);
1010      }
1011    } else {
1012      # completely normal package, just add it
1013      $localtlpdb->add_tlpobj($tlpobj);
1014    }
1015    $localtlpdb->save;
1016  }
1017  # no error checking here for now
1018  return ($F_OK);
1019}
1020
1021
1022#  REMOVE
1023#
1024# tlmgr remove foo bar baz
1025#   will remove the packages foo bar baz itself
1026#   and will remove all .ARCH dependencies, too
1027#   and if some of them are collections it will also remove the
1028#   depending packages which are NOT Collections|Schemes.
1029#   if some of them are referenced somewhere they will not be removed
1030#   unless --force given
1031#
1032# tlmgr remove --no-depends foo bar baz
1033#   will remove the packages foo bar baz itself without any dependencies
1034#   but it will still remove all .ARCH dependency
1035#   if some of them are referenced somewhere they will not be removed
1036#   unless --force given
1037#
1038# tlmgr remove --no-depends-at-all foo bar baz
1039#   will absolutely only install foo bar baz not even taking .ARCH into
1040#   account
1041#
1042sub action_remove {
1043  my $ret = $F_OK;
1044  # we do the following:
1045  # - (not implemented) order collections such that those depending on
1046  #   other collections are first removed, and then those which only
1047  #   depend on packages. Otherwise
1048  #     remove collection-latex collection-latexrecommended
1049  #   will not succeed
1050  # - first loop over all cmd line args and consider only the collections
1051  # - for each to be removed collection:
1052  #   . check that no other collections/scheme asks for that collection
1053  #   . remove the collection
1054  #   . remove all dependencies
1055  # - for each normal package not already removed (via the above)
1056  #   . check that no collection/scheme still depends on this package
1057  #   . remove the package
1058  #
1059  $opts{"no-depends"} = 1 if $opts{"no-depends-at-all"};
1060  my %already_removed;
1061  my @more_removal;
1062  init_local_db();
1063  return($F_ERROR) if !check_on_writable();
1064  info("$prg remove: dry run, no changes will be made\n") if $opts{"dry-run"};
1065  my @packs = @ARGV;
1066  #
1067  # we have to be carefull not to remove too many packages. The idea is
1068  # as follows:
1069  # - let A be the set of all packages to be removed from the cmd line
1070  # - let A* be the set of A with all dependencies expanded
1071  # - let B be the set of all packages
1072  # - let C = B \ A*, ie the set of all packages without those packages
1073  #   in the set of A*
1074  # - let C* be the set of C with all dependencies expanded
1075  # - let D = A* \ C*, ie the set of all packages to be removed (A*)
1076  #   without all the package that are still needed (C*)
1077  # - remove all package in D
1078  # - for any package in A (not in A*, in A, ie on the cmd line) that is
1079  #   also in C* (so a package that was asked for to be removed on the
1080  #   cmd line, but it isn't because someone else asks for it), warn the
1081  #   user that it is still needed
1082  #
1083  # remove all .ARCH dependencies, too, unless $opts{"no-depends-at-all"}
1084  @packs = $localtlpdb->expand_dependencies("-only-arch", $localtlpdb, @packs)
1085    unless $opts{"no-depends-at-all"};
1086  # remove deps unless $opts{"no-depends"}
1087  @packs = $localtlpdb->expand_dependencies("-no-collections", $localtlpdb, @packs) unless $opts{"no-depends"};
1088  my %allpacks;
1089  for my $p ($localtlpdb->list_packages) { $allpacks{$p} = 1; }
1090  for my $p (@packs) { delete($allpacks{$p}); }
1091  my @neededpacks = $localtlpdb->expand_dependencies($localtlpdb, keys %allpacks);
1092  my %packs;
1093  my %origpacks;
1094  my @origpacks = $localtlpdb->expand_dependencies("-only-arch", $localtlpdb, @ARGV) unless $opts{"no-depends-at-all"};
1095  for my $p (@origpacks) { $origpacks{$p} = 1; }
1096  for my $p (@packs) { $packs{$p} = 1; }
1097  for my $p (@neededpacks) {
1098    if (defined($origpacks{$p})) {
1099      # that package was asked for to be removed on the cmd line
1100      my @needed = $localtlpdb->needed_by($p);
1101      if ($opts{"force"}) {
1102        info("$prg: $p is needed by " . join(" ", @needed) . "\n");
1103        info("$prg: removing it anyway, due to --force\n");
1104      } else {
1105        delete($packs{$p});
1106        tlwarn("$prg: not removing $p, needed by " .
1107          join(" ", @needed) . "\n");
1108        $ret |= $F_WARNING;
1109      }
1110    } else {
1111      delete($packs{$p});
1112    }
1113  }
1114  @packs = keys %packs;
1115  foreach my $pkg (sort @packs) {
1116    my $tlp = $localtlpdb->get_package($pkg);
1117    next if defined($already_removed{$pkg});
1118    if (!defined($tlp)) {
1119      info("$pkg: package not present, cannot remove\n");
1120      $ret |= $F_WARNING;
1121    } else {
1122      # in the first round we only remove collections, nothing else
1123      # but removing collections will remove all dependencies, too
1124      # save the information of which packages have already been removed
1125      # into %already_removed.
1126      if ($tlp->category eq "Collection") {
1127        my $foo = 0;
1128        info ("$prg: removing $pkg\n");
1129        if (!$opts{"dry-run"}) {
1130          $foo = $localtlpdb->remove_package($pkg);
1131          logpackage("remove: $pkg");
1132        }
1133        if ($foo) {
1134          # removal was successful, so the return is at least 0x0001 mktexlsr
1135          # remove dependencies, too
1136          $already_removed{$pkg} = 1;
1137        }
1138      } else {
1139        # save all the other packages into the @more_removal list to
1140        # be removed at the second state. Note that if a package has
1141        # already been removed due to a removal of a collection
1142        # it will be marked as such in %already_removed and not tried again
1143        push (@more_removal, $pkg);
1144      }
1145    }
1146  }
1147  foreach my $pkg (sort @more_removal) {
1148    if (!defined($already_removed{$pkg})) {
1149      info ("$prg: removing package $pkg\n");
1150      if (!$opts{"dry-run"}) {
1151        if ($localtlpdb->remove_package($pkg)) {
1152          # removal was successful
1153          logpackage("remove: $pkg");
1154          $already_removed{$pkg} = 1;
1155        }
1156      }
1157    }
1158  }
1159  if ($opts{"dry-run"}) {
1160    # stop here, don't do any postinstall actions
1161    return ($ret | $F_NOPOSTACTION);
1162  } else {
1163    $localtlpdb->save;
1164    my @foo = sort keys %already_removed;
1165    if (@foo) {
1166      info("$prg: ultimately removed these packages: @foo\n");
1167    } else {
1168      info("$prg: no packages removed.\n");
1169    }
1170  }
1171  return ($ret);
1172}
1173
1174
1175#  PAPER
1176# ARGV can look like:
1177#   paper a4
1178#   paper letter
1179#   [xdvi|...|context] paper [help|papersize|--list]
1180#
1181sub action_paper {
1182  init_local_db();
1183  my $texmfconfig;
1184  if ($opts{"usermode"}) {
1185    chomp($texmfconfig = `kpsewhich -var-value=TEXMFCONFIG`);
1186  } else {
1187    chomp($texmfconfig = `kpsewhich -var-value=TEXMFSYSCONFIG`);
1188  }
1189  $ENV{"TEXMFCONFIG"} = $texmfconfig;
1190
1191  my $action = shift @ARGV;
1192  if ($action =~ m/^paper$/i) {  # generic paper
1193    my $newpaper = shift @ARGV;
1194    if ($opts{"list"}) {  # tlmgr paper --list => complain.
1195      tlwarn("$prg: ignoring paper setting to $newpaper with --list\n")
1196        if $newpaper;  # complain if they tried to set, too.
1197      tlwarn("$prg: please specify a program before paper --list, ",
1198             "as in: tlmgr pdftex paper --list\n");
1199      return($F_ERROR)
1200
1201    } elsif (!defined($newpaper)) {  # tlmgr paper => show all current sizes.
1202      return TeXLive::TLPaper::paper_all($texmfconfig,undef);
1203
1204    } elsif ($newpaper !~ /^(a4|letter)$/) {  # tlmgr paper junk => complain.
1205      $newpaper = "the empty string" if !defined($newpaper);
1206      tlwarn("$prg: expected `a4' or `letter' after paper, not $newpaper\n");
1207      return($F_ERROR);
1208
1209    } else { # tlmgr paper {a4|letter} => do it.
1210      return ($F_ERROR) if !check_on_writable();
1211      return (TeXLive::TLPaper::paper_all($texmfconfig,$newpaper));
1212    }
1213
1214  } else {  # program-specific paper
1215    my $prog = $action;     # first argument is the program to change
1216    my $arg = shift @ARGV;  # get "paper" argument
1217    if (!defined($arg) || $arg ne "paper") {
1218      $arg = "the empty string." if ! $arg;
1219      tlwarn("$prg: expected `paper' after $prog, not $arg\n");
1220      return ($F_ERROR);
1221    }
1222    # the do_paper progs check for the argument --list, so if given
1223    # restore it to the cmd line.
1224    if (@ARGV) {
1225      return ($F_ERROR) if !check_on_writable();
1226    }
1227    unshift(@ARGV, "--list") if $opts{"list"};
1228    return(TeXLive::TLPaper::do_paper($prog,$texmfconfig,@ARGV));
1229  }
1230  # we should not come here anyway
1231  return($F_OK);
1232}
1233
1234
1235#  PATH
1236#
1237sub action_path {
1238  if ($opts{"usermode"}) {
1239    tlwarn("action `path' not supported in usermode!\n");
1240    exit 1;
1241  }
1242  my $what = shift @ARGV;
1243  if (!defined($what) || ($what !~ m/^(add|remove)$/i)) {
1244    $what = "" if ! $what;
1245    tlwarn("$prg: action path requires add or remove, not: $what\n");
1246    return ($F_ERROR);
1247  }
1248  init_local_db();
1249  my $winadminmode = 0;
1250  if (win32()) {
1251    #
1252    # for w32 we do system wide vs user setting detection as follows:
1253    # - if --w32mode is NOT given,
1254    #   - if admin
1255    #     --> honor opt_w32_multi_user setting in tlpdb
1256    #   - if not admin
1257    #     - if opt_w32_multi_user == NO
1258    #       --> do user path adjustment
1259    #     - if opt_w32_multi_user == YES
1260    #       --> do nothing, warn that the setting is on, suggest --w32mode user
1261    # - if --w32mode admin
1262    #   - if admin
1263    #     --> ignore opt_w32_multi_user and do system path adjustment
1264    #   - if non-admin
1265    #     --> do nothing but warn that user does not have privileges
1266    # - if --w32mode user
1267    #   - if admin
1268    #     --> ignore opt_w32_multi_user and do user path adjustment
1269    #   - if non-admin
1270    #     --> ignore opt_w32_multi_user and do user path adjustment
1271    if (!$opts{"w32mode"}) {
1272      $winadminmode = $localtlpdb->option("w32_multi_user");
1273      if (!TeXLive::TLWinGoo::admin()) {
1274        if ($winadminmode) {
1275          tlwarn("The TLPDB specifies system wide path adjustments\nbut you don't have admin privileges.\nFor user path adjustment please use\n\t--w32mode user\n");
1276          # and do nothing
1277          return ($F_ERROR);
1278        }
1279      }
1280    } else {
1281      # we are in the block where a --w32mode argument is given
1282      # we reverse the tests:
1283      if (TeXLive::TLWinGoo::admin()) {
1284        # in admin mode we simply use what is given on the cmd line
1285        if ($opts{"w32mode"} eq "user") {
1286          $winadminmode = 0;
1287        } elsif ($opts{"w32mode"} eq "admin") {
1288          $winadminmode = 1;
1289        } else {
1290          tlwarn("Unknown --w32admin mode: $opts{w32mode}, should be 'admin' or 'user'\n");
1291          return ($F_ERROR);
1292        }
1293      } else {
1294        # we are non-admin
1295        if ($opts{"w32mode"} eq "user") {
1296          $winadminmode = 0;
1297        } elsif ($opts{"w32mode"} eq "admin") {
1298          tlwarn("You don't have the privileges to work in --w32mode admin\n");
1299          return ($F_ERROR);
1300        } else {
1301          tlwarn("Unknown --w32admin mode: $opts{w32mode}, should be 'admin' or 'user'\n");
1302          return ($F_ERROR);
1303        }
1304      }
1305    }
1306  }
1307  my $ret = $F_OK;
1308  if ($what =~ m/^add$/i) {
1309    if (win32()) {
1310      $ret |= TeXLive::TLUtils::w32_add_to_path(
1311        $localtlpdb->root . "/bin/win32",
1312        $winadminmode);
1313      $ret |= TeXLive::TLWinGoo::broadcast_env();
1314    } else {
1315      $ret |= TeXLive::TLUtils::add_symlinks($localtlpdb->root,
1316        $localtlpdb->platform(),
1317        $localtlpdb->option("sys_bin"),
1318        $localtlpdb->option("sys_man"),
1319        $localtlpdb->option("sys_info"));
1320    }
1321  } elsif ($what =~ m/^remove$/i) {
1322    if (win32()) {
1323      $ret |= TeXLive::TLUtils::w32_remove_from_path(
1324        $localtlpdb->root . "/bin/win32",
1325        $winadminmode);
1326      $ret |= TeXLive::TLWinGoo::broadcast_env();
1327    } else {
1328      # remove symlinks
1329      $ret |= TeXLive::TLUtils::remove_symlinks($localtlpdb->root,
1330        $localtlpdb->platform(),
1331        $localtlpdb->option("sys_bin"),
1332        $localtlpdb->option("sys_man"),
1333        $localtlpdb->option("sys_info"));
1334    }
1335  } else {
1336    tlwarn("\n$prg: Should not happen, action_path what=$what\n");
1337    return ($F_ERROR);
1338  }
1339  # we should not need to run any post actions here, since
1340  # that changes only integrations, but no rebuild of formats etc etc
1341  # is needed
1342  return ($ret | $F_NOPOSTACTION);
1343}
1344
1345#  DUMP TLPDB
1346#
1347sub action_dumptlpdb {
1348  init_local_db();
1349
1350  # we are basically doing machine-readable output.
1351  my $savemr = $::machinereadable;
1352  $::machinereadable = 1;
1353
1354  if ($opts{"local"} && !$opts{"remote"}) {
1355    # for consistency we write out the location of the installation,
1356    # too, in the same format as when dumping the remote tlpdb
1357    print "location-url\t", $localtlpdb->root, "\n";
1358    $localtlpdb->writeout;
1359
1360  } elsif ($opts{"remote"} && !$opts{"local"}) {
1361    init_tlmedia_or_die();
1362    $remotetlpdb->writeout;
1363
1364  } else {
1365    tlwarn("tlmgr dump-tlpdb: need exactly one of --local and --remote.\n");
1366    return ($F_ERROR);
1367  }
1368
1369  $::machinereadable = $savemr;
1370  return ($F_OK | $F_NOPOSTACTION);
1371}
1372
1373#  INFO
1374#
1375sub action_info {
1376  init_local_db();
1377  my ($what,@todo) = @ARGV;
1378  my $ret = $F_OK | $F_NOPOSTACTION;
1379  #
1380  # tlmgr info
1381  # tlmgr info collection
1382  # tlmgr info scheme
1383  # these commands just list the packages/collections/schemes installed with
1384  # a short list
1385  if (!defined($what) || ($what =~ m/^(collections|schemes)$/i)) {
1386    show_list_of_packages($what);
1387    return ($F_OK | $F_NOPOSTACTION);
1388  }
1389  # we are still here, so $what is defined and neither collection nor scheme,
1390  # so assume the arguments are package names
1391  foreach my $ppp ($what, @todo) {
1392    my ($pkg, $tag) = split ('@', $ppp, 2);
1393    my $tlpdb = $localtlpdb;
1394    my $source_found;
1395    my $tlp = $localtlpdb->get_package($pkg);
1396    my $installed = 0;
1397    if (!$tlp) {
1398      if (!$remotetlpdb) {
1399        init_tlmedia_or_die();
1400      }
1401      if (defined($tag)) {
1402        if (!$remotetlpdb->is_virtual) {
1403          tlwarn("$prg: specifying implicit tags is not allowed for non-virtual databases!\n");
1404          $ret |= $F_WARNING;
1405          next;
1406        } else {
1407          if (!$remotetlpdb->is_repository($tag)) {
1408            tlwarn("$prg: no such repository tag defined: $tag\n");
1409            $ret |= $F_WARNING;
1410            next;
1411          }
1412        }
1413      }
1414      $tlp = $remotetlpdb->get_package($pkg, $tag);
1415      if (!$tlp) {
1416        if (defined($tag)) {
1417          # we already searched for the package in a specific tag, don't retry
1418          # all candidates!
1419          tlwarn("$prg: Cannot find package $pkg in repository $tag\n");
1420          $ret |= $F_WARNING;
1421          next;
1422        }
1423        if ($remotetlpdb->is_virtual) {
1424          # we might have a package that is available in a
1425          # subsidiary repository, but not installable
1426          # because it is not pinned
1427          # we will list it but warn about this fact
1428          my @cand = $remotetlpdb->candidates($pkg);
1429          if (@cand) {
1430            my $first = shift @cand;
1431            if (defined($first)) {
1432              tlwarn("strange, we have a first candidate but no tlp: $pkg\n");
1433              $ret |= $F_WARNING;
1434              next;
1435            }
1436            # already shifted away the first element
1437            if ($#cand >= 0) {
1438              # recursively showing all tags, but warn
1439              print "package:     ", $pkg, "\n";
1440              print "WARNING:     This package is not pinned but present in subsidiary repositories\n";
1441              print "WARNING:     As long as it is not pinned it is not installable.\n";
1442              print "WARNING:     Listing all available copies of the package.\n";
1443              my @aaa;
1444              for my $a (@cand) {
1445                my ($t,$r) = split(/\//, $a, 2);
1446                push @aaa, "$pkg" . '@' . $t;
1447              }
1448              $ret |= action_info(@aaa);
1449              next;
1450            } else {
1451              tlwarn("strange, package listed but no residual candidates: $pkg\n");
1452              next;
1453            }
1454          } else {
1455            tlwarn("strange, package listed but no candidates: $pkg\n");
1456            $ret |= $F_WARNING;
1457            next;
1458          }
1459        }
1460        # we didn't find a package like this, so use search
1461        info("$prg: cannot find package $pkg, searching for other matches:\n");
1462        my ($foundfile, $founddesc) = search_tlpdb($remotetlpdb, $pkg, 1, 1, 0);
1463        print "\nPackages containing \`$pkg\' in their title/description:\n";
1464        print $founddesc;
1465        print "\nPackages containing files matching \`$pkg\':\n";
1466        print $foundfile;
1467        #$ret |= $F_WARNING;
1468        next;
1469      }
1470      # we want to also show the source if it is known
1471      if (defined($tag)) {
1472        $source_found = $tag;
1473      } else {
1474        if ($remotetlpdb->is_virtual) {
1475          my ($firsttag, @cand) = $remotetlpdb->candidates($pkg);
1476          $source_found = $firsttag;
1477        } else {
1478          # might be single user repository, don't mention anything
1479        }
1480      }
1481      $tlpdb = $remotetlpdb;
1482    } else {
1483      $installed = 1;
1484    }
1485    my @colls;
1486    if ($tlp->category ne "Collection" && $tlp->category ne "Scheme") {
1487      @colls = $localtlpdb->needed_by($pkg);
1488      if (!@colls) {
1489        # not referenced in the local tlpdb, so try the remote here, too
1490        if (!$remotetlpdb) {
1491          init_tlmedia_or_die();
1492        }
1493        @colls = $remotetlpdb->needed_by($pkg);
1494      }
1495    }
1496    # some packages might depend on other packages, so do not
1497    # include arbitrary package in the list of collections, but
1498    # only collectons:
1499    @colls = grep {m;^collection-;} @colls;
1500    print "package:     ", $tlp->name, "\n";
1501    print "repository:  ", $source_found, "\n" if (defined($source_found));
1502    print "category:    ", $tlp->category, "\n";
1503    print "shortdesc:   ", $tlp->shortdesc, "\n" if ($tlp->shortdesc);
1504    print "longdesc:    ", $tlp->longdesc, "\n" if ($tlp->longdesc);
1505    print "installed:   ", ($installed ? "Yes" : "No"), "\n";
1506    print "revision:    ", $tlp->revision, "\n" if ($installed);
1507    # print out sizes
1508    my $sizestr = "";
1509    my $srcsize = $tlp->srcsize * $TeXLive::TLConfig::BlockSize;
1510    $sizestr = sprintf("%ssrc: %dk", $sizestr, int($srcsize / 1024) + 1)
1511      if ($srcsize > 0);
1512    my $docsize = $tlp->docsize * $TeXLive::TLConfig::BlockSize;
1513    $sizestr .= sprintf("%sdoc: %dk",
1514      ($sizestr ? ", " : ""), int($docsize / 1024) + 1)
1515        if ($docsize > 0);
1516    my $runsize = $tlp->runsize * $TeXLive::TLConfig::BlockSize;
1517    $sizestr .= sprintf("%srun: %dk",
1518      ($sizestr ? ", " : ""), int($runsize / 1024) + 1)
1519        if ($runsize > 0);
1520    # check for .ARCH expansions
1521    my $do_archs = 0;
1522    for my $d ($tlp->depends) {
1523      if ($d =~ m/^(.*)\.ARCH$/) {
1524        $do_archs = 1;
1525        last;
1526      }
1527    }
1528    if ($do_archs) {
1529      my @a = $localtlpdb->available_architectures;
1530      my %binsz = %{$tlp->binsize};
1531      my $binsize = 0;
1532      for my $a (@a) {
1533        $binsize += $binsz{$a} if defined($binsz{$a});
1534        my $atlp = $tlpdb->get_package($tlp->name . ".$a");
1535        if (!$atlp) {
1536          tlwarn("$prg: cannot find depending package" . $tlp->name . ".$a\n");
1537          $ret |= $F_WARNING;
1538          next;
1539        }
1540        my %abinsz = %{$atlp->binsize};
1541        $binsize += $abinsz{$a} if defined($abinsz{$a});
1542      }
1543      $binsize *= $TeXLive::TLConfig::BlockSize;
1544      $sizestr .= sprintf("%sbin: %dk",
1545        ($sizestr ? ", " : ""), int($binsize / 1024) + 1)
1546          if ($binsize > 0);
1547    }
1548    print "sizes:       ", $sizestr, "\n";
1549    print "relocatable: ", ($tlp->relocated ? "Yes" : "No"), "\n";
1550    print "cat-version: ", $tlp->cataloguedata->{'version'}, "\n"
1551      if $tlp->cataloguedata->{'version'};
1552    print "cat-date:    ", $tlp->cataloguedata->{'date'}, "\n"
1553      if $tlp->cataloguedata->{'date'};
1554    print "cat-license: ", $tlp->cataloguedata->{'license'}, "\n"
1555      if $tlp->cataloguedata->{'license'};
1556    print "collection:  ", @colls, "\n" if (@colls);
1557    if ($opts{"list"}) {
1558      if ($tlp->category eq "Collection" || $tlp->category eq "Scheme") {
1559        # in the case of collections of schemes we list the deps
1560        my @deps = $tlp->depends;
1561        if (@deps) {
1562          print "depends:\n";
1563          for my $d (@deps) {
1564            print "\t$d\n";
1565          }
1566        }
1567      }
1568      print "Included files, by type:\n";
1569      # if the package has a .ARCH dependency we also list the files for
1570      # those packages
1571      my @todo = $tlpdb->expand_dependencies("-only-arch", $tlpdb, ($pkg));
1572      for my $d (sort @todo) {
1573        my $foo = $tlpdb->get_package($d);
1574        if (!$foo) {
1575          tlwarn ("\nShould not happen, no dependent package $d\n");
1576          $ret |= $F_WARNING;
1577          next;
1578        }
1579        if ($d ne $pkg) {
1580          print "depending package $d:\n";
1581        }
1582        if ($foo->runfiles) {
1583          print "run files:\n";
1584          for my $f (sort $foo->runfiles) { print "  $f\n"; }
1585        }
1586        if ($foo->srcfiles) {
1587          print "source files:\n";
1588          for my $f (sort $foo->srcfiles) { print "  $f\n"; }
1589        }
1590        if ($foo->docfiles) {
1591          print "doc files:\n";
1592          for my $f (sort $foo->docfiles) {
1593            print "  $f";
1594            my $dfd = $foo->docfiledata;
1595            if (defined($dfd->{$f})) {
1596              for my $k (keys %{$dfd->{$f}}) {
1597                print " $k=\"", $dfd->{$f}->{$k}, '"';
1598              }
1599            }
1600            print "\n";
1601          }
1602        }
1603        # in case we have them
1604        if ($foo->allbinfiles) {
1605          print "bin files (all platforms):\n";
1606        for my $f (sort $foo->allbinfiles) { print " $f\n"; }
1607        }
1608      }
1609    }
1610    print "\n";
1611  }
1612  return ($ret);
1613}
1614
1615
1616#  SEARCH
1617#
1618sub action_search {
1619  my ($r) = @ARGV;
1620  my $tlpdb;
1621  # check the arguments
1622  my $search_type_nr = 0;
1623  $search_type_nr++ if $opts{"file"};
1624  $search_type_nr++ if $opts{"all"};
1625  if ($search_type_nr > 1) {
1626    tlwarn("$prg: please specify only one thing to search for\n");
1627    return ($F_ERROR);
1628  }
1629  #
1630  if (!defined($r) || !$r) {
1631    tlwarn("$prg: nothing to search for.\n");
1632    return ($F_ERROR);
1633  }
1634
1635  init_local_db();
1636  if ($opts{"global"}) {
1637    init_tlmedia_or_die();
1638    $tlpdb = $remotetlpdb;
1639  } else {
1640    $tlpdb = $localtlpdb;
1641  }
1642
1643  my ($foundfile, $founddesc) = search_tlpdb($tlpdb, $r,
1644    $opts{'file'} || $opts{'all'},
1645    (!$opts{'file'} || $opts{'all'}),
1646    $opts{'word'});
1647
1648  print $founddesc;
1649  print $foundfile;
1650
1651  return ($F_OK | $F_NOPOSTACTION);
1652}
1653
1654sub search_tlpdb {
1655  my ($tlpdb, $what, $dofile, $dodesc, $inword) = @_;
1656  my $retfile = '';
1657  my $retdesc = '';
1658  foreach my $pkg ($tlpdb->list_packages) {
1659    my $tlp = $tlpdb->get_package($pkg);
1660
1661    # --file or --all -> search (full) file names
1662    if ($dofile) {
1663      my @ret = search_pkg_files($tlp, $what);
1664      if (@ret) {
1665        $retfile .= "$pkg:\n";
1666        foreach (@ret) {
1667          $retfile .= "\t$_\n";
1668        }
1669      }
1670    }
1671    #
1672    # no options or --all -> search package names/descriptions
1673    if ($dodesc) {
1674      next if ($pkg =~ m/\./);
1675      my $matched = search_pkg_desc($tlp, $what, $inword);
1676      $retdesc .= "$matched\n" if ($matched);
1677    }
1678  }
1679  return($retfile, $retdesc);
1680}
1681
1682sub search_pkg_desc {
1683  my ($tlp, $what, $inword) = @_;
1684  my $pkg = $tlp->name;
1685  my $t = "$pkg\n";
1686  $t = $t . $tlp->shortdesc . "\n" if (defined($tlp->shortdesc));
1687  $t = $t . $tlp->longdesc . "\n" if (defined($tlp->longdesc));
1688  my $pat = $what;
1689  $pat = '\W' . $what . '\W' if ($inword);
1690  my $matched = "";
1691  if ($t =~ m/$pat/i) {
1692    my $shortdesc = $tlp->shortdesc || "";
1693    $matched .= "$pkg - $shortdesc";
1694  }
1695  return $matched;
1696}
1697
1698sub search_pkg_files {
1699  my ($tlp, $what) = @_;
1700  my @files = $tlp->all_files;
1701  if ($tlp->relocated) {
1702    for (@files) { s:^$RelocPrefix/:$RelocTree/:; }
1703  }
1704  my @ret = grep(m;$what;, @files);
1705  return @ret;
1706}
1707
1708#  RESTORE
1709#
1710# read the directory and check what files/package/rev are available
1711# for restore
1712sub get_available_backups {
1713  my $bd = shift;
1714  my $do_stat = shift;
1715  # initialize the hash(packages) of hash(revisions)
1716  my %backups;
1717  opendir (DIR, $bd) || die "opendir($bd) failed: $!";
1718  my @dirents = readdir (DIR);
1719  closedir (DIR) || warn "closedir($bd) failed: $!";
1720  #
1721  # see below for explanation, this has effects only on W32
1722  my $oldwsloppy = ${^WIN32_SLOPPY_STAT};
1723  ${^WIN32_SLOPPY_STAT} = 1;
1724  #
1725  for my $dirent (@dirents) {
1726    next if (-d $dirent);
1727    next if ($dirent !~ m/^(.*)\.r([0-9]+)\.tar\.xz$/);
1728    if (!$do_stat) {
1729      $backups{$1}->{$2} = 1;
1730      next;
1731    }
1732    my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
1733      $atime,$mtime,$ctime,$blksize,$blocks) = stat("$bd/$dirent");
1734    # times: as we want to be portable we try the following times:
1735    # - first choice is ctime which hopefully works nicely
1736    # - on UFS (OSX) ctime is not supported, so use mtime
1737    # furthermore, if we are on W32 we want to be fast and make only
1738    # a sloppy stat
1739    # for more on that please see man perlport
1740    my $usedt = $ctime;
1741    if (!$usedt) {
1742      # can happen on
1743      $usedt = $mtime;
1744    }
1745    if (!$usedt) {
1746      # stat failed, set key to -1 as a sign that there is a backup
1747      # but we cannot stat it
1748      $backups{$1}->{$2} = -1;
1749    } else {
1750      $backups{$1}->{$2} = $usedt;
1751    }
1752  }
1753  # reset the original value of the w32 sloppy mode for stating files
1754  ${^WIN32_SLOPPY_STAT} = $oldwsloppy;
1755  return %backups;
1756}
1757
1758sub restore_one_package {
1759  my ($pkg, $rev, $bd) = @_;
1760  # first remove the package, then reinstall it
1761  # this way we get rid of useless files
1762  my $restore_file = "$bd/${pkg}.r${rev}.tar.xz";
1763  if (! -r $restore_file) {
1764    tlwarn("Cannot read $restore_file, no action taken\n");
1765    return ($F_ERROR);
1766  }
1767  $localtlpdb->remove_package($pkg);
1768  TeXLive::TLPDB->_install_package($restore_file , 0, [] ,$localtlpdb);
1769  logpackage("restore: $pkg ($rev)");
1770  # now we have to read the .tlpobj file and add it to the DB
1771  my $tlpobj = TeXLive::TLPOBJ->new;
1772  $tlpobj->from_file($localtlpdb->root . "/tlpkg/tlpobj/$pkg.tlpobj");
1773  $localtlpdb->add_tlpobj($tlpobj);
1774  TeXLive::TLUtils::announce_execute_actions("enable",
1775                                      $localtlpdb->get_package($pkg));
1776  $localtlpdb->save;
1777  # TODO_ERROCHECKING we should check the return values of the
1778  # various calls above
1779  return ($F_OK);
1780}
1781
1782sub check_backupdir_selection {
1783  my $warntext = "";
1784  if ($opts{"backupdir"}) {
1785    my $ob = abs_path($opts{"backupdir"});
1786    $ob && ($opts{"backupdir"} = $ob);
1787    if (! -d $opts{"backupdir"}) {
1788      $warntext .= "$prg: backupdir argument\n";
1789      $warntext .= "  $opts{'backupdir'}\n";
1790      $warntext .= "is not a directory.\n";
1791      return ($F_ERROR, $warntext);
1792    }
1793  } else {
1794    # no argument, check for presence in TLPDB
1795    init_local_db(1);
1796    $opts{"backupdir"} = norm_tlpdb_path($localtlpdb->option("backupdir"));
1797    if (!$opts{"backupdir"}) {
1798      return (0, "$prg: No way to determine backupdir.\n");
1799    }
1800    # we are still here, there is something set in tlpdb
1801    my $ob = abs_path($opts{"backupdir"});
1802    $ob && ($opts{"backupdir"} = $ob);
1803    if (! -d $opts{"backupdir"}) {
1804      $warntext =  "$prg: backupdir as set in tlpdb\n";
1805      $warntext .= "  $opts{'backupdir'}\n";
1806      $warntext .= "is not a directory.\n";
1807      return ($F_ERROR, $warntext);
1808    }
1809  }
1810  return $F_OK;
1811}
1812
1813sub action_restore {
1814  # tlmgr restore [--backupdir dir] --all
1815  #   restores of all packages found in backupdir the latest version
1816  # tlmgr restore --backupdir dir
1817  #   lists all packages with all revisions
1818  # tlmgr restore --backupdir dir pkg
1819  #   lists all revisions of pkg
1820  # tlmgr restore --backupdir dir pkg rev
1821  #   restores pkg to revision rev
1822  # check the backup dir argument
1823
1824  {
1825    my ($a, $b) = check_backupdir_selection();
1826    if ($a & $F_ERROR) {
1827      # in all these cases we want to terminate in the non-gui mode
1828      tlwarn($b);
1829      return ($F_ERROR);
1830    }
1831  }
1832  info("$prg restore: dry run, no changes will be made\n") if $opts{"dry-run"};
1833
1834  # initialize the hash(packages) of hash(revisions), do stat files! (the 1)
1835  my %backups = get_available_backups($opts{"backupdir"}, 1);
1836  my ($pkg, $rev) = @ARGV;
1837  if (defined($pkg) && $opts{"all"}) {
1838    tlwarn("$prg: Specify either --all or individual package(s) ($pkg)\n");
1839    tlwarn("$prg: to restore, not both.  Terminating.\n");
1840    return ($F_ERROR);
1841  }
1842  if ($opts{"all"}) {
1843    init_local_db(1);
1844    return ($F_ERROR) if !check_on_writable();
1845    if (!$opts{"force"}) {
1846      print "Do you really want to restore all packages to the latest revision found in\n\t$opts{'backupdir'}\n===> (y/N): ";
1847      my $yesno = <STDIN>;
1848      if ($yesno !~ m/^y(es)?$/i) {
1849        print "Ok, cancelling the restore!\n";
1850        return ($F_OK | $F_NOPOSTACTION);
1851      }
1852    }
1853    for my $p (sort keys %backups) {
1854      my @tmp = sort {$b <=> $a} (keys %{$backups{$p}});
1855      my $rev = $tmp[0];
1856      print "Restoring $p, $rev from $opts{'backupdir'}/${p}.r${rev}.tar.xz\n";
1857      if (!$opts{"dry-run"}) {
1858        # first remove the package, then reinstall it
1859        # this way we get rid of useless files
1860        # TODO_ERRORCHECK needs check for return values!!
1861        restore_one_package($p, $rev, $opts{"backupdir"});
1862      }
1863    }
1864    # localtlpdb already saved, so we are finished
1865    return ($F_OK);
1866  }
1867  #
1868  # intermediate sub
1869  sub report_backup_revdate {
1870    my $p = shift;
1871    my %revs = @_;
1872    my @rs = sort {$b <=> $a} (keys %revs);
1873    for my $rs (@rs) {
1874      my $dstr;
1875      if ($revs{$rs} == -1) {
1876        $dstr = "unknown";
1877      } else {
1878        my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
1879          localtime($revs{$rs});
1880        # localtime returns dates starting from 1900, and the month is 0..11
1881        $dstr = sprintf "%04d-%02d-%02d %02d:%02d",
1882          $year+1900, $mon+1, $mday, $hour, $min;
1883      }
1884      print "$rs ($dstr) ";
1885    }
1886  }
1887  # end sub
1888  if (!defined($pkg)) {
1889    if (keys %backups) {
1890      print "Available backups:\n";
1891      foreach my $p (sort keys %backups) {
1892        print "$p: ";
1893        report_backup_revdate($p, %{$backups{$p}});
1894        print "\n";
1895      }
1896    } else {
1897      print "No backups available in $opts{'backupdir'}\n";
1898    }
1899    return ($F_OK | $F_NOPOSTACTION);
1900  }
1901  if (!defined($rev)) {
1902    print "Available backups for $pkg: ";
1903    report_backup_revdate($pkg, %{$backups{$pkg}});
1904    print "\n";
1905    return ($F_OK | $F_NOPOSTACTION);
1906  }
1907  # we did arrive here, so we try to restore ...
1908  if (defined($backups{$pkg}->{$rev})) {
1909    return if !check_on_writable();
1910    if (!$opts{"force"}) {
1911      print "Do you really want to restore $pkg to revision $rev (y/N): ";
1912      my $yesno = <STDIN>;
1913      if ($yesno !~ m/^y(es)?$/i) {
1914        print "Ok, cancelling the restore!\n";
1915        return ($F_OK | $F_NOPOSTACTION);
1916      }
1917    }
1918    print "Restoring $pkg, $rev from $opts{'backupdir'}/${pkg}.r${rev}.tar.xz\n";
1919    if (!$opts{"dry-run"}) {
1920      init_local_db(1);
1921      # first remove the package, then reinstall it
1922      # this way we get rid of useless files
1923      restore_one_package($pkg, $rev, $opts{"backupdir"});
1924    }
1925    # TODO_ERRORCHECKING check return value of restore_one_package
1926    return ($F_OK);
1927  } else {
1928    print "revision $rev for $pkg is not present in $opts{'backupdir'}\n";
1929    return ($F_ERROR);
1930  }
1931}
1932
1933sub action_backup {
1934  init_local_db(1);
1935  # --clean argument
1936  # can be either -1 ... don't clean
1937  #               0  ... remove all backups
1938  #               N  ... keep only N backups
1939  # that parallels the value of autoclean in the configuration
1940  # we have to be careful, because if simply --clean is given, we should
1941  # check for the value saved in the tlpdb, and if that is not present
1942  # do nothing.
1943  # We have set clean to clean:-99 which makes -99 the default value
1944  # if only --clean is given without any argument
1945  # !defined($opts{"clean"})  -> no --clean given
1946  # $opts{"clean"} = -99      -> --clean without argument given, check tlpdb
1947  # $opts{"clean"} = -1, 0, N -> --clean=N given, check argument
1948  #
1949  my $clean_mode = 0;
1950  $clean_mode = 1 if defined($opts{"clean"});
1951  if ($clean_mode) {
1952    if ($opts{"clean"} == -99) {
1953      # we need to check the tlpdb
1954      my $tlpdb_option = $localtlpdb->option("autobackup");
1955      if (!defined($tlpdb_option)) {
1956        tlwarn ("--clean given without an argument, but no default clean\n");
1957        tlwarn ("mode specified in the tlpdb.\n");
1958        return ($F_ERROR);
1959      }
1960      $opts{"clean"} = $tlpdb_option;
1961    }
1962    # now $opts{"clean"} is something, but maybe not a number, check for
1963    # validity
1964    if ($opts{"clean"} =~ m/^(-1|[0-9]+)$/) {
1965      # get rid of leading zeros etc etc
1966      $opts{"clean"} = $opts{"clean"} + 0;
1967    } else {
1968      tlwarn ("clean mode as specified on the command line or as given by default\n");
1969      tlwarn ("must be an integer larger or equal than -1, terminating.\n");
1970      return($F_ERROR);
1971    }
1972  }
1973  # check the backup dir argument
1974  {
1975    my ($a, $b) = check_backupdir_selection();
1976    if ($a & $F_ERROR) {
1977      # in all these cases we want to terminate in the non-gui mode
1978      tlwarn($b);
1979      return($F_ERROR);
1980    }
1981  }
1982
1983  # if we do --clean --all we also want to remove packages that
1984  # are not present anymore in the tlpdb, so use the readdir mode
1985  # to determine backups
1986  if ($opts{"all"} && $clean_mode) {
1987    # initialize the hash(packages) of hash(revisions)
1988    # no need to stat the files
1989    my %backups = get_available_backups($opts{"backupdir"}, 0);
1990    init_local_db(1);
1991    for my $p (sort keys %backups) {
1992      clear_old_backups ($p, $opts{"backupdir"}, $opts{"clean"}, $opts{"dry-run"});
1993    }
1994    return ($F_OK | $F_NOPOSTACTION);
1995  }
1996
1997  # in case we are not cleaning or cleaning only specific packages
1998  # use the one-by-one mode
1999  my @todo;
2000  if ($opts{"all"}) {
2001    @todo = $localtlpdb->list_packages;
2002  } else {
2003    @todo = @ARGV;
2004    @todo = $localtlpdb->expand_dependencies("-only-arch", $localtlpdb, @todo);
2005  }
2006  if (!@todo) {
2007    printf "tlmgr backup takes either a list of packages or --all\n";
2008    return ($F_ERROR);
2009  }
2010  foreach my $pkg (@todo) {
2011    if ($clean_mode) {
2012      clear_old_backups ($pkg, $opts{"backupdir"}, $opts{"clean"}, $opts{"dry-run"});
2013    } else {
2014      my $tlp = $localtlpdb->get_package($pkg);
2015      info("saving current status of $pkg to $opts{'backupdir'}/${pkg}.r" .
2016        $tlp->revision . ".tar.xz\n");
2017      if (!$opts{"dry-run"}) {
2018        $tlp->make_container("xz", $localtlpdb->root,
2019                             $opts{"backupdir"}, "${pkg}.r" . $tlp->revision);
2020      }
2021    }
2022  }
2023  # TODO_ERRORCHECKING neets checking of the above
2024  return ($F_OK);
2025}
2026
2027# =====================================================================
2028#                  INFRASTRUCTURE UPDATE ON WINDOWS
2029# =====================================================================
2030#      Infrastructure files cannot be updated directly from the
2031# tlmgr.pl script due to file locking problem on Windows - files that
2032# are in use (either open or executing) cannot be removed or replaced.
2033# For that reason the update process is performed by a batch script
2034# outside of tlmgr.pl.
2035#      There are three pieces involved in the update: tlmgr.bat
2036# launcher, write_w32_updater subroutine below and a batch
2037# updater script. Their roles are as follows:
2038# * tlmgr.bat is a watchdog, it launches tlmgr.pl and watches for
2039#   the updater script that is to be executed. If the updater script
2040#   exists before tlmgr.pl is launched, it will be removed or
2041#   tlmgr.bat will abort if it fails to do so. This means that the
2042#   updater script has to be created by the current invocation of
2043#   tlmgr.pl. Futhermore, the updater script is renamed from
2044#   updater-w32 to updater-w32.bat just before it is run, and thus
2045#   it can be executed only once.
2046# * write_w32_updater subroutine in tlmgr.pl prepares the update
2047#   and writes the updater script. Packages in .xz archives are
2048#   dowloaded/copied and uncompressed to .tar files. Also .tar
2049#   backups of the current packages are made. If everything is
2050#   successful, the update script is created from the template.
2051#   Otherwise the update is aborted.
2052# * updater-w32[.bat] batch script, triggers and executes the actual
2053#   update. It first restarts itself in a separate instance of cmd.exe
2054#   (and in a new console window in gui mode) and runs the update
2055#   from there. The update is run with echo on and all output is
2056#   logged to a file (or stderr in verbose mode). After successful
2057#   infrastructure update, tlmgr is optionally restarted if update
2058#   of other packages is asked for.
2059#      The infrastructure update itself proceeds as follows:
2060#   (1) untar all package archives
2061#   (2) include .tlpobj files into tlpdb
2062#   (3) print update info to console
2063#      Any error during (1) or (2) triggers the rollback sequence:
2064#   (1) print failed update info to console
2065#   (2) untar all package backups
2066#   (3) include .tlpobj files (from backup) into tlpdb
2067#   (4) print restore info to console
2068#      Any error during (2) or (3) and we go into panic state.  At this
2069#   point there is no guarantee that the installation is still working.
2070#   There is not much we can do but to print failed restore info and
2071#   give instructions to download and run 'update-tlmgr-latest.exe'
2072#   to repair the installation.
2073# =====================================================================
2074#
2075sub write_w32_updater {
2076  my ($restart_tlmgr, $ref_files_to_be_removed, @w32_updated) = @_;
2077  my @infra_files_to_be_removed = @$ref_files_to_be_removed;
2078  # TODO do something with these files TODO
2079  my $media = $remotetlpdb->media;
2080  # we have to download/copy also the src/doc files if necessary!
2081  my $container_src_split = $remotetlpdb->config_src_container;
2082  my $container_doc_split = $remotetlpdb->config_doc_container;
2083  # get options about src/doc splitting from $totlpdb
2084  # TT: should we use local options to decide about install of doc & src?
2085  my $opt_src = $localtlpdb->option("install_srcfiles");
2086  my $opt_doc = $localtlpdb->option("install_docfiles");
2087  my $root = $localtlpdb->root;
2088  my $temp = "$root/temp";
2089  TeXLive::TLUtils::mkdirhier($temp);
2090  tlwarn("Backup option not implemented for infrastructure update.\n") if ($opts{"backup"});
2091  if ($media eq 'local_uncompressed') {
2092    tlwarn("Creating updater from local_uncompressed currently not implemented!\n");
2093    tlwarn("But it should not be necessary!\n");
2094    return 1; # abort
2095  }
2096  my (@upd_tar, @upd_tlpobj, @upd_info, @rst_tar, @rst_tlpobj, @rst_info);
2097  foreach my $pkg (@w32_updated) {
2098    my $repo;
2099    my $mediatlp;
2100    if ($media eq "virtual") {
2101      my $maxtlpdb;
2102      (undef, undef, $mediatlp, $maxtlpdb) =
2103        $remotetlpdb->virtual_candidate($pkg);
2104      $repo = $maxtlpdb->root . "/$Archive";
2105      # update the media type of the used tlpdb
2106      # otherwise later on we stumble when preparing the updater
2107      $media = $maxtlpdb->media;
2108    } else {
2109      $mediatlp = $remotetlpdb->get_package($pkg);
2110      $repo = $remotetlpdb->root . "/$Archive";
2111    }
2112    my $localtlp = $localtlpdb->get_package($pkg);
2113    my $oldrev = $localtlp->revision;
2114    my $newrev = $mediatlp->revision;
2115    # we do install documenation files for category Documentation even if
2116    # option("install_docfiles") is false
2117    my $opt_real_doc = ($mediatlp->category =~ m/documentation/i) ? 1 : $opt_doc;
2118    my @pkg_parts = ($pkg);
2119    push(@pkg_parts, "$pkg.source") if ($container_src_split && $opt_src && $mediatlp->srcfiles);
2120    push(@pkg_parts, "$pkg.doc") if ($container_doc_split && $opt_real_doc && $mediatlp->docfiles);
2121    foreach my $pkg_part (@pkg_parts) {
2122      push (@upd_tar, "$pkg_part.tar");
2123      push (@upd_tlpobj, "tlpkg\\tlpobj\\$pkg_part.tlpobj");
2124    }
2125    push (@upd_info, "$pkg ^($oldrev -^> $newrev^)");
2126    push (@rst_tar, "__BACKUP_$pkg.r$oldrev.tar");
2127    push (@rst_tlpobj, "tlpkg\\tlpobj\\$pkg.tlpobj");
2128    push (@rst_info, "$pkg ^($oldrev^)");
2129    next if ($opts{"dry-run"});
2130    # create backup; make_container expects file name in a format: some-name.r[0-9]+
2131    my ($size, $md5, $fullname) = $localtlp->make_container("tar", $root, $temp, "__BACKUP_$pkg.r$oldrev");
2132    if ($size <= 0) {
2133      tlwarn("Creation of backup container of $pkg failed.\n");
2134      return 1; # backup failed? abort
2135    }
2136    foreach my $pkg_part (@pkg_parts) {
2137      if ($media eq 'local_compressed') {
2138        copy("$repo/$pkg_part.tar.xz", "$temp");
2139      } else { # net
2140        TeXLive::TLUtils::download_file("$repo/$pkg_part.tar.xz", "$temp/$pkg_part.tar.xz");
2141      }
2142      # now we should have the file present
2143      if (!-r "$temp/$pkg_part.tar.xz") {
2144        tlwarn("Couldn't get $pkg_part.tar.xz, that is bad\n");
2145        return 1; # abort
2146      }
2147      # unpack xz archive
2148      my $sysret = system("$::progs{'xzdec'} < \"$temp/$pkg_part.tar.xz\" > \"$temp/$pkg_part.tar\"");
2149      if ($sysret) {
2150        tlwarn("Couldn't unpack $pkg_part.tar.xz\n");
2151        return 1; # unpack failed? abort
2152      }
2153      unlink("$temp/$pkg_part.tar.xz"); # we don't need that archive anymore
2154    }
2155  }
2156
2157  # prepare updater script
2158  my $respawn_cmd = "cmd.exe /e:on/v:off/d/c";
2159  $respawn_cmd = "start /wait $respawn_cmd" if ($::gui_mode);
2160  my $gui_pause = ($::gui_mode ? "pause" : "rem");
2161  my $upd_log = ($::opt_verbosity ? "STDERR" : '"%~dp0update-self.log"');
2162  my $std_handles_redir = ($::opt_verbosity ? "1^>^&2" : "2^>$upd_log 1^>^&2");
2163  my $pkg_log = ($packagelogfile ? "\"$packagelogfile\"" : "nul");
2164  my $post_update_msg = "You may now close this window.";
2165  my $rerun_tlmgr = "rem";
2166  if ($restart_tlmgr) {
2167    $post_update_msg = "About to restart tlmgr to complete update ...";
2168    # quote all arguments for tlmgr restart in case of spaces
2169    $rerun_tlmgr = join (" ", map ("\"$_\"", @::SAVEDARGV) );
2170    $rerun_tlmgr = "if not errorlevel 1 tlmgr.bat $rerun_tlmgr";
2171  }
2172  my $batch_script = <<"EOF";
2173:: This file is part of an automated update process of
2174:: infrastructure files and should not be run standalone.
2175:: For more details about the update process see comments
2176:: in tlmgr.pl (subroutine write_w32_updater).
2177
2178  if [%1]==[:doit] goto :doit
2179  if not exist "%~dp0tar.exe" goto :notar
2180  $respawn_cmd call "%~f0" :doit $std_handles_redir
2181  $rerun_tlmgr
2182  goto :eof
2183
2184:notar
2185  echo %~nx0: cannot run without "%~dp0tar.exe"
2186  findstr "^::" <"%~f0"
2187  exit /b 1
2188
2189:doit
2190  set prompt=TL\$G
2191  title TeX Live Manager $TeXLive::TLConfig::ReleaseYear Update
2192  set PERL5LIB=$root/tlpkg/tlperl/lib
2193  >con echo DO NOT CLOSE THIS WINDOW!
2194  >con echo TeX Live infrastructure update in progress ...
2195  >con echo Detailed command logging to $upd_log
2196  chdir /d "%~dp0.."
2197  if not errorlevel 1 goto :update
2198  >con echo Could not change working directory to "%~dp0.."
2199  >con echo Aborting infrastructure update, no changes have been made.
2200  >con $gui_pause
2201  exit /b 1
2202
2203:update
2204  for %%I in (@upd_tar) do (
2205    temp\\tar.exe -xmf temp\\%%I
2206    if errorlevel 1 goto :rollback
2207  )
2208  tlpkg\\tlperl\\bin\\perl.exe .\\texmf-dist\\scripts\\texlive\\tlmgr.pl _include_tlpobj @upd_tlpobj
2209  if errorlevel 1 goto :rollback
2210  >>$pkg_log echo [%date% %time%] self update: @upd_info
2211  >con echo self update: @upd_info
2212  del "%~dp0*.tar" "%~dp0tar.exe"
2213  >con echo Infrastructure update finished successfully.
2214  >con echo $post_update_msg
2215  >con $gui_pause
2216  exit /b 0
2217
2218:rollback
2219  >>$pkg_log echo [%date% %time%] failed self update: @upd_info
2220  >con echo failed self update: @upd_info
2221  >con echo Rolling back to previous version ...
2222  for %%I in (@rst_tar) do (
2223    temp\\tar.exe -xmf temp\\%%I
2224    if errorlevel 1 goto :panic
2225  )
2226  tlpkg\\tlperl\\bin\\perl.exe .\\texmf-dist\\scripts\\texlive\\tlmgr.pl _include_tlpobj @rst_tlpobj
2227  if errorlevel 1 goto :panic
2228  >>$pkg_log echo [%date% %time%] self restore: @rst_info
2229  >con echo self restore: @rst_info
2230  >con echo Infrastructure update failed. Previous version has been restored.
2231  >con $gui_pause
2232  exit /b 1
2233
2234:panic
2235  >>$pkg_log echo [%date% %time%] failed self restore: @rst_info
2236  >con echo failed self restore: @rst_info
2237  >con echo FATAL ERROR:
2238  >con echo Infrastructure update failed and backup recovery failed too.
2239  >con echo To repair your TeX Live installation download and run:
2240  >con echo $TeXLive::TLConfig::TeXLiveURL/update-tlmgr-latest.exe
2241  >con $gui_pause
2242  exit /b 666
2243EOF
2244
2245  ddebug("\n:: UPDATER BATCH SCRIPT ::\n$batch_script\n:: END OF FILE ::\n");
2246  if ($opts{"dry-run"}) {
2247    my $upd_info = "self update: @upd_info";
2248    $upd_info =~ s/\^//g;
2249    info($upd_info);
2250  } else {
2251    copy("$root/tlpkg/installer/tar.exe", "$temp");
2252    # make sure copied tar is working
2253    if (system("\"$temp/tar.exe\" --version >nul")) {
2254      tlwarn("Could not copy tar.exe, that is bad.\n");
2255      return 1; # abort
2256    }
2257    open UPDATER, ">$temp/updater-w32" or die "Cannot create updater script: $!";
2258    print UPDATER $batch_script;
2259    close UPDATER;
2260  }
2261  return 0;
2262}
2263
2264
2265#  UPDATE
2266
2267# compute the list of auto-install, auto-remove, forcibly-removed
2268# packages from the list of packages to be installed
2269# the list of packages passed in is already expanded
2270sub auto_remove_install_force_packages {
2271  my @todo = @_;
2272  my %removals_full;
2273  my %forcermpkgs_full;
2274  my %newpkgs_full;
2275  my %new_pkgs_due_forcerm_coll;
2276  # check for new/removed/forcibly removed packages.
2277  # we start from the list of installed collections in the local tlpdb
2278  # which are also present in the remote database
2279  # and expand this list once with expand_dependencies in the local tlpdb
2280  # and once in the tlmedia tlpdb. Then we compare the lists
2281  # let A = set of local expansions
2282  #     B = set of remote expansions
2283  # then we should(?) have
2284  #     B \ A  set of new packages
2285  #     A \ B  set of packages removed on the server
2286  #     A \cup B set of packages which should be checked for forcible removal
2287  #
2288  my @all_schmscolls = ();
2289  for my $p ($localtlpdb->schemes) {
2290    push (@all_schmscolls, $p) if defined($remotetlpdb->get_package($p));
2291  }
2292  for my $p ($localtlpdb->collections) {
2293    push (@all_schmscolls, $p) if defined($remotetlpdb->get_package($p));
2294  }
2295  my @localexpansion_full =
2296    $localtlpdb->expand_dependencies($localtlpdb, @all_schmscolls);
2297  my @remoteexpansion_full =
2298    $remotetlpdb->expand_dependencies($localtlpdb, @all_schmscolls);
2299
2300  # compute new/remove/forcerm based on the full expansions
2301  for my $p (@remoteexpansion_full) {
2302    $newpkgs_full{$p} = 1;
2303  }
2304  for my $p (@localexpansion_full) {
2305    delete($newpkgs_full{$p});
2306    $removals_full{$p} = 1;
2307  }
2308  for my $p (@remoteexpansion_full) {
2309    delete($removals_full{$p});
2310  }
2311  # in a first round we check only for forcibly removed collections
2312  # this is necessary to NOT declare a package that is contained
2313  # in a forcibly removed collections as auto-install since it appears
2314  # in the @remoteexpansion_full, but not in @localexpansion_full.
2315  for my $p (@localexpansion_full) {
2316    # intersection, don't check A\B and B\A
2317    next if $newpkgs_full{$p};
2318    next if $removals_full{$p};
2319    my $remotetlp = $remotetlpdb->get_package($p);
2320    if (!defined($remotetlp)) {
2321      tlwarn("Strange, $p mentioned but not found anywhere!\n");
2322      next;
2323    }
2324    next if ($remotetlp->category ne "Collection");
2325    my $tlp = $localtlpdb->get_package($p);
2326    if (!defined($tlp)) {
2327      if ($opts{"reinstall-forcibly-removed"}) {
2328        $newpkgs_full{$p} = 1;
2329      } else {
2330        $forcermpkgs_full{$p} = 1;
2331      }
2332    }
2333  }
2334  # now we have in %forcermpkgs_full only collections that have been
2335  # forcibly removed. Again, expand those against the remote tlpdb
2336  # and remove the expanded packages from the list of localexpansion.
2337  my @pkgs_from_forcerm_colls =
2338    $remotetlpdb->expand_dependencies($localtlpdb, keys %forcermpkgs_full);
2339  #
2340  # the package in @pkgs_from_forcerm_colls would be auto-installed, so
2341  # check for that:
2342  for my $p (keys %newpkgs_full) {
2343    if (member($p, @pkgs_from_forcerm_colls)) {
2344      delete $newpkgs_full{$p};
2345      $new_pkgs_due_forcerm_coll{$p} = 1;
2346    }
2347  }
2348  #
2349  # now create the final list of forcerm packages by checking against
2350  # all packages
2351  for my $p (@localexpansion_full) {
2352    # intersection, don't check A\B and B\A
2353    next if $newpkgs_full{$p};
2354    next if $removals_full{$p};
2355    my $tlp = $localtlpdb->get_package($p);
2356    if (!defined($tlp)) {
2357      if ($opts{"reinstall-forcibly-removed"}) {
2358        $newpkgs_full{$p} = 1;
2359      } else {
2360        $forcermpkgs_full{$p} = 1;
2361      }
2362    }
2363  }
2364  #
2365  # for some packages (texworks, psview, ...) we only have w32 packages
2366  # in the repository, but it is possible that alternative repositories
2367  # ship binaries for some platforms (like texworks for linux on tlcontrib)
2368  # currently updating from tlnet will remove these alternative .ARCH
2369  # packages because they are not listed anywhere locally, so they
2370  # are considered as disappearing.
2371  # We remove here packages PKG.ARCH if the main package PKG is found
2372  # here and is *not* disappearing, from the removal hash
2373  for my $p (keys %removals_full) {
2374    if ($p =~ m/^([^.]*)\./) {
2375      my $mpkg = $1;
2376      if (!defined($removals_full{$mpkg})) {
2377        delete($removals_full{$p});
2378      }
2379    }
2380  }
2381  #
2382  # now take only the subset of packages that is in @todo
2383  # note that @todo is already expanded in action_updated according
2384  # to the --no-depends and --no-depends-at-all options
2385  #
2386  my %removals;
2387  my %forcermpkgs;
2388  my %newpkgs;
2389  for my $p (@todo) {
2390    $removals{$p} = 1 if defined($removals_full{$p});
2391    $forcermpkgs{$p} = 1 if defined($forcermpkgs_full{$p});
2392    $newpkgs{$p} = 1 if defined($newpkgs_full{$p});
2393  }
2394  debug ("$prg: new pkgs: " . join("\n\t",keys %newpkgs) . "\n");
2395  debug ("$prg: deleted : " . join("\n\t",keys %removals) . "\n");
2396  debug ("$prg: forced  : " . join("\n\t",keys %forcermpkgs) . "\n");
2397
2398  return (\%removals, \%newpkgs, \%forcermpkgs, \%new_pkgs_due_forcerm_coll);
2399}
2400
2401# tlmgr update foo
2402#   if foo is of type Package|Documentation it will update only foo
2403#     and the respective .ARCH dependencies
2404#   if foo is of type Collection|Scheme it will update itself AND
2405#     will check all depending packs of type NOT(COllection|Scheme)
2406#     for necessary updates
2407#
2408# tlmgr update --no-depends foo
2409#   as above, but will not check for depends of Collections/Schemes
2410#   but it will still update .ARCH deps
2411#
2412# tlmgr update --no-depends-at-all foo
2413#   will absolutely only update foo not even taking .ARCH into account
2414#
2415# TLPDB->install_package INSTALLS ONLY ONE PACKAGE, no deps whatsoever
2416# anymore. That has all to be done by hand.
2417#
2418sub machine_line {
2419  my ($flag1) = @_;
2420  my $ret = 0;
2421  if ($flag1 eq "-ret") {
2422    $ret = 1;
2423    shift;
2424  }
2425  my ($pkg, $flag, $lrev, $rrev, $size, $runtime, $esttot, $tag, $lcv, $rcv) = @_;
2426  $lrev ||= "-";
2427  $rrev ||= "-";
2428  $flag ||= "?";
2429  $size ||= "-";
2430  $runtime ||= "-";
2431  $esttot ||= "-";
2432  $tag ||= "-";
2433  $lcv ||= "-";
2434  $rcv ||= "-";
2435  my $str = join("\t", $pkg, $flag, $lrev, $rrev, $size, $runtime, $esttot, $tag, $lcv, $rcv);
2436  $str .= "\n";
2437  return($str) if $ret;
2438  print $str;
2439}
2440
2441sub upd_info {
2442  my ($pkg, $kb, $lrev, $mrev, $txt) = @_;
2443  my $flen = 25;
2444  my $kbstr = ($kb >= 0 ? " [${kb}k]" : "");
2445  my $kbstrlen = length($kbstr);
2446  my $pkglen = length($pkg);
2447  my $is = sprintf("%-9s ", "$txt:");
2448  if ($pkglen + $kbstrlen > $flen) {
2449    $is .= "$pkg$kbstr: ";
2450  } else {
2451    $is .= sprintf ('%*2$s', $pkg, -($flen-$kbstrlen));
2452    $is .= "$kbstr: ";
2453  }
2454  $is .= sprintf("local: %8s, source: %8s",
2455                         $lrev,       $mrev);
2456  info("$is\n");
2457}
2458
2459sub action_update {
2460  my $ret = $F_OK;
2461
2462  init_local_db(1);
2463  $opts{"no-depends"} = 1 if $opts{"no-depends-at-all"};
2464
2465  # make a quick check on command line arguments to avoid loading
2466  # the remote db uselessly.
2467  # we require:
2468  # if no --list is given: either --self or --all or <pkgs>
2469  # if --list is given:    nothing
2470  # other options just change the behaviour
2471  if (!($opts{"list"} || @ARGV || $opts{"all"} || $opts{"self"})) {
2472    tlwarn("tlmgr update: specify --list, --all, --self, or a list of package names.\n");
2473    return ($F_ERROR);
2474  }
2475
2476  init_tlmedia_or_die();
2477  info("$prg update: dry run, no changes will be made\n") if $opts{"dry-run"};
2478
2479  my @excluded_pkgs = ();
2480  if ($opts{"exclude"}) {
2481    @excluded_pkgs = @{$opts{"exclude"}};
2482  }
2483
2484  if (!$opts{"list"}) {
2485    return ($F_ERROR) if !check_on_writable();
2486  }
2487
2488  # check for updates to tlmgr and die unless either --force or --list or --self
2489  # is given
2490  my @critical;
2491  if (!$opts{"usermode"}) {
2492    @critical = check_for_critical_updates($localtlpdb, $remotetlpdb);
2493  }
2494  my $dry_run_cont = $opts{"dry-run"} && ($opts{"dry-run"} < 0);
2495  if ( !$dry_run_cont  && !$opts{"self"} && @critical) {
2496    critical_updates_warning();
2497    if ($opts{"force"}) {
2498      tlwarn("$prg: Continuing due to --force.\n");
2499    } elsif ($opts{"list"}) {
2500      # do not warn here
2501    } else {
2502      return($F_ERROR);
2503    }
2504  }
2505
2506  my $autobackup = 0;
2507  # check for the tlpdb option autobackup, and if present and true (!= 0)
2508  # assume we are doing backups
2509  if (!$opts{"backup"}) {
2510    $autobackup = $localtlpdb->option("autobackup");
2511    if ($autobackup) {
2512      # check the format, we currently allow only natural numbers, and -1
2513      if ($autobackup eq "-1") {
2514        debug ("Automatic backups activated, keeping all backups.\n");
2515        $opts{"backup"} = 1;
2516      } elsif ($autobackup eq "0") {
2517        debug ("Automatic backups disabled.\n");
2518      } elsif ($autobackup =~ m/^[0-9]+$/) {
2519        debug ("Automatic backups activated, keeping $autobackup backups.\n");
2520        $opts{"backup"} = 1;
2521      } else {
2522        tlwarn ("Option autobackup can only be an integer >= -1.\n");
2523        tlwarn ("Disabling auto backups.\n");
2524        $localtlpdb->option("autobackup", 0);
2525        $autobackup = 0;
2526        $ret |= $F_WARNING;
2527      }
2528    }
2529  }
2530
2531  # cmd line --backup, we check for --backupdir, and if that is not given
2532  # we try to get the default from the tlpdb. If that doesn't work, exit.
2533  if ($opts{"backup"}) {
2534    my ($a, $b) = check_backupdir_selection();
2535    if ($a & $F_ERROR) {
2536      # in all these cases we want to terminate in the non-gui mode
2537      tlwarn($b);
2538      return ($F_ERROR);
2539    }
2540  }
2541
2542  # finally, if we have --backupdir, but no --backup, just enable it
2543  $opts{"backup"} = 1 if $opts{"backupdir"};
2544
2545  info("$prg: saving backups to $opts{'backupdir'}\n")
2546    if $opts{"backup"} && !$::machinereadable;
2547
2548  # these two variables are used throughout this function
2549  my $root = $localtlpdb->root;
2550  my $temp = "$root/temp";
2551
2552  # remove old _BACKUP packages that have piled up in temp
2553  # they can be recognized by their name starting with __BACKUP_
2554  for my $f (<$temp/__BACKUP_*>) {
2555    unlink($f) unless $opts{"dry-run"};
2556  }
2557
2558
2559  my @todo;
2560  if ($opts{"list"}) {
2561    if ($opts{"all"}) {
2562      @todo = $localtlpdb->list_packages;
2563    } elsif ($opts{"self"}) {
2564      @todo = @critical;
2565    } else {
2566      if (@ARGV) {
2567        @todo = @ARGV;
2568      } else {
2569        @todo = $localtlpdb->list_packages;
2570      }
2571    }
2572  } elsif ($opts{"self"} && @critical) {
2573    @todo = @critical;
2574  } elsif ($opts{"all"}) {
2575    @todo = $localtlpdb->list_packages;
2576  } else {
2577    @todo = @ARGV;
2578  }
2579  # don't do anything if we have been invoked in a strange way
2580  if (!@todo) {
2581    if ($opts{"self"}) {
2582      info("$prg: no updates for tlmgr present.\n");
2583    } else {
2584      tlwarn("tlmgr update: please specify a list of packages, --all, or --self.\n");
2585      return ($F_ERROR);
2586    }
2587  }
2588
2589  if (!($opts{"self"} && @critical) || ($opts{"self"} && $opts{"list"})) {
2590    # update all .ARCH dependencies, too, unless $opts{"no-depends-at-all"}:
2591    @todo = $remotetlpdb->expand_dependencies("-only-arch", $localtlpdb, @todo)
2592      unless $opts{"no-depends-at-all"};
2593    #
2594    # update general deps unless $opts{"no-depends"}:
2595    @todo = $remotetlpdb->expand_dependencies("-no-collections",$localtlpdb,@todo)
2596      unless $opts{"no-depends"};
2597    #
2598    # filter out critical packages
2599    @todo = grep (!m/$CriticalPackagesRegexp/, @todo)
2600      unless $opts{"list"};
2601  }
2602
2603  my ($remref, $newref, $forref, $new_due_to_forcerm_coll_ref) =
2604    auto_remove_install_force_packages(@todo);
2605  my %removals = %$remref;
2606  my %forcermpkgs = %$forref;
2607  my %newpkgs = %$newref;
2608  my %new_due_to_forcerm_coll = %$new_due_to_forcerm_coll_ref;
2609
2610  # check that the --exclude options do not conflict with the
2611  # options --no-auto-remove, --no-auto-install, --reinstall-forcibly-removed
2612  my @option_conflict_lines = ();
2613  my $in_conflict = 0;
2614  if (!$opts{"no-auto-remove"} && $config{"auto-remove"}) {
2615    for my $pkg (keys %removals) {
2616      for my $ep (@excluded_pkgs) {
2617        if ($pkg eq $ep || $pkg =~ m/^$ep\./) {
2618          push @option_conflict_lines, "$pkg: excluded but scheduled for auto-removal\n";
2619          $in_conflict = 1;
2620          last; # of the --exclude for loop
2621        }
2622      }
2623    }
2624  }
2625  if (!$opts{"no-auto-install"}) {
2626    for my $pkg (keys %newpkgs) {
2627      for my $ep (@excluded_pkgs) {
2628        if ($pkg eq $ep || $pkg =~ m/^$ep\./) {
2629          push @option_conflict_lines, "$pkg: excluded but scheduled for auto-install\n";
2630          $in_conflict = 1;
2631          last; # of the --exclude for loop
2632        }
2633      }
2634    }
2635  }
2636  if ($opts{"reinstall-forcibly-removed"}) {
2637    for my $pkg (keys %forcermpkgs) {
2638      for my $ep (@excluded_pkgs) {
2639        if ($pkg eq $ep || $pkg =~ m/^$ep\./) {
2640          push @option_conflict_lines, "$pkg: excluded but scheduled for reinstall\n";
2641          $in_conflict = 1;
2642          last; # of the --exclude for loop
2643        }
2644      }
2645    }
2646  }
2647  if ($in_conflict) {
2648    tlwarn("Conflicts have been found:\n");
2649    for (@option_conflict_lines) { tlwarn("  $_"); }
2650    tlwarn("Please resolve these conflicts!\n");
2651    return ($F_ERROR);
2652  }
2653
2654  #
2655  # we first collect the list of packages to be actually updated or installed
2656  my %updated;
2657  my @new;
2658  my @addlines;
2659
2660  TODO: foreach my $pkg (sort @todo) {
2661    next if ($pkg =~ m/^00texlive/);
2662    for my $ep (@excluded_pkgs) {
2663      if ($pkg eq $ep || $pkg =~ m/^$ep\./) {
2664        info("Skipping excluded package $pkg\n");
2665        next TODO;
2666      }
2667    }
2668    my $tlp = $localtlpdb->get_package($pkg);
2669    if (!defined($tlp)) {
2670      # if the user has forcibly removed (say) bin-makeindex, then the
2671      # loop above has no way to add bin-makeindex.ARCH into the
2672      # %forcermpkgs hash, but the .ARCH will still be in the dependency
2673      # expansion.  So try both with and without the .ARCH extension.
2674      (my $pkg_noarch = $pkg) =~ s/\.[^.]*$//;
2675      my $forcerm_coll = $forcermpkgs{$pkg} || $forcermpkgs{$pkg_noarch};
2676
2677      # similarly for new packages.  If latexmk is new, latexmk.ARCH
2678      # will be in the dependency expansion, and we want it.
2679      my $newpkg_coll = $newpkgs{$pkg} || $newpkgs{$pkg_noarch};
2680      if ($forcerm_coll) {
2681        if ($::machinereadable) {
2682          # TODO should we add a revision number
2683          push @addlines,
2684            # $pkg, $flag, $lrev, $rrev, $size, $runtime, $esttot, $tag, $lcv, $rcv
2685            machine_line("-ret", $pkg, $FLAG_FORCIBLE_REMOVED);
2686        } else {
2687          info("skipping forcibly removed package $pkg\n");
2688        }
2689        next;
2690      } elsif ($newpkg_coll) {
2691        # do nothing here, it will be reported below.
2692      } elsif (defined($removals{$pkg})) {
2693        # skipping this package, it has been removed due to server removal
2694        # and has already been removed
2695        next;
2696      } elsif (defined($new_due_to_forcerm_coll{$pkg})) {
2697        debug("$prg: $pkg seems to be contained in a forcibly removed" .
2698          " collection, not auto-installing it!\n");
2699        next;
2700      } else {
2701        tlwarn("\n$prg: $pkg mentioned, but neither new nor forcibly removed\n");
2702        next;
2703      }
2704      # install new packages
2705      my $mediatlp = $remotetlpdb->get_package($pkg);
2706      if (!defined($mediatlp)) {
2707        tlwarn("\nShould not happen: $pkg not found in $location\n");
2708        $ret |= $F_WARNING;
2709        next;
2710      }
2711      my $mediarev = $mediatlp->revision;
2712      push @new, $pkg;
2713      next;
2714    }
2715    my $rev = $tlp->revision;
2716    my $lctanvers = $tlp->cataloguedata->{'version'};
2717    my $mediatlp;
2718    my $maxtag;
2719    if ($remotetlpdb->is_virtual) {
2720      ($maxtag, undef, $mediatlp, undef) =
2721        $remotetlpdb->virtual_candidate($pkg);
2722    } else {
2723      $mediatlp = $remotetlpdb->get_package($pkg);
2724    }
2725    if (!defined($mediatlp)) {
2726      debug("$pkg cannot be found in $location\n");
2727      next;
2728    }
2729    my $rctanvers = $mediatlp->cataloguedata->{'version'};
2730    my $mediarev = $mediatlp->revision;
2731    my $mediarevstr = $mediarev;
2732    my @addargs = ();
2733    if ($remotetlpdb->is_virtual) {
2734      push @addargs, $maxtag;
2735      $mediarevstr .= "\@$maxtag";
2736    } else {
2737      push @addargs, undef;
2738    }
2739    push @addargs, $lctanvers, $rctanvers;
2740    if ($rev < $mediarev) {
2741      $updated{$pkg} = 0; # will be changed to one on successful update
2742    } elsif ($rev > $mediarev) {
2743      if ($::machinereadable) {
2744        # $pkg, $flag, $lrev, $rrev, $size, $runtime, $esttot, $tag, $lcv, $rcv
2745        push @addlines,
2746          machine_line("-ret", $pkg, $FLAG_REVERSED_UPDATE, $rev, $mediarev, "-", "-", "-", @addargs);
2747      } else {
2748        if ($opts{"list"}) {
2749          # not issueing anything if we keep a package
2750          upd_info($pkg, -1, $rev, $mediarevstr, "keep");
2751        }
2752      }
2753    }
2754  }
2755  my @updated = sort keys %updated;
2756  for my $i (sort @new) {
2757    debug("$i new package\n");
2758  }
2759  for my $i (@updated) {
2760    debug("$i upd package\n");
2761  }
2762
2763  # number calculation
2764  # without w32 special packages, those are dealt with in the updater batch
2765  # script
2766  my $totalnr = $#updated + 1;
2767  my @alltodo = @updated;
2768  my $nrupdated = 0;
2769  my $currnr = 1;
2770
2771  # we have to remove all the stuff before we install other packages
2772  # to support moving of files from one package to another.
2773  # remove the packages that have disappeared:
2774  # we add that only to the list of total packages do be worked on
2775  # when --all is given, because we remove packages only on --all
2776  if (!$opts{"no-auto-remove"} && $config{"auto-remove"}) {
2777    my @foo = keys %removals;
2778    $totalnr += $#foo + 1;
2779  }
2780  if (!$opts{"no-auto-install"}) {
2781    $totalnr += $#new + 1;
2782    push @alltodo, @new;
2783  }
2784
2785  # sizes_of_packages returns the sizes of *all* packages if nothing
2786  # is passed over, so if @new and @updated both are empty we will
2787  # get something wrong back, namely the total size of all packages
2788  # the third argument is undef to compute *all* platforms
2789  my %sizes;
2790  if (@alltodo) {
2791    %sizes = %{$remotetlpdb->sizes_of_packages(
2792      $localtlpdb->option("install_srcfiles"),
2793      $localtlpdb->option("install_docfiles"), undef, @alltodo)};
2794  } else {
2795    $sizes{'__TOTAL__'} = 0;
2796  }
2797
2798  print "total-bytes\t$sizes{'__TOTAL__'}\n" if $::machinereadable;
2799  print "end-of-header\n" if $::machinereadable;
2800
2801  # print deferred machine-readable lines after the header
2802  for (@addlines) { print; }
2803
2804  #
2805  # compute the list of moved files from %removals, @new, @updated
2806  #
2807  my %do_warn_on_move;
2808  {
2809    # keep all these vars local to this block
2810    my @removals = keys %removals;
2811    my %old_files_to_pkgs;
2812    my %new_files_to_pkgs;
2813    # first save for each file in the currently installed packages
2814    # to be updated the packages it is contained it (might be more!)
2815    #
2816    # TODO WHY WHY is there the next so that all the file move checks
2817    # are actually disabled?!?!?!
2818    for my $p (@updated, @removals) {
2819      my $pkg = $localtlpdb->get_package($p);
2820      tlwarn("Should not happen: $p not found in local tlpdb\n") if (!$pkg);
2821      next;
2822      for my $f ($pkg->all_files) {
2823        push @{$old_files_to_pkgs{$f}}, $p;
2824      }
2825    }
2826    for my $p (@updated, @new) {
2827      my $pkg = $remotetlpdb->get_package($p);
2828      tlwarn("Should not happen: $p not found in $location\n") if (!$pkg);
2829      next;
2830      for my $f ($pkg->all_files) {
2831        if ($pkg->relocated) {
2832          $f =~ s:^$RelocPrefix/:$RelocTree/:;
2833        }
2834        push @{$new_files_to_pkgs{$f}}, $p;
2835      }
2836    }
2837    #
2838    # the idea of supressing warnings is simply that if a file is present
2839    # in more than one package either in the beginning or after a full
2840    # update then this should give a warning. In all other cases
2841    # the warning should be supressed.
2842    for my $f (keys %old_files_to_pkgs) {
2843      my @a = @{$old_files_to_pkgs{$f}};
2844      $do_warn_on_move{$f} = 1 if ($#a > 0)
2845    }
2846    for my $f (keys %new_files_to_pkgs) {
2847      my @a = @{$new_files_to_pkgs{$f}};
2848      $do_warn_on_move{$f} = 1 if ($#a > 0)
2849    }
2850  }
2851
2852  # parameters for field width
2853  my $totalnrdigits = length("$totalnr");
2854
2855  #
2856  # ORDER OF PACKAGE ACTIONS
2857  # 1. removals
2858  # 2. updates
2859  # 3. auto-install
2860  # that way if a file has been moved from one to another package it
2861  # removing the old version after the new package has been installed
2862  # will not give a warning about files being included somewhere else
2863  #
2864
2865  #
2866  # REMOVALS
2867  #
2868  for my $p (keys %removals) {
2869    if ($opts{"no-auto-remove"} || !$config{"auto-remove"}) {
2870      info("not removing $p due to -no-auto-remove or config file option (removed on server)\n");
2871    } else {
2872      &ddebug("removing package $p\n");
2873      my $pkg = $localtlpdb->get_package($p);
2874      if (! $pkg) {
2875        # This happened when a collection was removed by the user,
2876        # and then renamed on the server, e.g., collection-langarab ->
2877        # collection-langarabic; Luecking report 20 July 2009.
2878        &ddebug(" get_package($p) failed, ignoring");
2879        next;
2880      }
2881      my $rev = $pkg->revision;
2882      my $lctanvers = $pkg->cataloguedata->{'version'};
2883      if ($opts{"list"}) {
2884        if ($::machinereadable) {
2885          # $pkg, $flag, $lrev, $rrev, $size, $runtime, $esttot, $tag, $lcv, $rcv
2886          machine_line($p, $FLAG_REMOVE, $rev, "-", "-", "-", "-", "-", $lctanvers);
2887        } else {
2888          upd_info($p, -1, $rev, "<absent>", "autorm");
2889        }
2890        $currnr++;
2891      } else {
2892        # new we are sure that:
2893        # - $opts{"no-auto-remove"} is *not* set
2894        # - $opts{"list"} is *not* set
2895        # we have to check in addition that
2896        # - $opts{"dry-run"} is not set
2897        if ($::machinereadable) {
2898          # $pkg, $flag, $lrev, $rrev, $size, $runtime, $esttot, $tag, $lcv, $rcv
2899          machine_line($p, $FLAG_REMOVE, $rev, "-", "-", "-", "-", "-", $lctanvers);
2900        } else {
2901          info("[" . sprintf ('%*2$s', $currnr, $totalnrdigits) .
2902            "/$totalnr] auto-remove: $p ... ");
2903        }
2904        if (!$opts{"dry-run"}) {
2905          # older tlmgr forgot to clear the relocated bit when saving a tlpobj
2906          # into the local tlpdb, although the paths were rewritten.
2907          # We have to clear this bit otherwise the make_container calls below
2908          # for creating the backup will create some rubbish!
2909          # Same as further down in the update part!
2910          if ($pkg->relocated) {
2911            debug("$prg: warn, relocated bit set for $p, but that is wrong!\n");
2912            $pkg->relocated(0);
2913          }
2914          if ($opts{"backup"}) {
2915            $pkg->make_container("xz", $root,
2916                                 $opts{"backupdir"},
2917                                 "${p}.r" . $pkg->revision,
2918                                 $pkg->relocated);
2919            if ($autobackup) {
2920              # in case we do auto backups we remove older backups
2921              clear_old_backups($p, $opts{"backupdir"}, $autobackup);
2922            }
2923          }
2924          $localtlpdb->remove_package($p);
2925          logpackage("remove: $p");
2926        }
2927        info("done\n") unless $::machinereadable;
2928        $currnr++;
2929      }
2930    }
2931  }
2932
2933
2934  my $starttime = time();
2935  my $donesize = 0;
2936  my $totalsize = $sizes{'__TOTAL__'};
2937
2938
2939  #
2940  # UPDATES AND NEW PACKAGES
2941  #
2942  # order:
2943  # - update normal packages
2944  # - install new normal packages
2945  # - update collections
2946  # - install new collections
2947  # - update schemes
2948  # - install new schemes (? will not happen?)
2949  #
2950  # this makes sure that only if all depending packages are installed
2951  # the collection is updated, which in turn makes sure that
2952  # if the installation of a new package does break it will not be
2953  # counted as forcibly removed later on.
2954  #
2955  my @inst_packs;
2956  my @inst_colls;
2957  my @inst_schemes;
2958  for my $pkg (@updated) {
2959    # we do name checking here, not to load all tlpobj again and again
2960    if ($pkg =~ m/^scheme-/) {
2961      push @inst_schemes, $pkg;
2962    } elsif ($pkg =~ m/^collection-/) {
2963      push @inst_colls, $pkg;
2964    } else {
2965      push @inst_packs, $pkg;
2966    }
2967  }
2968  @inst_packs = sort packagecmp @inst_packs;
2969
2970  my @new_packs;
2971  my @new_colls;
2972  my @new_schemes;
2973  for my $pkg (sort @new) {
2974    # we do name checking here, not to load all tlpobj again and again
2975    if ($pkg =~ m/^scheme-/) {
2976      push @new_schemes, $pkg;
2977    } elsif ($pkg =~ m/^collection-/) {
2978      push @new_colls, $pkg;
2979    } else {
2980      push @new_packs, $pkg;
2981    }
2982  }
2983  @new_packs = sort packagecmp @new_packs;
2984  my %is_new;
2985  for my $pkg (@new_packs, @new_colls, @new_schemes) {
2986    $is_new{$pkg} = 1;
2987  }
2988
2989  #
2990  # TODO idea
2991  # currently this big loop contains a long if then for new packages
2992  # and updated package. That *could* be merged into one so that
2993  # some things like the logging has not been written two times.
2994  # OTOH, the control flow in the "new package" part is much simpler
2995  # and following it after the change would make it much harder
2996  #
2997  foreach my $pkg (@inst_packs, @new_packs, @inst_colls, @new_colls, @inst_schemes, @new_schemes) {
2998
2999    if (!$is_new{$pkg}) {
3000      # skip this loop if infra update on w32
3001      next if ($pkg =~ m/^00texlive/);
3002      my $tlp = $localtlpdb->get_package($pkg);
3003      # we checked already that this package is present!
3004      # but our checks seem to be wrong, no idea why
3005      # ahhh, it seems that it can happen due to a stupid incident, a bug
3006      # on the server:
3007      # - remove a package from a collection
3008      # - at the same time increase its version number
3009      # then what happens is:
3010      # - first the package is removed (auto-remove!)
3011      # - then it is tried to be updated here, which is not working!
3012      # report that and ask for report
3013      if (!defined($tlp)) {
3014        tlwarn("$prg: inconsistency on the server:\n");
3015        tlwarn("$prg: tlp for package $pkg cannot be found, please report.\n");
3016        $ret |= $F_WARNING;
3017        next;
3018      }
3019      my $unwind_package;
3020      my $remove_unwind_container = 0;
3021      my $rev = $tlp->revision;
3022      my $lctanvers = $tlp->cataloguedata->{'version'};
3023      my $mediatlp;
3024      my $maxtag;
3025      if ($remotetlpdb->is_virtual) {
3026        ($maxtag, undef, $mediatlp, undef) =
3027          $remotetlpdb->virtual_candidate($pkg);
3028      } else {
3029        $mediatlp = $remotetlpdb->get_package($pkg);
3030      }
3031      if (!defined($mediatlp)) {
3032        debug("$pkg cannot be found in $location\n");
3033        next;
3034      }
3035      my $rctanvers = $mediatlp->cataloguedata->{'version'};
3036      my $mediarev = $mediatlp->revision;
3037      my $mediarevstr = $mediarev;
3038      my @addargs = ();
3039      if ($remotetlpdb->is_virtual) {
3040        push @addargs, $maxtag;
3041        $mediarevstr .= "\@$maxtag";
3042      } else {
3043        push @addargs, undef;
3044      }
3045      push @addargs, $lctanvers, $rctanvers;
3046      $nrupdated++;
3047      if ($opts{"list"}) {
3048        if ($::machinereadable) {
3049          # $pkg, $flag, $lrev, $rrev, $size, $runtime, $esttot, $tag, $lcv, $rcv
3050          machine_line($pkg, $FLAG_UPDATE, $rev, $mediarev, $sizes{$pkg}, "-", "-", @addargs);
3051        } else {
3052          my $kb = int($sizes{$pkg} / 1024) + 1;
3053          upd_info($pkg, $kb, $rev, $mediarevstr, "update");
3054          if ($remotetlpdb->is_virtual) {
3055            my @cand = $remotetlpdb->candidates($pkg);
3056            shift @cand;  # remove the top element
3057            if (@cand) {
3058              print "\tother candidates: ";
3059              for my $a (@cand) {
3060                my ($t,$r) = split(/\//, $a, 2);
3061                print $r . '@' . $t . " ";
3062              }
3063              print "\n";
3064            }
3065          }
3066        }
3067        $updated{$pkg} = 1;
3068        next;
3069      } elsif (win32() && ($pkg =~ m/$CriticalPackagesRegexp/)) {
3070        # we pretend that the update happened
3071        # in order to calculate file changes properly
3072        $updated{$pkg} = 1;
3073        next;
3074      }
3075
3076      # older tlmgr forgot to clear the relocated bit when saving a tlpobj
3077      # into the local tlpdb, although the paths were rewritten.
3078      # We have to clear this bit otherwise the make_container calls below
3079      # for creating an unwind container will create some rubbish
3080      # TODO for user mode we should NOT clear this bit!
3081      if ($tlp->relocated) {
3082        debug("$prg: warn, relocated bit set for $pkg, but that is wrong!\n");
3083        $tlp->relocated(0);
3084      }
3085
3086      if ($opts{"backup"} && !$opts{"dry-run"}) {
3087        $tlp->make_container("xz", $root,
3088                             $opts{"backupdir"}, "${pkg}.r" . $tlp->revision,
3089                             $tlp->relocated);
3090        $unwind_package =
3091            "$opts{'backupdir'}/${pkg}.r" . $tlp->revision . ".tar.xz";
3092
3093        if ($autobackup) {
3094          # in case we do auto backups we remove older backups
3095          clear_old_backups($pkg, $opts{"backupdir"}, $autobackup);
3096        }
3097      }
3098
3099      my ($estrem, $esttot);
3100      if (!$opts{"list"}) {
3101        ($estrem, $esttot) = TeXLive::TLUtils::time_estimate($totalsize,
3102                                                             $donesize, $starttime);
3103      }
3104
3105      if ($::machinereadable) {
3106        machine_line($pkg, $FLAG_UPDATE, $rev, $mediarev, $sizes{$pkg}, $estrem, $esttot, @addargs);
3107      } else {
3108        my $kb = int ($sizes{$pkg} / 1024) + 1;
3109        info("[" . sprintf ('%*2$s', $currnr, $totalnrdigits) .
3110          "/$totalnr, $estrem/$esttot] update: $pkg [${kb}k] ($rev -> $mediarevstr)");
3111      }
3112      $donesize += $sizes{$pkg};
3113      $currnr++;
3114
3115      if ($opts{"dry-run"}) {
3116        info("\n") unless $::machinereadable;
3117        $updated{$pkg} = 1;
3118        next;
3119      } else {
3120        info(" ... ") unless $::machinereadable;  # more to come
3121      }
3122
3123      if (!$unwind_package) {
3124        # no backup was made, so let us create a temporary .tar file
3125        # of the package
3126        my $tlp = $localtlpdb->get_package($pkg);
3127        my ($s, $m, $fullname) = $tlp->make_container("tar", $root, $temp,
3128                                      "__BACKUP_${pkg}.r" . $tlp->revision,
3129                                      $tlp->relocated);
3130        if ($s <= 0) {
3131          tlwarn("\n$prg: Creation of backup container of $pkg failed.\n");
3132          tlwarn("Continuing to update other packages, please retry...\n");
3133          $ret |= $F_WARNING;
3134          # we should try to update other packages at least
3135          next;
3136        }
3137        $remove_unwind_container = 1;
3138        $unwind_package = "$fullname";
3139      }
3140      # first remove the package, then reinstall it
3141      # this way we get rid of useless files
3142      # force the deinstallation since we will reinstall it
3143      #
3144      # the remove_package should also remove empty dirs in case
3145      # a dir is changed into a file
3146      if ($pkg =~ m/$CriticalPackagesRegexp/) {
3147        debug("Not removing critical package $pkg\n");
3148      } else {
3149        $localtlpdb->remove_package($pkg,
3150          "remove-warn-files" => \%do_warn_on_move);
3151      }
3152      if ($remotetlpdb->install_package($pkg, $localtlpdb)) {
3153        # installation succeeded because we got a reference
3154        logpackage("update: $pkg ($rev -> $mediarevstr)");
3155        unlink($unwind_package) if $remove_unwind_container;
3156        # remember successful update
3157        $updated{$pkg} = 1;
3158        #
3159        # if we updated a .ARCH package we have to announce the postactions
3160        # of the parent package so that formats are rebuild
3161        if ($pkg =~ m/^([^.]*)\./) {
3162          my $parent = $1;
3163          if (!TeXLive::TLUtils::member($parent, @inst_packs, @new_packs, @inst_colls, @new_colls, @inst_schemes, @new_schemes)) {
3164            # ok, nothing happens with the parent package, so we have to
3165            # find it and execute the postactions
3166            my $parentobj = $localtlpdb->get_package($parent);
3167            if (!defined($parentobj)) {
3168              # well, in this case we might have hit a package that only
3169              # has .ARCH package, like psv.win32, so do nothing
3170              debug("$prg: .ARCH package without parent, not announcing postaction\n");
3171            } else {
3172              debug("$prg: announcing parent execute action for $pkg\n");
3173              TeXLive::TLUtils::announce_execute_actions("enable", $parentobj);
3174            }
3175          }
3176        }
3177      } else {
3178        # install_package returned a scalar, so error.
3179        # now in fact we should do some cleanup, removing files and
3180        # dirs from the new package before re-installing the old one.
3181        # TODO
3182        logpackage("failed update: $pkg ($rev -> $mediarevstr)");
3183        tlwarn("\n\nInstallation of new version of $pkg did fail, trying to unwind.\n");
3184        if (win32()) {
3185          # w32 is notorious for not releasing a file immediately
3186          # we experienced permission denied errors
3187          my $newname = $unwind_package;
3188          $newname =~ s/__BACKUP/___BACKUP/;
3189          copy ("-f", $unwind_package, $newname);
3190          # try to remove the file if has been created by us
3191          unlink($unwind_package) if $remove_unwind_container;
3192          # and make sure that the temporary file is removed in any case
3193          $remove_unwind_container = 1;
3194          $unwind_package = $newname;
3195        }
3196        my $instret = TeXLive::TLPDB->_install_package("$unwind_package", 0,
3197                                                       [], $localtlpdb);
3198        if ($instret) {
3199          # now we have to include the tlpobj
3200          my $tlpobj = TeXLive::TLPOBJ->new;
3201          $tlpobj->from_file($root . "/tlpkg/tlpobj/$pkg.tlpobj");
3202          $localtlpdb->add_tlpobj($tlpobj);
3203          $localtlpdb->save;
3204          logpackage("restore: $pkg ($rev)");
3205          $ret |= $F_WARNING;
3206          tlwarn("Restoring old package state succeeded.\n");
3207        } else {
3208          logpackage("failed restore: $pkg ($rev)");
3209          tlwarn("Restoring of old package did NOT succeed.\n");
3210          tlwarn("Most likely repair: run tlmgr install $pkg and hope.\n");
3211          # TODO_ERRORCHECKING
3212          # should we return F_ERROR here??? If we would do this, then
3213          # no postactions at all would run? Maybe better only to give
3214          # a warning
3215          $ret |= $F_WARNING;
3216        }
3217        unlink($unwind_package) if $remove_unwind_container;
3218      }
3219      info("done\n") unless $::machinereadable;
3220    } else { # $is_new{$pkg} is true!!!
3221      #
3222      # NEW PACKAGES
3223      #
3224      if ($opts{"no-auto-install"}) {
3225        info("not auto-installing $pkg due to -no-auto-install (new on server)\n")
3226            unless $::machinereadable;
3227      } else {
3228        # install new packages
3229        my $mediatlp;
3230        my $maxtag;
3231        if ($remotetlpdb->is_virtual) {
3232          ($maxtag, undef, $mediatlp, undef) =
3233            $remotetlpdb->virtual_candidate($pkg);
3234        } else {
3235          $mediatlp = $remotetlpdb->get_package($pkg);
3236        }
3237        if (!defined($mediatlp)) {
3238          tlwarn("\nShould not happen: $pkg not found in $location\n");
3239          $ret |= $F_WARNING;
3240          next;
3241        }
3242        my $mediarev = $mediatlp->revision;
3243        my $mediarevstr = $mediarev;
3244        my @addargs;
3245        if ($remotetlpdb->is_virtual) {
3246          $mediarevstr .= "\@$maxtag";
3247          push @addargs, $maxtag;
3248        }
3249        my ($estrem, $esttot);
3250        if (!$opts{"list"}) {
3251          ($estrem, $esttot) = TeXLive::TLUtils::time_estimate($totalsize,
3252                                          $donesize, $starttime);
3253        }
3254        if ($::machinereadable) {
3255          my @maargs = ($pkg, $FLAG_AUTOINSTALL, "-", $mediatlp->revision, $sizes{$pkg});
3256          if (!$opts{"list"}) {
3257            push @maargs, $estrem, $esttot;
3258          } else {
3259            push @maargs, undef, undef;
3260          }
3261          machine_line(@maargs, @addargs);
3262        } else {
3263          my $kb = int($sizes{$pkg} / 1024) + 1;
3264          if ($opts{"list"}) {
3265            upd_info($pkg, $kb, "<absent>", $mediarevstr, "autoinst");
3266          } else {
3267            info("[" . sprintf ('%*2$s', $currnr, $totalnrdigits) .
3268              "/$totalnr, $estrem/$esttot] auto-install: $pkg ($mediarevstr) [${kb}k] ... ");
3269          }
3270        }
3271        $currnr++;
3272        $donesize += $sizes{$pkg};
3273        next if ($opts{"dry-run"} || $opts{"list"});
3274        if ($remotetlpdb->install_package($pkg, $localtlpdb)) {
3275          # installation succeeded because we got a reference
3276          logpackage("auto-install new: $pkg ($mediarevstr)");
3277          $nrupdated++;
3278          info("done\n") unless $::machinereadable;
3279        } else {
3280          tlwarn("$prg: couldn't install new package $pkg\n");
3281        }
3282      }
3283    }
3284  }
3285
3286  #
3287  # special check for depending format updates:
3288  # if one of latex or tex has been updated, we rebuild the formats
3289  # defined in packages *depending* on these packages.
3290  if (!$opts{"list"}) {
3291    TeXLive::TLUtils::announce_execute_actions("latex-updated") if ($updated{"latex"});
3292    TeXLive::TLUtils::announce_execute_actions("tex-updated") if ($updated{"tex"});
3293  }
3294
3295  print "end-of-updates\n" if $::machinereadable;
3296
3297  #
3298  # check that if updates to the critical packages are present all of
3299  # them have been successfully updated
3300  my $infra_update_done = 1;
3301  my @infra_files_to_be_removed;
3302  if ($opts{"list"}) {
3303    $infra_update_done = 0;
3304  } else {
3305    for my $pkg (@critical) {
3306      next unless (defined($updated{$pkg}));
3307      $infra_update_done &&= $updated{$pkg};
3308      my $oldtlp;
3309      my $newtlp;
3310      if ($updated{$pkg}) {
3311        $oldtlp = $localtlpdb->get_package($pkg);
3312        $newtlp = $remotetlpdb->get_package($pkg);
3313      } else {
3314        # update failed but we could introduce new files, that
3315        # should be removed now as a part of restoring backup
3316        $oldtlp = $remotetlpdb->get_package($pkg);
3317        $newtlp = $localtlpdb->get_package($pkg);
3318      }
3319      die ("That shouldn't happen: $pkg not found in tlpdb") if !defined($newtlp);
3320      die ("That shouldn't happen: $pkg not found in tlpdb") if !defined($oldtlp);
3321      my @old_infra_files = $oldtlp->all_files;
3322      my @new_infra_files = $newtlp->all_files;
3323      my %del_files;
3324      @del_files{@old_infra_files} = ();
3325      delete @del_files{@new_infra_files};
3326      for my $k (keys %del_files) {
3327        my @found_pkgs = $localtlpdb->find_file($k);
3328        if ($#found_pkgs >= 0) {
3329          my $bad_file = 1;
3330          if (win32()) {
3331            # on w32 the packages have not been removed already,
3332            # so we check that the only package listed in @found_pkgs
3333            # is the one we are working on ($pkg)
3334            if ($#found_pkgs == 0 && $found_pkgs[0] =~ m/^$pkg:/) {
3335              # only one package has been returned and it
3336              # matches the current package followed by a colon
3337              # remember the TLPDB->find_file returns
3338              #   $pkg:$file
3339              # in this case we can ignore it
3340              $bad_file = 0;
3341            }
3342          }
3343          if ($bad_file) {
3344            tlwarn("$prg: The file $k has disappeared from the critical" .
3345                   "package $pkg but is still present in @found_pkgs\n");
3346            $ret |= $F_WARNING;
3347          } else {
3348            push @infra_files_to_be_removed, $k;
3349          }
3350        } else {
3351          push @infra_files_to_be_removed, $k;
3352        }
3353      }
3354    }
3355
3356    if (!win32()) {
3357      for my $f (@infra_files_to_be_removed) {
3358        # TODO actually unlink the stuff
3359        #unlink("$Master/$f");
3360        debug("removing disappearing file $f\n");
3361      }
3362    }
3363  } # end of if ($opts{"list"}) ... else part
3364
3365  # check if any additional updates are asked for
3366  my $other_updates_asked_for = 0;
3367  if ($opts{"all"}) {
3368    $other_updates_asked_for = 1;
3369  } else {
3370    foreach my $p (@ARGV) {
3371      if ($p !~ m/$CriticalPackagesRegexp/) {
3372        $other_updates_asked_for = 1;
3373        last;
3374      }
3375    }
3376  }
3377
3378  my $restart_tlmgr = 0;
3379  if ($opts{"self"} && @critical &&
3380      $infra_update_done && $other_updates_asked_for) {
3381    # weed out the --self argument from the saved arguments
3382    @::SAVEDARGV = grep (!m/^-?-self$/, @::SAVEDARGV);
3383    $restart_tlmgr = 1;
3384  }
3385
3386  # infra update and tlmgr restart on w32 is done by the updater batch script
3387  if (win32() && !$opts{"list"} && @critical) {
3388    info("$prg: Preparing TeX Live infrastructure update...\n");
3389    for my $f (@infra_files_to_be_removed) {
3390      debug("file scheduled for removal $f\n");
3391    }
3392    my $ret = write_w32_updater($restart_tlmgr,
3393                                \@infra_files_to_be_removed, @critical);
3394    if ($ret) {
3395      tlwarn ("$prg: Aborting infrastructure update.\n");
3396      $ret |= $F_ERROR;
3397      $restart_tlmgr = 0 if ($opts{"dry-run"});
3398    }
3399  }
3400
3401  # only when we are not dry-running we restart the program
3402  if (!win32() && $restart_tlmgr && !$opts{"dry-run"} && !$opts{"list"}) {
3403    info ("Restarting tlmgr to complete update ...\n");
3404    debug("restarting tlmgr @::SAVEDARGV\n");
3405    exec("tlmgr", @::SAVEDARGV);
3406    # we need warn here, otherwise perl gives warnings!
3407    warn ("$prg: cannot restart tlmgr, please retry update\n");
3408    return ($F_ERROR);
3409  }
3410
3411  # for --dry-run we cannot restart tlmgr (no way to fake successful
3412  # infra update) instead we call action_update() again and signal this
3413  # by $opts{"dry-run"} = -1
3414  if ($opts{"dry-run"} && !$opts{"list"} && $restart_tlmgr) {
3415    $opts{"self"} = 0;
3416    $opts{"dry-run"} = -1;
3417    $localtlpdb = undef;
3418    $remotetlpdb = undef;
3419    info ("Restarting tlmgr to complete update ...\n");
3420    $ret |= action_update();
3421    return ($ret);
3422  }
3423
3424  # if a real update from default disk location didn't find anything,
3425  # warn if nothing is updated.
3426  if (!(@new || @updated)) {
3427    info("$prg: no updates available\n");
3428    if ($remotetlpdb->media ne "NET"
3429        && $remotetlpdb->media ne "virtual"
3430        && !$opts{"dry-run"}
3431        && !$opts{"repository"}
3432        && !$ENV{"TEXLIVE_INSTALL_ENV_NOCHECK"}
3433       ) {
3434      tlwarn(<<END_DISK_WARN);
3435$prg: Your installation is set up to look on the disk for updates.
3436To install from the Internet for this one time only, run:
3437  tlmgr -repository $TeXLiveURL ACTION ARG...
3438where ACTION is install, update, etc.; see tlmgr -help if needed.
3439
3440To change the default for all future updates, run:
3441  tlmgr option repository $TeXLiveURL
3442END_DISK_WARN
3443    }
3444  }
3445  return ($ret);
3446}
3447
3448
3449#  INSTALL
3450#
3451# tlmgr install foo bar baz
3452#   will create the closure under dependencies of {foo,bar,baz}, i.e. all
3453#   dependencies recursively down to the last package, and install all
3454#   the packages that are necessary
3455#
3456# tlmgr install --no-depends foo bar baz
3457#   will *only* install these three packages (if they are not already installed
3458#   but it will STILL INSTALL foo.ARCH if they are necessary.
3459#
3460# tlmgr install --no-depends-at-all foo bar baz
3461#   will absolutely only install these three packages, and will not even
3462#   take .ARCH deps into account
3463#
3464# tlmgr install --reinstall ...
3465#   behaves exactely like without --reinstall BUT the following two
3466#   differences:
3467#   . dependencies are not expanded from collection to collection, so
3468#     if you reinstall a collection then all its dependencies of type
3469#     Package will be reinstalled, too, but not the dependencies on
3470#     other collection, because that would force the full reinstallation
3471#     of the whole installation
3472#   . it does not care for whether a package seems to be installed or
3473#     not (that is the --reinstall)
3474#
3475# TLPDB->install_package does ONLY INSTALL ONE PACKAGE, no deps whatsoever
3476# anymore!  That has all to be done by the caller.
3477#
3478sub action_install {
3479  init_local_db(1);
3480  my $ret = $F_OK;
3481  return ($F_ERROR) if !check_on_writable();
3482
3483  # installation from a .tar.xz
3484  if ($opts{"file"}) {
3485    if ($localtlpdb->install_package_files(@ARGV)) {
3486      return ($ret);
3487    } else {
3488      return ($F_ERROR);
3489    }
3490  }
3491
3492  # if we are still here, we are installing from some repository
3493  # initialize the TLPDB from $location
3494  $opts{"no-depends"} = 1 if $opts{"no-depends-at-all"};
3495  init_tlmedia_or_die();
3496
3497  # check for updates to tlmgr itself, and die unless --force is given
3498  if (!$opts{"usermode"}) {
3499    if (check_for_critical_updates( $localtlpdb, $remotetlpdb)) {
3500      critical_updates_warning();
3501      if ($opts{"force"}) {
3502        tlwarn("Continuing due to --force\n");
3503      } else {
3504        if ($::gui_mode) {
3505          # return here and don't do any updates
3506          return ($F_ERROR);
3507        } else {
3508          die "$prg: Terminating; please see warning above!\n";
3509        }
3510      }
3511    }
3512  }
3513
3514  $opts{"no-depends"} = 1 if $opts{"no-depends-at-all"};
3515  info("$prg install: dry run, no changes will be made\n") if $opts{"dry-run"};
3516
3517  my @packs = @ARGV;
3518  # first expand the .ARCH dependencies unless $opts{"no-depends-at-all"}
3519  @packs = $remotetlpdb->expand_dependencies("-only-arch", $localtlpdb, @ARGV)
3520    unless $opts{"no-depends-at-all"};
3521  #
3522  # if no-depends, we're done; else get rest of deps.
3523  unless ($opts{"no-depends"}) {
3524    if ($opts{"reinstall"} || $opts{"usermode"}) {
3525      # if reinstall or usermode, omit collection->collection deps
3526      @packs = $remotetlpdb->expand_dependencies("-no-collections",
3527                                                 $localtlpdb, @packs);
3528    } else {
3529      @packs = $remotetlpdb->expand_dependencies($localtlpdb, @packs);
3530    }
3531  }
3532  #
3533  # expand dependencies returns a list pkg@tag in case of a virtual
3534  # remote db.
3535  my %packs;
3536  for my $p (@packs) {
3537    my ($pp, $aa) = split('@', $p);
3538    $packs{$pp} = (defined($aa) ? $aa : 0);
3539  }
3540  #
3541  # installation order of packages:
3542  # first all normal packages, then collections, then schemes
3543  # isn't already installed, but the collection already updated, it will
3544  # be reported as forcibly removed.
3545  my @inst_packs;
3546  my @inst_colls;
3547  my @inst_schemes;
3548  for my $pkg (sort keys %packs) {
3549    # we do name checking here, not to load all tlpobj again and again
3550    if ($pkg =~ m/^scheme-/) {
3551      push @inst_schemes, $pkg;
3552    } elsif ($pkg =~ m/^collection-/) {
3553      push @inst_colls, $pkg;
3554    } else {
3555      push @inst_packs, $pkg;
3556    }
3557  }
3558  @inst_packs = sort packagecmp @inst_packs;
3559
3560  my $starttime = time();
3561  # count packages
3562  my $totalnr = 0;
3563  my %revs;
3564  my @todo;
3565  for my $pkg (@inst_packs, @inst_colls, @inst_schemes) {
3566    my $pkgrev = 0;
3567    # if the package name is asked from a specific repository, use
3568    # that one, otherwise leave the  decision to $remotetlpdb by not
3569    # giving a final argument
3570    my $mediatlp = $remotetlpdb->get_package($pkg,
3571      ($packs{$pkg} ? $packs{$pkg} : undef));
3572    if (!defined($mediatlp)) {
3573      tlwarn("$prg install: package $pkg not present in repository.\n");
3574      $ret |= $F_WARNING;
3575      next;
3576    }
3577    if (defined($localtlpdb->get_package($pkg))) {
3578      if ($opts{"reinstall"}) {
3579        $totalnr++;
3580        $revs{$pkg} = $mediatlp->revision;
3581        push @todo, $pkg;
3582      } else {
3583        # debug msg that we have this one.
3584        debug("already installed: $pkg\n");
3585        # if explicitly requested by user (not a dep), tell them.
3586        info("$prg install: package already present: $pkg\n")
3587          if grep { $_ eq $pkg } @ARGV;
3588      }
3589    } else {
3590      $totalnr++;
3591      $revs{$pkg} = $mediatlp->revision;
3592      push (@todo, $pkg);
3593    }
3594  }
3595  # return if there is nothing to install!
3596  return ($ret) if (!@todo);
3597
3598  my $orig_do_src = $localtlpdb->option("install_srcfiles");
3599  my $orig_do_doc = $localtlpdb->option("install_docfiles");
3600  if (!$opts{"dry-run"}) {
3601    $localtlpdb->option("install_srcfiles", 1) if $opts{'with-src'};
3602    $localtlpdb->option("install_docfiles", 1) if $opts{'with-doc'};
3603  }
3604
3605  my $currnr = 1;
3606  # undef here is a ref to array of platforms, if undef all are used
3607  my %sizes = %{$remotetlpdb->sizes_of_packages(
3608    $localtlpdb->option("install_srcfiles"),
3609    $localtlpdb->option("install_docfiles"), undef, @todo)};
3610  defined($sizes{'__TOTAL__'}) || ($sizes{'__TOTAL__'} = 0);
3611  my $totalsize = $sizes{'__TOTAL__'};
3612  my $donesize = 0;
3613
3614  print "total-bytes\t$sizes{'__TOTAL__'}\n" if $::machinereadable;
3615  print "end-of-header\n" if $::machinereadable;
3616
3617  foreach my $pkg (@todo) {
3618    my $flag = $FLAG_INSTALL;
3619    my $re = "";
3620    my $tlp = $remotetlpdb->get_package($pkg);
3621    my $rctanvers = $tlp->cataloguedata->{'version'};
3622    if (!defined($tlp)) {
3623      info("Unknown package $pkg\n");
3624      next;
3625    }
3626    if (!$tlp->relocated && $opts{"usermode"}) {
3627      info("Package $pkg is not relocatable, cannot install it in user mode!\n");
3628      next;
3629    }
3630    my $lctanvers;
3631    if (defined($localtlpdb->get_package($pkg))) {
3632      my $lctanvers = $localtlpdb->get_package($pkg)->cataloguedata->{'version'};
3633      if ($opts{"reinstall"}) {
3634        $re = "re";
3635        $flag = $FLAG_REINSTALL;
3636      } else {
3637        debug("already installed (but didn't we say that already?): $pkg\n");
3638        next;
3639      }
3640    }
3641    my ($estrem, $esttot) = TeXLive::TLUtils::time_estimate($totalsize,
3642                              $donesize, $starttime);
3643    my $kb = int($sizes{$pkg} / 1024) + 1;
3644    my @addargs = ();
3645    my $tagstr = "";
3646    if ($remotetlpdb->is_virtual) {
3647      if ($packs{$pkg} ne "0") {
3648        push @addargs, $packs{$pkg};
3649        $tagstr = " \@" . $packs{$pkg};
3650      } else {
3651        my ($maxtag,undef,undef,undef) = $remotetlpdb->virtual_candidate($pkg);
3652        push @addargs, $maxtag;
3653        $tagstr = " \@" . $maxtag;
3654      }
3655    }
3656    push @addargs, $lctanvers, $rctanvers;
3657    if ($::machinereadable) {
3658      machine_line($pkg, $flag, "-", $revs{$pkg}, $sizes{$pkg}, $estrem, $esttot, @addargs);
3659    } else {
3660      info("[$currnr/$totalnr, $estrem/$esttot] ${re}install: $pkg$tagstr [${kb}k]\n");
3661    }
3662    if (!$opts{"dry-run"}) {
3663      $remotetlpdb->install_package($pkg, $localtlpdb,
3664        ($packs{$pkg} ? $packs{$pkg} : undef) );
3665      logpackage("${re}install: $pkg$tagstr");
3666    }
3667    $donesize += $sizes{$pkg};
3668    $currnr++;
3669  }
3670  print "end-of-updates\n" if $::machinereadable;
3671
3672
3673  if ($opts{"dry-run"}) {
3674    # stop here, don't do any postinstall actions
3675    return($ret | $F_NOPOSTACTION);
3676  } else {
3677    # reset option if --with-src argument was given
3678    $localtlpdb->option("install_srcfiles", $orig_do_src) if $opts{'with-src'};
3679    $localtlpdb->option("install_docfiles", $orig_do_doc) if $opts{'with-doc'};
3680    $localtlpdb->save if ($opts{'with-src'} || $opts{'with-doc'});
3681  }
3682  return ($ret);
3683}
3684
3685sub show_list_of_packages {
3686  init_local_db();
3687  # make sure that the @ARGV hash is not changed in case we switch to
3688  # show mode
3689  my ($what) = @_;
3690  $what = "" if !$what;
3691  my $tlm;
3692  if ($opts{"only-installed"}) {
3693    $tlm = $localtlpdb;
3694  } else {
3695    init_tlmedia_or_die();
3696    $tlm = $remotetlpdb;
3697  }
3698  my @whattolist;
3699  if ($what =~ m/^collections/i) {
3700    @whattolist = $tlm->collections;
3701  } elsif ($what =~ m/^schemes/i) {
3702    @whattolist = $tlm->schemes;
3703  } else {
3704    if ($tlm->is_virtual) {
3705      @whattolist = $tlm->list_packages("-all");
3706    } else {
3707      @whattolist = $tlm->list_packages;
3708    }
3709  }
3710  foreach (@whattolist) {
3711    next if ($_ =~ m/^00texlive/);
3712    if (defined($localtlpdb->get_package($_))) {
3713      print "i ";
3714    } else {
3715      print "  ";
3716    }
3717    my $tlp = $tlm->get_package($_);
3718    if (!$tlp) {
3719      if ($remotetlpdb->is_virtual) {
3720        # we might have the case that a package is present in a
3721        # subsidiary repository, but not pinned, so it will
3722        # not be found by ->get_package
3723        # In this case we list all repositories shipping it,
3724        # but warn that it is not pinned and thus not reachable.
3725        my @cand = $remotetlpdb->candidates($_);
3726        if (@cand) {
3727          my $first = shift @cand;
3728          if (defined($first)) {
3729            tlwarn("strange, we have a first candidate but no tlp: $_\n");
3730            next;
3731          }
3732          # already shifted away the first element
3733          if ($#cand >= 0) {
3734            print "$_: --- no installable candidate found, \n";
3735            print "    but present in subsidiary repositories without a pin.\n";
3736            print "    This package is not reachable without pinning.\n";
3737            print "    Repositories containing this package:\n";
3738            for my $a (@cand) {
3739              my ($t,$r) = split(/\//, $a, 2);
3740              my $tlp = $remotetlpdb->get_package($_, $t);
3741              my $foo = $tlp->shortdesc;
3742              print "      $t: ", defined($foo) ? $foo : "(shortdesc missing)" , "\n";
3743            }
3744            next;
3745          } else {
3746            tlwarn("strange, package listed but no residual candidates: $_\n");
3747            next;
3748          }
3749        } else {
3750          tlwarn("strange, package listed but no candidates: $_\n");
3751          next;
3752        }
3753      } else {
3754        tlwarn("strange, package cannot be found in remote tlpdb: $_\n");
3755        next;
3756      }
3757    }
3758    my $foo = $tlp->shortdesc;
3759    print "$_: ", defined($foo) ? $foo : "(shortdesc missing)" , "\n";
3760  }
3761  return;
3762}
3763
3764#  PINNING
3765#
3766# this action manages the pinning file
3767# of course it can be edited by hand, but we want to make this
3768# easier for people to use
3769# tlmgr pinning show
3770# tlmgr pinning check
3771# tlmgr pinning add <repo> <pkgglob> [<pkgglob> ...]
3772# tlmgr pinning remove <repo> <pkgglob> [<pkgglob> ...]
3773# tlmgr pinning remove <repo> --all
3774sub action_pinning {
3775  my $what = shift @ARGV;
3776  $what || ($what = 'show');
3777  init_local_db();
3778  init_tlmedia_or_die();
3779  if (!$remotetlpdb->is_virtual) {
3780    tlwarn("$prg: only one repository configured, "
3781           . "pinning actions not supported.\n");
3782    return;
3783  }
3784  my $pinref = $remotetlpdb->virtual_pindata();
3785  my $pf = $remotetlpdb->virtual_pinning();
3786
3787  if ($what =~ m/^show$/i) {
3788    my @pins = @$pinref;
3789    if (!@pins) {
3790      tlwarn("$prg: no pinning data present.\n");
3791      return 0;
3792    }
3793    info("$prg: this pinning data is defined:\n");
3794    for my $p (@pins) {
3795      info("  ", $p->{'repo'}, ":", $p->{'glob'}, "\n");
3796    }
3797    return 1;
3798
3799  } elsif ($what =~ m/^check$/i) {
3800    tlwarn("$prg: not implemented yet, sorry!\n");
3801    return 0;
3802
3803  } elsif ($what =~ m/^add$/i) {
3804    # we need at least two more arguments
3805    if (@ARGV < 2) {
3806      tlwarn("$prg: need at least two arguments to pinning add\n");
3807      return;
3808    }
3809    my $repo = shift @ARGV;
3810    my @new = ();
3811    my @ov = $pf->value($repo);
3812    for my $n (@ARGV) {
3813      if (member($n, @ov)) {
3814        info("$prg: already pinned to $repo: $n\n");
3815      } else {
3816        push (@ov, $n);
3817        push (@new, $n);
3818      }
3819    }
3820    $pf->value($repo, @ov);
3821    $remotetlpdb->virtual_update_pins();
3822    $pf->save;
3823    info("$prg: new pinning data for $repo: @new\n") if @new;
3824    return 1;
3825
3826  } elsif ($what =~ m/^remove$/i) {
3827    my $repo = shift @ARGV;
3828    if (!defined($repo)) {
3829      tlwarn("$prg: missing repository argument to pinning remove\n");
3830      return 0;
3831    }
3832    if ($opts{'all'}) {
3833      if (@ARGV) {
3834        tlwarn("$prg: additional argument(s) not allowed with --all: @ARGV\n");
3835        return 0;
3836      }
3837      $pf->delete_key($repo);
3838      $remotetlpdb->virtual_update_pins();
3839      $pf->save;
3840      info("$prg: all pinning data removed for repository $repo\n");
3841      return 1;
3842    }
3843    # complicated case, we want to remove only one setting
3844    my @ov = $pf->value($repo);
3845    my @nv;
3846    for my $pf (@ov) {
3847      push (@nv, $pf) if (!member($pf, @ARGV));
3848    }
3849    if ($#ov == $#nv) {
3850      info("$prg: no changes in pinning data for $repo\n");
3851      return 1;
3852    }
3853    if (@nv) {
3854      $pf->value($repo, @nv);
3855    } else {
3856      $pf->delete_key($repo);
3857    }
3858    $remotetlpdb->virtual_update_pins();
3859    $pf->save;
3860    info("$prg: removed pinning data for repository $repo: @ARGV\n");
3861    return 1;
3862
3863  } else {
3864    tlwarn("$prg: unknown argument for pinning action: $what\n");
3865    return 0;
3866  }
3867  # $pin{'repo'} = $repo;
3868  # $pin{'glob'} = $glob;
3869  # $pin{'re'} = $re;
3870  # $pin{'line'} = $line; # for debug/warning purpose
3871  return 0;
3872}
3873
3874#  REPOSITORY
3875#
3876# this action manages the list of repositories
3877# tlmgr repository list               -> lists repositories
3878# tlmgr repository list path|tag      -> lists content of repo path|tag
3879# tlmgr repository add path [tag]     -> add repository with optional tag
3880# tlmgr repository remove [path|tag]  -> removes repository or tag
3881# tlmgr repository set path[#tag] [path[#tag] ...] -> sets the list
3882#
3883
3884sub array_to_repository {
3885  my %r = @_;
3886  my @ret;
3887  my @k = keys %r;
3888  if ($#k == 0) {
3889    # only one repo, don't write any tag
3890    return $r{$k[0]};
3891  }
3892  for my $k (keys %r) {
3893    my $v = $r{$k};
3894    if ($k ne $v) {
3895      $v = "$v#$k";
3896    }
3897    # encode spaces and % in the path and tags
3898    $v =~ s/%/%25/g;
3899    $v =~ s/ /%20/g;
3900    push @ret, $v;
3901  }
3902  return "@ret";
3903}
3904sub repository_to_array {
3905  my $r = shift;
3906  my %r;
3907  my @repos = split ' ', $r;
3908  if ($#repos == 0) {
3909    # only one repo, this is the main one!
3910    $r{'main'} = $repos[0];
3911    return %r;
3912  }
3913  for my $rr (@repos) {
3914    my $tag;
3915    my $url;
3916    # decode spaces and % in reverse order
3917    $rr =~ s/%20/ /g;
3918    $rr =~ s/%25/%/g;
3919    $tag = $url = $rr;
3920    if ($rr =~ m/^([^#]+)#(.*)$/) {
3921      $tag = $2;
3922      $url = $1;
3923    }
3924    $r{$tag} = $url;
3925  }
3926  return %r;
3927}
3928sub merge_sub_packages {
3929  my %pkgs;
3930  for my $p (@_) {
3931    if ($p =~ m/^(.*)\.([^.]*)$/) {
3932      my $n = $1;
3933      my $a = $2;
3934      if ($p eq "texlive.infra") {
3935        push @{$pkgs{$p}}, "all";
3936      } else {
3937        push @{$pkgs{$n}}, $a;
3938      }
3939    } else {
3940      push @{$pkgs{$p}}, "all";
3941    }
3942  }
3943  return %pkgs;
3944}
3945sub action_repository {
3946  init_local_db();
3947  my $what = shift @ARGV;
3948  $what = "list" if !defined($what);
3949  my %repos = repository_to_array($localtlpdb->option("location"));
3950  if ($what =~ m/^list$/i) {
3951    if (@ARGV) {
3952      # list what is in a repository
3953      for my $repo (@ARGV) {
3954        my $loc = $repo;
3955        if (defined($repos{$repo})) {
3956          $loc = $repos{$repo};
3957        }
3958        my ($tlpdb, $errormsg) = setup_one_remotetlpdb($loc);
3959        if (!defined($tlpdb)) {
3960          tlwarn("cannot get TLPDB from location $loc\n\n");
3961        } else {
3962          print "Packages at $loc:\n";
3963          my %pkgs = merge_sub_packages($tlpdb->list_packages);
3964          for my $p (sort keys %pkgs) {
3965            next if ($p =~ m/00texlive/);
3966            print "  $p";
3967            if (!$opts{'with-platforms'}) {
3968              print "\n";
3969            } else {
3970              my @a = @{$pkgs{$p}};
3971              if ($#a == 0) {
3972                if ($a[0] eq "all") {
3973                  # no further information necessary
3974                  print "\n";
3975                } else {
3976                  print ".$a[0]\n";
3977                }
3978              } else {
3979                print " (@{$pkgs{$p}})\n";
3980              }
3981            }
3982          }
3983        }
3984      }
3985    } else {
3986      print "List of repositories (with tags if set):\n";
3987      for my $k (keys %repos) {
3988        my $v = $repos{$k};
3989        print "\t$v";
3990        if ($k ne $v) {
3991          print " ($k)";
3992        }
3993        print "\n";
3994      }
3995    }
3996    return ($F_OK);
3997  }
3998  if ($what eq "add") {
3999    my $p = shift @ARGV;
4000    if (!defined($p)) {
4001      tlwarn("$prg: no repository given (to add)\n");
4002      return ($F_ERROR);
4003    }
4004    # check if it is either url or absolute path
4005    if (($p !~ m!^(http|ftp)://!i) &&
4006        !File::Spec->file_name_is_absolute($p)) {
4007      tlwarn("$prg: neither http/ftp URL nor absolute path, no action: $p\n");
4008      return ($F_ERROR);
4009    }
4010    my $t = shift @ARGV;
4011    $t = $p if (!defined($t));
4012    if (defined($repos{$t})) {
4013      tlwarn("$prg: repository or its tag already defined, no action: $p\n");
4014      return ($F_ERROR);
4015    }
4016    # TODO more checks needed?
4017    # if there was till now only *one* repository and that without
4018    # a tag, we give that one the "main" tag which is necessary
4019    # for proper operation!
4020    my @tags = keys %repos;
4021    if ($#tags == 0) {
4022      # we have only one repository, check if it has the main tag
4023      my $maintag = $tags[0];
4024      if ($maintag ne 'main') {
4025        $repos{'main'} = $repos{$maintag};
4026        delete $repos{$maintag};
4027      }
4028    }
4029    $repos{$t} = $p;
4030    $localtlpdb->option("location", array_to_repository(%repos));
4031    $localtlpdb->save;
4032    if ($t eq $p) {
4033      print "$prg: added repository: $p\n";
4034    } else {
4035      print "$prg: added repository with tag $t: $p\n";
4036    }
4037    return ($F_OK);
4038  }
4039  if ($what eq "remove") {
4040    my $p = shift @ARGV;
4041    if (!defined($p)) {
4042      tlwarn("$prg: no repository given (to remove)\n");
4043      return ($F_ERROR);
4044    }
4045    my $found = 0;
4046    for my $k (keys %repos) {
4047      if ($k eq $p || $repos{$k} eq $p) {
4048        $found = 1;
4049        delete $repos{$k};
4050      }
4051    }
4052    if (!$found) {
4053      tlwarn("$prg: repository not defined, cannot remove: $p\n");
4054      return ($F_ERROR);
4055    } else {
4056      $localtlpdb->option("location", array_to_repository(%repos));
4057      $localtlpdb->save;
4058      print "$prg: removed repository: $p\n";
4059      return ($F_OK);
4060    }
4061    # no reached
4062    return ($F_OK);
4063  }
4064  if ($what eq "set") {
4065    # TODO TODO
4066    # we have to make sure that there is ONE main repository!!!
4067    %repos = repository_to_array("@ARGV");
4068    $localtlpdb->option("location", array_to_repository(%repos));
4069    $localtlpdb->save;
4070    return ($F_OK);
4071  }
4072  # we are still here, unknown command to repository
4073  tlwarn("$prg: unknown subaction for tlmgr repository: $what\n");
4074  return ($F_ERROR);
4075}
4076
4077sub action_candidates {
4078  my $what = shift @ARGV;
4079  if (!defined($what)) {
4080    tlwarn("$prg: candidates needs a package name as argument\n");
4081    return ($F_ERROR);
4082  }
4083  init_local_db();
4084  init_tlmedia_or_die();
4085  my @cand = $remotetlpdb->candidates($what);
4086  if (@cand) {
4087    my $first = shift @cand;
4088    if (defined($first)) {
4089      my ($t,$r) = split(/\//, $first, 2);
4090      print "Install candidate for $what from $t ($r)\n";
4091    } else {
4092      print "No install candidate for $what found.\n";
4093    }
4094    # already shifted away the first element
4095    if ($#cand >= 0) {
4096      print "Other repositories providing this package:\n";
4097      for my $a (@cand) {
4098        my ($t,$r) = split(/\//, $a, 2);
4099        print "$t ($r)\n";
4100      }
4101    }
4102  } else {
4103    print "Package $what not found.\n";
4104    return ($F_WARNING);
4105  }
4106  return ($F_OK);;
4107}
4108
4109#  OPTION
4110#
4111sub action_option {
4112  my $what = shift @ARGV;
4113  $what = "show" unless defined($what);
4114  init_local_db();
4115  my $ret = $F_OK;
4116  if ($what =~ m/^show$/i) {
4117    for my $o (keys %{$localtlpdb->options}) {
4118      # ignore some things which are w32 specific
4119      next if ($o eq "desktop_integration" && !win32());
4120      next if ($o eq "file_assocs" && !win32());
4121      next if ($o eq "w32_multi_user" && !win32());
4122      if (win32()) {
4123        next if ($o =~ m/^sys_/);
4124      }
4125      if (defined $TLPDBOptions{$o}) {
4126        if ($::machinereadable) {
4127          print "$TLPDBOptions{$o}->[2]\t", $localtlpdb->option($o), "\n";
4128        } else {
4129          info("$TLPDBOptions{$o}->[3] ($TLPDBOptions{$o}->[2]): " .
4130                $localtlpdb->option($o) . "\n");
4131        }
4132      } else {
4133        tlwarn ("$prg: option $o not supported\n");
4134        $ret |= $F_WARNING;
4135      }
4136    }
4137  } elsif ($what =~ m/^showall$/i) {
4138    my %loc = %{$localtlpdb->options};
4139    for my $o (sort keys %TLPDBOptions) {
4140      if ($::machinereadable) {
4141        print "$TLPDBOptions{$o}->[2]\t",
4142          (defined($loc{$o}) ? $loc{$o} : "(not set)"), "\n";
4143      } else {
4144        info("$TLPDBOptions{$o}->[3] ($TLPDBOptions{$o}->[2]): " .
4145             (defined($loc{$o}) ? $loc{$o} : "(not set)") . "\n");
4146      }
4147    }
4148  } else {
4149    if ($what eq "location" || $what eq "repo") {
4150      # silently rewrite location|repo -> repository
4151      $what = "repository";
4152    }
4153    my $found = 0;
4154    for my $opt (keys %TLPDBOptions) {
4155      if ($what eq $TLPDBOptions{$opt}->[2]) {
4156        $found = 1;
4157        # the option argument matches the name
4158        my $val = shift @ARGV;
4159        if (defined($val)) {
4160          return ($F_ERROR) if !check_on_writable();
4161          # set new value
4162          # here we have to care for some special cases
4163          if ($what eq $TLPDBOptions{"location"}->[2]) {
4164            # support "ctan" on the cmd line
4165            if ($val =~ m/^ctan$/i) {
4166              $val = "$TeXLive::TLConfig::TeXLiveURL";
4167            }
4168            info("$prg: setting default package repository to $val\n");
4169            $localtlpdb->option($opt, $val);
4170          } elsif ($what eq $TLPDBOptions{"backupdir"}->[2]) {
4171            info("$prg: setting option $what to $val.\n");
4172            if (! -d $val) {
4173              info("$prg: the directory $val does not exists, it has to be created\n");
4174              info("$prg: before backups can be done automatically.\n");
4175            }
4176            $localtlpdb->option($opt, $val);
4177          } elsif ($what eq $TLPDBOptions{"w32_multi_user"}->[2]) {
4178            # when running w32 do not allow that a non-admin users sets
4179            # this from false to true
4180            my $do_it = 0;
4181            if (win32()) {
4182              if (admin()) {
4183                $do_it = 1;
4184              } else {
4185                if ($val) {
4186                  # non admin and tries to set to true, warn
4187                  tlwarn("$prg: non-admin user cannot set $TLPDBOptions{'w32_multi_user'}->[2] option to true\n");
4188                } else {
4189                  $do_it = 1;
4190                }
4191              }
4192            } else {
4193              $do_it = 1;
4194            }
4195            if ($do_it) {
4196              if ($val) {
4197                info("$prg: setting option $what to 1.\n");
4198                $localtlpdb->option($opt, 1);
4199              } else {
4200                info("$prg: setting option $what to 0.\n");
4201                $localtlpdb->option($opt, 0);
4202              }
4203            }
4204          } else {
4205            # default case, switch for different types
4206            if ($TLPDBOptions{$opt}->[0] eq "b") {
4207              if ($val) {
4208                info("$prg: setting option $what to 1.\n");
4209                $localtlpdb->option($opt, 1);
4210              } else {
4211                info("$prg: setting option $what to 0.\n");
4212                $localtlpdb->option($opt, 0);
4213              }
4214            } elsif ($TLPDBOptions{$opt}->[0] eq "p") {
4215              info("$prg: setting option $what to $val.\n");
4216              $localtlpdb->option($opt, $val);
4217            } elsif ($TLPDBOptions{$opt}->[0] eq "u") {
4218              info("$prg: setting option $what to $val.\n");
4219              $localtlpdb->option($opt, $val);
4220            } elsif ($TLPDBOptions{$opt}->[0] =~ m/^n(:((-)?\d+)?..((-)?\d+)?)?$/) {
4221              my $isgood = 1;
4222              my $n = int($val);
4223              my $low;
4224              my $up;
4225              if (defined($1)) {
4226                # range given
4227                if (defined($2)) {
4228                  # lower border
4229                  if ($2 > $n) {
4230                    tlwarn("value $n for $what out of range ($TLPDBOptions{$opt}->[0])\n");
4231                    $isgood = 0;
4232                  }
4233                }
4234                if (defined($4)) {
4235                  # upper border
4236                  if ($4 < $n) {
4237                    tlwarn("value $n for $what out of range ($TLPDBOptions{$opt}->[0])\n");
4238                    $isgood = 0;
4239                  }
4240                }
4241              }
4242              if ($isgood) {
4243                info("$prg: setting option $what to $n.\n");
4244                $localtlpdb->option($opt, $n);
4245              }
4246            } else {
4247              tlwarn ("Unknown type of option $opt: $TLPDBOptions{$opt}->[0]\n");
4248              return ($F_ERROR);
4249            }
4250          }
4251          $localtlpdb->save;
4252          # now also save the TLPOBJ of 00texlive.installation
4253          my $tlpo = $localtlpdb->get_package("00texlive.installation");
4254          if ($tlpo) {
4255            if (open(TOFD, ">$::maintree/tlpkg/tlpobj/00texlive.installation.tlpobj")) {
4256              $tlpo->writeout(\*TOFD);
4257              close(TOFD);
4258            } else {
4259              tlwarn("Cannot save 00texlive.installation to $::maintree/tlpkg/tlpobj/00texlive.installation.tlpobj\n");
4260              $ret |= $F_WARNING;
4261            }
4262          }
4263        } else {
4264          # show current value
4265          if ($::machinereadable) {
4266            print "$TLPDBOptions{$opt}->[2]\t", $localtlpdb->option($opt), "\n";
4267          } else {
4268            info ("$TLPDBOptions{$opt}->[3] ($TLPDBOptions{$opt}->[2]): " .
4269                  $localtlpdb->option($opt) . "\n");
4270          }
4271        }
4272        last;
4273      }
4274    }
4275    if (!$found) {
4276      tlwarn("$prg: option $what not supported!\n");
4277      return ($F_ERROR);
4278    }
4279  }
4280  return ($ret);
4281}
4282
4283
4284#  ARCH
4285#
4286sub action_platform {
4287  my @extra_w32_packs = qw/tlperl.win32 tlgs.win32 tlpsv.win32
4288                           collection-wintools
4289                           dviout.win32 wintools.win32/;
4290  if ($^O=~/^MSWin(32|64)$/i) {
4291    warn("action `platform' not supported on Windows\n");
4292    return();
4293  }
4294  if ($opts{"usermode"}) {
4295    tlwarn("action `platform' not supported in usermode\n");
4296    exit 1;
4297  }
4298  my $what = shift @ARGV;
4299  init_local_db(1);
4300  info("$prg platform: dry run, no changes will be made\n") if $opts{"dry-run"};
4301  $what || ($what = "list");
4302  if ($what =~ m/^list$/i) {
4303    # list the available platforms
4304    # initialize the TLPDB from $location
4305    init_tlmedia_or_die();
4306    my @already_installed_arch = $localtlpdb->available_architectures;
4307    print "Available platforms:\n";
4308    foreach my $a ($remotetlpdb->available_architectures) {
4309      if (member($a,@already_installed_arch)) {
4310        print "(i) $a\n";
4311      } else {
4312        print "    $a\n";
4313      }
4314    }
4315    print "Already installed platforms are marked with (i)\n";
4316    print "You can add new platforms with: tlmgr platform add ARCH1 ARCH2...\n";
4317    return ($F_OK | $F_NOPOSTACTION);
4318  } elsif ($what =~ m/^add$/i) {
4319    return if !check_on_writable();
4320    init_tlmedia_or_die();
4321    my @already_installed_arch = $localtlpdb->available_architectures;
4322    my @available_arch = $remotetlpdb->available_architectures;
4323    my @todoarchs;
4324    foreach my $a (@ARGV) {
4325      if (TeXLive::TLUtils::member($a, @already_installed_arch)) {
4326        print "Platform $a is already installed\n";
4327        next;
4328      }
4329      if (!TeXLive::TLUtils::member($a, @available_arch)) {
4330        print "Platform $a not available, use 'tlmgr platform list'!\n";
4331        next;
4332      }
4333      push @todoarchs, $a;
4334    }
4335    foreach my $pkg ($localtlpdb->list_packages) {
4336      next if ($pkg =~ m/^00texlive/);
4337      my $tlp = $localtlpdb->get_package($pkg);
4338      foreach my $dep ($tlp->depends) {
4339        if ($dep =~ m/^(.*)\.ARCH$/) {
4340          # we have to install something
4341          foreach my $a (@todoarchs) {
4342            if ($remotetlpdb->get_package("$pkg.$a")) {
4343              info("install: $pkg.$a\n");
4344              $remotetlpdb->install_package("$pkg.$a", $localtlpdb)
4345                if (!$opts{"dry-run"});
4346            }
4347          }
4348        }
4349      }
4350    }
4351    if (TeXLive::TLUtils::member('win32', @todoarchs)) {
4352      # install the necessary w32 stuff
4353      for my $p (@extra_w32_packs) {
4354        info("install: $p\n");
4355        $remotetlpdb->install_package($p, $localtlpdb) if (!$opts{"dry-run"});
4356      }
4357    }
4358    # update the option("available_architectures") list of installed archs
4359    if (!$opts{"dry-run"}) {
4360      my @larchs = $localtlpdb->setting("available_architectures");
4361      push @larchs, @todoarchs;
4362      $localtlpdb->setting("available_architectures",@larchs);
4363      $localtlpdb->save;
4364    }
4365  } elsif ($what =~ m/^remove$/i) {
4366    return if !check_on_writable();
4367    my @already_installed_arch = $localtlpdb->available_architectures;
4368    my @todoarchs;
4369    my $currentarch = $localtlpdb->platform();
4370    foreach my $a (@ARGV) {
4371      if (!TeXLive::TLUtils::member($a, @already_installed_arch)) {
4372        print "Platform $a not installed, use 'tlmgr platform list'!\n";
4373        next;
4374      }
4375      if ($currentarch eq $a) {
4376        info("You are running on platform $a, you cannot remove that one!\n");
4377        next;
4378      }
4379      push @todoarchs, $a;
4380    }
4381    foreach my $pkg ($localtlpdb->list_packages) {
4382      next if ($pkg =~ m/^00texlive/);
4383      my $tlp = $localtlpdb->get_package($pkg);
4384      if (!$tlp) {
4385        # that is a package foobar.$a that has already been remove but
4386        # is still in the list above, so ignore that
4387        next;
4388      }
4389      foreach my $dep ($tlp->depends) {
4390        if ($dep =~ m/^(.*)\.ARCH$/) {
4391          # we have to install something
4392          foreach my $a (@todoarchs) {
4393            if ($localtlpdb->get_package("$pkg.$a")) {
4394              info("remove: $pkg.$a\n");
4395              $localtlpdb->remove_package("$pkg.$a") if (!$opts{"dry-run"});
4396            }
4397          }
4398        }
4399      }
4400    }
4401    if (TeXLive::TLUtils::member('win32', @todoarchs)) {
4402      for my $p (@extra_w32_packs) {
4403        info("remove: $p\n");
4404        $localtlpdb->remove_package($p) if (!$opts{"dry-run"});
4405      }
4406    }
4407    if (!$opts{"dry-run"}) {
4408      # try to remove bin/$a dirs
4409      for my $a (@todoarchs) {
4410        if (!rmdir("$Master/bin/$a")) {
4411          tlwarn("binary directory $Master/bin/$a not empty after removal of $a.\n");
4412        }
4413      }
4414      # update the option("available_architectures") list of installed archs
4415      my @larchs = $localtlpdb->setting("available_architectures");
4416      my @newarchs;
4417      for my $a (@larchs) {
4418        push @newarchs, $a if !member($a, @todoarchs);
4419      }
4420      $localtlpdb->setting("available_architectures",@newarchs);
4421      $localtlpdb->save;
4422    }
4423  } elsif ($what =~ m/^set$/i) {
4424    return if !check_on_writable();
4425    my $arg = shift @ARGV;
4426    die "Missing argument to platform set" unless defined($arg);
4427    my @already_installed_arch = $localtlpdb->available_architectures;
4428    if ($arg =~ m/^auto$/i) {
4429      info("Setting platform detection to auto mode.\n");
4430      $localtlpdb->setting('-clear', 'platform');
4431      $localtlpdb->save;
4432    } else {
4433      if (!TeXLive::TLUtils::member($arg, @already_installed_arch)) {
4434        tlwarn("cannot set platform to a not installed one.\n");
4435        return;
4436      }
4437      $localtlpdb->setting('platform', $arg);
4438      $localtlpdb->save;
4439    }
4440  } else {
4441    die "Unknown option for platform: $what";
4442  }
4443}
4444
4445
4446#  GENERATE
4447#
4448sub action_generate {
4449  if ($opts{"usermode"}) {
4450    tlwarn("action `generate' not supported in usermode!\n");
4451    return $F_ERROR;
4452  }
4453  my $what = shift @ARGV;
4454  init_local_db();
4455
4456  # we create fmtutil.cnf, language.dat, language.def in TEXMFSYSVAR and
4457  # updmap.cfg in TEXMFDIST. The reason is that we are now using an
4458  # implementation of updmap that supports multiple updmap files.
4459  # Local adaptions should not be made there, but only in TEXMFLOCAL
4460  # or TEXMF(SYS)CONFIG updmap.cfg
4461  #
4462  chomp (my $TEXMFSYSVAR = `kpsewhich -var-value=TEXMFSYSVAR`);
4463  chomp (my $TEXMFSYSCONFIG = `kpsewhich -var-value=TEXMFSYSCONFIG`);
4464  chomp (my $TEXMFLOCAL = `kpsewhich -var-value=TEXMFLOCAL`);
4465  chomp (my $TEXMFDIST = `kpsewhich -var-value=TEXMFDIST`);
4466
4467  # we do generate all config files, treat $opts{"dest"} as pattern
4468  # and make it append the respective extensions
4469  my $append_extension = (($opts{"dest"} && ($what eq "language")) ? 1 : 0);
4470
4471  if ($what =~ m/^language(\.dat|\.def|\.dat\.lua)?$/i) {
4472    #
4473    # if --rebuild-sys is given *and* --dest we warn that this might not
4474    # work if the destination is not the default one
4475    if ($opts{"rebuild-sys"} && $opts{"dest"}) {
4476      tlwarn("tlmgr generate $what: warning: both --rebuild-sys and --dest\n",
4477             "given; the call to fmtutil-sys can fail if the given\n",
4478             "destination is different from the default.\n");
4479    }
4480    #
4481    # we have to set TEXMFVAR, TEXMFCONFIG in the environment so that
4482    # searching for language.(dat/def) does search in the right place
4483    if ($what =~ m/^language(\.dat\.lua)?$/i) {
4484      my $dest = $opts{"dest"} ||
4485        "$TEXMFSYSVAR/tex/generic/config/language.dat.lua";
4486      $dest .= ".dat.lua" if $append_extension;
4487      my $localcfg = $opts{"localcfg"} ||
4488        "$TEXMFLOCAL/tex/generic/config/language-local.dat.lua";
4489      debug("$prg: writing language.dat.lua data to $dest\n");
4490      TeXLive::TLUtils::create_language_lua($localtlpdb, $dest, $localcfg);
4491      if ($opts{"rebuild-sys"}) {
4492        do_cmd_and_check
4493                     ("fmtutil-sys $common_fmtutil_args --byhyphen \"$dest\"");
4494      } else {
4495        info("To make the newly-generated language.dat.lua take effect,"
4496             . " run fmtutil-sys --byhyphen $dest.\n");
4497      }
4498    }
4499    if ($what =~ m/^language(\.dat)?$/i) {
4500      my $dest = $opts{"dest"} ||
4501        "$TEXMFSYSVAR/tex/generic/config/language.dat";
4502      $dest .= ".dat" if $append_extension;
4503      my $localcfg = $opts{"localcfg"} ||
4504        "$TEXMFLOCAL/tex/generic/config/language-local.dat";
4505      debug ("$prg: writing language.dat data to $dest\n");
4506      TeXLive::TLUtils::create_language_dat($localtlpdb, $dest, $localcfg);
4507      if ($opts{"rebuild-sys"}) {
4508        do_cmd_and_check
4509                     ("fmtutil-sys $common_fmtutil_args --byhyphen \"$dest\"");
4510      } else {
4511        info("To make the newly-generated language.dat take effect,"
4512             . " run fmtutil-sys --byhyphen $dest.\n");
4513      }
4514    }
4515    if ($what =~ m/^language(\.def)?$/i) {
4516      my $dest = $opts{"dest"} ||
4517        "$TEXMFSYSVAR/tex/generic/config/language.def";
4518      $dest .= ".def" if $append_extension;
4519      my $localcfg = $opts{"localcfg"} ||
4520        "$TEXMFLOCAL/tex/generic/config/language-local.def";
4521      debug("$prg: writing language.def data to $dest\n");
4522      TeXLive::TLUtils::create_language_def($localtlpdb, $dest, $localcfg);
4523      if ($opts{"rebuild-sys"}) {
4524        do_cmd_and_check
4525                     ("fmtutil-sys $common_fmtutil_args --byhyphen \"$dest\"");
4526      } else {
4527        info("To make the newly-generated language.def take effect,"
4528             . " run fmtutil-sys --byhyphen $dest.\n");
4529      }
4530    }
4531
4532  } elsif ($what =~ m/^fmtutil$/i) {
4533    tlwarn("$prg: generate fmtutil is no longer needed or supported.\n");
4534    tlwarn("$prg: Please read the documentation of the `fmtutil' program.\n");
4535    tlwarn("$prg: Goodbye.\n");
4536    return $F_ERROR;
4537
4538  } elsif ($what =~ m/^_fmtutil$/i) {
4539    my $dest = $opts{"dest"} || "$TEXMFDIST/web2c/fmtutil.cnf";
4540    debug("$prg: writing new fmtutil.cnf to $dest\n");
4541    TeXLive::TLUtils::create_fmtutil($localtlpdb, $dest);
4542
4543    if ($opts{"rebuild-sys"}) {
4544      do_cmd_and_check("fmtutil-sys $common_fmtutil_args --all");
4545    } else {
4546      info("To make the newly-generated fmtutil.cnf take effect,"
4547           . " run fmtutil-sys --all.\n");
4548    }
4549
4550  } elsif ($what =~ m/^updmap$/i) {
4551    tlwarn("$prg: generate updmap is no longer needed or supported.\n");
4552    tlwarn("$prg: Please read the documentation of the `updmap' program.\n");
4553    tlwarn("$prg: Goodbye.\n");
4554    return $F_ERROR;
4555
4556  } elsif ($what =~ m/^_updmap$/i) {
4557    my $dest = $opts{"dest"} || "$TEXMFDIST/web2c/updmap.cfg";
4558    debug("$prg: writing new updmap.cfg to $dest\n");
4559    TeXLive::TLUtils::create_updmap($localtlpdb, $dest);
4560
4561    if ($opts{"rebuild-sys"}) {
4562      do_cmd_and_check("updmap-sys");
4563    } else {
4564      info("To make the newly-generated updmap.cfg take effect,"
4565           . " run updmap-sys.\n");
4566    }
4567
4568  } else {
4569    tlwarn("$prg: Unknown option for generate: $what; try --help if you need it.\n");
4570    return $F_ERROR;
4571  }
4572
4573  return $F_OK;
4574}
4575
4576
4577#  GUI
4578#
4579sub action_gui {
4580  eval { require Tk; };
4581  if ($@) {
4582    # that didn't work out, give some usefull error message and stop
4583    my $tkmissing = 0;
4584    if ($@ =~ /^Can\'t locate Tk\.pm/) {
4585      $tkmissing = 1;
4586    }
4587    if ($tkmissing) {
4588      if ($^O=~/^MSWin(32|64)$/i) {
4589        # that should not happen, we are shipping Tk!!
4590        require Win32;
4591        my $msg = "Cannot load Tk, that should not happen as we ship it!\nHow did you start tlmgrgui??\n(Error message: $@)\n";
4592        Win32::MsgBox($msg, 1|Win32::MB_ICONSTOP(), "Warning");
4593      } else {
4594        printf STDERR "
4595$prg: Cannot load Tk, thus the GUI cannot be started!
4596The Perl/Tk module is not shipped with the TeX Live installation.
4597You have to install it to get the tlmgr GUI working.
4598(INC = @INC)
4599
4600See http://tug.org/texlive/distro.html#perltk for more details.
4601Goodbye.
4602";
4603      }
4604    } else {
4605      printf STDERR "$prg: unexpected problem loading Tk: $@\n";
4606    }
4607    exit 1;
4608  }
4609
4610  # now check that we can actually create a top level window,
4611  # on darwin the X server might not be started, or on unix we are working
4612  # on a console, or whatever.
4613  eval { my $foo = Tk::MainWindow->new; $foo->destroy; };
4614  if ($@) {
4615    printf STDERR "perl/Tk unusable, cannot create main windows.
4616That could be a consequence of not having X Windows installed or started!
4617Error message from creating MainWindow:
4618  $@
4619";
4620    exit 1;
4621  }
4622
4623  # be sure that sub actions do *not* finish
4624  $::gui_mode = 1;
4625  # also unset the $opts{"gui"} to make recursive calls to action_* not starting
4626  # another GUI instance (or better trying to ...)
4627  $opts{"gui"} = 0;
4628
4629  require("tlmgrgui.pl");
4630  # should not be reached
4631  exit(1);
4632}
4633
4634
4635#  UNINSTALL
4636#
4637sub action_uninstall {
4638  if (win32()) {
4639    printf STDERR "Please use \"Add/Remove Programs\" from the Control Panel to removing TeX Live!\n";
4640    return ($F_ERROR);
4641  }
4642  return if !check_on_writable();
4643  my $force = defined($opts{"force"}) ? $opts{"force"} : 0;
4644  if (!$force) {
4645    print("If you answer yes here the whole TeX Live installation will be removed!\n");
4646    print "Remove TeX Live (y/N): ";
4647    my $yesno = <STDIN>;
4648    if ($yesno !~ m/^y(es)?$/i) {
4649      print "Ok, cancelling the removal!\n";
4650      return ($F_OK | $F_NOPOSTACTION);
4651    }
4652  }
4653  print ("Ok, removing the whole installation:\n");
4654  init_local_db();
4655  TeXLive::TLUtils::remove_symlinks($localtlpdb->root,
4656    $localtlpdb->platform(),
4657    $localtlpdb->option("sys_bin"),
4658    $localtlpdb->option("sys_man"),
4659    $localtlpdb->option("sys_info"));
4660  # now do remove the rest
4661  system("rm", "-rf", "$Master/texmf-dist");
4662  system("rm", "-rf", "$Master/texmf-doc");
4663  system("rm", "-rf", "$Master/texmf-var");
4664  system("rm", "-rf", "$Master/tlpkg");
4665  system("rm", "-rf", "$Master/bin");
4666  system("rm", "-rf", "$Master/readme-html.dir");
4667  system("rm", "-rf", "$Master/readme-txt.dir");
4668  for my $f (qw/doc.html index.html LICENSE.CTAN LICENSE.TL README
4669                README.usergroups release-texlive.txt texmf.cnf/) {
4670    system("rm", "-f", "$Master/$f");
4671  }
4672  if (-d "$Master/temp") {
4673    system("rmdir", "--ignore-fail-on-non-empty", "$Master/temp");
4674  }
4675  unlink("$Master/install-tl.log");
4676  # should we do that????
4677  system("rm", "-rf", "$Master/texmf-config");
4678  system("rmdir", "--ignore-fail-on-non-empty", "$Master");
4679}
4680
4681
4682#  RECREATE-TLPDB
4683#
4684sub action_recreate_tlpdb {
4685  return if !check_on_writable();
4686  my $tlpdb = TeXLive::TLPDB->new;
4687  $tlpdb->root($Master);
4688  my $inst = TeXLive::TLPOBJ->new;
4689  $inst->name("00texlive.installation");
4690  $inst->category("TLCore");
4691  my @deps;
4692  # options are done further down with $tlpdb->reset_options()
4693  #for my $k (keys %TeXLive::TLConfig::TLPDBOptions) {
4694  # push @deps, "opt_$k:" . $TeXLive::TLConfig::TLPDBOptions{k}->[1];
4695  #}
4696  # find list of available archs
4697  my @archs;
4698  opendir (DIR, "$Master/bin") || die "opendir($Master/bin) failed: $!";
4699  my @dirents = readdir (DIR);
4700  closedir (DIR) || warn "closedir($Master/bin) failed: $!";
4701  for my $dirent (@dirents) {
4702    next if $dirent eq ".";
4703    next if $dirent eq "..";
4704    next unless -d "$Master/bin/$dirent";
4705    if (-r "$Master/bin/$dirent/kpsewhich" || -r "$Master/bin/$dirent/kpsewhich.exe") {
4706      push @archs, $dirent;
4707      debug("Skipping directory $Master/bin/$dirent, no kpsewhich there\n");
4708    }
4709  }
4710  push @deps, "setting_available_architectures:" . join(" ",@archs);
4711  # we have to find out the default arch
4712  # if there is only one dir in $Master/bin then we are settled,
4713  # otherwise we expect the user to pass a correct arch string
4714  if (!TeXLive::TLUtils::member(TeXLive::TLUtils::platform(), @archs)) {
4715    # hmm that is bad, the platform as detected is not in the list
4716    # of installed platforms, so the option --arch has to be given
4717    # if only one is installed use that one
4718    if ($#archs == 0) {
4719      # only one arch available, fine, use it as default
4720      push @deps, "setting_platform:$archs[0]";
4721    } else {
4722      if (defined($opts{"platform"})) {
4723        if (member($opts{"platform"}, @archs)) {
4724          push @deps, "setting_platform:" . $opts{"platform"};
4725        } else {
4726          tlwarn("The platform you passed in with --platform is not present in $Master/bin\n");
4727          tlwarn("Please specify one of the available ones: @archs\n");
4728          exit(1);
4729        }
4730      } else {
4731        tlwarn("More than one platform available: @archs\n");
4732        tlwarn("Please pass one as the default you are running on with --platform=...\n");
4733        exit(1);
4734      }
4735    }
4736  }
4737  $inst->depends(@deps);
4738  # now we have all the stuff for 00texlive.installation done
4739  $tlpdb->add_tlpobj($inst);
4740  # reset the options to default values
4741  $tlpdb->add_default_options();
4742  # check for location == _MASTER_
4743  if ($tlpdb->option("location") eq "__MASTER__") {
4744    $tlpdb->option("location", $TeXLive::TLConfig::TeXLiveURL);
4745  }
4746  # add the other stuff in $Master/tlpkg/tlpobj/*.tlpobj
4747  # we can ignore *.{source,doc}.tlpobj because they are already
4748  # included in the *.tlpobj parent one at install time
4749  # (TODO: we should actually REMOVE the *.{source,doc}.tlpobj files
4750  #        at package install time)
4751  opendir (DIR, "$Master/tlpkg/tlpobj") or die "opendir($Master/tlpkg/tlpobj) failed: $!";
4752  my @tlps = readdir(DIR);
4753  closedir (DIR) || warn "closedir($Master/tlpkg/tlpobj) failed: $!";
4754  for my $t (@tlps) {
4755    next if -d $t; # also does . and ..
4756    next if ($t !~ m/\.tlpobj$/i);
4757    # ignore .source and .doc tlpobjs
4758    next if ($t =~ m/\.(source|doc)\.tlpobj$/i);
4759    my $tlp = TeXLive::TLPOBJ->new;
4760    $tlp->from_file("$Master/tlpkg/tlpobj/$t");
4761    $tlpdb->add_tlpobj($tlp);
4762  }
4763  # writeout the re-created tlpdb to stdout
4764  $tlpdb->writeout;
4765  return;
4766}
4767
4768#  CHECK
4769#
4770sub init_tltree {
4771  my ($svn) = @_;
4772
4773  # if we are on W32, die (no find).
4774  my $arch = $localtlpdb->platform();
4775  if ($arch eq "win32") {
4776    tldie("$prg: sorry, cannot check this on Windows.\n");
4777  }
4778
4779  my $Master = $localtlpdb->root;
4780  my $tltree = TeXLive::TLTREE->new ("svnroot" => $Master);
4781  if ($svn) {
4782    debug("Initializine TLTREE from svn\n");
4783    $tltree->init_from_svn;
4784  } else {
4785    debug("Initializine TLTREE from find\n");
4786    $tltree->init_from_files;
4787  }
4788  return($tltree);
4789}
4790
4791sub action_check {
4792  my $svn = defined($opts{"use-svn"}) ? $opts{"use-svn"} : 0;
4793  my $what = shift @ARGV;
4794  $what || ($what = "all");
4795  init_local_db();
4796  my $ret = 0;
4797  if ($what =~ m/^all/i) {
4798    my $tltree = init_tltree($svn);
4799    print "Running check files:\n";
4800    $ret |= check_files($tltree);
4801    print "Running check depends:\n";
4802    $ret |= check_depends();
4803    print "Running check executes:\n";
4804    $ret |= check_executes();
4805    print "Running check runfiles:\n";
4806    $ret |= check_runfiles();
4807  } elsif ($what =~ m/^files/i) {
4808    my $tltree = init_tltree($svn);
4809    $ret |= check_files($tltree);
4810  } elsif ($what =~ m/^collections/i) {
4811    tlwarn("the \"collections\" check is replaced by the \"depends\" check.\n");
4812    $ret |= check_depends();
4813  } elsif ($what =~ m/^depends/i) {
4814    $ret |= check_depends();
4815  } elsif ($what =~ m/^runfiles/i) {
4816    $ret |= check_runfiles();
4817  } elsif ($what =~ m/^executes/i) {
4818    $ret |= check_executes();
4819  } else {
4820    print "No idea how to check that: $what\n";
4821  }
4822  if ($ret) {
4823    return ($F_ERROR);
4824  } else {
4825    return ($F_OK);
4826  }
4827}
4828
4829# check file coverage in both direction.
4830#
4831sub check_files {
4832  my $tltree = shift;
4833  my $ret = 0;
4834  my %filetopacks;
4835  my $Master = $localtlpdb->root;
4836  debug("Collecting all files of all packages\n");
4837  for my $p ($localtlpdb->list_packages()) {
4838    # ignore files in the installer
4839    next if ($p eq "00texlive.installer");
4840    my $tlp = $localtlpdb->get_package($p);
4841    my @files = $tlp->all_files;
4842    if ($tlp->relocated) {
4843      for (@files) { s:^$RelocPrefix/:$RelocTree/:; }
4844    }
4845    for my $f (@files) {
4846      push @{$filetopacks{$f}}, $p;
4847    }
4848  }
4849  my @multiple = ();
4850  my @missing = ();
4851  debug("Checking for occurrences and existence of all files\n");
4852  for (keys %filetopacks) {
4853    push @missing, $_ if (! -r "$Master/$_");
4854    my @foo = @{$filetopacks{$_}};
4855    if ($#foo < 0) {
4856      warn "that shouldn't happen: $_\n";
4857    } elsif ($#foo > 0) {
4858      push @multiple, $_;
4859    }
4860  }
4861  if ($#multiple >= 0) {
4862    $ret = 1;
4863    print "\f Multiple included files (relative to $Master):\n";
4864    for (sort @multiple) {
4865      my @foo = @{$filetopacks{$_}};
4866      print "  $_ (@foo)\n";
4867    }
4868    print "\n";
4869  }
4870  if ($#missing >= 0) {
4871    $ret = 1;
4872    print "\f Files mentioned in tlpdb but missing (relative to $Master):\n";
4873    for my $m (@missing) {
4874      print "\t$m\n";
4875    }
4876    print "\n";
4877  }
4878
4879  # check that all files in the trees are covered, along with
4880  # 00texlive.image, q.v.  The ones here are not included in the
4881  # archival source/ tarball;
4882  my @IgnorePatterns = qw!
4883    source/
4884    texmf-dist/ls-R$ texmf-doc/ls-R$
4885    tlpkg/archive tlpkg/backups tlpkg/installer
4886    tlpkg/texlive.tlpdb tlpkg/tlpobj tlpkg/texlive.profile
4887    texmf-config/ texmf-var/
4888    texmf.cnf texmfcnf.lua install-tl.log
4889  !;
4890  my %tltreefiles = %{$tltree->{'_allfiles'}};
4891  my @tlpdbfiles = keys %filetopacks;
4892  my @nohit;
4893  for my $f (keys %tltreefiles) {
4894    # if it is mentioned in the tlpdb or is ignored it is considered
4895    # as covered, thus, otherwise we push it onto the nothit list
4896    if (!defined($filetopacks{$f})) {
4897      my $ignored = 0;
4898      for my $p (@IgnorePatterns) {
4899        if ($f =~ m/^$p/) {
4900          $ignored = 1;
4901          last;
4902        }
4903      }
4904      if (!$ignored) {
4905        push @nohit, $f;
4906      }
4907    }
4908  }
4909  if (@nohit) {
4910    $ret = 1;
4911    print "\f Files present but not covered (relative to $Master):\n";
4912    for my $f (sort @nohit) {
4913      print "  $f\n";
4914    }
4915    print "\n";
4916  }
4917  return($ret);
4918}
4919
4920# Check for runtime files with the same name but different contents.
4921#
4922sub check_runfiles {
4923  my $Master = $localtlpdb->root;
4924
4925  # build a list of all runtime files associated to 'normal' packages
4926  (my $non_normal = `ls "$Master/bin"`) =~ s/\n/\$|/g; # binaries
4927  $non_normal .= '^0+texlive|^bin-|^collection-|^scheme-|^texlive-|^texworks';
4928  $non_normal .= '|^pgf$';  # has lots of intentionally duplicated .lua
4929  my @runtime_files = ();
4930  #
4931  foreach my $tlpn ($localtlpdb->list_packages) {
4932    next if ($tlpn =~ /$non_normal/);
4933    #
4934    my $tlp = $localtlpdb->get_package($tlpn);
4935    my @files = $tlp->runfiles;
4936    if ($tlp->relocated) {
4937      for (@files) {
4938        s!^$TeXLive::TLConfig::RelocPrefix/!$TeXLive::TLConfig::RelocTree/!;
4939      }
4940    }
4941    # special case for koma-script where doc/src files are in runfiles section
4942    if ($tlpn eq "koma-script") {
4943      @files = grep {!m;^texmf-dist/source/latex/koma-script/;} @files;
4944      @files = grep {!m;^texmf-dist/doc/latex/koma-script/;} @files;
4945    }
4946    push @runtime_files, @files;
4947  }
4948
4949  # build the duplicates list.
4950  my @duplicates = (""); # just to use $duplicates[-1] freely
4951  my $prev = "";
4952  foreach my $f (sort map { TeXLive::TLUtils::basename($_) } @runtime_files) {
4953    push (@duplicates, $f) if (($f eq $prev) and not ($f eq $duplicates[-1]));
4954    $prev = $f;
4955  }
4956  shift @duplicates; # get rid of the fake 1st value
4957
4958  # check if duplicates are different files.
4959  foreach my $f (@duplicates) {
4960    # assume tex4ht, xdy, afm stuff is ok, and don't worry about
4961    # Changes, README et al.  Other per-format versions.
4962    next if $f =~ /\.(afm|cfg|dll|exe|4hf|htf|xdy)$/;
4963    next if $f
4964      =~ /^((czech|slovak)\.sty
4965            |Changes
4966            |Makefile
4967            |README
4968            |cid2code\.txt
4969            |etex\.src
4970            |kinsoku\.tex
4971            |language\.dat
4972            |language\.def
4973            |local\.mf
4974            |m-tex4ht\.tex
4975            |metatex\.tex
4976            |.*-noEmbed\.map
4977            |ps2mfbas\.mf
4978            |pstricks\.con
4979            |sample\.bib
4980            |tex4ht\.env
4981            |test\.mf
4982            |texutil\.rb
4983            |tlmgrgui\.pl
4984           )$/x;
4985    #
4986    my @copies = grep (/\/$f$/, @runtime_files);
4987    # map files can be duplicated between (but not within) formats.
4988    if ($f =~ /\.map$/) {
4989      my $need_check = 0;
4990      my $prev_dir = "";
4991      my @cop = @copies; # don't break the outside list
4992      map { s#^texmf-dist/fonts/map/(.*?)/.*#$1# } @cop;
4993      foreach my $dir (sort @cop ) {
4994        last if ($need_check = ($dir eq $prev_dir));
4995        $prev_dir = $dir;
4996      }
4997      next unless $need_check;
4998    }
4999    # if all copies are identical, ok, else, complain
5000    my $diff = 0;
5001    for (my $i = 1; $i < scalar(@copies); $i++) {
5002      if ($diff = tlcmp("$Master/$copies[$i-1]", "$Master/$copies[$i]")) {
5003        print "# $f\ndiff $Master/$copies[$i-1] $Master/$copies[$i]\n";
5004        last;
5005      }
5006    }
5007    print join ("\n", @copies), "\n" if ($diff and (scalar(@copies) > 2));
5008  }
5009}
5010
5011# check executes
5012#
5013sub check_executes {
5014  my $Master = $localtlpdb->root;
5015  my (%maps,%langcodes,%fmtlines);
5016  for my $pkg ($localtlpdb->list_packages) {
5017    for my $e ($localtlpdb->get_package($pkg)->executes) {
5018      if ($e =~ m/add(Mixed|Kanji)?Map\s+(.*)$/) {
5019        my $foo = $2;
5020        chomp($foo);
5021        if ($foo !~ m/\@kanjiEmbed@/) {
5022          push @{$maps{$foo}}, $pkg;
5023        }
5024      } elsif ($e =~ m/AddFormat\s+(.*)$/) {
5025        my $foo = $1;
5026        chomp($foo);
5027        push @{$fmtlines{$foo}}, $pkg;
5028      } elsif ($e =~ m/AddHyphen\s+.*\s+file=(\S+)(\s*$|\s+.*)/) {
5029        my $foo = $1;
5030        chomp($foo);
5031        push @{$langcodes{$foo}}, $pkg;
5032      } else {
5033        warn "$pkg: unmatched execute: $e\n";
5034      }
5035    }
5036  }
5037  my %badmaps;
5038  foreach my $mf (keys %maps) {
5039    my @pkgsfound = @{$maps{$mf}};
5040    if ($#pkgsfound > 0) {
5041      tlwarn ("map file $mf is referenced in the executes of @pkgsfound\n");
5042    } else {
5043      # less then 1 occurrences is not possible, so we have only one
5044      # package that contains the reference to that map file
5045      my $pkgfoundexecute = $pkgsfound[0];
5046      my @found = $localtlpdb->find_file($mf);
5047      if ($#found < 0) {
5048        $badmaps{$mf} = $maps{$mf};
5049      } elsif ($#found > 0) {
5050        # we want to check for multiple inclusions
5051        my %mapfn;
5052        foreach my $foo (@found) {
5053          $foo =~ m/^(.*):(.*)$/;
5054          push @{$mapfn{$2}}, $1;
5055        }
5056        foreach my $k (keys %mapfn) {
5057          my @bla = @{$mapfn{$k}};
5058          if ($#bla > 0) {
5059            tlwarn ("map file $mf occurs multiple times (in pkgs: @bla)!\n");
5060          }
5061        }
5062      } else {
5063        # only one occurrence found, we check that the map is also contained
5064        # in the right package!
5065        my ($pkgcontained) = ( $found[0] =~ m/^(.*):.*$/ );
5066        if ($pkgcontained ne $pkgfoundexecute) {
5067          tlwarn("map file $mf: execute in $pkgfoundexecute, map file in $pkgcontained\n");
5068        }
5069      }
5070    }
5071  }
5072  if (keys %badmaps) {
5073    tlwarn("$prg: mentioned map file not present in any package:\n");
5074    foreach my $mf (keys %badmaps) {
5075      print "\t$mf (execute in @{$badmaps{$mf}})\n";
5076    }
5077  }
5078  my %badhyphcodes;
5079  my %problemhyphen;
5080  foreach my $lc (keys %langcodes) {
5081    next if ($lc eq "zerohyph.tex");
5082    my @found = $localtlpdb->find_file("texmf-dist/tex/generic/hyph-utf8/loadhyph/$lc");
5083    if ($#found < 0) {
5084      # try again this time search all packages
5085      my @found = $localtlpdb->find_file("$lc");
5086      if ($#found < 0) {
5087        $badhyphcodes{$lc} = $langcodes{$lc};
5088      } else {
5089        $problemhyphen{$lc} = [ @found ];
5090      }
5091    }
5092  }
5093  if (keys %badhyphcodes) {
5094    print "\f mentioned hyphen loaders without file:\n";
5095    foreach my $mf (keys %badhyphcodes) {
5096      print "\t$mf (execute in @{$badhyphcodes{$mf}})\n";
5097    }
5098  }
5099  # disable the echoing of problematic hyphens
5100  #if (keys %problemhyphen) {
5101  #  print "hyphen files with possible problematic location:\n";
5102  #  foreach my $mf (keys %problemhyphen) {
5103  #    print "\t$mf (@{$problemhyphen{$mf}})\n";
5104  #  }
5105  #}
5106  #
5107  # what should be checked for the executes? we could check
5108  # - the existence of the engine in bin/i386-linux or all $arch
5109  # - the existence of the format name link/bat
5110  # - parse the options parameter and check for the inifile
5111  # - rework the format definition that we have inifile=pdflatex.ini
5112  #   isn't the * unnecessary?
5113  my %missingbins;
5114  my %missingengines;
5115  my %missinginis;
5116  for (keys %fmtlines) {
5117    my %r = TeXLive::TLUtils::parse_AddFormat_line("$_");
5118    if (defined($r{"error"})) {
5119      die "$r{'error'}, parsing $_, package(s) @{$fmtlines{$_}}";
5120    }
5121    my $opt = $r{"options"};
5122    my $engine = $r{"engine"};
5123    my $name = $r{"name"};
5124    my $mode = $r{"mode"};
5125    # special case for cont-en ...
5126    next if ($name eq "cont-en");
5127    # we check that the name exist in bin/$arch
5128    my @archs_to_check = $localtlpdb->available_architectures;
5129    if ($engine eq "luajittex") {
5130      # luajittex is special since it is not available on all architectures
5131      # due to inherent reasons (machine code)
5132      # We do not want to have error messages here, so we do the following:
5133      # * if tlpkg/tlpsrc/luatex.tlpsrc is available, then load it
5134      #   and filter away those archs that are excluded with f/!...
5135      # * if tlpkg/tlpsrc/luatex.tlpsrc is *not* available (user installation)
5136      #   we just ignore it completely.
5137      my $tlpsrc_file = $localtlpdb->root . "/tlpkg/tlpsrc/luatex.tlpsrc";
5138      if (-r $tlpsrc_file) {
5139        require TeXLive::TLPSRC;
5140        my $tlpsrc = new TeXLive::TLPSRC;
5141        $tlpsrc->from_file($tlpsrc_file);
5142        my @binpats = $tlpsrc->binpatterns;
5143        my @negarchs;
5144        for my $p (@binpats) {
5145          if ($p =~ m%^(\w+)/(!?[-_a-z0-9,]+)\s+(.*)$%) {
5146            my $pt = $1;
5147            my $aa = $2;
5148            my $pr = $3;
5149            if ($pr =~ m!/luajittex$!) {
5150              # bingo, get the negative patterns
5151              if ($aa =~ m/^!(.*)$/) {
5152                @negarchs = split(/,/,$1);
5153              }
5154            }
5155          }
5156        }
5157        my %foo;
5158        for my $a (@archs_to_check) {
5159          $foo{$a} = 1;
5160        }
5161        for my $a (@negarchs) {
5162          delete $foo{$a} if defined($foo{$a});
5163        }
5164        @archs_to_check = keys %foo;
5165      } else {
5166        @archs_to_check = ();
5167      }
5168    }
5169    for my $a (@archs_to_check) {
5170      my $f = "$Master/bin/$a/$name";
5171      if (!check_file($a, $f)) {
5172        push @{$missingbins{$_}}, "bin/$a/$name" if $mode;
5173      }
5174      if (!check_file($a, "$Master/bin/$a/$engine")) {
5175        push @{$missingengines{$_}}, "bin/$a/$engine" if $mode;
5176      }
5177    }
5178    # check for the existence of the .ini file
5179    # by using the last word in the options value
5180    my $inifile = $opt;
5181    # $inifile now contains "bla bla bla *file.ini"
5182    # strip initial and trailing "
5183    $inifile =~ s/^"(.*)"$/$1/;
5184    # remove everything before the last space
5185    $inifile =~ s/^.* ([^ ]*)$/$1/;
5186    # remove the optional leading *
5187    $inifile =~ s/^\*//;
5188    my @found = $localtlpdb->find_file("$inifile");
5189    if ($#found < 0) {
5190      $missinginis{$_} = "$inifile";
5191    }
5192  }
5193  if (keys %missinginis) {
5194    print "\f mentioned ini files that cannot be found:\n";
5195    for my $i (keys %missinginis) {
5196      print "\t $missinginis{$i} (execute: $i)\n";
5197    }
5198  }
5199  if (keys %missingengines) {
5200    print "\f mentioned engine files that cannot be found:\n";
5201    for my $i (keys %missingengines) {
5202      print "\t @{$missingengines{$i}}\n";
5203    }
5204  }
5205  if (keys %missingbins) {
5206    print "\f mentioned bin files that cannot be found:\n";
5207    for my $i (keys %missingbins) {
5208      print "\t @{$missingbins{$i}}\n";
5209    }
5210  }
5211}
5212
5213sub check_file {
5214  my ($a, $f) = @_;
5215  if (-r $f) {
5216    return 1;
5217  } else {
5218    # not -r, so check for the extensions .bat and .exe on windoze-ish.
5219    if ($a =~ /win[0-9]|.*-cygwin/) {
5220      if (-r "$f.exe" || -r "$f.bat") {
5221        return 1;
5222      }
5223    }
5224    return 0;
5225  }
5226}
5227
5228# check depends
5229#
5230sub check_depends {
5231  my $ret = 0;
5232  my $Master = $localtlpdb->root;
5233  my %presentpkg;
5234  for my $pkg ($localtlpdb->list_packages) {
5235    $presentpkg{$pkg} = 1;
5236  }
5237  # list of collections.
5238  my @colls = $localtlpdb->collections;
5239  my @coll_deps
5240    = $localtlpdb->expand_dependencies("-no-collections", $localtlpdb, @colls);
5241  my %coll_deps;
5242  @coll_deps{@coll_deps} = ();  # initialize hash with keys from list
5243
5244  my (%wrong_dep, @no_dep);
5245  for my $pkg ($localtlpdb->list_packages) {
5246    # do not check any package starting with 00texlive.
5247    next if $pkg =~ m/^00texlive/;
5248
5249    # For each package, check that it is a dependency of some collection.
5250    if (! exists $coll_deps{$pkg}) {
5251      # Except that schemes and our ugly Windows packages are ok.
5252      push (@no_dep, $pkg) unless $pkg =~/^scheme-|\.win32$/;
5253    }
5254
5255    # For each dependency, check that we have a package.
5256    for my $d ($localtlpdb->get_package($pkg)->depends) {
5257      next if ($d =~ m/\.ARCH$/);
5258      if (!defined($presentpkg{$d})) {
5259        push (@{$wrong_dep{$d}}, $pkg);
5260      }
5261    }
5262  }
5263
5264  # check whether packages are included more than one time in a collection
5265  my %pkg2mother;
5266  for my $c (@colls) {
5267    for my $p ($localtlpdb->get_package($c)->depends) {
5268      next if ($p =~ /^collection-/);
5269      push @{$pkg2mother{$p}}, $c;
5270    }
5271  }
5272  my @double_inc_pkgs;
5273  for my $k (keys %pkg2mother) {
5274    if (@{$pkg2mother{$k}} > 1) {
5275      push @double_inc_pkgs, $k;
5276    }
5277  }
5278
5279  if (keys %wrong_dep) {
5280    $ret++;
5281    print "\f DEPENDS WITHOUT PACKAGES:\n";
5282    for my $d (keys %wrong_dep) {
5283      print "$d in: @{$wrong_dep{$d}}\n";
5284    }
5285  }
5286
5287  if (@no_dep) {
5288    $ret++;
5289    print "\f PACKAGES NOT IN ANY COLLECTION: @no_dep\n";
5290  }
5291
5292  if (@double_inc_pkgs) {
5293    $ret++;
5294    print "\f PACKAGES IN MORE THAN ONE COLLECTION: @double_inc_pkgs\n";
5295  }
5296
5297  return $ret;
5298}
5299
5300#  POSTACTION
5301# explictly run the various post actions, e.g.,
5302# on a client system or overriding global settings.
5303#
5304# tlmgr postaction [--w32mode=user|admin] [--fileassocmode=1|2] [--all]
5305#    [install|remove] [shortcut|fileassoc|script] [<pkg>...]
5306
5307sub action_postaction {
5308  my $how = shift @ARGV;
5309  if (!defined($how) || ($how !~ m/^(install|remove)$/i)) {
5310    tlwarn("action postaction needs at least two arguments, first being either 'install' or 'remove'\n");
5311    return;
5312  }
5313  my $type = shift @ARGV;
5314  my $badtype = 0;
5315  if (!defined($type)) {
5316    $badtype = 1;
5317  } elsif ($type !~ m/^(shortcut|fileassoc|script)$/i) {
5318    $badtype = 1;
5319  }
5320  if ($badtype) {
5321    tlwarn("action postaction needs as second argument one from 'shortcut', 'fileassoc', 'script'\n");
5322    return;
5323  }
5324  if (win32()) {
5325    if ($opts{"w32mode"}) {
5326      if ($opts{"w32mode"} eq "user") {
5327        if (TeXLive::TLWinGoo::admin()) {
5328          debug("Switching to user mode on user request\n");
5329          TeXLive::TLWinGoo::non_admin();
5330        }
5331        # in user mode we also switch TEXMFSYSVAR to TEXMFVAR since
5332        # xetex.pl, but maybe others are writing to TEXMFSYSVAR
5333        chomp($ENV{"TEXMFSYSVAR"} = `kpsewhich -var-value TEXMFVAR`);
5334      } elsif ($opts{"w32mode"} eq "admin") {
5335        if (!TeXLive::TLWinGoo::admin()) {
5336          tlwarn("You don't have the permissions for --w32mode=admin\n");
5337          return;
5338        }
5339      } else {
5340        tlwarn("action postaction --w32mode can only be 'admin' or 'user'\n");
5341        return;
5342      }
5343    }
5344  }
5345  my @todo;
5346  if ($opts{"all"}) {
5347    init_local_db();
5348    @todo = $localtlpdb->list_packages;
5349  } else {
5350    if ($#ARGV < 0) {
5351      tlwarn("action postaction: need either --all or a list of packages\n");
5352      return;
5353    }
5354    init_local_db();
5355    @todo = @ARGV;
5356    @todo = $localtlpdb->expand_dependencies("-only-arch", $localtlpdb, @todo);
5357  }
5358  if ($type =~ m/^shortcut$/i) {
5359    if (!win32()) {
5360      tlwarn("action postaction shortcut only works on windows.\n");
5361      return;
5362    }
5363    for my $p (@todo) {
5364      my $tlp = $localtlpdb->get_package($p);
5365      if (!defined($tlp)) {
5366        tlwarn("$p is not installed, ignoring it.\n");
5367      } else {
5368        # run all shortcut actions, desktop and menu integration
5369        TeXLive::TLUtils::do_postaction($how, $tlp, 0, 1, 1, 0);
5370      }
5371    }
5372  } elsif ($type =~ m/^fileassoc$/i) {
5373    if (!win32()) {
5374      tlwarn("action postaction fileassoc only works on windows.\n");
5375      return;
5376    }
5377    my $fa = $localtlpdb->option("file_assocs");
5378    if ($opts{"fileassocmode"}) {
5379      if ($opts{"fileassocmode"} < 1 || $opts{"fileassocmode"} > 2) {
5380        tlwarn("action postaction: value of --fileassocmode can only be 1 or 2\n");
5381        return;
5382      }
5383      $fa = $opts{"fileassocmode"};
5384    }
5385    for my $p (@todo) {
5386      my $tlp = $localtlpdb->get_package($p);
5387      if (!defined($tlp)) {
5388        tlwarn("$p is not installed, ignoring it.\n");
5389      } else {
5390        TeXLive::TLUtils::do_postaction($how, $tlp, $fa, 0, 0, 0);
5391      }
5392    }
5393  } elsif ($type =~ m/^script$/i) {
5394    for my $p (@todo) {
5395      my $tlp = $localtlpdb->get_package($p);
5396      if (!defined($tlp)) {
5397        tlwarn("$p is not installed, ignoring it.\n");
5398      } else {
5399        TeXLive::TLUtils::do_postaction($how, $tlp, 0, 0, 0, 1);
5400      }
5401    }
5402  } else {
5403    tlwarn("action postaction needs one of 'shortcut', 'fileassoc', 'script'\n");
5404    return;
5405  }
5406}
5407
5408#  INIT USER TREE
5409# sets up the user tree for tlmgr in user mode
5410sub action_init_usertree {
5411  # init_local_db but do not die if localtlpdb is not found!
5412  init_local_db(2);
5413  my $tlpdb = TeXLive::TLPDB->new;
5414  my $usertree;
5415  if ($opts{"usertree"}) {
5416    $usertree = $opts{"usertree"};
5417  } else {
5418    chomp($usertree = `kpsewhich -var-value TEXMFHOME`);
5419  }
5420  if (-r "$usertree/$InfraLocation/$DatabaseName") {
5421    tldie("$prg: user mode database already set up in\n$prg:   $usertree/$InfraLocation/$DatabaseName\n$prg: not overwriting it.\n");
5422  }
5423  $tlpdb->root($usertree);
5424  # copy values from main installation over
5425  my $maininsttlp;
5426  my $inst;
5427  if (defined($localtlpdb)) {
5428    $maininsttlp = $localtlpdb->get_package("00texlive.installation");
5429    $inst = $maininsttlp->copy;
5430  } else {
5431    $inst = TeXLive::TLPOBJ->new;
5432    $inst->name("00texlive.installation");
5433    $inst->category("TLCore");
5434  }
5435  $tlpdb->add_tlpobj($inst);
5436  # remove all available architectures
5437  $tlpdb->setting( "available_architectures", "");
5438  $tlpdb->option( "location", $TeXLive::TLConfig::TeXLiveURL);
5439  # specify that we are in user mode
5440  $tlpdb->setting( "usertree", 1 );
5441  $tlpdb->save;
5442  #
5443  # we need to create web2c dir for TLMedia to succeed setting up
5444  # and for tlmgr.log file
5445  mkdir ("$usertree/web2c");
5446  mkdir ("$usertree/tlpkg/tlpobj");
5447}
5448
5449#  CONF
5450# tries to mimic texconfig conf but can also set values for both tlmgr
5451# and texmf conf files.
5452#
5453sub action_conf {
5454  my $arg = shift @ARGV;
5455  if (!defined($arg)) {
5456    texconfig_conf_mimic();
5457    return;
5458  }
5459  if ($arg eq "tlmgr" || $arg eq "texmf" || $arg eq "updmap") {
5460    my ($fn,$cf);
5461    if ($opts{'conffile'}) {
5462      $fn = $opts{'conffile'} ;
5463    }
5464    if ($arg eq "tlmgr") {
5465      chomp (my $TEXMFCONFIG = `kpsewhich -var-value=TEXMFCONFIG`);
5466      $fn || ( $fn = "$TEXMFCONFIG/tlmgr/config" ) ;
5467      $cf = TeXLive::TLConfFile->new($fn, "#", "=");
5468    } elsif ($arg eq "texmf") {
5469      $fn || ( $fn = "$Master/texmf.cnf" ) ;
5470      $cf = TeXLive::TLConfFile->new($fn, "[%#]", "=");
5471    } elsif ($arg eq "updmap") {
5472      $fn || ( chomp ($fn = `kpsewhich updmap.cfg`) ) ;
5473      $cf = TeXLive::TLConfFile->new($fn, '(#|(Mixed)?Map)', ' ');
5474    } else {
5475      die "Should not happen, conf arg=$arg";
5476    }
5477    my ($key,$val) = @ARGV;
5478    if (!defined($key)) {
5479      # show all settings
5480      if ($cf) {
5481        info("$arg configuration values (from $fn):\n");
5482        for my $k ($cf->keys) {
5483          info("$k = " . $cf->value($k) . "\n");
5484        }
5485      } else {
5486        info("$arg config file $fn not present\n");
5487      }
5488    } else {
5489      if (!defined($val)) {
5490        if (defined($opts{'delete'})) {
5491          if (defined($cf->value($key))) {
5492            info("removing setting $arg $key value: " . $cf->value($key) . "from $fn\n");
5493            $cf->delete_key($key);
5494          } else {
5495            info("$arg $key not defined, cannot remove ($fn)\n");
5496          }
5497        } else {
5498          if (defined($cf->value($key))) {
5499            info("$arg $key value: " . $cf->value($key) . " ($fn)\n");
5500          } else {
5501            info("$key not defined in $arg config file ($fn)\n");
5502            if ($arg eq "texmf") {
5503              # not in user-specific file, show anything kpsewhich gives us.
5504              chomp (my $defval = `kpsewhich -var-value $key`);
5505              if ($? != 0) {
5506                info("$arg $key default value is unknown");
5507              } else {
5508                info("$arg $key default value: $defval");
5509              }
5510              info(" (kpsewhich -var-value)\n");
5511            }
5512          }
5513        }
5514      } else {
5515        if (defined($opts{'delete'})) {
5516          warning("$arg --delete and value for key $key given, don't know what to do!\n");
5517        } else {
5518          info("setting $arg $key to $val (in $fn)\n");
5519          $cf->value($key, $val);
5520        }
5521      }
5522    }
5523    if ($cf->is_changed) {
5524      $cf->save;
5525    }
5526  } else {
5527    warn "$prg: unknown conf arg: $arg (try tlmgr or texmf or updmap)\n";
5528  }
5529}
5530
5531# output various values in same form as texconfig conf.
5532sub texconfig_conf_mimic {
5533  my $PATH = $ENV{'PATH'};
5534  info("=========================== version information ==========================\n");
5535  info(give_version());
5536  info("==================== executables found by searching PATH =================\n");
5537  info("PATH: $PATH\n");
5538  for my $cmd (qw/kpsewhich updmap fmtutil tlmgr tex pdftex mktexpk
5539                  dvips dvipdfmx/) {
5540    info("$cmd: " . TeXLive::TLUtils::which($cmd) . "\n");
5541  }
5542  info("=========================== active config files ==========================\n");
5543  for my $m (qw/texmf.cnf updmap.cfg/) {
5544    for my $f (`kpsewhich -all $m`) {
5545      info("$m: $f");
5546    }
5547  }
5548  for my $m (qw/fmtutil.cnf config.ps mktex.cnf pdftexconfig.tex/) {
5549    info("$m: " . `kpsewhich $m`);
5550  }
5551
5552  #tlwarn("missing finding of XDvi, config!\n");
5553
5554  info("============================= font map files =============================\n");
5555  for my $m (qw/psfonts.map pdftex.map ps2pk.map kanjix.map/) {
5556    info("$m: " . `kpsewhich $m`);
5557  }
5558
5559  info("=========================== kpathsea variables ===========================\n");
5560  for my $v (qw/TEXMFMAIN TEXMFDIST TEXMFLOCAL TEXMFSYSVAR TEXMFSYSCONFIG TEXMFVAR TEXMFCONFIG TEXMFHOME VARTEXFONTS TEXMF SYSTEXMF TEXMFDBS WEB2C TEXPSHEADERS TEXCONFIG ENCFONTS TEXFONTMAPS/) {
5561    info("$v=" . `kpsewhich -var-value=$v`);
5562  }
5563
5564  info("==== kpathsea variables from environment only (ok if no output here) ====\n");
5565  my @envVars = qw/
5566    AFMFONTS BIBINPUTS BSTINPUTS CMAPFONTS CWEBINPUTS ENCFONTS GFFONTS
5567    GLYPHFONTS INDEXSTYLE LIGFONTS MFBASES MFINPUTS MFPOOL MFTINPUTS
5568    MISCFONTS MPINPUTS MPMEMS MPPOOL MPSUPPORT OCPINPUTS OFMFONTS
5569    OPENTYPEFONTS OPLFONTS OTPINPUTS OVFFONTS OVPFONTS PDFTEXCONFIG PKFONTS
5570    PSHEADERS SFDFONTS T1FONTS T1INPUTS T42FONTS TEXBIB TEXCONFIG TEXDOCS
5571    TEXFONTMAPS TEXFONTS TEXFORMATS TEXINDEXSTYLE TEXINPUTS TEXMFCNF
5572    TEXMFDBS TEXMFINI TEXMFSCRIPTS TEXPICTS TEXPKS TEXPOOL TEXPSHEADERS
5573    TEXSOURCES TFMFONTS TRFONTS TTFONTS VFFONTS WEB2C WEBINPUTS
5574  /;
5575  for my $v (@envVars) {
5576    if (defined($ENV{$v})) {
5577      info("$v=$ENV{$v}\n");
5578    }
5579  }
5580}
5581
5582
5583# Subroutines galore.
5584#
5585# set global $location variable.
5586#
5587# argument $should_i_die specifies what is requried
5588# to suceed during initialization.
5589#
5590# undef or false: TLPDB needs to be found and initialized, but
5591#                 support programs need not be found
5592# 1             : TLPDB initialized and support programs must work
5593# 2             : not even TLPDB needs to be found
5594# if we cannot read tlpdb, die if arg SHOULD_I_DIE is true.
5595#
5596# if an argument is given and is true init_local_db will die if
5597# setting up of programs failed.
5598#
5599sub init_local_db {
5600  my ($should_i_die) = @_;
5601  defined($should_i_die) or ($should_i_die = 0);
5602  # if the localtlpdb is already defined do simply return here already
5603  # to make sure that the settings in the local tlpdb do not overwrite
5604  # stuff changed via the GUI
5605  return if defined $localtlpdb;
5606  $localtlpdb = TeXLive::TLPDB->new ( root => $::maintree );
5607  if (!defined($localtlpdb)) {
5608    if ($should_i_die == 2) {
5609      return undef;
5610    } else {
5611      die("cannot setup TLPDB in $::maintree");
5612    }
5613  }
5614  # setup the programs, for w32 we need the shipped wget/xz etc, so we
5615  # pass the location of these files to setup_programs.
5616  if (!setup_programs("$Master/tlpkg/installer", $localtlpdb->platform)) {
5617    tlwarn("Couldn't set up the necessary programs.\nInstallation of packages is not supported.\nPlease report to texlive\@tug.org.\n");
5618    if (defined($should_i_die) && $should_i_die) {
5619      return ($F_ERROR);
5620    } else {
5621      tlwarn("Continuing anyway ...\n");
5622      return ($F_WARNING);
5623    }
5624  }
5625  # let cmd line options override the settings in localtlpdb
5626  my $loc = norm_tlpdb_path($localtlpdb->option("location"));
5627  if (defined($loc)) {
5628    $location = $loc;
5629  }
5630  if (defined($opts{"location"})) {
5631    $location = $opts{"location"};
5632  }
5633  if (!defined($location)) {
5634    die("$prg: No installation source found: neither in texlive.tlpdb nor on command line.\n$prg: Please specify one!");
5635  }
5636  if ($location =~ m/^ctan$/i) {
5637    $location = "$TeXLive::TLConfig::TeXLiveURL";
5638  }
5639  # we normalize the path only if it is
5640  # - a url starting with neither http or ftp
5641  # - if we are on Windows, it does not start with Drive:[\/]
5642  if (! ( $location =~ m!^(http|ftp)://!i  ||
5643          (win32() && (!(-e $location) || ($location =~ m!^.:[\\/]!) ) ) ) ) {
5644    # seems to be a local path, try to normalize it
5645    my $testloc = abs_path($location);
5646    # however, if we were given a url, that will get "normalized" to the
5647    # empty string, it not being a path.  Restore the original value if so.
5648    $location = $testloc if $testloc;
5649  }
5650}
5651
5652
5653# initialize the global $remotetlpdb object, or die.
5654# uses the global $location.
5655#
5656sub init_tlmedia_or_die {
5657  my ($ret, $err) = init_tlmedia();
5658  if (!$ret) {
5659    tldie("$prg: $err\n");
5660  }
5661}
5662
5663sub init_tlmedia
5664{
5665  # first check if $location contains multiple locations
5666  # in this case we go to virtual mode
5667  #my %repos = repository_to_array($localtlpdb->option("location"));
5668  my %repos = repository_to_array($location);
5669  my @tags = keys %repos;
5670  # if we have only one repo, but this one contains a name tag #....
5671  # then we remove it and save the local tlpdb
5672  if ($#tags == 0 && ($location =~ m/#/)) {
5673    $location = $repos{$tags[0]};
5674    $localtlpdb->option("location", $location);
5675    $localtlpdb->save;
5676    %repos = repository_to_array($location);
5677  }
5678  # check if we are only one tag/repo
5679  if ($#tags == 0) {
5680    # go to normal mode
5681    return _init_tlmedia();
5682  }
5683  # we are still here, so we have more tags
5684
5685  # check that there is a main repository
5686  if (!TeXLive::TLUtils::member('main', @tags)) {
5687    return(0, "Cannot find main repository, you have to tag one as main!");
5688  }
5689
5690  # TODO TODO
5691  # - abstract the set up of a single media tlpdb
5692  # - make clear how to check for a already loaded remotetlpdb
5693  $remotetlpdb = TeXLive::TLPDB->new();
5694  $remotetlpdb->make_virtual;
5695
5696  my $locstr = $repos{'main'};
5697  my ($tlmdb, $errormsg) = setup_one_remotetlpdb($locstr);
5698  if (!defined($tlmdb)) {
5699    return (0, $errormsg);
5700  }
5701  $remotetlpdb->virtual_add_tlpdb($tlmdb, "main");
5702  for my $t (@tags) {
5703    if ($t ne 'main') {
5704      my ($tlmdb, $errormsg) = setup_one_remotetlpdb($repos{$t});
5705      if (!defined($tlmdb)) {
5706        return(0, $errormsg);
5707      }
5708      $remotetlpdb->virtual_add_tlpdb($tlmdb, $t);
5709      $locstr .= " $repos{$t}";
5710    }
5711  }
5712
5713  # now check/setup pinning
5714  if (!$opts{"pin-file"}) {
5715    # check for pinning file in TEXMFLOCAL/tlpkg/pinning.txt
5716    chomp (my $TEXMFLOCAL = `kpsewhich -var-value=TEXMFLOCAL`);
5717    debug("trying to load pinning file $TEXMFLOCAL/tlpkg/pinning.txt\n");
5718    # since we use TLConfFile it does not matter if the file
5719    # is not existing, it will be treated properly in TLConfFile
5720    $opts{"pin-file"} = "$TEXMFLOCAL/tlpkg/pinning.txt";
5721  }
5722  $pinfile = TeXLive::TLConfFile->new($opts{"pin-file"}, "#", ":", 'multiple');
5723  $remotetlpdb->virtual_pinning($pinfile);
5724  # this "location-url" line should not be changed since GUI programs
5725  # depend on it:
5726  print "location-url\t$locstr\n" if $::machinereadable;
5727  info("$prg: package repositories:\n");
5728  info("\tmain = " . $repos{'main'} . "\n");
5729  for my $t (@tags) {
5730    if ($t ne 'main') {
5731      info("\t$t = " . $repos{$t} . "\n");
5732    }
5733  }
5734  return 1;
5735}
5736
5737
5738
5739
5740sub _init_tlmedia
5741{
5742
5743  # if we are already initialized to the same location, nothing
5744  # needs to be done.
5745  # if we are initialized to a virtual tlpdb, then we have to
5746  # do in any case an initialization
5747  if (defined($remotetlpdb) && !$remotetlpdb->is_virtual &&
5748      ($remotetlpdb->root eq $location)) {
5749    # nothing to be done
5750    return 1;
5751  }
5752
5753  # choose a mirror if we are asked.
5754  if ($location =~ m/^ctan$/i) {
5755    $location = give_ctan_mirror();
5756  } elsif ($location =~ m,^$TeXLiveServerURL,) {
5757    my $mirrorbase = TeXLive::TLUtils::give_ctan_mirror_base();
5758    $location =~ s,^$TeXLiveServerURL,$mirrorbase,;
5759  }
5760
5761  my $errormsg;
5762  ($remotetlpdb, $errormsg) = setup_one_remotetlpdb($location);
5763  if (!defined($remotetlpdb)) {
5764    return(0, $errormsg);
5765  }
5766
5767
5768  # this "location-url" line should not be changed since GUI programs
5769  # depend on it:
5770  print "location-url\t$location\n" if $::machinereadable;
5771  info("$prg: package repository $location\n");
5772  return 1;
5773}
5774
5775sub setup_one_remotetlpdb
5776{
5777  my $location = shift;
5778  my $remotetlpdb;
5779
5780  # TODO
5781  # check if that is already loaded!!!
5782
5783  # choose a mirror if we are asked.
5784  if ($location =~ m/^ctan$/i) {
5785    $location = give_ctan_mirror();
5786  } elsif ($location =~ m,^$TeXLiveServerURL,) {
5787    my $mirrorbase = TeXLive::TLUtils::give_ctan_mirror_base();
5788    $location =~ s,^$TeXLiveServerURL,$mirrorbase,;
5789  }
5790
5791  # if we talk about a net location try to download the hash of the tlpdb
5792  # - if that is possible, check for the locally saved file and if the hash
5793  #   agrees load the local copy if present instead of the remote one,
5794  #   if the hashes disagree, load the remote tlpdb
5795  # - if that does not work assume we are offline or target not reachable,
5796  #   so warn the user and use saved, but note that installation will
5797  #   not work
5798
5799  my $local_copy_tlpdb_used = 0;
5800  if ($location =~ m;^(http|ftp)://;) {
5801    # first check that the saved tlpdb is present at all
5802    my $loc_digest = Digest::MD5::md5_hex($location);
5803    my $loc_copy_of_remote_tlpdb =
5804      "$Master/$InfraLocation/texlive.tlpdb.$loc_digest";
5805    ddebug("loc_digest = $loc_digest\n");
5806    ddebug("loc_copy = $loc_copy_of_remote_tlpdb\n");
5807    if (-r $loc_copy_of_remote_tlpdb) {
5808      ddebug("loc copy found!\n");
5809      # we found the tlpdb matching the current location
5810      # check for the remote hash
5811      my $path = "$location/$InfraLocation/$DatabaseName.md5";
5812      ddebug("remote path of digest = $path\n");
5813      my $fh = TeXLive::TLUtils::download_file($path, "|");
5814      my $rem_digest;
5815      if (read ($fh, $rem_digest, 32) != 32) {
5816        info(<<END_NO_INTERNET);
5817Unable to download the remote TeX Live database,
5818but found a local copy so using that.
5819
5820You may want to try specifying an explicit or different CTAN mirror;
5821see the information and examples for the -repository option at
5822http://tug.org/texlive/doc/install-tl.html
5823(or in the output of install-tl --help).
5824
5825END_NO_INTERNET
5826        # above text duplicated in install-tl
5827
5828        $remotetlpdb = TeXLive::TLPDB->new(root => $location,
5829          tlpdbfile => $loc_copy_of_remote_tlpdb);
5830        $local_copy_tlpdb_used = 1;
5831      } else {
5832        ddebug("found remote digest: $rem_digest\n");
5833        my $rem_copy_digest = TeXLive::TLUtils::tlmd5($loc_copy_of_remote_tlpdb);
5834        ddebug("rem_copy_digest = $rem_copy_digest\n");
5835        if ($rem_copy_digest eq $rem_digest) {
5836          debug("md5 of local copy identical with remote hash\n");
5837          $remotetlpdb = TeXLive::TLPDB->new(root => $location,
5838            tlpdbfile => $loc_copy_of_remote_tlpdb);
5839          $local_copy_tlpdb_used = 1;
5840        }
5841      }
5842    }
5843  }
5844  if (!$local_copy_tlpdb_used) {
5845    $remotetlpdb = TeXLive::TLPDB->new(root => $location);
5846  }
5847  if (!defined($remotetlpdb)) {
5848    return(undef, $loadmediasrcerror . $location);
5849  }
5850  # we allow a range of years to be specified by the remote tlpdb
5851  # for which it might work.
5852  # the lower limit is TLPDB->config_minrelease
5853  # the upper limit is TLPDB->config_release
5854  # if the later is not present only the year in config_release is accepted
5855  # checks are done on the first 4 digits only
5856  # Why only the first four places: some optional network distributions
5857  # might use
5858  #   release/2009-foobar
5859  # If it should work for 2009 and 2010, please use
5860  #   minrelease/2009-foobar
5861  #   release/2010-foobar
5862  my $texlive_release = $remotetlpdb->config_release;
5863  my $texlive_minrelease = $remotetlpdb->config_minrelease;
5864  my $rroot = $remotetlpdb->root;
5865  if (!defined($texlive_release)) {
5866    return(undef, "The installation repository ($rroot) does not specify a "
5867          . "release year for which it was prepared, goodbye.");
5868  }
5869  # still here, so we have $texlive_release defined
5870  my $texlive_release_year = $texlive_release;
5871  $texlive_release_year =~ s/^(....).*$/$1/;
5872  if ($texlive_release_year !~ m/^[1-9][0-9][0-9][0-9]$/) {
5873    return(undef, "The installation repository ($rroot) does not specify a "
5874          . "valid release year, goodbye: $texlive_release");
5875  }
5876  # so $texlive_release_year is numeric, good
5877  if (defined($texlive_minrelease)) {
5878    # we specify a range of years!
5879    my $texlive_minrelease_year = $texlive_minrelease;
5880    $texlive_minrelease_year =~ s/^(....).*$/$1/;
5881    if ($texlive_minrelease_year !~ m/^[1-9][0-9][0-9][0-9]$/) {
5882      return(undef, "The installation repository ($rroot) does not specify a "
5883            . "valid minimal release year, goodbye: $texlive_minrelease");
5884    }
5885    # ok, all numeric and fine, check for range
5886    if ($TeXLive::TLConfig::ReleaseYear < $texlive_minrelease_year
5887        || $TeXLive::TLConfig::ReleaseYear > $texlive_release_year) {
5888      return (undef, "The TeX Live versions supported by the repository
5889$rroot
5890  ($texlive_minrelease_year--$texlive_release_year)
5891do not include the version of the local installation
5892  ($TeXLive::TLConfig::ReleaseYear).");
5893    }
5894  } else {
5895    # $texlive_minrelease not defined, so only one year is valid
5896    if ($texlive_release_year != $TeXLive::TLConfig::ReleaseYear) {
5897      return(undef, "The TeX Live versions of the local installation
5898and the repository are not compatible:
5899      local: $TeXLive::TLConfig::ReleaseYear
5900 repository: $texlive_release_year ($rroot)
5901(Perhaps you need to use a different CTAN mirror? Just a guess.)");
5902    }
5903  }
5904
5905  # check for being frozen
5906  if ($remotetlpdb->option("frozen")) {
5907    my $frozen_msg = <<FROZEN;
5908TeX Live $TeXLive::TLConfig::ReleaseYear is frozen forever and will no
5909longer be updated.  This happens in preparation for a new release.
5910
5911If you're interested in helping to pretest the new release (when
5912pretests are available), please read http://tug.org/texlive/pretest.html.
5913Otherwise, just wait, and the new release will be ready in due time.
5914FROZEN
5915    # don't die here, we want to allow updates even if tlnet is frozen!
5916    tlwarn($frozen_msg);
5917  }
5918
5919  # save remote database if it is a net location
5920  # make sure that the writeout of the tlpdb is done in UNIX mode
5921  # since otherwise the sha256 will change.
5922  if (!$local_copy_tlpdb_used && $location =~ m;^(http|ftp)://;) {
5923    my $loc_digest = Digest::MD5::md5_hex($location);
5924    my $loc_copy_of_remote_tlpdb =
5925      "$Master/$InfraLocation/texlive.tlpdb.$loc_digest";
5926    my $tlfh;
5927    if (!open($tlfh, ">:unix", $loc_copy_of_remote_tlpdb)) {
5928      # that should be only a debug statement, since a user without
5929      # write permission might have done a tlmgr search --global or
5930      # similar
5931      &debug("Cannot save remote TeX Live database to $loc_copy_of_remote_tlpdb: $!\n");
5932    } else {
5933      &debug("writing out tlpdb to $loc_copy_of_remote_tlpdb\n");
5934      $remotetlpdb->writeout($tlfh);
5935      close($tlfh);
5936    }
5937  }
5938
5939  return($remotetlpdb);
5940}
5941
5942
5943
5944# finish handles the -pause option (wait for input from stdin),
5945# and then exits unless the global $::gui_mode is set, in which case we
5946# merely return.
5947#
5948sub finish {
5949  my ($ret) = @_;
5950
5951  if ($ret > 0) {
5952    print "$prg: exiting unsuccessfully (status $ret).\n";
5953  }
5954
5955  if ($::gui_mode) {
5956    return $ret;
5957  } else {
5958    exit($ret);
5959  }
5960}
5961
5962
5963# tlmgr config file handling.  These config files are located in
5964# TEXMFCONFIG/tlmgr/config, thus specific for each user.
5965#
5966# format:
5967#  key=value
5968#
5969sub load_config_file {
5970  #
5971  # first set default values
5972  # the default for gui-expertmode is 1 since that is what we
5973  # have shipped till now
5974  $config{"gui-expertmode"} = 1;
5975  #
5976  # by default we remove packages
5977  $config{"auto-remove"} = 1;
5978
5979  chomp (my $TEXMFCONFIG = `kpsewhich -var-value=TEXMFCONFIG`);
5980  my $fn = "$TEXMFCONFIG/tlmgr/config";
5981  $tlmgr_config_file = TeXLive::TLConfFile->new($fn, "#", "=");
5982
5983  # switched names for this one after initial release.
5984  if ($tlmgr_config_file->key_present("gui_expertmode")) {
5985    $tlmgr_config_file->rename_key("gui_expertmode", "gui-expertmode");
5986  }
5987
5988  for my $key ($tlmgr_config_file->keys) {
5989    my $val = $tlmgr_config_file->value($key);
5990    if ($key eq "gui-expertmode") {
5991      if ($val eq "0") {
5992        $config{"gui-expertmode"} = 0;
5993      } elsif ($val eq "1") {
5994        $config{"gui-expertmode"} = 1;
5995      } else {
5996        tlwarn("$fn: Unknown value for gui-expertmode: $val\n");
5997      }
5998
5999    } elsif ($key eq "persistent-downloads") {
6000      if (($val eq "0") || ($val eq "1")) {
6001        $config{'persistent-downloads'} = $val;
6002      } else {
6003        tlwarn("$fn: Unknown value for persistent-downloads: $val\n");
6004      }
6005
6006    } elsif ($key eq "gui-lang") {
6007      $config{'gui-lang'} = $val;
6008
6009    } elsif ($key eq "auto-remove") {
6010      if ($val eq "0") {
6011        $config{"auto-remove"} = 0;
6012      } elsif ($val eq "1") {
6013        $config{"auto-remove"} = 1;
6014      } else {
6015        tlwarn("$fn: Unknown value for auto-remove: $val\n");
6016      }
6017
6018    } else {
6019      tlwarn("$fn: Unknown tlmgr configuration variable: $key\n");
6020    }
6021  }
6022}
6023
6024sub write_config_file {
6025  if (!defined($tlmgr_config_file)) {
6026    chomp (my $TEXMFCONFIG = `kpsewhich -var-value=TEXMFCONFIG`);
6027    my $dn = "$TEXMFCONFIG/tlmgr";
6028    my $fn = "$dn/config";
6029    # create a new one
6030    $tlmgr_config_file = TeXLive::TLConfFile->new($fn, "#", "=");
6031  }
6032  for my $k (keys %config) {
6033    # it doesn't hurt to save all config settings as we check in TLConfFile
6034    # if the value has actually changed
6035    $tlmgr_config_file->value($k, $config{$k});
6036  }
6037  # make sure that deleted config entries are carried over
6038  for my $k ($tlmgr_config_file->keys) {
6039    if (not(defined($config{$k}))) {
6040      $tlmgr_config_file->delete_key($k);
6041    }
6042  }
6043  if ($tlmgr_config_file->is_changed) {
6044    $tlmgr_config_file->save;
6045  }
6046}
6047
6048# if the packagelog variable is set then write to PACKAGELOG filehandle
6049#
6050sub logpackage
6051{
6052  if ($packagelogfile) {
6053    $packagelogged++;
6054    my $tim = localtime();
6055    print PACKAGELOG "[$tim] @_\n";
6056  }
6057}
6058
6059# resolve relative paths from tlpdb wrt tlroot
6060sub norm_tlpdb_path
6061{
6062  my ($path) = @_;
6063  return if (!defined($path));
6064  $path =~ s!\\!/!;
6065  # just return if absolute path
6066  return $path if ($path =~ m!^/|:!);
6067  init_local_db() unless defined($localtlpdb);
6068  return $localtlpdb->root . "/$path";
6069}
6070
6071# clear the backup dir for $pkg and keep only $autobackup packages
6072# mind that with $autobackup == 0 all packages are cleared
6073sub clear_old_backups
6074{
6075  my ($pkg, $backupdir, $autobackup, $dry) = @_;
6076
6077  my $dryrun = 0;
6078  $dryrun = 1 if ($dry);
6079  # keep arbitrary many backups
6080  return if ($autobackup == -1);
6081
6082  opendir (DIR, $backupdir) || die "opendir($backupdir) failed: $!";
6083  my @dirents = readdir (DIR);
6084  closedir (DIR) || warn "closedir($backupdir) failed: $!";
6085  my @backups;
6086  for my $dirent (@dirents) {
6087    next if (-d $dirent);
6088    next if ($dirent !~ m/^$pkg\.r([0-9]+)\.tar\.xz$/);
6089    push @backups, $1;
6090  }
6091  my $i = 1;
6092  for my $e (reverse sort {$a <=> $b} @backups) {
6093    if ($i > $autobackup) {
6094      log ("Removing backup $backupdir/$pkg.r$e.tar.xz\n");
6095      unlink("$backupdir/$pkg.r$e.tar.xz") unless $dryrun;
6096    }
6097    $i++;
6098  }
6099}
6100
6101# check for updates to tlcritical packages
6102#
6103sub check_for_critical_updates
6104{
6105  my ($localtlpdb, $mediatlpdb) = @_;
6106
6107  my $criticalupdate = 0;
6108  my @critical = $localtlpdb->expand_dependencies("-no-collections",
6109    $localtlpdb, @CriticalPackagesList);
6110  my @critical_upd;
6111  for my $pkg (sort @critical) {
6112    my $tlp = $localtlpdb->get_package($pkg);
6113    if (!defined($tlp)) {
6114      # that should not happen, we expanded in the localtlpdb so why
6115      # should it not be present, any anyway, those are so fundamental
6116      # so they have to be there
6117      tlwarn("\nFundamental package $pkg not present, uh oh, goodbye");
6118      die "Should not happen, $pkg not found";
6119    }
6120    my $localrev = $tlp->revision;
6121    my $mtlp = $mediatlpdb->get_package($pkg);
6122    if (!defined($mtlp)) {
6123      debug("Very surprising, $pkg is not present in the remote tlpdb.\n");
6124      next;
6125    }
6126    my $remoterev = $mtlp->revision;
6127    push (@critical_upd, $pkg) if ($remoterev > $localrev);
6128  }
6129  return(@critical_upd);
6130}
6131
6132sub critical_updates_warning {
6133  tlwarn("=" x 79, "\n");
6134  tlwarn("tlmgr itself needs to be updated.\n");
6135  tlwarn("Please do this via either\n");
6136  tlwarn("  tlmgr update --self\n");
6137  tlwarn("or by getting the latest updater for Unix-ish systems:\n");
6138  tlwarn("  $TeXLiveURL/update-tlmgr-latest.sh\n");
6139  tlwarn("and/or Windows systems:\n");
6140  tlwarn("  $TeXLiveURL/update-tlmgr-latest.exe\n");
6141  tlwarn("Then continue with other updates as usual.\n");
6142  tlwarn("=" x 79, "\n");
6143}
6144
6145#
6146# our compare function for package sorting, which makes sure that
6147# packages with .ARCH names are sorted *before* the main packages
6148sub packagecmp {
6149  my $aa = $a;
6150  my $bb = $b;
6151  # remove the part after the . if at all present
6152  $aa =~ s/\..*$//;
6153  $bb =~ s/\..*$//;
6154  if ($aa lt $bb) {
6155    return -1;
6156  } elsif ($aa gt $bb) {
6157    return 1;
6158  } else {
6159    # the parts before the . are the same
6160    # sort the .something *before* the ones without
6161    if ($a eq $aa && $b eq $bb) {
6162      return 0;
6163    } elsif ($a eq $aa) {
6164      # so  $a = foobar
6165      # and $b = foobar.something
6166      # this is the special case where we want to invert the order
6167      return 1;
6168    } elsif ($b eq $bb) {
6169      # so  $a = foobar.something
6170      # and $b = foobar
6171      return -1;
6172    } else {
6173      return ($a cmp $b);
6174    }
6175  }
6176}
6177
6178sub check_on_writable {
6179  return 1 if $opts{"usermode"};
6180  if (!TeXLive::TLUtils::dir_writable("$Master/tlpkg")) {
6181    tlwarn("You don't have permission to change the installation in any way,\n");
6182    tlwarn("specifically, the directory $Master/tlpkg/ is not writable.\n");
6183    tlwarn("Please run this program as administrator, or contact your local admin.\n");
6184    if ($opts{"dry-run"}) {
6185      tlwarn("Continuing due to --dry-run\n");
6186      return 1;
6187    } else {
6188      return 0;
6189    }
6190  }
6191  return 1;
6192}
6193
61941;
6195__END__
6196
6197=head1 NAME
6198
6199tlmgr - the TeX Live Manager
6200
6201=head1 SYNOPSIS
6202
6203tlmgr [I<option>]... I<action> [I<option>]... [I<operand>]...
6204
6205=head1 DESCRIPTION
6206
6207B<tlmgr> manages an existing TeX Live installation, both packages and
6208configuration options.  For information on initially downloading and
6209installing TeX Live, see L<http://tug.org/texlive/acquire.html>.
6210
6211The most up-to-date version of this documentation (updated nightly from
6212the development sources) is available at
6213L<http://tug.org/texlive/tlmgr.html>, along with procedures for updating
6214C<tlmgr> itself and information about test versions.
6215
6216TeX Live is organized into a few top-level I<schemes>, each of which is
6217specified as a different set of I<collections> and I<packages>, where a
6218collection is a set of packages, and a package is what contains actual
6219files.  Schemes typically contain a mix of collections and packages, but
6220each package is included in exactly one collection, no more and no less.
6221A TeX Live installation can be customized and managed at any level.
6222
6223See L<http://tug.org/texlive/doc> for all the TeX Live documentation
6224available.
6225
6226=head1 EXAMPLES
6227
6228After successfully installing TeX Live, here are a few common operations
6229with C<tlmgr>:
6230
6231=over 4
6232
6233=item C<tlmgr option repository http://mirror.ctan.org/systems/texlive/tlnet>
6234
6235Tell C<tlmgr> to use a nearby CTAN mirror for future updates; useful if
6236you installed TeX Live from the DVD image and want continuing updates.
6237
6238=item C<tlmgr update --list>
6239
6240Report what would be updated without actually updating anything.
6241
6242=item C<tlmgr update --all>
6243
6244Make your local TeX installation correspond to what is in the package
6245repository (typically useful when updating from CTAN).
6246
6247=item C<tlmgr info> I<what>
6248
6249Display detailed information about a package I<what>, such as the installation
6250status and description, of searches for I<what> in all packages.
6251
6252=back
6253
6254For all the capabilities and details of C<tlmgr>, please read the
6255following voluminous information.
6256
6257=head1 OPTIONS
6258
6259The following options to C<tlmgr> are global options, not specific to
6260any action.  All options, whether global or action-specific, can be
6261given anywhere on the command line, and in any order.  The first
6262non-option argument will be the main action.  In all cases,
6263C<-->I<option> and C<->I<option> are equivalent, and an C<=> is optional
6264between an option name and its value.
6265
6266=over 4
6267
6268=item B<--repository> I<url|path>
6269
6270Specifies the package repository from which packages should be installed
6271or updated, overriding the default package repository found in the
6272installation's TeX Live Package Database (a.k.a. the TLPDB, defined
6273entirely in the file C<tlpkg/texlive.tlpdb>).  The documentation for
6274C<install-tl> has more details about this
6275(L<http://tug.org/texlive/doc/install-tl.html>).
6276
6277C<--repository> changes the repository location only for the current
6278run; to make a permanent change, use C<option repository> (see the
6279L</option> action).
6280
6281For backward compatibility and convenience, C<--location> and C<--repo>
6282are accepted as aliases for this option.
6283
6284
6285=item B<--gui> [I<action>]
6286
6287C<tlmgr> has a graphical interface as well as the command line
6288interface.  You can give this option, C<--gui>, together with an action
6289to be brought directly into the respective screen of the GUI.  For
6290example, running
6291
6292  tlmgr --gui update
6293
6294starts you directly at the update screen.  If no action is given, the
6295GUI will be started at the main screen.
6296
6297=for comment Keep language list in sync with install-tl.
6298
6299=item B<--gui-lang> I<llcode>
6300
6301By default, the GUI tries to deduce your language from the environment
6302(on Windows via the registry, on Unix via C<LC_MESSAGES>). If that fails
6303you can select a different language by giving this option with a
6304language code (based on ISO 639-1).  Currently supported (but not
6305necessarily completely translated) are: English (en, default), Czech
6306(cs), German (de), French (fr), Italian (it), Japanese (ja), Dutch (nl),
6307Polish (pl), Brazilian Portuguese (pt_BR), Russian (ru), Slovak (sk),
6308Slovenian (sl), Serbian (sr), Ukrainian (uk), Vietnamese (vi),
6309simplified Chinese (zh_CN), and traditional Chinese (zh_TW).
6310
6311=item B<--debug-translation>
6312
6313In GUI mode, this switch tells C<tlmgr> to report any untranslated (or
6314missing) messages to standard error.  This can help translators to see
6315what remains to be done.
6316
6317=item B<--machine-readable>
6318
6319Instead of the normal output intended for human consumption, write (to
6320standard output) a fixed format more suitable for machine parsing.  See
6321the L</MACHINE-READABLE OUTPUT> section below.
6322
6323=item B<--no-execute-actions>
6324
6325Suppress the execution of the execute actions as defined in the tlpsrc
6326files.  Documented only for completeness, as this is only useful in
6327debugging.
6328
6329=item B<--package-logfile> I<file>
6330
6331C<tlmgr> logs all package actions (install, remove, update, failed
6332updates, failed restores) to a separate log file, by default
6333C<TEXMFSYSVAR/web2c/tlmgr.log>.  This option allows you to specific a
6334different file for the log.
6335
6336=item B<--pause>
6337
6338This option makes C<tlmgr> wait for user input before exiting.  Useful on
6339Windows to avoid disappearing command windows.
6340
6341=item B<--persistent-downloads>
6342
6343=item B<--no-persistent-downloads>
6344
6345For network-based installations, this option (on by default) makes
6346C<tlmgr> try to set up a persistent connection (using the C<LWP> Perl
6347module).  The idea is to open and reuse only one connection per session
6348between your computer and the server, instead of initiating a new
6349download for each package.
6350
6351If this is not possible, C<tlmgr> will fall back to using C<wget>.  To
6352disable these persistent connections, use C<--no-persistent-downloads>.
6353
6354=item B<--pin-file>
6355
6356Change the pinning file location from C<TEXMFLOCAL/tlpkg/pinning.txt>
6357(see L</Pinning> below).  Documented only for completeness, as this is
6358only useful in debugging.
6359
6360=item B<--usermode>
6361
6362Activates user mode for this run of C<tlmgr>; see L<USER MODE> below.
6363
6364=item B<--usertree> I<dir>
6365
6366Uses I<dir> for the tree in user mode; see L<USER MODE> below.
6367
6368=back
6369
6370The standard options for TeX Live programs are also accepted:
6371C<--help/-h/-?>, C<--version>, C<-q> (no informational messages), C<-v>
6372(debugging messages, can be repeated).  For the details about these, see
6373the C<TeXLive::TLUtils> documentation.
6374
6375The C<--version> option shows version information about the TeX Live
6376release and about the C<tlmgr> script itself.  If C<-v> is also given,
6377revision number for the loaded TeX Live Perl modules are shown, too.
6378
6379
6380=head1 ACTIONS
6381
6382=head2 help
6383
6384Display this help information and exit (same as C<--help>, and on the
6385web at L<http://tug.org/texlive/doc/tlmgr.html>).  Sometimes the
6386C<perldoc> and/or C<PAGER> programs on the system have problems,
6387resulting in control characters being literally output.  This can't
6388always be detected, but you can set the C<NOPERLDOC> environment
6389variable and C<perldoc> will not be used.
6390
6391=head2 version
6392
6393Gives version information (same as C<--version>).
6394
6395If C<-v> has been given the revisions of the used modules are reported, too.
6396
6397=head2 backup [--clean[=I<N>]] [--backupdir I<dir>] [--all | I<pkg>]...
6398
6399If the C<--clean> option is not specified, this action makes a backup of
6400the given packages, or all packages given C<--all>. These backups are
6401saved to the value of the C<--backupdir> option, if that is an existing and
6402writable directory. If C<--backupdir> is not given, the C<backupdir>
6403option setting in the TLPDB is used, if present.  If both are missing,
6404no backups are made.
6405
6406If the C<--clean> option is specified, backups are pruned (removed)
6407instead of saved. The optional integer value I<N> may be specified to
6408set the number of backups that will be retained when cleaning. If C<N>
6409is not given, the value of the C<autobackup> option is used. If both are
6410missing, an error is issued. For more details of backup pruning, see
6411the C<option> action.
6412
6413Options:
6414
6415=over 4
6416
6417=item B<--backupdir> I<directory>
6418
6419Overrides the C<backupdir> option setting in the TLPDB.
6420The I<directory> argument is required and must specify an existing,
6421writable directory where backups are to be placed.
6422
6423=item B<--all>
6424
6425If C<--clean> is not specified, make a backup of all packages in the TeX
6426Live installation; this will take quite a lot of space and time.  If
6427C<--clean> is specified, all packages are pruned.
6428
6429=item B<--clean>[=I<N>]
6430
6431Instead of making backups, prune the backup directory of old backups, as
6432explained above. The optional integer argument I<N> overrides the
6433C<autobackup> option set in the TLPDB.  You must use C<--all> or a list
6434of packages together with this option, as desired.
6435
6436=item B<--dry-run>
6437
6438Nothing is actually backed up or removed; instead, the actions to be
6439performed are written to the terminal.
6440
6441=back
6442
6443
6444=head2 candidates I<pkg>
6445
6446=over 4
6447
6448=item B<candidates I<pkg>>
6449
6450Shows the available candidate repositories for package I<pkg>.
6451See L</MULTIPLE REPOSITORIES> below.
6452
6453
6454=back
6455
6456=head2 check [I<option>]... [files|depends|executes|runfiles|all]
6457
6458Executes one (or all) check(s) on the consistency of the installation.
6459
6460=over 4
6461
6462=item B<files>
6463
6464Checks that all files listed in the local TLPDB (C<texlive.tlpdb>) are
6465actually present, and lists those missing.
6466
6467=item B<depends>
6468
6469Lists those packages which occur as dependencies in an installed collections,
6470but are themselves not installed, and those packages that are not
6471contained in any collection.
6472
6473If you call C<tlmgr check collections> this test will be carried out
6474instead since former versions for C<tlmgr> called it that way.
6475
6476=item B<executes>
6477
6478Check that the files referred to by C<execute> directives in the TeX
6479Live Database are present.
6480
6481=item B<runfiles>
6482
6483List those filenames that are occurring more than one time in the runfiles.
6484
6485=back
6486
6487Options:
6488
6489=over 4
6490
6491=item B<--use-svn>
6492
6493Use the output of C<svn status> instead of listing the files; for
6494checking the TL development repository.
6495
6496=back
6497
6498
6499=head2 conf [texmf|tlmgr|updmap [--conffile I<file>] [--delete] [I<key> [I<value>]]]
6500
6501With only C<conf>, show general configuration information for TeX Live,
6502including active configuration files, path settings, and more.  This is
6503like the C<texconfig conf> call, but works on all supported platforms.
6504
6505With either C<conf texmf>, C<conf tlmgr>, or C<conf updmap> given in
6506addition, shows all key/value pairs (i.e., all settings) as saved in
6507C<ROOT/texmf.cnf>, the tlmgr configuration file (see below), or the
6508first found (via kpsewhich) C<updmap.cfg> file, respectively.
6509
6510If I<key> is given in addition, shows the value of only that I<key> in
6511the respective file.  If option I<--delete> is also given, the
6512configuration file -- it is removed, not just commented out!
6513
6514If I<value> is given in addition, I<key> is set to I<value> in the
6515respective file.  I<No error checking is done!>
6516
6517In all cases the file used can be explicitly specified via the option
6518C<--conffile I<file>>, in case one wants to operate on a different file.
6519
6520Practical application: if the execution of (some or all) system commands
6521via C<\write18> was left enabled during installation, you can disable
6522it afterwards:
6523
6524  tlmgr conf texmf shell_escape 0
6525
6526A more complicated example: the C<TEXMFHOME> tree (see the main TeX Live
6527guide, L<http://tug.org/texlive/doc.html>) can be set to multiple
6528directories, but they must be enclosed in braces and separated by
6529commas, so quoting the value to the shell is a good idea.  Thus:
6530
6531  tlmgr conf texmf TEXMFHOME "{~/texmf,~/texmfbis}"
6532
6533Warning: The general facility is here, but tinkering with settings in
6534this way is very strongly discouraged.  Again, no error checking on
6535either keys or values is done, so any sort of breakage is possible.
6536
6537
6538=head2 dump-tlpdb [--local|--remote]
6539
6540Dump complete local or remote TLPDB to standard output, as-is.  The
6541output is analogous to the C<--machine-readable> output; see
6542L<MACHINE-READABLE OUTPUT> section.
6543
6544Options:
6545
6546=over 4
6547
6548=item B<--local>
6549
6550Dump the local tlpdb.
6551
6552=item B<--remote>
6553
6554Dump the remote tlpdb.
6555
6556=back
6557
6558Exactly one of C<--local> and C<--remote> must be given.
6559
6560In either case, the first line of the output specifies the repository
6561location, in this format:
6562
6563  "location-url" "\t" location
6564
6565where C<location-url> is the literal field name, followed by a tab, and
6566I<location> is the file or url to the repository.
6567
6568Line endings may be either LF or CRLF depending on the current platform.
6569
6570
6571=head2 generate [I<option>]... I<what>
6572
6573=over 4
6574
6575=item B<generate language>
6576
6577=item B<generate language.dat>
6578
6579=item B<generate language.def>
6580
6581=item B<generate language.dat.lua>
6582
6583=back
6584
6585The C<generate> action overwrites any manual changes made in the
6586respective files: it recreates them from scratch based on the
6587information of the installed packages, plus local adaptions.
6588The TeX Live installer and C<tlmgr> routinely call C<generate> for
6589all of these files.
6590
6591For managing your own fonts, please read the C<updmap --help>
6592information and/or L<http://tug.org/fonts/fontinstall.html>.
6593
6594For managing your own formats, please read the C<fmtutil --help>
6595information.
6596
6597In more detail: C<generate> remakes any of the configuration files
6598C<language.dat>, C<language.def>, and C<language.dat.lua>
6599from the information present in the local TLPDB, plus
6600locally-maintained files.
6601
6602The locally-maintained files are C<language-local.dat>,
6603C<language-local.def>, or C<language-local.dat.lua>,
6604searched for in C<TEXMFLOCAL> in the respective
6605directories.  If local additions are present, the final file is made by
6606starting with the main file, omitting any entries that the local file
6607specifies to be disabled, and finally appending the local file.
6608
6609(Historical note: The formerly supported C<updmap-local.cfg> and
6610C<fmtutil-local.cnf> are no longer read, since C<updmap> and C<fmtutil>
6611now reads and supports multiple configuration files.  Thus,
6612local additions can and should be put into an C<updmap.cfg> of C<fmtutil.cnf>
6613file in C<TEXMFLOCAL>.  The C<generate updmap> and C<generate fmtutil> actions
6614no longer exist.)
6615
6616Local files specify entries to be disabled with a comment line, namely
6617one of these:
6618
6619  %!NAME
6620  --!NAME
6621
6622where C<language.dat> and C<language.def> use C<%>,
6623and C<language.dat.lua> use C<-->.  In all cases, the I<name> is
6624the respective format name or hyphenation pattern identifier.
6625Examples:
6626
6627  %!german
6628  --!usenglishmax
6629
6630(Of course, you're not likely to actually want to disable those
6631particular items.  They're just examples.)
6632
6633After such a disabling line, the local file can include another entry
6634for the same item, if a different definition is desired.  In general,
6635except for the special disabling lines, the local files follow the same
6636syntax as the master files.
6637
6638The form C<generate language> recreates all three files C<language.dat>,
6639C<language.def>, and C<language.dat.lua>, while the forms with an
6640extension recreates only that given language file.
6641
6642Options:
6643
6644=over 4
6645
6646=item B<--dest> I<output_file>
6647
6648specifies the output file (defaults to the respective location in
6649C<TEXMFSYSVAR>).  If C<--dest> is given to C<generate language>, it
6650serves as a basename onto which C<.dat> will be appended for the name of
6651the C<language.dat> output file, C<.def> will be appended to the value
6652for the name of the C<language.def> output file, and C<.dat.lua> to the
6653name of the C<language.dat.lua> file.  (This is just to avoid
6654overwriting; if you want a specific name for each output file, we
6655recommend invoking C<tlmgr> twice.)
6656
6657=item B<--localcfg> I<local_conf_file>
6658
6659specifies the (optional) local additions (defaults to the respective
6660location in C<TEXMFLOCAL>).
6661
6662=item B<--rebuild-sys>
6663
6664tells tlmgr to run necessary programs after config files have been
6665regenerated. These are:
6666C<fmtutil-sys --all> after C<generate fmtutil>,
6667C<fmtutil-sys --byhyphen .../language.dat> after C<generate language.dat>,
6668and
6669C<fmtutil-sys --byhyphen .../language.def> after C<generate language.def>.
6670
6671These subsequent calls cause the newly-generated files to actually take
6672effect.  This is not done by default since those calls are lengthy
6673processes and one might want to made several related changes in
6674succession before invoking these programs.
6675
6676=back
6677
6678The respective locations are as follows:
6679
6680  tex/generic/config/language.dat (and language-local.dat);
6681  tex/generic/config/language.def (and language-local.def);
6682  tex/generic/config/language.dat.lua (and language-local.dat.lua);
6683
6684
6685=head2 gui
6686
6687Start the graphical user interface. See B<GUI> below.
6688
6689
6690=head2 info [I<option>...] [collections|schemes|I<pkg>...]
6691
6692With no argument, lists all packages available at the package
6693repository, prefixing those already installed with C<i>.
6694
6695With the single word C<collections> or C<schemes> as the argument, lists
6696the request type instead of all packages.
6697
6698With any other arguments, display information about I<pkg>: the name,
6699category, short and long description, installation status, and TeX Live
6700revision number.  If I<pkg> is not locally installed, searches in the
6701remote installation source.
6702
6703If I<pkg> is not found locally or remotely, the search action is used
6704and lists matching packages and files.
6705
6706It also displays information taken from the TeX Catalogue, namely the
6707package version, date, and license.  Consider these, especially the
6708package version, as approximations only, due to timing skew of the
6709updates of the different pieces.  By contrast, the C<revision> value
6710comes directly from TL and is reliable.
6711
6712The former actions C<show> and C<list> are merged into this action,
6713but are still supported for backward compatibility.
6714
6715Options:
6716
6717=over 4
6718
6719=item B<--list>
6720
6721If the option C<--list> is given with a package, the list of contained
6722files is also shown, including those for platform-specific dependencies.
6723When given with schemes and collections, C<--list> outputs their
6724dependencies in a similar way.
6725
6726=item B<--only-installed>
6727
6728If this options is given,  the installation source will
6729not be used; only locally installed packages, collections, or schemes
6730are listed.
6731(Does not work for listing of packages for now)
6732
6733=back
6734
6735
6736=head2 init-usertree
6737
6738Sets up a texmf tree for so-called user mode management, either the
6739default user tree (C<TEXMFHOME>), or one specified on the command line
6740with C<--usertree>.  See L<USER MODE> below.
6741
6742
6743=head2 install [I<option>]... I<pkg>...
6744
6745Install each I<pkg> given on the command line, if it is not already
6746installed.  (It does not touch existing packages; see the C<update>
6747action for how to get the latest version of a package.)
6748
6749By default this also installs all packages on which the given I<pkg>s are
6750dependent.  Options:
6751
6752=over 4
6753
6754=item B<--dry-run>
6755
6756Nothing is actually installed; instead, the actions to be performed are
6757written to the terminal.
6758
6759=item B<--file>
6760
6761Instead of fetching a package from the installation repository, use
6762the package files given on the command line.  These files must
6763be standard TeX Live package files (with contained tlpobj file).
6764
6765=item B<--force>
6766
6767If updates to C<tlmgr> itself (or other parts of the basic
6768infrastructure) are present, C<tlmgr> will bail out and not perform the
6769installation unless this option is given.  Not recommended.
6770
6771=item B<--no-depends>
6772
6773Do not install dependencies.  (By default, installing a package ensures
6774that all dependencies of this package are fulfilled.)
6775
6776=item B<--no-depends-at-all>
6777
6778Normally, when you install a package which ships binary files the
6779respective binary package will also be installed.  That is, for a
6780package C<foo>, the package C<foo.i386-linux> will also be installed on
6781an C<i386-linux> system.  This option suppresses this behavior, and also
6782implies C<--no-depends>.  Don't use it unless you are sure of what you
6783are doing.
6784
6785=item B<--reinstall>
6786
6787Reinstall a package (including dependencies for collections) even if it
6788already seems to be installed (i.e, is present in the TLPDB).  This is
6789useful to recover from accidental removal of files in the hierarchy.
6790
6791When re-installing, only dependencies on normal packages are followed
6792(i.e., not those of category Scheme or Collection).
6793
6794=item B<--with-doc>
6795
6796=item B<--with-src>
6797
6798While not recommended, the C<install-tl> program provides an option to
6799omit installation of all documentation and/or source files.  (By
6800default, everything is installed.)  After such an installation, you may
6801find that you want the documentation or source files for a given package
6802after all.  You can get them by using these options in conjunction with
6803C<--reinstall>, as in (using the C<fontspec> package as the example):
6804
6805  tlmgr install --reinstall --with-doc --with-src fontspec
6806
6807=back
6808
6809
6810=head2 option
6811
6812=over 4
6813
6814=item B<option [show]>
6815
6816=item B<option showall>
6817
6818=item B<option I<key> [I<value>]>
6819
6820=back
6821
6822The first form shows the global TeX Live settings currently saved in the
6823TLPDB with a short description and the C<key> used for changing it in
6824parentheses.
6825
6826The second form is similar, but also shows options which can be defined
6827but are not currently set to any value.
6828
6829In the third form, if I<value> is not given, the setting for I<key> is
6830displayed.  If I<value> is present, I<key> is set to I<value>.
6831
6832Possible values for I<key> are (run C<tlmgr option showall> for
6833the definitive list):
6834
6835 repository (default package repository),
6836 formats    (create formats at installation time),
6837 postcode   (run postinst code blobs)
6838 docfiles   (install documentation files),
6839 srcfiles   (install source files),
6840 backupdir  (default directory for backups),
6841 autobackup (number of backups to keep).
6842 sys_bin    (directory to which executables are linked by the path action)
6843 sys_man    (directory to which man pages are linked by the path action)
6844 sys_info   (directory to which Info files are linked by the path action)
6845 desktop_integration (Windows-only: create Start menu shortcuts)
6846 fileassocs (Windows-only: change file associations)
6847 multiuser  (Windows-only: install for all users)
6848
6849One common use of C<option> is to permanently change the installation to
6850get further updates from the Internet, after originally installing from
6851DVD.  To do this, you can run
6852
6853 tlmgr option repository http://mirror.ctan.org/systems/texlive/tlnet
6854
6855The C<install-tl> documentation has more information about the possible
6856values for C<repository>.  (For backward compatibility, C<location> can
6857be used as alternative name for C<repository>.)
6858
6859If C<formats> is set (this is the default), then formats are regenerated
6860when either the engine or the format files have changed.  Disable this
6861only when you know what you are doing.
6862
6863The C<postcode> option controls execution of per-package
6864postinstallation action code.  It is set by default, and again disabling
6865is not likely to be of interest except perhaps to developers.
6866
6867The C<docfiles> and C<srcfiles> options control the installation of
6868their respective files of a package. By default both are enabled (1).
6869This can be disabled (set to 0) if disk space is (very) limited.
6870
6871The options C<autobackup> and C<backupdir> determine the defaults for
6872the actions C<update>, C<backup> and C<restore>.  These three actions
6873need a directory in which to read or write the backups.  If
6874C<--backupdir> is not specified on the command line, the C<backupdir>
6875option value is used (if set).
6876
6877The C<autobackup> option (de)activates automatic generation of backups.
6878Its value is an integer.  If the C<autobackup> value is C<-1>, no
6879backups are removed.  If C<autobackup> is 0 or more, it specifies the
6880number of backups to keep.  Thus, backups are disabled if the value is
68810.  In the C<--clean> mode of the C<backup> action this option also
6882specifies the number to be kept.
6883
6884To setup C<autobackup> to C<-1> on the command line, use:
6885
6886  tlmgr option -- autobackup -1
6887
6888The C<--> avoids having the C<-1> treated as an option.  (C<--> stops
6889parsing for options at the point where it appears; this is a general
6890feature across most Unix programs.)
6891
6892The C<sys_bin>, C<sys_man>, and C<sys_info> options are used on
6893Unix-like systems to control the generation of links for executables,
6894info files and man pages. See the C<path> action for details.
6895
6896The last three options control behaviour on Windows installations.  If
6897C<desktop_integration> is set, then some packages will install items in
6898a sub-folder of the Start menu for C<tlmgr gui>, documentation, etc.  If
6899C<fileassocs> is set, Windows file associations are made (see also the
6900C<postaction> action).  Finally, if C<multiuser> is set, then adaptions
6901to the registry and the menus are done for all users on the system
6902instead of only the current user.  All three options are on by default.
6903
6904
6905=head2 paper
6906
6907=over 4
6908
6909=item B<paper [a4|letter]>
6910
6911=item B<S<[xdvi|pdftex|dvips|dvipdfmx|context|psutils] paper [I<papersize>|--list]>>
6912
6913=back
6914
6915With no arguments (C<tlmgr paper>), shows the default paper size setting
6916for all known programs.
6917
6918With one argument (e.g., C<tlmgr paper a4>), sets the default for all
6919known programs to that paper size.
6920
6921With a program given as the first argument and no paper size specified
6922(e.g., C<tlmgr dvips paper>), shows the default paper size for that
6923program.
6924
6925With a program given as the first argument and a paper size as the last
6926argument (e.g., C<tlmgr dvips paper a4>), set the default for that
6927program to that paper size.
6928
6929With a program given as the first argument and C<--list> given as the
6930last argument (e.g., C<tlmgr dvips paper --list>), shows all valid paper
6931sizes for that program.  The first size shown is the default.
6932
6933Incidentally, this syntax of having a specific program name before the
6934C<paper> keyword is unusual.  It is inherited from the longstanding
6935C<texconfig> script, which supports other configuration settings for
6936some programs, notably C<dvips>.  C<tlmgr> does not support those extra
6937settings.
6938
6939
6940=head2 path [--w32mode=user|admin] [add|remove]
6941
6942On Unix, merely adds or removes symlinks for binaries, man pages, and
6943info pages in the system directories specified by the respective options
6944(see the L</option> description above).  Does not change any
6945initialization files, either system or personal.
6946
6947On Windows, the registry part where the binary directory is added or
6948removed is determined in the following way:
6949
6950If the user has admin rights, and the option C<--w32mode> is not given,
6951the setting I<w32_multi_user> determines the location (i.e., if it is
6952on then the system path, otherwise the user path is changed).
6953
6954If the user has admin rights, and the option C<--w32mode> is given, this
6955option determines the path to be adjusted.
6956
6957If the user does not have admin rights, and the option C<--w32mode>
6958is not given, and the setting I<w32_multi_user> is off, the user path
6959is changed, while if the setting I<w32_multi_user> is on, a warning is
6960issued that the caller does not have enough privileges.
6961
6962If the user does not have admin rights, and the option C<--w32mode>
6963is given, it must be B<user> and the user path will be adjusted. If a
6964user without admin rights uses the option C<--w32mode admin> a warning
6965is issued that the caller does not have enough privileges.
6966
6967
6968=head2 pinning
6969
6970The C<pinning> action manages the pinning file, see L</Pinning> below.
6971
6972=over 4
6973
6974=item C<pinning show>
6975
6976Shows the current pinning data.
6977
6978=item C<pinning add> I<repo> I<pkgglob>...
6979
6980Pins the packages matching the I<pkgglob>(s) to the repository
6981I<repo>.
6982
6983=item C<pinning remove> I<repo> I<pkgglob>...
6984
6985Any packages recorded in the pinning file matching the <pkgglob>s for
6986the given repository I<repo> are removed.
6987
6988=item C<pinning remove I<repo> --all>
6989
6990Remove all pinning data for repository I<repo>.
6991
6992=back
6993
6994=head2 platform list|add|remove I<platform>...
6995
6996=head2 platform set I<platform>
6997
6998=head2 platform set auto
6999
7000C<platform list> lists the TeX Live names of all the platforms
7001(a.k.a. architectures), (C<i386-linux>, ...) available at the package
7002repository.
7003
7004C<platform add> I<platform>... adds the executables for each given platform
7005I<platform> to the installation from the repository.
7006
7007C<platform remove> I<platform>... removes the executables for each given
7008platform I<platform> from the installation, but keeps the currently
7009running platform in any case.
7010
7011C<platform set> I<platform> switches TeX Live to always use the given
7012platform instead of auto detection.
7013
7014C<platform set auto> switches TeX Live to auto detection mode for platform.
7015
7016Platform detection is needed to select the proper C<xz>, C<xzdec> and
7017C<wget> binaries that are shipped with TeX Live.
7018
7019C<arch> is a synonym for C<platform>.
7020
7021Options:
7022
7023=over 4
7024
7025=item B<--dry-run>
7026
7027Nothing is actually installed; instead, the actions to be performed are
7028written to the terminal.
7029
7030=back
7031
7032
7033=cut
7034
7035# keep the following on *ONE* line otherwise Losedows perldoc does
7036# not show it!!!!
7037
7038=pod
7039
7040=head2 postaction [--w32mode=user|admin] [--fileassocmode=1|2] [--all] [install|remove] [shortcut|fileassoc|script] [I<pkg>]...
7041
7042Carry out the postaction C<shortcut>, C<fileassoc>, or C<script> given
7043as the second required argument in install or remove mode (which is the
7044first required argument), for either the packages given on the command
7045line, or for all if C<--all> is given.
7046
7047If the option C<--w32mode> is given the value C<user>, all actions will
7048only be carried out in the user-accessible parts of the
7049registry/filesystem, while the value C<admin> selects the system-wide
7050parts of the registry for the file associations.  If you do not have
7051enough permissions, using C<--w32mode=admin> will not succeed.
7052
7053C<--fileassocmode> specifies the action for file associations.  If it is
7054set to 1 (the default), only new associations are added; if it is set to
70552, all associations are set to the TeX Live programs.  (See also
7056C<option fileassocs>.)
7057
7058
7059=head2 print-platform
7060
7061Print the TeX Live identifier for the detected platform
7062(hardware/operating system) combination to standard output, and exit.
7063C<--print-arch> is a synonym.
7064
7065
7066=head2 remove [I<option>]... I<pkg>...
7067
7068Remove each I<pkg> specified.  Removing a collection removes all package
7069dependencies (unless C<--no-depends> is specified), but not any
7070collection dependencies of that collection.  However, when removing a
7071package, dependencies are never removed.  Options:
7072
7073=over 4
7074
7075=item B<--no-depends>
7076
7077Do not remove dependent packages.
7078
7079=item B<--no-depends-at-all>
7080
7081See above under B<install> (and beware).
7082
7083=item B<--force>
7084
7085By default, removal of a package or collection that is a dependency of
7086another collection or scheme is not allowed.  With this option, the
7087package will be removed unconditionally.  Use with care.
7088
7089A package that has been removed using the C<--force> option because it
7090is still listed in an installed collection or scheme will not be
7091updated, and will be mentioned as B<forcibly removed> in the output of
7092B<tlmgr update --list>.
7093
7094=item B<--dry-run>
7095
7096Nothing is actually removed; instead, the actions to be performed are
7097written to the terminal.
7098
7099=back
7100
7101
7102=head2 repository
7103
7104=over 4
7105
7106=item B<repository list>
7107
7108=item B<repository list I<path|tag>>
7109
7110=item B<repository add I<path> [I<tag>]>
7111
7112=item B<repository remove I<path|tag>>
7113
7114=item B<repository set I<path>[#I<tag>] [I<path>[#I<tag>] ...]>
7115
7116This action manages the list of repositories.  See L</MULTIPLE
7117REPOSITORIES> below for detailed explanations.
7118
7119The first form (C<list>) lists all configured repositories and the
7120respective tags if set. If a path, url, or tag is given after the
7121C<list> keyword, it is interpreted as source from where to
7122initialize a TeX Live Database and lists the contained packages.
7123This can also be an up-to-now not used repository, both locally
7124and remote. If one pass in addition C<--with-platforms>, for each
7125package the available platforms (if any) are listed, too.
7126
7127The third form (C<add>) adds a repository
7128(optionally attaching a tag) to the list of repositories.  The forth
7129form (C<remove>) removes a repository, either by full path/url, or by
7130tag.  The last form (C<set>) sets the list of repositories to the items
7131given on the command line, not keeping previous settings
7132
7133In all cases, one of the repositories must be tagged as C<main>;
7134otherwise, all operations will fail!
7135
7136=back
7137
7138
7139=head2 restore [--backupdir I<dir>] [--all | I<pkg> [I<rev>]]
7140
7141Restore a package from a previously-made backup.
7142
7143If C<--all> is given, try to restore the latest revision of all
7144package backups found in the backup directory.
7145
7146Otherwise, if neither I<pkg> nor I<rev> are given, list the available
7147backup revisions for all packages.  With I<pkg> given but no I<rev>,
7148list all available backup revisions of I<pkg>.
7149
7150When listing available packages tlmgr shows the revision, and in
7151parenthesis the creation time if available (in format yyyy-mm-dd hh:mm).
7152
7153If (and only if) both I<pkg> and a valid revision number I<rev> are
7154specified, try to restore the package from the specified backup.
7155
7156Options:
7157
7158=over 4
7159
7160=item B<--all>
7161
7162Try to restore the latest revision of all package backups found in the
7163backup directory. Additional non-option arguments (like I<pkg>) are not
7164allowed.
7165
7166=item B<--backupdir> I<directory>
7167
7168Specify the directory where the backups are to be found. If not given it
7169will be taken from the configuration setting in the TLPDB.
7170
7171=item B<--dry-run>
7172
7173Nothing is actually restored; instead, the actions to be performed are
7174written to the terminal.
7175
7176=item B<--force>
7177
7178Don't ask questions.
7179
7180=back
7181
7182
7183=head2 search [I<option>...] I<what>
7184
7185=head3 search [I<option>...] --file I<what>
7186
7187=head3 search [I<option>...] --all I<what>
7188
7189By default, search the names, short descriptions, and long descriptions
7190of all locally installed packages for the argument I<what>, interpreted
7191as a (Perl) regular expression.
7192
7193Options:
7194
7195=over 4
7196
7197=item B<--file>
7198
7199List all filenames containing I<what>.
7200
7201=item B<--all>
7202
7203Search everything: package names, descriptions and filenames.
7204
7205=item B<--global>
7206
7207Search the TeX Live Database of the installation medium, instead of the
7208local installation.
7209
7210=item B<--word>
7211
7212Restrict the search of package names and descriptions (but not
7213filenames) to match only full words.  For example, searching for
7214C<table> with this option will not output packages containing the word
7215C<tables> (unless they also contain the word C<table> on its own).
7216
7217=back
7218
7219
7220=head2 uninstall
7221
7222Uninstalls the entire TeX Live installation.  Options:
7223
7224=over 4
7225
7226=item B<--force>
7227
7228Do not ask for confirmation, remove immediately.
7229
7230=back
7231
7232
7233=head2 update [I<option>]... [I<pkg>]...
7234
7235Updates the packages given as arguments to the latest version available
7236at the installation source.  Either C<--all> or at least one I<pkg> name
7237must be specified.  Options:
7238
7239=over 4
7240
7241=item B<--all>
7242
7243Update all installed packages except for C<tlmgr> itself.  Thus, if
7244updates to C<tlmgr> itself are present, this will simply give an error,
7245unless also the option C<--force> or C<--self> is given.  (See below.)
7246
7247In addition to updating the installed packages, during the update of a
7248collection the local installation is (by default) synchronized to the
7249status of the collection on the server, for both additions and removals.
7250
7251This means that if a package has been removed on the server (and thus
7252has also been removed from the respective collection), C<tlmgr> will
7253remove the package in the local installation.  This is called
7254``auto-remove'' and is announced as such when using the option
7255C<--list>.  This auto-removal can be suppressed using the option
7256C<--no-auto-remove> (not recommended, see option description).
7257
7258Analogously, if a package has been added to a collection on the server
7259that is also installed locally, it will be added to the local
7260installation.  This is called ``auto-install'' and is announced as such
7261when using the option C<--list>.  This auto-installation can be
7262suppressed using the option C<--no-auto-install>.
7263
7264An exception to the collection dependency checks (including the
7265auto-installation of packages just mentioned) are those that have been
7266``forcibly removed'' by you, that is, you called C<tlmgr remove --force>
7267on them.  (See the C<remove> action documentation.)  To reinstall any
7268such forcibly removed packages use C<--reinstall-forcibly-removed>.
7269
7270If you want to exclude some packages from the current update run (e.g.,
7271due to a slow link), see the C<--exclude> option below.
7272
7273=item B<--self>
7274
7275Update C<tlmgr> itself (that is, the infrastructure packages) if updates
7276to it are present. On Windows this includes updates to the private Perl
7277interpreter shipped inside TeX Live.
7278
7279If this option is given together with either C<--all> or a list of
7280packages, then C<tlmgr> will be updated first and, if this update
7281succeeds, the new version will be restarted to complete the rest of the
7282updates.
7283
7284In short:
7285
7286  tlmgr update --self        # update infrastructure only
7287  tlmgr update --self --all  # update infrastructure and all packages
7288  tlmgr update --force --all # update all packages but *not* infrastructure
7289                             # ... this last at your own risk, not recommended!
7290
7291=item B<--dry-run>
7292
7293Nothing is actually installed; instead, the actions to be performed are
7294written to the terminal.  This is a more detailed report than C<--list>.
7295
7296=item B<--list> [I<pkg>]
7297
7298Concisely list the packages which would be updated, newly installed, or
7299removed, without actually changing anything.
7300If C<--all> is also given, all available updates are listed.
7301If C<--self> is given, but not C<--all>, only updates to the
7302critical packages (tlmgr, texlive infrastructure, perl on Windows, etc.)
7303are listed.
7304If neither C<--all> nor C<--self> is given, and in addition no I<pkg> is
7305given, then C<--all> is assumed (thus, C<tlmgr update --list> is the
7306same as C<tlmgr update --list --all>).
7307If neither C<--all> nor C<--self> is given, but specific package names are
7308given, those packages are checked for updates.
7309
7310=item B<--exclude> I<pkg>
7311
7312Exclude I<pkg> from the update process.  If this option is given more
7313than once, its arguments accumulate.
7314
7315An argument I<pkg> excludes both the package I<pkg> itself and all
7316its related platform-specific packages I<pkg.ARCH>.  For example,
7317
7318  tlmgr update --all --exclude a2ping
7319
7320will not update C<a2ping>, C<a2ping.i386-linux>, or
7321any other C<a2ping.>I<ARCH> package.
7322
7323If this option specifies a package that would otherwise be a candidate
7324for auto-installation, auto-removal, or reinstallation of a forcibly
7325removed package, C<tlmgr> quits with an error message.  Excludes are not
7326supported in these circumstances.
7327
7328=item B<--no-auto-remove> [I<pkg>]...
7329
7330By default, C<tlmgr> tries to remove packages which have disappeared on
7331the server, as described above under C<--all>.  This option prevents
7332such removals, either for all packages (with C<--all>), or for just the
7333given I<pkg> names.  This can lead to an inconsistent TeX installation,
7334since packages are not infrequently renamed or replaced by their
7335authors.  Therefore this is not recommend.
7336
7337=item B<--no-auto-install> [I<pkg>]...
7338
7339Under normal circumstances C<tlmgr> will install packages which are new
7340on the server, as described above under C<--all>.  This option prevents
7341any such automatic installation, either for all packages (with
7342C<--all>), or the given I<pkg> names.
7343
7344Furthermore, after the C<tlmgr> run using this has finished, the
7345packages that would have been auto-installed I<will be considered as
7346forcibly removed>.  So, if C<foobar> is the only new package on the
7347server, then
7348
7349  tlmgr update --all --no-auto-install
7350
7351is equivalent to
7352
7353  tlmgr update --all
7354  tlmgr remove --force foobar
7355
7356=item B<--reinstall-forcibly-removed>
7357
7358Under normal circumstances C<tlmgr> will not install packages that have
7359been forcibly removed by the user; that is, removed with C<remove
7360--force>, or whose installation was prohibited by C<--no-auto-install>
7361during an earlier update.
7362
7363This option makes C<tlmgr> ignore the forcible removals and re-install
7364all such packages. This can be used to completely synchronize an
7365installation with the server's idea of what is available:
7366
7367  tlmgr update --reinstall-forcibly-removed --all
7368
7369=item B<--backup> and B<--backupdir> I<directory>
7370
7371These two options control the creation of backups of packages I<before>
7372updating; that is, backup of packages as currently installed.  If
7373neither of these options are given, no backup package will be saved. If
7374C<--backupdir> is given and specifies a writable directory then a backup
7375will be made in that location. If only C<--backup> is given, then a
7376backup will be made to the directory previously set via the C<option>
7377action (see below). If both are given then a backup will be made to the
7378specified I<directory>.
7379
7380You can set options via the C<option> action to automatically create
7381backups for all packages, and/or keep only a certain number of
7382backups.  Please see the C<option> action for details.
7383
7384C<tlmgr> always makes a temporary backup when updating packages, in case
7385of download or other failure during an update.  In contrast, the purpose
7386of this C<--backup> option is to allow you to save a persistent backup
7387in case the actual I<content> of the update causes problems, e.g.,
7388introduces an incompatibility.
7389
7390The C<restore> action explains how to restore from a backup.
7391
7392=item B<--no-depends>
7393
7394If you call for updating a package normally all depending packages
7395will also be checked for updates and updated if necessary. This switch
7396suppresses this behavior.
7397
7398=item B<--no-depends-at-all>
7399
7400See above under B<install> (and beware).
7401
7402=item B<--force>
7403
7404Force update of normal packages, without updating C<tlmgr> itself
7405(unless the C<--self> option is also given).  Not recommended.
7406
7407Also, C<update --list> is still performed regardless of this option.
7408
7409=back
7410
7411If the package on the server is older than the package already installed
7412(e.g., if the selected mirror is out of date), C<tlmgr> does not
7413downgrade.  Also, packages for uninstalled platforms are not installed.
7414
7415C<tlmgr> saves a copy of the C<texlive.tlpdb> file used for an update
7416with a suffix representing the repository url, as in
7417C<tlpkg/texlive.tlpdb.>I<long-hash-string>.  These can be useful for
7418fallback information, but if you don't like them accumulating (e.g.,
7419on each run C<mirror.ctan.org> might resolve to a new host, resulting in
7420a different hash), it's harmless to delete them.
7421
7422=head1 USER MODE
7423
7424C<tlmgr> provides a restricted way, called ``user mode'', to manage
7425arbitrary texmf trees in the same way as the main installation.  For
7426example, this allows people without write permissions on the
7427installation location to update/install packages into a tree of their
7428own.
7429
7430C<tlmgr> is switched into user mode with the command line option
7431C<--usermode>.  It does not switch automatically, nor is there any
7432configuration file setting for it.  Thus, this option has to be
7433explicitly given every time user mode is to be activated.
7434
7435This mode of C<tlmgr> works on a user tree, by default the value of the
7436C<TEXMFHOME> variable.  This can be overridden with the command line
7437option C<--usertree>.  In the following when we speak of the user tree
7438we mean either C<TEXMFHOME> or the one given on the command line.
7439
7440Not all actions are allowed in user mode; C<tlmgr> will warn you and not
7441carry out any problematic actions.  Currently not supported (and
7442probably will never be) is the C<platform> action.  The C<gui> action is
7443currently not supported, but may be in a future release.
7444
7445Some C<tlmgr> actions don't need any write permissions and thus work the
7446same in user mode and normal mode.  Currently these are: C<check>,
7447C<help>, C<list>, C<print-platform>, C<search>, C<show>, C<version>.
7448
7449On the other hand, most of the actions dealing with package management
7450do need write permissions, and thus behave differently in user mode, as
7451described below: C<install>, C<update>, C<remove>, C<option>, C<paper>,
7452C<generate>, C<backup>, C<restore>, C<uninstall>, C<symlinks>.
7453
7454Before using C<tlmgr> in user mode, you have to set up the user tree
7455with the C<init-usertree> action.  This creates I<usertree>C</web2c> and
7456I<usertree>C</tlpkg/tlpobj>, and a minimal
7457I<usertree>C</tlpkg/texlive.tlpdb>.  At that point, you can tell
7458C<tlmgr> to do the (supported) actions by adding the C<--usermode>
7459command line option.
7460
7461In user mode the file I<usertree>C</tlpkg/texlive.tlpdb> contains only
7462the packages that have been installed into the user tree using C<tlmgr>,
7463plus additional options from the ``virtual'' package
7464C<00texlive.installation> (similar to the main installation's
7465C<texlive.tlpdb>).
7466
7467All actions on packages in user mode can only be carried out on packages
7468that are known as C<relocatable>.  This excludes all packages containing
7469executables and a few other core packages.  Of the 2500 or so packages
7470currently in TeX Live the vast majority are relocatable and can be
7471installed into a user tree.
7472
7473Description of changes of actions in user mode:
7474
7475=head2 User mode install
7476
7477In user mode, the C<install> action checks that the package and all
7478dependencies are all either relocated or already installed in the system
7479installation.  If this is the case, it unpacks all containers to be
7480installed into the user tree (to repeat, that's either C<TEXMFHOME> or
7481the value of C<--usertree>) and add the respective packages to the user
7482tree's C<texlive.tlpdb> (creating it if need be).
7483
7484Currently installing a collection in user mode installs all dependent
7485packages, but in contrast to normal mode, does I<not> install dependent
7486collections.  For example, in normal mode C<tlmgr install
7487collection-context> would install C<collection-basic> and other
7488collections, while in user mode, I<only> the packages mentioned in
7489C<collection-context> are installed.
7490
7491=head2 User mode backup, restore, remove, update
7492
7493In user mode, these actions check that all packages to be acted on are
7494installed in the user tree before proceeding; otherwise, they behave
7495just as in normal mode.
7496
7497=head2 User mode generate, option, paper
7498
7499In user mode, these actions operate only on the user tree's
7500configuration files and/or C<texlive.tlpdb>.
7501creates configuration files in user tree
7502
7503
7504=head1 CONFIGURATION FILE FOR TLMGR
7505
7506A small subset of the command line options can be set in a config file
7507for C<tlmgr> which resides in C<TEXMFCONFIG/tlmgr/config>.  By default, the
7508config file is in C<~/.texliveYYYY/texmf-config/tlmgr/config> (replacing
7509C<YYYY> with the year of your TeX Live installation). This is I<not>
7510C<TEXMFSYSVAR>, so that the file is specific to a single user.
7511
7512In this file, empty lines and lines starting with # are ignored.  All
7513other lines must look like
7514
7515  key = value
7516
7517where the allowed keys are C<gui-expertmode> (value 0 or 1),
7518C<persistent-downloads> (value 0 or 1), C<auto-remove> (value 0 or 1),
7519and C<gui-lang> (value like in the command line option).
7520
7521C<persistent-downloads>, C<gui-lang>, and C<auto-remove> correspond to
7522the respective command line options of the same name.  C<gui-expertmode>
7523switches between the full GUI and a simplified GUI with only the
7524important and mostly used settings.
7525
7526
7527=head1 MULTIPLE REPOSITORIES
7528
7529The main TeX Live repository contains a vast array of packages.
7530Nevertheless, additional local repositories can be useful to provide
7531locally-installed resources, such as proprietary fonts and house styles.
7532Also, alternative package repositories distribute packages that cannot
7533or should not be included in TeX Live, for whatever reason.
7534
7535The simplest and most reliable method is to temporarily set the
7536installation source to any repository (with the C<-repository> or
7537C<option repository> command line options), and perform your operations.
7538
7539When you are using multiple repositories over a sustained time, however,
7540explicitly switching between them becomes inconvenient.  Thus, it's
7541possible to tell C<tlmgr> about additional repositories you want to use.
7542The basic command is C<tlmgr repository add>.  The rest of this section
7543explains further.
7544
7545When using multiple repositories, one of them has to be set as the main
7546repository, which distributes most of the installed packages.  When you
7547switch from a single repository installation to a multiple repository
7548installation, the previous sole repository will be set as the main
7549repository.
7550
7551By default, even if multiple repositories are configured, packages are
7552I<still> I<only> installed from the main repository.  Thus, simply
7553adding a second repository does not actually enable installation of
7554anything from there.  You also have to specify which packages should be
7555taken from the new repository, by specifying so-called ``pinning''
7556rules, described next.
7557
7558=head2 Pinning
7559
7560When a package C<foo> is pinned to a repository, a package C<foo> in any
7561other repository, even if it has a higher revision number, will not be
7562considered an installable candidate.
7563
7564As mentioned above, by default everything is pinned to the main
7565repository.  Let's now go through an example of setting up a second
7566repository and enabling updates of a package from it.
7567
7568First, check that we have support for multiple repositories, and have
7569only one enabled (as is the case by default):
7570
7571 $ tlmgr repository list
7572 List of repositories (with tags if set):
7573   /var/www/norbert/tlnet
7574
7575Ok.  Let's add the C<tlcontrib> repository (this is a real
7576repository, hosted at L<http://tlcontrib.metatex.org>, maintained by
7577Taco Hoekwater et al.), with the tag C<tlcontrib>:
7578
7579 $ tlmgr repository add http://tlcontrib.metatex.org/2012 tlcontrib
7580
7581Check the repository list again:
7582
7583 $ tlmgr repository list
7584 List of repositories (with tags if set):
7585    http://tlcontrib.metatex.org/2012 (tlcontrib)
7586    /var/www/norbert/tlnet (main)
7587
7588Now we specify a pinning entry to get the package C<context> from
7589C<tlcontrib>:
7590
7591 $ tlmgr pinning add tlcontrib context
7592
7593Check that we can find C<context>:
7594
7595 $ tlmgr show context
7596 tlmgr: package repositories:
7597 ...
7598 package:     context
7599 repository:  tlcontrib/26867
7600 ...
7601
7602- install C<context>:
7603
7604 $ tlmgr install context
7605 tlmgr: package repositories:
7606 ...
7607 [1/1,  ??:??/??:??] install: context @tlcontrib [
7608
7609In the output here you can see that the C<context> package has been
7610installed from the C<tlcontrib> repository (C<@tlcontrib>).
7611
7612Finally, C<tlmgr pinning> also supports removing certain or all packages
7613from a given repository:
7614
7615  $ tlmgr pinning remove tlcontrib context  # remove just context
7616  $ tlmgr pinning remove tlcontrib --all    # take nothing from tlcontrib
7617
7618A summary of the C<tlmgr pinning> actions is given above.
7619
7620
7621=head1 GUI FOR TLMGR
7622
7623The graphical user interface for C<tlmgr> needs Perl/Tk to be installed.
7624For Windows the necessary modules are shipped within TeX Live, for all
7625other (i.e., Unix-based) systems Perl/Tk (as well as Perl of course) has
7626to be installed.  L<http://tug.org/texlive/distro.html#perltk> has a
7627list of invocations for some distros.
7628
7629When started with C<tlmgr gui> the graphical user interface will be
7630shown.  The main window contains a menu bar, the main display, and a
7631status area where messages normally shown on the console are displayed.
7632
7633Within the main display there are three main parts: the C<Display
7634configuration> area, the list of packages, and the action buttons.
7635
7636Also, at the top right the currently loaded repository is shown; this
7637also acts as a button and when clicked will try to load the default
7638repository.  To load a different repository, see the C<tlmgr> menu item.
7639
7640Finally, the status area at the bottom of the window gives additional
7641information about what is going on.
7642
7643
7644=head2 Main display
7645
7646=head3 Display configuration area
7647
7648The first part of the main display allows you to specify (filter) which
7649packages are shown.  By default, all are shown.  Changes here are
7650reflected right away.
7651
7652=over 4
7653
7654=item Status
7655
7656Select whether to show all packages (the default), only those installed,
7657only those I<not> installed, or only those with update available.
7658
7659=item Category
7660
7661Select which categories are shown: packages, collections, and/or
7662schemes.  These are briefly explained in the L</DESCRIPTION> section
7663above.
7664
7665=item Match
7666
7667Select packages matching for a specific pattern.  By default, this
7668searches both descriptions and filenames.  You can also select a subset
7669for searching.
7670
7671=item Selection
7672
7673Select packages to those selected, those not selected, or all.  Here,
7674``selected'' means that the checkbox in the beginning of the line of a
7675package is ticked.
7676
7677=item Display configuration buttons
7678
7679To the right there are three buttons: select all packages, select none
7680(a.k.a. deselect all), and reset all these filters to the defaults,
7681i.e., show all available.
7682
7683=back
7684
7685=head3 Package list area
7686
7687The second are of the main display lists all installed packages.  If a
7688repository is loaded, those that are available but not installed are
7689also listed.
7690
7691Double clicking on a package line pops up an informational window with
7692further details: the long description, included files, etc.
7693
7694Each line of the package list consists of the following items:
7695
7696=over 4
7697
7698=item a checkbox
7699
7700Used to select particular packages; some of the action buttons (see
7701below) work only on the selected packages.
7702
7703=item package name
7704
7705The name (identifier) of the package as given in the database.
7706
7707=item local revision (and version)
7708
7709If the package is installed the TeX Live revision number for the
7710installed package will be shown.  If there is a catalogue version given
7711in the database for this package, it will be shown in parentheses.
7712However, the catalogue version, unlike the TL revision, is not
7713guaranteed to reflect what is actually installed.
7714
7715=item remote revision (and version)
7716
7717If a repository has been loaded the revision of the package in the
7718repository (if present) is shown.  As with the local column, if a
7719catalogue version is provided it will be displayed.  And also as with
7720the local column, the catalogue version may be stale.
7721
7722=item short description
7723
7724The short description of the package.
7725
7726=back
7727
7728=head3 Main display action buttons
7729
7730Below the list of packages are several buttons:
7731
7732=over 4
7733
7734=item Update all installed
7735
7736This calls C<tlmgr update --all>, i.e., tries to update all available
7737packages.  Below this button is a toggle to allow reinstallation of
7738previously removed packages as part of this action.
7739
7740The other four buttons only work on the selected packages, i.e., those
7741where the checkbox at the beginning of the package line is ticked.
7742
7743=item Update
7744
7745Update only the selected packages.
7746
7747=item Install
7748
7749Install the selected packages; acts like C<tlmgr install>, i.e., also
7750installs dependencies.  Thus, installing a collection installs all its
7751constituent packages.
7752
7753=item Remove
7754
7755Removes the selected packages; acts like C<tlmgr remove>, i.e., it will
7756also remove dependencies of collections (but not dependencies of normal
7757packages).
7758
7759=item Backup
7760
7761Makes a backup of the selected packages; acts like C<tlmgr backup>. This
7762action needs the option C<backupdir> set (see C<Options -> General>).
7763
7764=back
7765
7766
7767=head2 Menu bar
7768
7769The following entries can be found in the menu bar:
7770
7771=over 4
7772
7773=item C<tlmgr> menu
7774
7775The items here load various repositories: the default as specified in
7776the TeX Live database, the default network repository, the repository
7777specified on the command line (if any), and an arbitrarily
7778manually-entered one.  Also has the so-necessary C<quit> operation.
7779
7780=item C<Options menu>
7781
7782Provides access to several groups of options: C<Paper> (configuration of
7783default paper sizes), C<Platforms> (only on Unix, configuration of the
7784supported/installed platforms), C<GUI Language> (select language used in
7785the GUI interface), and C<General> (everything else).
7786
7787Several toggles are also here.  The first is C<Expert options>, which is
7788set by default.  If you turn this off, the next time you start the GUI a
7789simplified screen will be shown that display only the most important
7790functionality.  This setting is saved in the configuration file of
7791C<tlmgr>; see L<CONFIGURATION FILE FOR TLMGR> for details.
7792
7793The other toggles are all off by default: for debugging output, to
7794disable the automatic installation of new packages, and to disable the
7795automatic removal of packages deleted from the server.  Playing with the
7796choices of what is or isn't installed may lead to an inconsistent TeX Live
7797installation; e.g., when a package is renamed.
7798
7799=item C<Actions menu>
7800
7801Provides access to several actions: update the filename database (aka
7802C<ls-R>, C<mktexlsr>, C<texhash>), rebuild all formats (C<fmtutil-sys
7803--all>), update the font map database (C<updmap-sys>), restore from a backup
7804of a package, and use of symbolic links in system directories (not on
7805Windows).
7806
7807The final action is to remove the entire TeX Live installation (also not
7808on Windows).
7809
7810=item C<Help menu>
7811
7812Provides access to the TeX Live manual (also on the web at
7813L<http://tug.org/texlive/doc.html>) and the usual ``About'' box.
7814
7815=back
7816
7817
7818=head1 MACHINE-READABLE OUTPUT
7819
7820With the C<--machine-readable> option, C<tlmgr> writes to stdout in the
7821fixed line-oriented format described here, and the usual informational
7822messages for human consumption are written to stderr (normally they are
7823written to stdout).  The idea is that a program can get all the
7824information it needs by reading stdout.
7825
7826Currently this option only applies to the
7827L<update|/update [I<option>]... [I<pkg>]...>,
7828L<install|/install [I<option>]... I<pkg>...>, and
7829L</option> actions.
7830
7831
7832=head2 Machine-readable C<update> and C<install> output
7833
7834The output format is as follows:
7835
7836  fieldname "\t" value
7837  ...
7838  "end-of-header"
7839  pkgname status localrev serverrev size runtime esttot
7840  ...
7841  "end-of-updates"
7842  other output from post actions, not in machine readable form
7843
7844The header section currently has two fields: C<location-url> (the
7845repository source from which updates are being drawn), and
7846C<total-bytes> (the total number of bytes to be downloaded).
7847
7848The I<localrev> and I<serverrev> fields for each package are the
7849revision numbers in the local installation and server repository,
7850respectively.  The I<size> field is the number of bytes to be
7851downloaded, i.e., the size of the compressed tar file for a network
7852installation, not the unpacked size. The runtime and esttot fields
7853are only present for updated and auto-install packages, and contain
7854the currently passed time since start of installation/updates
7855and the estimated total time.
7856
7857Line endings may be either LF or CRLF depending on the current platform.
7858
7859=over 4
7860
7861=item C<location-url> I<location>
7862
7863The I<location> may be a url (including C<file:///foo/bar/...>), or a
7864directory name (C</foo/bar>).  It is the package repository from which
7865the new package information was drawn.
7866
7867=item C<total-bytes> I<count>
7868
7869The I<count> is simply a decimal number, the sum of the sizes of all the
7870packages that need updating or installing (which are listed subsequently).
7871
7872=back
7873
7874Then comes a line with only the literal string C<end-of-header>.
7875
7876Each following line until a line with literal string C<end-of-updates>
7877reports on one package.  The fields on
7878each line are separated by a tab.  Here are the fields.
7879
7880=over 4
7881
7882=item I<pkgname>
7883
7884The TeX Live package identifier, with a possible platform suffix for
7885executables.  For instance, C<pdftex> and C<pdftex.i386-linux> are given
7886as two separate packages, one on each line.
7887
7888=item I<status>
7889
7890The status of the package update.  One character, as follows:
7891
7892=over 8
7893
7894=item C<d>
7895
7896The package was removed on the server.
7897
7898=item C<f>
7899
7900The package was removed in the local installation, even though a
7901collection depended on it.  (E.g., the user ran C<tlmgr remove
7902--force>.)
7903
7904=item C<u>
7905
7906Normal update is needed.
7907
7908=item C<r>
7909
7910Reversed non-update: the locally-installed version is newer than the
7911version on the server.
7912
7913=item C<a>
7914
7915Automatically-determined need for installation, the package is new on
7916the server and is (most probably) part of an installed collection.
7917
7918=item C<i>
7919
7920Package will be installed and isn't present in the local installation
7921(action install).
7922
7923=item C<I>
7924
7925Package is already present but will be reinstalled (action install).
7926
7927=back
7928
7929=item I<localrev>
7930
7931The revision number of the installed package, or C<-> if it is not
7932present locally.
7933
7934=item I<serverrev>
7935
7936The revision number of the package on the server, or C<-> if it is not
7937present on the server.
7938
7939=item I<size>
7940
7941The size in bytes of the package on the server.  The sum of all the
7942package sizes is given in the C<total-bytes> header field mentioned above.
7943
7944=item I<runtime>
7945
7946The run time since start of installations or updates.
7947
7948=item I<esttot>
7949
7950The estimated total time.
7951
7952=back
7953
7954=head2 Machine-readable C<option> output
7955
7956The output format is as follows:
7957
7958  key "\t" value
7959
7960If a value is not saved in the database the string C<(not set)> is shown.
7961
7962If you are developing a program that uses this output, and find that
7963changes would be helpful, do not hesitate to write the mailing list.
7964
7965
7966=head1 AUTHORS AND COPYRIGHT
7967
7968This script and its documentation were written for the TeX Live
7969distribution (L<http://tug.org/texlive>) and both are licensed under the
7970GNU General Public License Version 2 or later.
7971
7972=cut
7973
7974# to remake HTML version: pod2html --cachedir=/tmp tlmgr.pl >/foo/tlmgr.html.
7975
7976### Local Variables:
7977### perl-indent-level: 2
7978### tab-width: 2
7979### indent-tabs-mode: nil
7980### End:
7981# vim:set tabstop=2 expandtab: #
7982