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