"Fossies" - the Fresh Open Source Software Archive

Member "install-tl-20231204/install-tl" (7 Aug 2023, 125713 Bytes) of package /linux/misc/install-tl-unx.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Perl source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

A hint: This file contains one or more very long lines, so maybe it is better readable using the pure text view mode that shows the contents as wrapped lines within the browser window.


    1 #!/usr/bin/env perl
    2 # $Id: install-tl 67839 2023-08-07 21:47:31Z preining $
    3 # Copyright 2007-2023
    4 # Reinhard Kotucha, Norbert Preining, Karl Berry, Siep Kroonenberg.
    5 # This file is licensed under the GNU General Public License version 2
    6 # or any later version.
    7 #
    8 # TeX Live standalone installer.
    9 #
   10 # Be careful when changing wording: *every* normal informational message
   11 # output here must be recognized by the long grep in tl-update-tlnet.
   12 
   13 use strict; use warnings;
   14 
   15 my $svnrev = '$Revision: 67839 $';
   16 $svnrev =~ m/: ([0-9]+) /;
   17 $::installerrevision = ($1 ? $1 : 'unknown');
   18 
   19 # taken from 00texlive.config: release, $tlpdb->config_release;
   20 our $texlive_release;
   21 
   22 BEGIN {
   23   $^W = 1;
   24   my $Master;
   25   my $me = $0;
   26   $me =~ s!\\!/!g if $^O =~ /^MSWin/i;
   27   if ($me =~ m!/!) {
   28     ($Master = $me) =~ s!(.*)/[^/]*$!$1!;
   29   } else {
   30     $Master = ".";
   31   }
   32   $::installerdir = $Master;
   33 
   34   # All platforms: add the installer modules
   35   unshift (@INC, "$::installerdir/tlpkg");
   36 }
   37 
   38 # debugging communication with external gui: use shared logfile
   39 
   40 our $dblfile = "/tmp/dblog";
   41 $dblfile = $ENV{'TEMP'} . "\\dblog.txt" if ($^O =~ /^MSWin/i);
   42 $dblfile = $ENV{'TMPDIR'} . "/dblog" if ($^O eq 'darwin'
   43                                          && exists $ENV{'TMPDIR'});
   44 sub dblog {
   45   my $s = shift;
   46   open(my $dbf, ">>", $dblfile);
   47   print $dbf "PERL: $s\n";
   48   close $dbf;
   49 }
   50 
   51 sub dblogsub {
   52   my $s = shift;
   53   my @stck = (caller(1));
   54   dblog "$stck[3] $s";
   55 }
   56 
   57 # On unix, this run of install-tl may do duty as a wrapper for
   58 # install-tl-gui.tcl, which in its turn will start an actual run of install-tl.
   59 # Skip this wrapper block if we can easily rule out a tcl gui:
   60 
   61 if (($^O !~ /^MSWin/i) &&
   62       # this wrapper is only for unix, since windows has its own wrapper
   63       ($#ARGV >= 0) && ($ARGV[0] ne '-from_ext_gui')
   64         # this run is not invoked by tcl
   65     ) {
   66 
   67   # make syntax uniform: --a => -a, a=b => 'a b'
   68   my @tmp_args = ();
   69   my $p;
   70   my $i=-1;
   71   while ($i<$#ARGV) {
   72     $p = $ARGV[++$i];
   73     $p =~ s/^--/-/;
   74     if ($p =~ /^(.*)=(.*)$/) {
   75       push (@tmp_args, $1, $2);
   76     } else {
   77       push (@tmp_args, $p);
   78     }
   79   }
   80 
   81   # build argument array @new_args for install-tl-gui.tcl.
   82   # '-gui' or '-gui tcl' will not be copied to @new_args.
   83   # quit scanning and building @new_args once tcl is ruled out.
   84   my $want_tcl = 0;
   85   my $asked4tcl = 0;
   86   my $forbid = 0;
   87   my @new_args = ();
   88   $i = -1;
   89   while ($i < $#tmp_args) {
   90     $p = $tmp_args[++$i];
   91     if ($p eq '-gui') {
   92       # look ahead at next parameter
   93       if ($i == $#tmp_args || $tmp_args[$i+1] =~ /^-/) {
   94         # just -gui, without value
   95         $want_tcl = 1;
   96         $asked4tcl = 1;
   97       } elsif ($tmp_args[$i+1] eq 'text') {
   98         $want_tcl = 0;
   99         $forbid = 1;
  100         last;
  101       } else {
  102         # check all allowed values for -gui
  103         my $q = $tmp_args[$i+1];
  104         if ($q eq 'tcl' || $q eq 'perltk' ||
  105             $q eq 'wizard' || $q eq 'expert') {
  106           $want_tcl = 1;
  107           $asked4tcl = 1;
  108           $i++;
  109         } else {
  110           die "$0: invalid value for parameter -gui: $q\n";
  111         }
  112       }
  113     } else {
  114       for my $q (qw/in-place profile help print-arch print-platform
  115                     version no-gui/) {
  116         if ($p eq "-$q") {
  117           # ignore gui mode
  118           $want_tcl = 0;
  119           $forbid = 1;
  120           last;
  121         }
  122       }
  123       last if $forbid;
  124       # not gui-related, continue collecting @new_args
  125       push (@new_args, $p);
  126     }
  127   }
  128   # done scanning arguments
  129   if ($want_tcl) {
  130     unshift (@new_args, "--");
  131     unshift (@new_args, "$::installerdir/tlpkg/installer/install-tl-gui.tcl");
  132     my @wishes = qw /wish wish8.7 wish8.6 wish8.5 tclkit/;
  133     unshift @wishes, $ENV{'WISH'} if (defined $ENV{'WISH'});
  134     foreach my $w (@wishes) {
  135       if (!exec($w, @new_args)) {
  136         next; # no return on successful exec
  137       }
  138     }
  139     # no succesful exec of wish
  140   } # else continue with main installer below
  141 }
  142 # end of wrapper block, start of the real installer
  143 
  144 use Cwd 'abs_path';
  145 use Getopt::Long qw(:config no_autoabbrev);
  146 use Pod::Usage;
  147 use POSIX ();
  148 
  149 use TeXLive::TLUtils qw(platform platform_desc sort_archs
  150    which getenv wndws unix info log debug tlwarn ddebug tldie
  151    member process_logging_options rmtree wsystem
  152    mkdirhier make_var_skeleton make_local_skeleton install_package copy
  153    install_packages dirname setup_programs native_slashify forward_slashify);
  154 use TeXLive::TLConfig;
  155 use TeXLive::TLCrypto;
  156 use TeXLive::TLDownload;
  157 use TeXLive::TLPDB;
  158 use TeXLive::TLPOBJ;
  159 use TeXLive::TLPaper;
  160 
  161 use Encode::Alias;
  162 eval {
  163   require Encode::Locale;
  164   Encode::Locale->import ();
  165   debug("Encode::Locale is loaded.\n");
  166 };
  167 if ($@) {
  168   if (wndws()) {
  169     die ("For Windows, Encode::Locale is required.\n");
  170   }
  171 
  172   debug("Encode::Locale is not found. Assuming all encodings are UTF-8.\n");
  173   Encode::Alias::define_alias('locale' => 'UTF-8');
  174   Encode::Alias::define_alias('locale_fs' => 'UTF-8');
  175   Encode::Alias::define_alias('console_in' => 'UTF-8');
  176   Encode::Alias::define_alias('console_out' => 'UTF-8');
  177 }
  178 binmode (STDIN, ':encoding(console_in)');
  179 binmode (STDOUT, ':encoding(console_out)');
  180 binmode (STDERR, ':encoding(console_out)');
  181 
  182 if (wndws()) {
  183   require TeXLive::TLWinGoo;
  184   TeXLive::TLWinGoo->import( qw(
  185     &admin
  186     &non_admin
  187     &reg_country
  188     &expand_string
  189     &get_system_path
  190     &get_user_path
  191     &setenv_reg
  192     &unsetenv_reg
  193     &adjust_reg_path_for_texlive
  194     &register_extension
  195     &unregister_extension
  196     &register_file_type
  197     &unregister_file_type
  198     &broadcast_env
  199     &update_assocs
  200     &add_menu_shortcut
  201     &remove_desktop_shortcut
  202     &remove_menu_shortcut
  203     &create_uninstaller
  204     &maybe_make_ro
  205   ));
  206 }
  207 
  208 # global list of lines that get logged (see TLUtils.pm::_logit).
  209 @::LOGLINES = ();
  210 # if --version, --help, etc., this just gets thrown away, which is ok.
  211 &log ("TeX Live installer invocation: $0", map { " $_" } @ARGV, "\n");
  212 
  213 # global list of warnings
  214 @::WARNLINES = ();
  215 
  216 # we play around with the environment, place to keep original
  217 my %origenv = ();
  218 
  219 # $install{$packagename} == 1 if it should be installed
  220 my %install;
  221 
  222 # the different modules have to assign a code blob to this global variable
  223 # which starts the installation.
  224 # Example: In install-menu-text.pl there is
  225 #   $::run_menu = \&run_menu_text;
  226 #
  227 $::run_menu = sub { die "no UI defined." ; };
  228 
  229 # the default scheme to be installed
  230 my $default_scheme='scheme-full';
  231 
  232 # common fmtutil args, keep in sync with tlmgr.pl.
  233 our $common_fmtutil_args =
  234   "--no-error-if-no-engine=$TeXLive::TLConfig::PartialEngineSupport";
  235 
  236 # some arrays where the lists of collections to be installed are saved
  237 # our for menus
  238 our @collections_std;
  239 
  240 # The global variable %vars is an associative list which contains all
  241 # variables and their values which can be changed by the user.
  242 # needs to be our since TeXLive::TLUtils uses it
  243 #
  244 # The following values are taken from the remote tlpdb using the
  245 #   $tlpdb->tlpdbopt_XXXXX
  246 # settings (i.e., taken from tlpkg/tlpsrc/00texlive.installation.tlpsrc
  247 #
  248 #        'tlpdbopt_sys_bin' => '/usr/local/bin',
  249 #        'tlpdbopt_sys_man' => '/usr/local/man',
  250 #        'tlpdbopt_sys_info' => '/usr/local/info',
  251 #        'tlpdbopt_install_docfiles' => 1,
  252 #        'tlpdbopt_install_srcfiles' => 1,
  253 #        'tlpdbopt_create_formats' => 0,
  254 our %vars=( # 'n_' means 'number of'.
  255         'this_platform' => '',
  256         'n_systems_available' => 0,
  257         'n_systems_selected' => 0,
  258         'n_collections_selected' => 0,
  259         'n_collections_available' => 0,
  260         'total_size' => 0,
  261         'src_splitting_supported' => 1,
  262         'doc_splitting_supported' => 1,
  263         'selected_scheme' => $default_scheme,
  264         'instopt_portable' => 0,
  265         'instopt_letter' => 0,
  266         'instopt_adjustrepo' => 1,
  267         'instopt_write18_restricted' => 1,
  268         'instopt_adjustpath' => 0,
  269     );
  270 
  271 my %path_keys = (
  272   'TEXDIR' => 1,
  273   'TEXMFHOME' => 1,
  274   'TEXMFLOCAL' => 1,
  275   'TEXMFCONFIG' => 1,
  276   'TEXMFSYSCONFIG' => 1,
  277   'TEXMFVAR' => 1,
  278   'TEXMFSYSVAR' => 1,
  279 );
  280 
  281 # option handling
  282 # tcl gui weeded out at start
  283 my $opt_allow_ftp = 0;
  284 my $opt_continue = 1;
  285 my $opt_custom_bin;
  286 my $opt_debug_fakenet = 0;
  287 my $opt_debug_setup_vars = 0;
  288 my $opt_doc_install = 1;
  289 my $opt_font;
  290 my $opt_force_arch;
  291 my $opt_gui = "text";
  292 my $opt_help = 0;
  293 my $opt_init_from_profile = "";
  294 my $opt_installation = 1;
  295 my $opt_interaction = 1;
  296 my $opt_location = "";
  297 my $opt_no_gui = 0;
  298 my $opt_no_interaction = 0;
  299 my $opt_nonadmin = 0;
  300 my $opt_paper = "";
  301 my $opt_persistent_downloads = 1;
  302 my $opt_portable = 0;
  303 my $opt_print_arch = 0;
  304 my $opt_profile = "";
  305 my $opt_scheme = "";
  306 my $opt_src_install = 1;
  307 my $opt_texdir = "";
  308 my $opt_texuserdir = "";
  309 my $opt_version = 0;
  310 my $opt_warn_checksums = 1;
  311 my %pathopts;
  312 # unusual cases:
  313 $::opt_select_repository = 0;
  314 our $opt_in_place = 0;
  315 # don't set this to a value, see below
  316 my $opt_verify_downloads;
  317 
  318 # show all options even those not relevant for that arch
  319 $::opt_all_options = 0;
  320 
  321 # default language for GUI installer
  322 $::lang = "en";
  323 
  324 # use the fancy directory selector for TEXDIR
  325 # no longer used, although we still accept the parameter
  326 #$::alternative_selector = 0;
  327 
  328 # do not debug translations by default
  329 $::debug_translation = 0;
  330 
  331 # List of packages that failed to install but we continued due to --continue
  332 @::installation_failed_packages = ();
  333 
  334 #
  335 # set up signal handlers to catch SIGINT and SIGTERM
  336 $SIG{'INT'} = \&signal_handler;
  337 # not necessary AFA we know
  338 # $SIG{TERM} = &signal_handler;
  339 
  340 # before we try to interact with the user, we need to know whether or not
  341 # install-tl was called from an external gui. This gui will start install-tl
  342 # with "-from_ext_gui" as its first command-line option.
  343 
  344 my $from_ext_gui = 0;
  345 if ((defined $ARGV[0]) && $ARGV[0] eq "-from_ext_gui") {
  346   shift @ARGV;
  347   $from_ext_gui = 1;
  348 
  349   # do not buffer output to the frontend
  350   select(STDERR); $| = 1;
  351   select(STDOUT); $| = 1;
  352 
  353   # windows: suppress console windows when invoking other programs
  354   Win32::SetChildShowWindow(0) if wndws();
  355 }
  356 
  357 # If we find a file installation.profile we ask the user whether we should
  358 # continue with the installation, unless there shouldn't be interaction.
  359 # We are in the directory from which the aborted installation was run.
  360 my %profiledata;
  361 if (-r "installation.profile"
  362     && $opt_interaction
  363     && !exists $ENV{"TEXLIVE_INSTALL_NO_RESUME"}) {
  364   if ($from_ext_gui) { # prepare for dialog interaction
  365     print "mess_yesno\n";
  366   }
  367   my $pwd = Cwd::getcwd();
  368   print "ABORTED TL INSTALLATION FOUND: installation.profile (in $pwd)\n";
  369   print
  370     "Do you want to continue with the exact same settings as before (y/N): ";
  371   print "\nendmess\n" if $from_ext_gui;
  372   my $answer = <STDIN>;
  373   if ($answer =~ m/^y(es)?$/i) {
  374     $opt_profile = "installation.profile";
  375   }
  376 }
  377 
  378 
  379 # first process verbosity/quiet options
  380 process_logging_options();
  381 # now the others
  382 GetOptions(
  383            "all-options"                 => \$::opt_all_options,
  384            "continue!"                   => \$opt_continue,
  385            "custom-bin=s"                => \$opt_custom_bin,
  386            "debug-fakenet"               => \$opt_debug_fakenet,
  387            "debug-setup-vars"            => \$opt_debug_setup_vars,
  388            "debug-translation"           => \$::debug_translation,
  389            "doc-install!"                => \$opt_doc_install,
  390            "fancyselector",
  391            "font=s"                      => \$opt_font,
  392            "force-platform|force-arch=s" => \$opt_force_arch,
  393            "gui:s"                       => \$opt_gui,
  394            "in-place"                    => \$opt_in_place,
  395            "init-from-profile=s"         => \$opt_init_from_profile,
  396            "installation!",              => \$opt_installation,
  397            "interaction!",               => \$opt_interaction,
  398            "lang|gui-lang=s"             => \$::opt_lang,
  399            "location|url|repository|repos|repo=s" => \$opt_location,
  400            "no-cls",                    # $::opt_no_cls in install-menu-text-pl
  401            "N"                           => \$opt_no_interaction,
  402            "no-gui"                      => \$opt_no_gui,
  403            "non-admin"                   => \$opt_nonadmin,
  404            "paper=s"                     => \$opt_paper,
  405            "persistent-downloads!"       => \$opt_persistent_downloads,
  406            "portable"                    => \$opt_portable,
  407            "print-platform|print-arch"   => \$opt_print_arch,
  408            "profile=s"                   => \$opt_profile,
  409            "scheme|s=s"                  => \$opt_scheme,
  410            "select-repository"           => \$::opt_select_repository,
  411            "src-install!"                => \$opt_src_install,
  412            "tcl",                       # handled by wrapper
  413            "texdir=s"                    => \$opt_texdir,
  414            "texmfconfig=s"               => \$pathopts{'texmfconfig'},
  415            "texmfhome=s"                 => \$pathopts{'texmfhome'},
  416            "texmflocal=s"                => \$pathopts{'texmflocal'},
  417            "texmfsysconfig=s"            => \$pathopts{'texmfsysconfig'},
  418            "texmfsysvar=s"               => \$pathopts{'texmfsysvar'},
  419            "texmfvar=s"                  => \$pathopts{'texmfvar'},
  420            "texuserdir=s"                => \$opt_texuserdir,
  421            "verify-downloads!"           => \$opt_verify_downloads,
  422            "version"                     => \$opt_version,
  423            "warn-checksums!"             => \$opt_warn_checksums,
  424            "help|?"                      => \$opt_help) or pod2usage(2);
  425 if ($from_ext_gui) {
  426   $opt_gui = "extl";
  427 }
  428 
  429 # just so we can use -N as abbreviation for --no-interaction.
  430 $opt_interaction = 0 if $opt_no_interaction;
  431 
  432 # informational invocations: help, version, platform
  433 
  434 if ($opt_help) {
  435   # theoretically we could make a subroutine with all the same
  436   # painful checks as we do in tlmgr, but let's not bother until people ask.
  437   my @noperldoc = ();
  438   if (wndws() || $ENV{"NOPERLDOC"}) {
  439     @noperldoc = ("-noperldoc", "1");
  440   }
  441 
  442   # Tweak less invocation same as tlmgr, though.
  443   # less can break control characters and thus the output of pod2usage
  444   # is broken.  We add/set LESS=-R in the environment and unset
  445   # LESSPIPE and LESSOPEN to try to help.
  446   # 
  447   if (defined($ENV{'LESS'})) {
  448     $ENV{'LESS'} .= " -R";
  449   } else {
  450     $ENV{'LESS'} = "-R";
  451   }
  452   delete $ENV{'LESSPIPE'};
  453   delete $ENV{'LESSOPEN'};
  454 
  455   pod2usage(-exitstatus => 0, -verbose => 2, @noperldoc);
  456   die "sorry, pod2usage did not work; maybe a download failure?";
  457 }
  458 
  459 if ($opt_version) {
  460   print "install-tl (TeX Live Cross Platform Installer)",
  461         " revision $::installerrevision\n";
  462   if (open (REL_TL, "$::installerdir/release-texlive.txt")) {
  463     # print first and last lines, which have the TL version info.
  464     my @rel_tl = <REL_TL>;
  465     print $rel_tl[0];
  466     print $rel_tl[$#rel_tl];
  467     close (REL_TL);
  468   }
  469   if ($::opt_verbosity > 0) {
  470     print "Module revisions:";
  471     print "\nTLConfig: " . TeXLive::TLConfig->module_revision();
  472     print "\nTLCrypto: " . TeXLive::TLCrypto->module_revision();
  473     print "\nTLDownload: ".TeXLive::TLDownload->module_revision();
  474     print "\nTLPDB:    " . TeXLive::TLPDB->module_revision();
  475     print "\nTLPOBJ:   " . TeXLive::TLPOBJ->module_revision();
  476     print "\nTLTREE:   " . TeXLive::TLTREE->module_revision();
  477     print "\nTLUtils:  " . TeXLive::TLUtils->module_revision();
  478     print "\nTLWinGoo: " . TeXLive::TLWinGoo->module_revision() if wndws();
  479     print "\n";
  480   }
  481   exit 0;
  482 }
  483 
  484 if ($opt_print_arch) {
  485   print platform()."\n";
  486   exit 0;
  487 }
  488 
  489 # now load translations, if applicable
  490 if (defined($::opt_lang)) {
  491   $::lang = $::opt_lang;
  492 }
  493 require("TeXLive/trans.pl");
  494 load_translations();
  495 
  496 # some option checks
  497 
  498 die "$0: Incompatible options: custom-bin and in-place.\n"
  499   if ($opt_in_place && $opt_custom_bin);
  500 
  501 die "$0: Incompatible options: in-place and profile ($opt_profile).\n"
  502   if ($opt_in_place && $opt_profile);
  503 
  504 die "$0: Incompatible options init-from-profile and in-place.\n"
  505   if ($opt_in_place && $opt_init_from_profile);
  506 
  507 # We now allow --texuserdir XXX --texmfhome YYYY
  508 # die "$0: Incompatible options: texuserdir ($opt_texuserdir) and "
  509 #     . "any of texmfhome, texmfconfig, texmfvar ("
  510 #     . "$pathopts{'texmfhome'}, $pathopts{'texmfvar'}, $pathopts{'texmfconfig'}"
  511 #     . ").\n"
  512 #   if ($opt_texuserdir && 
  513 #        ($pathopts{'texmfhome'} || $pathopts{'texmfvar'}
  514 #         || $pathopts{'texmfconfig'}));
  515 
  516 if ($#ARGV >= 0) {
  517   die "$0: Extra arguments `@ARGV'; try --help if you need it.\n";
  518 }
  519 
  520 
  521 if ($opt_profile) { # not allowed if in_place
  522   if (-r $opt_profile && -f $opt_profile) {
  523     info("Automated TeX Live installation using profile: $opt_profile\n");
  524   } else {
  525     $opt_profile = "";
  526     info(
  527 "Profile $opt_profile not readable or not a file, continuing in interactive mode.\n");
  528   }
  529 }
  530 
  531 if ($opt_nonadmin and wndws()) {
  532   non_admin();
  533 }
  534 
  535 # done with options
  536 
  537 
  538 # the TLPDB instances we will use. $tlpdb is for the one from the installation
  539 # media, while $localtlpdb is for the new installation
  540 # $tlpdb must be our because it is used in install-menu-text.pl
  541 our $tlpdb;
  542 my $localtlpdb;
  543 my $location;
  544 
  545 @::info_hook = ();
  546 
  547 our $media;
  548 our @media_available;
  549 
  550 TeXLive::TLUtils::initialize_global_tmpdir();
  551 
  552 if (TeXLive::TLCrypto::setup_checksum_method()) {
  553   # try to setup gpg:
  554   # either explicitly requested or nothing requested
  555   if ((defined($opt_verify_downloads) && $opt_verify_downloads)
  556       ||
  557       (!defined($opt_verify_downloads))) {
  558     if (TeXLive::TLCrypto::setup_gpg($::installerdir)) {
  559       # make sure we actually do verify ...
  560       $opt_verify_downloads = 1;
  561       log("Trying to verify cryptographic signatures!\n")
  562     } else {
  563       if ($opt_verify_downloads) {
  564         tldie("$0: No gpg found, but verification explicitly requested "
  565               . "on command line, so quitting.\n");
  566       } else {
  567         # implicitly requested, just 
  568         debug("Couldn't detect gpg so will proceed without verification!\n");
  569       }
  570     }
  571   }
  572 } else {
  573   if ($opt_warn_checksums) {
  574       tldie(<<END_NO_CHECKSUMS);
  575 $0: Quitting, cannot find a checksum implementation.
  576 Please install Digest::SHA (from CPAN), or openssl, or sha512sum,
  577 or use the --no-warn-checksums command line option.
  578 END_NO_CHECKSUMS
  579   }
  580 }
  581 
  582 
  583 # continuing with normal install
  584 
  585 if (defined($opt_force_arch)) {
  586   tlwarn("Overriding platform to $opt_force_arch\n");
  587   $::_platform_ = $opt_force_arch;
  588 }
  589 
  590 # initialize the correct platform
  591 platform();
  592 $vars{'this_platform'} = $::_platform_;
  593 
  594 # we do not support cygwin < 1.7, so check for that
  595 if (!$opt_custom_bin && (platform() eq "i386-cygwin")) {
  596   chomp( my $un = `uname -r`);
  597   if ($un =~ m/^(\d+)\.(\d+)\./) {
  598     if ($1 < 2 && $2 < 7) {
  599       tldie("$0: Sorry, the TL binaries require at least cygwin 1.7, "
  600             . "not $1.$2\n");
  601     }
  602   }
  603 }
  604 
  605 # determine which media are available, don't put NET here, it is
  606 # assumed to be available at any time
  607 {
  608   # check the installer dir for what is present
  609   my $tmp = $::installerdir;
  610   $tmp = abs_path($tmp);
  611   # remove trailing \ or / (e.g. root of dvd drive on w32)
  612   $tmp =~ s,[\\\/]$,,;
  613   if (-d "$tmp/$Archive") {
  614     push @media_available, "local_compressed#$tmp";
  615   }
  616   if (-r "$tmp/texmf-dist/web2c/texmf.cnf") {
  617     push @media_available, "local_uncompressed#$tmp";
  618   }
  619 }
  620 
  621 # check command line arguments if given
  622 if ($opt_location) {
  623   my $tmp = $opt_location;
  624   if ($tmp =~ m!^(https?|ftp)://!i) {
  625     push @media_available, "NET#$tmp";
  626 
  627   } elsif ($tmp =~ m!^(rsync|)://!i) {
  628     tldie ("$0: sorry, rsync unsupported; use an http or ftp url here.\n"); 
  629 
  630   } else {
  631     # remove leading file:/+ part
  632     $tmp =~ s!^file://*!/!i;
  633     $tmp = abs_path($tmp);
  634     # remove trailing \ or / (e.g. root of dvd drive on w32)
  635     $tmp =~ s,[\\\/]$,,;
  636     if (-d "$tmp/$Archive") {
  637       push @media_available, "local_compressed#$tmp";
  638     }
  639     if (-d "$tmp/texmf-dist/web2c") {
  640       push @media_available, "local_uncompressed#$tmp";
  641     }
  642   }
  643 }
  644 
  645 # find wget, tar, xz
  646 if (!setup_programs ("$::installerdir/tlpkg/installer", "$::_platform_")) {
  647   tldie("$0: Goodbye.\n");
  648 }
  649 
  650 
  651 if ($opt_profile eq "" && $opt_interaction) {
  652   if ($opt_init_from_profile) {
  653     read_profile("$opt_init_from_profile", seed => 1);
  654   }
  655   # do the normal interactive installation.
  656   #
  657   # here we could load different menu systems. Currently several things
  658   # are "our" so that the menu implementation can use it: The $tlpdb, the
  659   # %var, and all the @collection*.
  660   # install-menu-*.pl have to assign a code ref to $::run_menu which is
  661   # run, and should change ONLY stuff in %vars
  662   # The allowed keys in %vars should be specified somewhere ...
  663   # the menu implementation should return
  664   #    MENU_INSTALL  do the installation
  665   #    MENU_ABORT    abort every action immediately, no cleanup
  666   #    MENU_QUIT     try to quit and clean up mess
  667   our $MENU_INSTALL = 0;
  668   our $MENU_ABORT   = 1;
  669   our $MENU_QUIT    = 2;
  670   $opt_gui = "text" if ($opt_no_gui);
  671   # finally do check for additional screens in the $opt_gui setting:
  672   # format:
  673   #   --gui <plugin>:<a1>,<a2>,...
  674   # which will passed to run_menu (<a1>, <a2>, ...)
  675   #
  676   my @runargs;
  677   if ($opt_gui =~ m/^([^:]*):(.*)$/) {
  678     $opt_gui = $1;
  679     @runargs = split ",", $2;
  680   }
  681   if (-r "$::installerdir/tlpkg/installer/install-menu-${opt_gui}.pl") {
  682     require("installer/install-menu-${opt_gui}.pl");
  683   } else {
  684     tlwarn("UI plugin $opt_gui not found,\n");
  685     tlwarn("Using text mode installer.\n");
  686     require("installer/install-menu-text.pl");
  687   }
  688 
  689   # before we start the installation we check for the existence of
  690   # a previous installation, and in case we ship inform the UI
  691   if (!exists $ENV{"TEXLIVE_INSTALL_NO_RESUME"} && $opt_interaction) {
  692     my $tlmgrwhich = which("tlmgr");
  693     if ($tlmgrwhich) {
  694       my $dn = dirname($tlmgrwhich);
  695       $dn = abs_path("$dn/../..");
  696       # The "make Karl happy" case, check that we are not running install-tl
  697       # from the same tree where tlmgr is hanging around
  698       my $install_tl_root = abs_path($::installerdir);
  699       my $tlpdboldpath
  700        = $dn .
  701          "/$TeXLive::TLConfig::InfraLocation/$TeXLive::TLConfig::DatabaseName";
  702       if (-r $tlpdboldpath && $dn ne $install_tl_root) {
  703         debug ("found old installation in $dn\n");
  704         push @runargs, "-old-installation-found=$dn";
  705         # only the text-mode menu will pay attention!
  706       }
  707     }
  708   }
  709 
  710   my $ret = &{$::run_menu}(@runargs);
  711   if ($ret == $MENU_QUIT) {
  712     do_cleanup(); # log, profile, temp files
  713     flushlog();
  714     exit(1);
  715   } elsif ($ret == $MENU_ABORT) {
  716     # here, omit do_cleanup()
  717     flushlog();
  718     exit(2);
  719   }
  720   if ($ret != $MENU_INSTALL) {
  721     tlwarn("Unknown return value of run_menu: $ret\n");
  722     exit(3);
  723   }
  724 } else { # no interactive setting of options
  725   if (!do_remote_init()) {
  726     die ("Exiting installation.\n");
  727   }
  728   read_profile($opt_profile) if ($opt_profile ne "");
  729 }
  730 
  731 my $varsdump = "";
  732 foreach my $key (sort keys %vars) {
  733   my $val = $vars{$key} || "";
  734   $varsdump .= "  $key: \"$val\"\n";
  735 }
  736 log("Settings:\n" . $varsdump);
  737 
  738 # portable option overrides any system integration options
  739 $vars{'instopt_adjustpath'} = 0 if $vars{'instopt_portable'};
  740 $vars{'tlpdbopt_file_assocs'} = 0 if $vars{'instopt_portable'};
  741 $vars{'tlpdbopt_desktop_integration'} = 0 if $vars{'instopt_portable'};
  742 install_warnlines_hook(); # collect warnings in @::WARNLINES
  743 info("Installing to: $vars{TEXDIR}\n");
  744 
  745 if (!$opt_installation) {
  746   print STDERR "Not doing installation due to --no-installation, terminating here.\n";
  747   exit 0;
  748 }
  749 
  750 $::env_warns = "";
  751 create_welcome();
  752 my $status = 1;
  753 if ($opt_gui eq 'text' or $opt_gui eq 'extl' or $opt_profile ne "") {
  754   $status = do_installation();
  755   if (@::WARNLINES) {
  756     foreach my $t (@::WARNLINES) { print STDERR $t; }
  757   }
  758   if ($::env_warns) { tlwarn($::env_warns); }
  759   unless ($ENV{"TEXLIVE_INSTALL_NO_WELCOME"}) {
  760     info(join("\n", @::welcome_arr));
  761   }
  762   do_cleanup(); # sets $::LOGFILENAME if not already defined
  763   if ($::LOGFILENAME) {
  764     print STDOUT "\nLogfile: $::LOGFILENAME\n";
  765   } else {
  766     # do_cleanup sets $::LOGFILENAME to ""
  767     #if no logfile could be written
  768     print STDERR
  769       "Cannot create logfile $vars{'TEXDIR'}/install-tl.log: $!\n";
  770   }
  771   printf STDOUT "Installed on platform %s at %s\n",
  772       $vars{'this_platform'}, $vars{'TEXDIR'} if ($opt_gui eq 'extl');
  773 
  774   if (@::installation_failed_packages) {
  775     print <<EOF;
  776 
  777 *** PLEASE READ THIS WARNING ***********************************
  778 
  779 The following (inessential) packages failed to install properly:
  780 
  781   @::installation_failed_packages
  782 
  783 You can fix this by running this command:
  784   tlmgr update --all --reinstall-forcibly-removed
  785 to complete the installation.
  786 
  787 However, if the problem was a failure to download (by far the
  788 most common cause), check that you can connect to the chosen mirror
  789 in a browser; you may need to specify a mirror explicitly.
  790 ******************************************************************
  791 
  792 EOF
  793   }
  794 }
  795 exit $status;
  796 
  797 
  798 ###################################################################
  799 #
  800 # FROM HERE ON ONLY SUBROUTINES
  801 # NO VARIABLE DECLARATIONS OR CODE
  802 #
  803 ###################################################################
  804 
  805 #
  806 # SETUP OF REMOTE STUFF
  807 #
  808 # this is now a sub since it is called from the ui plugins on demand
  809 # this allows selecting a mirror first and then continuing
  810 
  811 sub only_load_remote {
  812   my $selected_location = shift;
  813 
  814   # determine where we will find the distribution to install from.
  815   #
  816   $location = $opt_location;
  817   $location = $selected_location if defined($selected_location);
  818   $location || ($location = "$::installerdir");
  819   if ($location =~ m!^(ctan$|(https?|ftp)://)!i) {
  820     # remove any trailing tlpkg[/texlive.tlpdb] or /
  821     $location =~ s,/(tlpkg(/texlive\.tlpdb)?|archive)?/*$,,;
  822     if ($location =~ m/^ctan$/i) {
  823       $location = TeXLive::TLUtils::give_ctan_mirror();
  824     } elsif ($location =~ m/^$TeXLiveServerURLRegexp/) {
  825       my $mirrorbase = TeXLive::TLUtils::give_ctan_mirror_base();
  826       $location =~ s,^($TeXLiveServerURLRegexp|ctan$),$mirrorbase,;
  827     }
  828     $TeXLiveURL = $location;
  829     $media = 'NET';
  830   } else {
  831     if (scalar grep($_ =~ m/^local_compressed/, @media_available)) {
  832       $media = 'local_compressed';
  833       # for in_place option we want local_uncompressed media
  834       $media = 'local_uncompressed' if $opt_in_place &&
  835         member('local_uncompressed', @media_available);
  836     } elsif (scalar grep($_ =~ m/^local_uncompressed/, @media_available)) {
  837       $media = 'local_uncompressed';
  838     } else {
  839       if ($opt_location) {
  840         # user gave a --location but nothing can be found there, so die
  841         die "$0: cannot find installation source at $opt_location.\n";
  842       }
  843       # no --location given, but NET installation
  844       $TeXLiveURL = $location = TeXLive::TLUtils::give_ctan_mirror();
  845       $media = 'NET';
  846     }
  847   }
  848   if ($from_ext_gui) {print "location: $location\n";}
  849   return load_tlpdb();
  850 } # only_load_remote
  851 
  852 sub do_remote_init {
  853   if (!only_load_remote(@_)) {
  854     tlwarn("$0: Could not load TeX Live Database from $location, goodbye.\n");
  855     return 0;
  856   }
  857   if (!do_version_agree()) {
  858     TeXLive::TLUtils::tldie <<END_MISMATCH;
  859 =============================================================================
  860 $0: The TeX Live versions of the local installation
  861 and the repository being accessed are not compatible:
  862       local: $TeXLive::TLConfig::ReleaseYear
  863  repository: $texlive_release
  864 Perhaps you need to use a different CTAN mirror?
  865 (For more, see the output of install-tl --help, especially the
  866  -repository option.  Online via https://tug.org/texlive/doc.)
  867 =============================================================================
  868 END_MISMATCH
  869   }
  870   final_remote_init();
  871   return 1;
  872 } # do_remote_init
  873 
  874 sub do_version_agree {
  875   $texlive_release = $tlpdb->config_release;
  876   if ($media eq "local_uncompressed") {
  877     # existing installation may not have 00texlive.config metapackage
  878     # so use TLConfig to establish what release we have
  879     $texlive_release ||= $TeXLive::TLConfig::ReleaseYear;
  880   }
  881 
  882   # if the release from the remote TLPDB does not agree with the
  883   # TLConfig::ReleaseYear in the first 4 places break out here.
  884   # Why only the first four places: some optional network distributions
  885   # might use
  886   #   release/2009-foobar
  887   if ($media eq "NET"
  888       && $texlive_release !~ m/^$TeXLive::TLConfig::ReleaseYear/) {
  889     return 0;
  890   } else {
  891     return 1;
  892   }
  893 } # do_version_agree
  894 
  895 sub final_remote_init {
  896   info("Installing TeX Live $TeXLive::TLConfig::ReleaseYear from: $location" .
  897     ($tlpdb->is_verified ? " (verified)" : " (not verified)") . "\n");
  898 
  899   info("Platform: ", platform(), " => \'", platform_desc(platform), "\'\n");
  900   if ($opt_custom_bin) {
  901     if (-d $opt_custom_bin && (-r "$opt_custom_bin/kpsewhich"
  902                                || -r "$opt_custom_bin/kpsewhich.exe")) {
  903       info("Platform overridden, binaries taken from $opt_custom_bin\n"
  904            . "and will be installed into .../bin/custom.\n");
  905     } else {
  906       tldie("$0: -custom-bin argument must be a directory "
  907             . "with TeX Live binaries, not like: $opt_custom_bin\n");
  908     }
  909   }
  910   if ($media eq "local_uncompressed") {
  911     info("Distribution: live (uncompressed)\n");
  912   } elsif ($media eq "local_compressed") {
  913     info("Distribution: inst (compressed)\n");
  914   } elsif ($media eq "NET") {
  915     info("Distribution: net  (downloading)\n");
  916     info("Using URL: $TeXLiveURL\n");
  917     TeXLive::TLUtils::setup_persistent_downloads() if $opt_persistent_downloads;
  918   } else {
  919     info("Distribution: $media\n");
  920   }
  921   info("Directory for temporary files: $::tl_tmpdir\n");
  922 
  923   if ($opt_in_place and ($media ne "local_uncompressed")) {
  924     print "TeX Live not local or not decompressed; 'in_place' option not applicable\n";
  925     $opt_in_place = 0;
  926   } elsif (
  927       $opt_in_place and (!TeXLive::TLUtils::texdir_check($::installerdir))) {
  928     print "Installer dir not writable; 'in_place' option not applicable\n";
  929     $opt_in_place = 0;
  930   }
  931   $opt_scheme = "" if $opt_in_place;
  932   $vars{'instopt_portable'} = $opt_portable;
  933   $vars{'instopt_adjustpath'} = 1 if wndws();
  934 
  935   log("Installer revision: $::installerrevision\n");
  936   log("Database revision: " . $tlpdb->config_revision . "\n");
  937 
  938   # correctly set the splitting support
  939   # for local_uncompressed we always support splitting
  940   if (($media eq "NET") || ($media eq "local_compressed")) {
  941     $vars{'src_splitting_supported'} = $tlpdb->config_src_container;
  942     $vars{'doc_splitting_supported'} = $tlpdb->config_doc_container;
  943   }
  944   set_platforms_supported();
  945   set_texlive_default_dirs();
  946   set_install_platform();
  947   initialize_collections();
  948   # size information
  949   $vars{'free_size'} = TeXLive::TLUtils::diskfree($vars{'TEXDIR'});
  950 
  951   update_default_scheme();
  952   update_default_paper();
  953   update_default_src_doc_install();
  954 } # final_remote_init
  955 
  956 sub update_default_scheme {
  957   # initialize the scheme from the command line value, if given.
  958   if ($opt_scheme) {
  959     # add the scheme- prefix if they didn't give it.
  960     $opt_scheme = "scheme-$opt_scheme" if $opt_scheme !~ /^scheme-/;
  961     #
  962     # add "only" if they said "infra" (Tired of making this typo, should
  963     # have named it "infra" in the first place, but too late.)
  964     $opt_scheme .= "only" if $opt_scheme eq "scheme-infra";
  965     #
  966     my $scheme = $tlpdb->get_package($opt_scheme);
  967     if (defined($scheme)) {
  968       select_scheme($opt_scheme);  # select it
  969     } else {
  970       tlwarn("Scheme $opt_scheme not defined, ignoring it.\n");
  971     }
  972   }
  973 } # update_default_scheme
  974 
  975 sub update_default_paper {
  976   # initialize default paper size from the command line or envvar value,
  977   # if either is given.
  978   my $env_paper = $ENV{"TEXLIVE_INSTALL_PAPER"};
  979   if ($opt_paper) {
  980     if (defined $env_paper && $env_paper ne $opt_paper) {
  981       tlwarn("$0: paper selected via both envvar TEXLIVE_INSTALL_PAPER and\n");
  982       tlwarn("$0:   cmdline arg --paper, preferring the latter: $opt_paper\n");
  983     }
  984     if ($opt_paper eq "letter") { $vars{'instopt_letter'} = 1; }
  985     elsif ($opt_paper eq "a4")  { $vars{'instopt_letter'} = 0; }
  986     else {
  987       tlwarn("$0: cmdline option --paper value must be letter or a4, not: "
  988              . "$opt_paper (ignoring)\n");
  989     }
  990   } elsif ($env_paper) {
  991     if ($env_paper eq "letter") { $vars{'instopt_letter'} = 1; } 
  992     elsif ($env_paper eq "a4") { ; } # do nothing
  993     else {
  994       tlwarn("$0: TEXLIVE_INSTALL_PAPER value must be letter or a4, not: "
  995              . "$env_paper (ignoring)\n");
  996     }
  997   }
  998 } # update_default_paper
  999 
 1000 sub update_default_src_doc_install {
 1001   if (! $opt_src_install) {
 1002     $vars{'tlpdbopt_install_srcfiles'} = 0;
 1003   }
 1004   if (! $opt_doc_install) {
 1005     $vars{'tlpdbopt_install_docfiles'} = 0;
 1006   }
 1007 } # update_default_src_doc_install
 1008 
 1009 
 1010 
 1011 sub do_installation {
 1012   if (wndws()) {
 1013     non_admin() if !$vars{'tlpdbopt_w32_multi_user'};
 1014   }
 1015   if ($vars{'instopt_portable'}) {
 1016     $vars{'tlpdbopt_desktop_integration'} = 0;
 1017     $vars{'tlpdbopt_file_assocs'} = 0;
 1018     $vars{'instopt_adjustpath'} = 0;
 1019     $vars{'tlpdbopt_w32_multi_user'} = 0;
 1020   }
 1021   if ($vars{'selected_scheme'} ne "scheme-infraonly"
 1022       && $vars{'n_collections_selected'} <= 0) {
 1023     tldie("$0: Nothing selected, nothing to install, exiting!\n");
 1024   }
 1025   # expand ~ in various variables just to be sure
 1026   # (but not the user dirs since we want the ~ to stay literal ... must
 1027   # think more ... qqq)
 1028   for my $v (qw/TEXDIR TEXMFLOCAL TEXMFSYSVAR TEXMFSYSCONFIG/) {
 1029     $vars{$v} = TeXLive::TLUtils::expand_tilde($vars{$v}) if ($vars{$v});
 1030   }
 1031   # maybe_make_ro tests for admin, local drive and NTFS before proceeding.
 1032   # making the root read-only automatically locks everything below it.
 1033   # do TEXDIR now, before it loses its final slash
 1034   mkdirhier "$vars{'TEXDIR'}";
 1035   if (wndws()) {
 1036     TeXLive::TLWinGoo::maybe_make_ro ($vars{'TEXDIR'});
 1037   }
 1038   # check for free disk space
 1039   my $diskfree = TeXLive::TLUtils::diskfree($vars{'TEXDIR'});
 1040   # -1 is returned if df not available or some other error
 1041   if ($diskfree != -1) {
 1042     my $reserve = 100;
 1043     if ($diskfree < $reserve + $vars{'total_size'}) {
 1044       my $msg = "($diskfree free < $reserve reserve "
 1045                 . "+ installed $vars{total_size})";
 1046       if ($ENV{'TEXLIVE_INSTALL_NO_DISKCHECK'}) {
 1047         tlwarn("$0: Insufficient disk space\n$msg\n"
 1048           ." but continuing anyway per envvar TEXLIVE_INSTALL_NO_DISKCHECK\n");
 1049       } else {
 1050         tldie("$0: DISK SPACE INSUFFICIENT!\n$msg\nAborting installation.\n"
 1051             . "  To skip the check, set the environment variable\n"
 1052             . "  TEXLIVE_INSTALL_NO_DISKCHECK=1\n");
 1053       }
 1054     }
 1055   }
 1056   # now remove final slash from TEXDIR even if it is the root of a drive
 1057   $vars{'TEXDIR'} =~ s!/$!!;
 1058   # do the actual installation
 1059   make_var_skeleton "$vars{'TEXMFSYSVAR'}";
 1060   my $oldlocal = -d $vars{'TEXMFLOCAL'};
 1061   make_local_skeleton "$vars{'TEXMFLOCAL'}";
 1062   mkdirhier "$vars{'TEXMFSYSCONFIG'}";
 1063   if (wndws()) {
 1064     TeXLive::TLWinGoo::maybe_make_ro ($vars{'TEXMFSYSVAR'});
 1065     TeXLive::TLWinGoo::maybe_make_ro ($vars{'TEXMFLOCAL'}) unless $oldlocal;
 1066     TeXLive::TLWinGoo::maybe_make_ro ($vars{'TEXMFSYSCONFIG'});
 1067   }
 1068 
 1069   if ($opt_in_place) {
 1070     $localtlpdb = $tlpdb;
 1071   } else {
 1072     $localtlpdb=new TeXLive::TLPDB;
 1073     $localtlpdb->root("$vars{'TEXDIR'}");
 1074   }
 1075   if (!$opt_in_place) {
 1076     # have to do top-level release-texlive.txt as a special file, so
 1077     # tl-update-images can insert the final version number without
 1078     # having to remake any packages.  But if the source does not exist,
 1079     # or the destination already exists, don't worry about it (even
 1080     # though these cases should never arise); it's not that important.
 1081     #
 1082     if (-e "$::installerdir/release-texlive.txt"
 1083         && ! -e "$vars{TEXDIR}/release-texlive.txt") {
 1084       copy("$::installerdir/release-texlive.txt", "$vars{TEXDIR}/");
 1085     }
 1086     #
 1087     calc_depends();
 1088     save_options_into_tlpdb();
 1089     # we need to do that dir, since we use the TLPDB->install_package which
 1090     # might change into texmf-dist for relocated packages
 1091     mkdirhier "$vars{'TEXDIR'}/texmf-dist";
 1092     do_install_packages();
 1093     if ($opt_custom_bin) {
 1094       $vars{'this_platform'} = "custom";
 1095       my $TEXDIR="$vars{'TEXDIR'}";
 1096       mkdirhier("$TEXDIR/bin/custom");
 1097       for my $f (<$opt_custom_bin/*>) {
 1098         copy($f, "$TEXDIR/bin/custom");
 1099       }
 1100     }
 1101   }
 1102   # now we save every scheme that is fully covered by the stuff we have
 1103   # installed to the $localtlpdb
 1104   foreach my $s ($tlpdb->schemes) {
 1105     my $stlp = $tlpdb->get_package($s);
 1106     die ("This cannot happen, $s not defined in tlpdb") if ! defined($stlp);
 1107     my $incit = 1;
 1108     foreach my $d ($stlp->depends) {
 1109       if (!defined($localtlpdb->get_package($d))) {
 1110         $incit = 0;
 1111         last;
 1112       }
 1113     }
 1114     if ($incit) {
 1115       $localtlpdb->add_tlpobj($stlp);
 1116     }
 1117   }
 1118   
 1119   # include a 00texlive.config package in the new tlpdb,
 1120   # so that further installations and updates using the new installation
 1121   # as the source can work.  Only include the release info, the other
 1122   # 00texlive.config entries are not relevant for this case.
 1123   my $tlpobj = new TeXLive::TLPOBJ;
 1124   $tlpobj->name("00texlive.config");
 1125   my $t = $tlpdb->get_package("00texlive.config");
 1126   $tlpobj->depends("minrelease/" . $tlpdb->config_minrelease,
 1127                    "release/"    . $tlpdb->config_release);
 1128   $localtlpdb->add_tlpobj($tlpobj);  
 1129   
 1130   $localtlpdb->save unless $opt_in_place;
 1131 
 1132   my $errcount = do_postinst_stuff();
 1133 
 1134   #tlwarn("!!! Dummy test warning\n");
 1135   #tlwarn("!!! Another test warning\n");
 1136   #$errcount += 2;
 1137 
 1138   # check environment for possibly tex-related strings:
 1139   check_env() unless $ENV{"TEXLIVE_INSTALL_ENV_NOCHECK"};
 1140 
 1141   # We do clean up in the main installation part
 1142   # don't do this here because it closes the log file and
 1143   # further messages (warnings, welcome) are not logged.
 1144   # log, profile, temp files:
 1145   # do_cleanup();
 1146 
 1147   # create_welcome(); already invoked in main program
 1148   if (@::WARNLINES) {
 1149     unshift @::WARNLINES, ("\nSummary of warnings:\n");
 1150   }
 1151   my $status = 0;
 1152   if ($errcount > 0) {
 1153     $status = 1;
 1154     warn "\n$0: errors in installation reported above\n";
 1155   }
 1156 
 1157   return $status;
 1158 } # do_installation
 1159 
 1160 sub run_postinst_cmd {
 1161   my ($cmd) = @_;
 1162   
 1163   info ("running $cmd ...");
 1164   my ($out,$ret) = TeXLive::TLUtils::run_cmd ("$cmd 2>&1");
 1165   if ($ret == 0) {
 1166     info ("done\n");
 1167   } else {
 1168     info ("failed\n");
 1169     tlwarn ("$0: $cmd failed (status $ret): $!\n");
 1170     $ret = 1; # be sure we don't overflow the sum on anything crazy
 1171   }
 1172   log ($out);
 1173   
 1174   return $ret;
 1175 } # run_postinst_cmd
 1176 
 1177 
 1178 # 
 1179 # Make texmf.cnf, backup directory, cleanups, path setting, and
 1180 # (most importantly) post-install subprograms: mktexlsr, fmtutil,
 1181 # and more.  Return count of errors detected, hopefully zero.
 1182 #
 1183 sub do_postinst_stuff {
 1184   my $TEXDIR = $vars{'TEXDIR'};
 1185   my $TEXMFSYSVAR = $vars{'TEXMFSYSVAR'};
 1186   my $TEXMFSYSCONFIG = $vars{'TEXMFSYSCONFIG'};
 1187   my $TEXMFVAR = $vars{'TEXMFVAR'};
 1188   my $TEXMFCONFIG = $vars{'TEXMFCONFIG'};
 1189   my $TEXMFLOCAL = $vars{'TEXMFLOCAL'};
 1190   my $tmv;
 1191 
 1192   do_texmf_cnf();
 1193 
 1194   # clean up useless files in texmf-dist/tlpkg as this is only
 1195   # created by the relocatable packages
 1196   if (-d "$TEXDIR/$TeXLive::TLConfig::RelocTree/tlpkg") {
 1197     rmtree("$TEXDIR/TeXLive::TLConfig::RelocTree/tlpkg");
 1198   }
 1199 
 1200   # create package backup directory for tlmgr autobackup to work
 1201   mkdirhier("$TEXDIR/$TeXLive::TLConfig::PackageBackupDir");
 1202 
 1203   # final program execution
 1204   # we have to do several things:
 1205   # - clean the environment from spurious TEXMF related variables
 1206   # - add the bin dir to the PATH
 1207   # - select perl interpreter and set the correct perllib
 1208   # - run the programs
 1209 
 1210   # Step 1: Clean the environment.
 1211   %origenv = %ENV;
 1212   my @TMFVARS=qw(VARTEXFONTS
 1213     TEXMF SYSTEXMF VARTEXFONTS
 1214     TEXMFDBS WEB2C TEXINPUTS TEXFORMATS MFBASES MPMEMS TEXPOOL MFPOOL MPPOOL
 1215     PSHEADERS TEXFONTMAPS TEXPSHEADERS TEXCONFIG TEXMFCNF
 1216     TEXMFMAIN TEXMFDIST TEXMFLOCAL TEXMFSYSVAR TEXMFSYSCONFIG
 1217     TEXMFVAR TEXMFCONFIG TEXMFHOME TEXMFCACHE);
 1218 
 1219   if (defined($ENV{'TEXMFCNF'})) {
 1220     tlwarn "WARNING: environment variable TEXMFCNF is set.
 1221 You should know what you are doing.
 1222 We will unset it for the post-install actions, but all further
 1223 operations might be disturbed.\n\n";
 1224   }
 1225   foreach $tmv (@TMFVARS) {
 1226     delete $ENV{$tmv} if (defined($ENV{$tmv}));
 1227   }
 1228 
 1229   # Step 2: Setup the PATH, switch to the new Perl
 1230 
 1231   my $pathsep = (wndws())? ';' : ':';
 1232   my $plat_bindir = "$TEXDIR/bin/$vars{'this_platform'}";
 1233   my $perl_bindir = "$TEXDIR/tlpkg/tlperl/bin";
 1234   my $perl_libdir = "$TEXDIR/tlpkg/tlperl/lib";
 1235   my $progext = (wndws())? '.exe' : '';
 1236 
 1237   debug("Prepending $plat_bindir to PATH\n");
 1238   $ENV{'PATH'} = $plat_bindir . $pathsep . $ENV{'PATH'};
 1239 
 1240   if (wndws()) {
 1241     debug("Prepending $perl_bindir to PATH\n");
 1242     $ENV{'PATH'} = "$perl_bindir" . "$pathsep" . "$ENV{'PATH'}";
 1243     $ENV{'PATH'} =~ s!/!\\!g;
 1244   }
 1245 
 1246   debug("\nNew PATH is:\n");
 1247   foreach my $dir (split $pathsep, $ENV{'PATH'}) {
 1248     debug("  $dir\n");
 1249   }
 1250   debug("\n");
 1251   if (wndws()) {
 1252     $ENV{'PERL5LIB'} = $perl_libdir;
 1253   }
 1254 
 1255   #
 1256   # post install actions
 1257   #
 1258 
 1259   my $usedtlpdb = $opt_in_place ? $tlpdb : $localtlpdb;
 1260 
 1261   if (wndws()) {
 1262     debug("Actual environment:\n" . `set` ."\n\n");
 1263     debug("Effective TEXMFCNF: " . `kpsewhich -expand-path=\$TEXMFCNF` ."\n");
 1264   }
 1265 
 1266   # Step 4: run the programs
 1267   my $errcount = 0;
 1268 
 1269   if (!$opt_in_place) {
 1270     wsystem("running", 'mktexlsr', "$TEXDIR/texmf-dist") && exit(1);
 1271   }
 1272 
 1273   # we have to generate the various config file. That could be done with
 1274   # texconfig generate * but Windows does not have texconfig. But we have
 1275   # $localtlpdb and this is simple code, so do it directly, i.e., duplicate
 1276   # the code from the various generate-*.pl scripts
 1277 
 1278   mkdirhier "$TEXDIR/texmf-dist/web2c";
 1279   info("writing fmtutil.cnf to $TEXDIR/texmf-dist/web2c/fmtutil.cnf\n");
 1280   TeXLive::TLUtils::create_fmtutil($usedtlpdb,
 1281     "$TEXDIR/texmf-dist/web2c/fmtutil.cnf");
 1282 
 1283   # warn if fmtutil-local.cnf is present
 1284   if (-r "$TEXMFLOCAL/web2c/fmtutil-local.cnf") {
 1285     tlwarn("Old configuration file $TEXMFLOCAL/web2c/fmtutil-local.cnf found.\n");
 1286     tlwarn("fmtutil now reads *all* fmtutil.cnf files, so probably the easiest way\nis to rename the above file to $TEXMFLOCAL/web2c/fmtutil.cnf\n");
 1287   }
 1288 
 1289   info("writing updmap.cfg to $TEXDIR/texmf-dist/web2c/updmap.cfg\n");
 1290   TeXLive::TLUtils::create_updmap ($usedtlpdb,
 1291     "$TEXDIR/texmf-dist/web2c/updmap.cfg");
 1292 
 1293   info("writing language.dat to $TEXMFSYSVAR/tex/generic/config/language.dat\n");
 1294   TeXLive::TLUtils::create_language_dat($usedtlpdb,
 1295     "$TEXMFSYSVAR/tex/generic/config/language.dat",
 1296     "$TEXMFLOCAL/tex/generic/config/language-local.dat");
 1297 
 1298   info("writing language.def to $TEXMFSYSVAR/tex/generic/config/language.def\n");
 1299   TeXLive::TLUtils::create_language_def($usedtlpdb,
 1300     "$TEXMFSYSVAR/tex/generic/config/language.def",
 1301     "$TEXMFLOCAL/tex/generic/config/language-local.def");
 1302 
 1303   info("writing language.dat.lua to $TEXMFSYSVAR/tex/generic/config/language.dat.lua\n");
 1304   TeXLive::TLUtils::create_language_lua($usedtlpdb,
 1305     "$TEXMFSYSVAR/tex/generic/config/language.dat.lua",
 1306     "$TEXMFLOCAL/tex/generic/config/language-local.dat.lua");
 1307 
 1308   wsystem("running", "mktexlsr",
 1309                      $TEXMFSYSVAR, $TEXMFSYSCONFIG, "$TEXDIR/texmf-dist")
 1310   && exit(1);
 1311 
 1312   if (-x "$plat_bindir/updmap-sys$progext") {
 1313     $errcount += run_postinst_cmd("updmap-sys --nohash");
 1314   } else {
 1315     info("not running updmap-sys (not installed)\n");
 1316   }
 1317 
 1318   # now work through the options if specified at all
 1319 
 1320   # letter instead of a4
 1321   if ($vars{'instopt_letter'}) {
 1322     # set paper size, but do not execute any post actions, which in this
 1323     # case would be mktexlsr and fmtutil-sys -all; clearly premature
 1324     # here at this point in the installer.
 1325     info("setting default paper size to letter:\n");
 1326     $errcount += run_postinst_cmd("tlmgr --no-execute-actions paper letter");
 1327   }
 1328 
 1329   # option settings in launcher.ini
 1330   if (wndws() && !$vars{'instopt_portable'}) {
 1331     if ($vars{'tlpdbopt_file_assocs'} != 1 || !$vars{'instopt_adjustpath'}) {
 1332       # create higher priority tlaunch.ini with adjusted settings
 1333       # whether or not launcher mode (desktop integration 2)
 1334       # was selected
 1335       rewrite_tlaunch_ini();
 1336     }
 1337   }
 1338 
 1339   # now rerun mktexlsr for updmap-sys and tlmgr paper letter updates.
 1340   wsystem("re-running", "mktexlsr", $TEXMFSYSVAR, $TEXMFSYSCONFIG) && exit(1);
 1341 
 1342   if (wndws() and !$vars{'instopt_portable'} and !$opt_in_place) {
 1343     if ($vars{'tlpdbopt_desktop_integration'} != 2) {
 1344       create_uninstaller($vars{'TEXDIR'});
 1345     } else {
 1346       $errcount += wsystem (
 1347         'Running','tlaunch.exe',
 1348         admin() ? 'admin_inst_silent' : 'user_inst_silent');
 1349     }
 1350   }
 1351 
 1352   # lmtx/context setup. The story here is that in 2023, the lmtx binary
 1353   # for x86_64-linux was too new to run on the system where we build TL.
 1354   # (luametatex: /lib64/libm.so.6: version `GLIBC_2.23' not found)
 1355   # So we have to try running it to see it succeeds, not just test for 
 1356   # the program's existence. And since it exits nonzero given no args,
 1357   # we have to specify --version. Hope it keeps working like that ...
 1358   my $lmtx = "$plat_bindir/luametatex$progext";
 1359   if (exists($install{"context"}) && $install{"context"} == 1
 1360       && !exists $ENV{"TEXLIVE_INSTALL_NO_CONTEXT_CACHE"}
 1361       && TeXLive::TLUtils::system_ok("$lmtx --version")
 1362      ) {
 1363     info("setting up ConTeXt cache: ");
 1364     $errcount += run_postinst_cmd("mtxrun --generate");
 1365     $errcount += run_postinst_cmd("context --luatex --generate");
 1366   } else {
 1367     debug("skipped ConTeXt cache setup\n");
 1368   }
 1369 
 1370   # all formats option
 1371   if ($vars{'tlpdbopt_create_formats'}) {
 1372     if (-x "$plat_bindir/fmtutil-sys$progext") {
 1373       info("pre-generating all format files, be patient...\n");
 1374       $errcount += run_postinst_cmd(
 1375                      "fmtutil-sys $common_fmtutil_args --no-strict --all");
 1376     } else {
 1377       info("not running fmtutil-sys (script not installed)\n");
 1378     }
 1379   } else {
 1380     info("not running fmtutil-sys (user option create_formats=0)\n");
 1381   }
 1382 
 1383   # do path adjustments: On Windows add/remove to PATH etc,
 1384   # on Unix set symlinks
 1385   # for portable, this option should be unset
 1386   # it should not be necessary to test separately for portable
 1387   $errcount += do_path_adjustments() if
 1388     $vars{'instopt_adjustpath'} and $vars{'tlpdbopt_desktop_integration'} != 2;
 1389 
 1390   # now do the system integration:
 1391   # on unix this means setting up symlinks
 1392   # on w32 this means settting registry values
 1393   # on both, we run the postaction directives of the tlpdb
 1394   # no need to test for portable or in_place:
 1395   # the menus (or profile?) should have set the required options
 1396   $errcount += do_tlpdb_postactions();
 1397   
 1398   return $errcount;
 1399 } # do_postinst_stuff
 1400 
 1401 
 1402 # Run the post installation code in the postaction tlpsrc entries.
 1403 # Return number of errors found, or zero.
 1404 
 1405 sub do_tlpdb_postactions {
 1406   info ("running package-specific postactions\n");
 1407 
 1408   # option settings already reflect portable- and in_place options.
 1409   my $usedtlpdb = $opt_in_place ? $tlpdb : $localtlpdb;
 1410   my $ret = 0; # n. of errors
 1411 
 1412   foreach my $package ($usedtlpdb->list_packages) {
 1413     # !!! alert: parameter 4 is menu shortcuts, parameter 5 does nothing !!!
 1414     if ($vars{'tlpdbopt_desktop_integration'}==2) {
 1415       # skip creation of shortcuts and file associations
 1416       if (!TeXLive::TLUtils::do_postaction(
 1417         "install", $usedtlpdb->get_package($package),
 1418         0, 0, 0, $vars{'tlpdbopt_post_code'})) { $ret += 1; }
 1419     } else {
 1420       # create shortcuts and file associations
 1421       # according to corresponding options
 1422       if (!TeXLive::TLUtils::do_postaction(
 1423         "install", $usedtlpdb->get_package($package),
 1424         $vars{'tlpdbopt_file_assocs'},
 1425         $vars{'tlpdbopt_desktop_integration'}, 0,
 1426         $vars{'tlpdbopt_post_code'})) { $ret += 1; }
 1427     }
 1428   }
 1429   # windows: alert the system about changed file associations
 1430   if (wndws()) { TeXLive::TLWinGoo::update_assocs(); }
 1431   info ("finished with package-specific postactions\n");
 1432   return $ret;
 1433 } # do_tlpdb_postactions
 1434 
 1435 sub rewrite_tlaunch_ini {
 1436   # create a higher-priority copy of tlaunch.ini in TEXMFSYSVAR
 1437   # with appropriate settings in the General section
 1438   my $ret = 0; # n. of errors
 1439 
 1440   chomp( my $tmfmain = `kpsewhich -var-value=TEXMFMAIN` ) ;
 1441   chomp( my $tmfsysvar = `kpsewhich -var-value=TEXMFSYSVAR` ) ;
 1442   if (open IN, "$tmfmain/web2c/tlaunch.ini") {
 1443     my $eolsave = $/;
 1444     undef $/;
 1445     my $ini = <IN>;
 1446     close IN;
 1447     # remove general section, if any
 1448     $ini =~ s/\r\n/\n/g;
 1449     $ini =~ s/\[general[^\[]*//si;
 1450     mkdirhier("$tmfsysvar/web2c");
 1451     if (open OUT, ">", "$tmfsysvar/web2c/tlaunch.ini") {
 1452       my @fts = ('none', 'new', 'overwrite');
 1453       $\ = "\n";
 1454       print OUT $ini;
 1455       print OUT "[General]";
 1456       print OUT "FILETYPES=$fts[$vars{'tlpdbopt_file_assocs'}]";
 1457       print OUT "SEARCHPATH=$vars{'instopt_adjustpath'}\n";
 1458       close OUT;
 1459       `mktexlsr $tmfsysvar`;
 1460     } else {
 1461       $ret += 1;
 1462       tlwarn("Cannot write modified tlaunch.ini\n");
 1463     }
 1464     $/ = $eolsave;
 1465   } else {
 1466     $ret += 1;
 1467     tlwarn("Cannot open tlaunch.ini for reading\n");
 1468   }
 1469   return $ret;
 1470 } # rewrite_tlaunch_ini
 1471 
 1472 sub do_path_adjustments {
 1473   my $ret = 0;
 1474   info ("running path adjustment actions\n");
 1475   if (wndws()) {
 1476     TeXLive::TLUtils::w32_add_to_path($vars{'TEXDIR'} . '/bin/windows',
 1477       $vars{'tlpdbopt_w32_multi_user'});
 1478     broadcast_env();
 1479   } else {
 1480     if ($F_OK != TeXLive::TLUtils::add_symlinks($vars{'TEXDIR'}, 
 1481          $vars{'this_platform'},
 1482          $vars{'tlpdbopt_sys_bin'}, $vars{'tlpdbopt_sys_man'},
 1483          $vars{'tlpdbopt_sys_info'})) {
 1484       $ret = 1;
 1485     }
 1486   }
 1487   info ("finished with path adjustment actions\n");
 1488   return $ret;
 1489 } # do_path_adjustments
 1490 
 1491 # we have to adjust the texmf.cnf file to the paths set in the configuration!
 1492 sub do_texmf_cnf {
 1493   open(TMF,"<$vars{'TEXDIR'}/texmf-dist/web2c/texmf.cnf")
 1494       or die "$vars{'TEXDIR'}/texmf-dist/web2c/texmf.cnf not found: $!";
 1495   my @texmfcnflines = <TMF>;
 1496   close(TMF);
 1497 
 1498   my @changedtmf = ();  # install to disk: write only changed items
 1499 
 1500   my $yyyy = $TeXLive::TLConfig::ReleaseYear;
 1501 
 1502   # we have to find TEXMFLOCAL TEXMFSYSVAR and TEXMFHOME
 1503   # at this point, a final slash of $vars{TEXDIR} itself has already
 1504   # been removed.
 1505   foreach my $line (@texmfcnflines) {
 1506     if ($line =~ m/^TEXMFLOCAL\b/) { # don't find TEXMFLOCALEDIR
 1507       # by default TEXMFLOCAL = TEXDIR/../texmf-local, if this is the case
 1508       # we don't have to write a new setting.
 1509       my $deftmflocal = Cwd::abs_path($vars{'TEXDIR'}.'/../texmf-local');
 1510       if (!defined $deftmflocal       # in case abs_path couldn't resolve
 1511           || Cwd::abs_path($vars{TEXMFLOCAL}) ne "$deftmflocal") {
 1512         push @changedtmf, "TEXMFLOCAL = $vars{'TEXMFLOCAL'}\n";
 1513       }
 1514     } elsif ($line =~ m/^TEXMFSYSVAR/) {
 1515       if ("$vars{'TEXMFSYSVAR'}" ne "$vars{'TEXDIR'}/texmf-var") {
 1516         push @changedtmf, "TEXMFSYSVAR = $vars{'TEXMFSYSVAR'}\n";
 1517       }
 1518     } elsif ($line =~ m/^TEXMFSYSCONFIG/) {
 1519       if ("$vars{'TEXMFSYSCONFIG'}" ne "$vars{'TEXDIR'}/texmf-config") {
 1520         push @changedtmf, "TEXMFSYSCONFIG = $vars{'TEXMFSYSCONFIG'}\n";
 1521       }
 1522     } elsif ($line =~ m/^TEXMFVAR/ && !$vars{'instopt_portable'}) {
 1523       if ($vars{"TEXMFVAR"} ne "~/.texlive$yyyy/texmf-var") {
 1524         push @changedtmf, "TEXMFVAR = $vars{'TEXMFVAR'}\n";
 1525       }
 1526     } elsif ($line =~ m/^TEXMFCONFIG/ && !$vars{'instopt_portable'}) {
 1527       if ("$vars{'TEXMFCONFIG'}" ne "~/.texlive$yyyy/texmf-config") {
 1528         push @changedtmf, "TEXMFCONFIG = $vars{'TEXMFCONFIG'}\n";
 1529       }
 1530     } elsif ($line =~ m/^TEXMFHOME/ && !$vars{'instopt_portable'}) {
 1531       if ("$vars{'TEXMFHOME'}" ne "~/texmf") {
 1532         push @changedtmf, "TEXMFHOME = $vars{'TEXMFHOME'}\n";
 1533       }
 1534     } elsif ($line =~ m/^OSFONTDIR/) {
 1535       if (wndws()) {
 1536         push @changedtmf, "OSFONTDIR = \$SystemRoot/fonts//;\$LOCALAPPDATA/Microsoft/Windows/Fonts//\n";
 1537       }
 1538     }
 1539   }
 1540 
 1541   if ($vars{'instopt_portable'}) {
 1542     push @changedtmf, "ASYMPTOTE_HOME = \$TEXMFCONFIG/asymptote\n";
 1543   }
 1544 
 1545   my ($TMF, $TMFLUA);
 1546   # we want to write only changes to texmf.cnf
 1547   # even for in_place installation
 1548   $TMF = ">$vars{'TEXDIR'}/texmf.cnf";
 1549   open(TMF, $TMF) || die "open($TMF) failed: $!";
 1550   print TMF <<EOF;
 1551 % (Public domain.)
 1552 % This texmf.cnf file should contain only your personal changes from the
 1553 % original texmf.cnf (for example, as chosen in the installer).
 1554 %
 1555 % That is, if you need to make changes to texmf.cnf, put your custom
 1556 % settings in this file, which is .../texlive/YYYY/texmf.cnf, rather than
 1557 % the distributed file (which is .../texlive/YYYY/texmf-dist/web2c/texmf.cnf).
 1558 % And include *only* your changed values, not a copy of the whole thing!
 1559 %
 1560 EOF
 1561   foreach (@changedtmf) {
 1562     # avoid absolute paths for TEXDIR, use $SELFAUTOPARENT instead
 1563     s/^(TEXMF\w+\s*=\s*)\Q$vars{'TEXDIR'}\E/$1\$SELFAUTOPARENT/;
 1564     print TMF;
 1565   }
 1566   if ($vars{'instopt_portable'}) {
 1567     print TMF "TEXMFHOME = \$TEXMFLOCAL\n";
 1568     print TMF "TEXMFVAR = \$TEXMFSYSVAR\n";
 1569     print TMF "TEXMFCONFIG = \$TEXMFSYSCONFIG\n";
 1570   }
 1571   #
 1572   # save the setting of shell_escape to the generated system texmf.cnf
 1573   # default in texmf-dist/web2c/texmf.cnf is
 1574   #   shell_escape = p
 1575   # so we write that only if the user *deselected* this option
 1576   if (!$vars{"instopt_write18_restricted"}) {
 1577     print TMF <<EOF;
 1578 
 1579 % Disable system commands via \\write18{...}.  See texmf-dist/web2c/texmf.cnf.
 1580 shell_escape = 0
 1581 EOF
 1582 ;
 1583   }
 1584 
 1585   # external perl for third-party scripts?
 1586   # the wrapper batchfile has set the environment variable extperl
 1587   # to its version if available and 0 otherwise.
 1588   if (wndws()) {
 1589     my $use_ext = 0;
 1590     if (!$vars{'instopt_portable'} &&
 1591           defined $ENV{'extperl'} &&  $ENV{'extperl'} =~ /^(\d+\.\d+)/) {
 1592       $use_ext = 1 if $1 >= 5.14;
 1593     }
 1594     print TMF <<EOF;
 1595 
 1596 % Prefer external Perl for third-party TeXLive Perl scripts
 1597 % Was set to 1 if at install time a sufficiently recent Perl was detected.
 1598 EOF
 1599 ;
 1600     print TMF "TEXLIVE_WINDOWS_TRY_EXTERNAL_PERL = " . $use_ext;
 1601     log("Configuring for using external perl for third-party scripts\n")
 1602   }
 1603 
 1604   close(TMF) || warn "close($TMF) failed: $!";
 1605 
 1606   $TMFLUA = ">$vars{'TEXDIR'}/texmfcnf.lua";
 1607   open(TMFLUA, $TMFLUA) || die "open($TMFLUA) failed: $!";
 1608     print TMFLUA <<EOF;
 1609 -- (Public domain.)
 1610 -- This texmfcnf.lua file should contain only your personal changes from the
 1611 -- original texmfcnf.lua (for example, as chosen in the installer).
 1612 --
 1613 -- That is, if you need to make changes to texmfcnf.lua, put your custom
 1614 -- settings in this file, which is .../texlive/YYYY/texmfcnf.lua, rather than
 1615 -- the distributed file (.../texlive/YYYY/texmf-dist/web2c/texmfcnf.lua).
 1616 -- And include *only* your changed values, not a copy of the whole thing!
 1617 
 1618 return { 
 1619   content = {
 1620     variables = {
 1621 EOF
 1622 ;
 1623   foreach (@changedtmf) {
 1624     my $luavalue = $_;
 1625     $luavalue =~ s/^(\w+\s*=\s*)(.*)\s*$/$1\"$2\",/;
 1626     $luavalue =~ s/\$SELFAUTOPARENT/selfautoparent:/g;
 1627     print TMFLUA "      $luavalue\n";
 1628   }
 1629   if ($vars{'instopt_portable'}) {
 1630     print TMFLUA "      TEXMFHOME = \"\$TEXMFLOCAL\",\n";
 1631     print TMFLUA "      TEXMFVAR = \"\$TEXMFSYSVAR\",\n";
 1632     print TMFLUA "      TEXMFCONFIG = \"\$TEXMFSYSCONFIG\",\n";
 1633   }
 1634   print TMFLUA "    },\n";
 1635   print TMFLUA "  },\n";
 1636   if (!$vars{"instopt_write18_restricted"}) {
 1637     print TMFLUA <<EOF;
 1638   directives = {
 1639        -- Disable system commands.  See texmf-dist/web2c/texmfcnf.lua
 1640     ["system.commandmode"]       = "none",
 1641   },
 1642 EOF
 1643 ;
 1644   }
 1645   print TMFLUA "}\n";
 1646   close(TMFLUA) || warn "close($TMFLUA) failed: $!";
 1647 } # do_texmf_cnf
 1648 
 1649 # Determine which platforms are supported.
 1650 sub set_platforms_supported {
 1651   my @binaries = $tlpdb->available_architectures;
 1652   for my $binary (@binaries) {
 1653     unless (defined $vars{"binary_$binary"}) {
 1654       $vars{"binary_$binary"}=0;
 1655     }
 1656   }
 1657   for my $key (keys %vars) {
 1658     ++$vars{'n_systems_available'} if ($key=~/^binary/);
 1659   }
 1660 } # set_platforms_supported
 1661 
 1662 sub dump_vars {
 1663   my $filename=shift;
 1664   my $fh;
 1665   if (ref($filename)) {
 1666     $fh = $filename;
 1667   } else {
 1668     open VARS, ">$filename";
 1669     $fh = \*VARS;
 1670   }
 1671   foreach my $key (keys %vars) {
 1672     print $fh "$key $vars{$key}\n";
 1673   }
 1674   close VARS if (!ref($filename));
 1675   debug("\n%vars dumped to '$filename'.\n");
 1676 } # dump_vars
 1677 
 1678 
 1679 # Environment variables and default values on UNIX:
 1680 #   TEXLIVE_INSTALL_PREFIX         /usr/local/texlive   => $tex_prefix
 1681 #                                  $tex_prefix/2010     => $TEXDIR
 1682 #   TEXLIVE_INSTALL_TEXMFSYSVAR    $TEXDIR/texmf-var
 1683 #   TEXLIVE_INSTALL_TEXMFSYSCONFIG $TEXDIR/texmf-config
 1684 #   TEXLIVE_INSTALL_TEXMFLOCAL     $tex_prefix/texmf-local
 1685 #   TEXLIVE_INSTALL_TEXMFHOME      '$HOME/texmf'
 1686 #   TEXLIVE_INSTALL_TEXMFVAR       ~/.texlive2010/texmf-var
 1687 #   TEXLIVE_INSTALL_TEXMFCONFIG    ~/.texlive2010/texmf-config
 1688 
 1689 sub set_var_from_alternatives {
 1690   my ($what, $whatref, @alternatives) = @_;
 1691   my @alt_text;
 1692   for my $i (@alternatives) {
 1693     push @alt_text, ($i ? $i : "undef")
 1694   }
 1695   my $final;
 1696   while (@alternatives) {
 1697     my $el = pop @alternatives;
 1698     $final = $el if ($el);
 1699   }
 1700   debug("setting $what to $final from @alt_text\n");
 1701   $$whatref = $final;
 1702 }
 1703 
 1704 sub set_standard_var {
 1705   my ($what, $envstr, $cmdlinestr, $default) = @_;
 1706   # warn if a value was set from both the profile and
 1707   # via env var
 1708   my $envvar = getenv($envstr);
 1709   my $cmdlinevar = $pathopts{$cmdlinestr};
 1710   my %nrdefs;
 1711   $nrdefs{$vars{$what}} = 1 if ($vars{$what});
 1712   $nrdefs{$envvar} = 1 if ($envvar);
 1713   $nrdefs{$cmdlinevar} = 1 if ($cmdlinevar);
 1714   # texmfhome/texmfvar/texmfconfig have actually been set by
 1715   # via $opt_texuserdir/....
 1716   # So warn about this
 1717   my $actual_cmdline_str = $cmdlinestr;
 1718   my $actual_cmdline_var = $cmdlinevar;
 1719   if ($opt_texuserdir) {
 1720     if ($cmdlinestr eq "texmfhome" || $cmdlinestr eq "texmfvar" || $cmdlinestr eq "texmfconfig") {
 1721       $actual_cmdline_str = "opt_texuserdir";
 1722       $actual_cmdline_var = $opt_texuserdir;
 1723     }
 1724   }
 1725   if (scalar keys %nrdefs > 1) {
 1726     # multiple conflicting definitions, fail!
 1727     tlwarn("Trying to define $what via conflicting settings:\n");
 1728     tlwarn("  from envvar $envstr = $envvar\n") if ($envvar);
 1729     tlwarn("  from profile = $vars{$what}\n") if ($vars{$what});
 1730     tlwarn("  from command line argument $actual_cmdline_str = $actual_cmdline_var\n") if ($actual_cmdline_var);
 1731     tlwarn("  Preferring the last value from above!\n");
 1732     # actual preference order is given via the below call
 1733   }
 1734   # default for most variables, in increasing priority
 1735   # - some default
 1736   # - environment variable
 1737   # - setting from profile saved already in $vars{$what}
 1738   # - command line
 1739   set_var_from_alternatives( $what, \$vars{$what},
 1740     $cmdlinevar,
 1741     $vars{$what},
 1742     $envvar,
 1743     $default);
 1744 }
 1745 
 1746 sub set_texlive_default_dirs {
 1747   my $homedir = (platform() =~ m/darwin/) ? "~/Library" : "~";
 1748   my $yyyy = $TeXLive::TLConfig::ReleaseYear;
 1749   #
 1750   # If the --texuserdir is given, assign values to texmfhome/var/config
 1751   # unless the separate cmd line options are also present.
 1752   if ($opt_texuserdir) {
 1753     $pathopts{'texmfhome'} = "$opt_texuserdir/texmf" if (!$pathopts{'texmfhome'});
 1754     $pathopts{'texmfvar'} = "$opt_texuserdir/texmf-var" if (!$pathopts{'texmfvar'});
 1755     $pathopts{'texmfconfig'} = "$opt_texuserdir/texmf-config" if (!$pathopts{'texmfconfig'});
 1756   }
 1757   #
 1758   # Sources of target directory settings in priority order:
 1759   # - env variable TEXLIVE_INSTALL_PREFIX
 1760   #   will be used with YYYY (in portable case without)
 1761   # - --texdir cmd line option
 1762   #   will be used as is, similar to profile setting
 1763   # - profile setting
 1764   #
 1765   # first compare whether profile setting and cmd line agree if both given
 1766   if ($opt_texdir && $vars{'TEXDIR'}) {
 1767     if ($opt_texdir ne $vars{'TEXDIR'}) {
 1768       tlwarn("Conflicting settings for installation path given:\n");
 1769       tlwarn("  from profile TEXDIR = $vars{'TEXDIR'}\n");
 1770       tlwarn("  from command line option --texdir = $opt_texdir\n");
 1771       tlwarn("  Preferring the command line value!\n");
 1772       # actual setting of preference is done below in the
 1773       #   set_var_from_alternatives( \$vars{'TEXDIR'},
 1774       # call, where the order determines the preference!
 1775     }
 1776   }
 1777   my $tlprefixenv = getenv('TEXLIVE_INSTALL_PREFIX');
 1778   if ($tlprefixenv && ($opt_texdir || $vars{'TEXDIR'})) {
 1779     # NOTE we cannot compare these two values because the one might
 1780     # contain the YYYY part (TEXDIR) while the other is the one without.
 1781     tlwarn("Trying to set up basic path using two incompatible methods:\n");
 1782     tlwarn("  from envvar TEXLIVE_INSTALL_PREFIX = $tlprefixenv\n");
 1783     tlwarn("  from profile TEXDIR = $vars{'TEXDIR'}\n") if ($vars{'TEXDIR'});
 1784     tlwarn("  from command line option --texdir = $opt_texdir\n") if ($opt_texdir);
 1785     tlwarn("  Preferring the later value!\n");
 1786     $tlprefixenv = undef;
 1787   }
 1788   # first set $tex_prefix
 1789   my $tex_prefix;
 1790   set_var_from_alternatives("TEX_PREFIX", \$tex_prefix,
 1791     ($opt_in_place ? abs_path($::installerdir) : undef),
 1792     $tlprefixenv,
 1793     (wndws() ? getenv('SystemDrive') . '/texlive' : '/usr/local/texlive'));
 1794   #
 1795   set_var_from_alternatives("TEXDIR", \$vars{'TEXDIR'},
 1796     $opt_texdir,
 1797     $vars{'TEXDIR'},
 1798     ($vars{'instopt_portable'} || $opt_in_place)
 1799       ? $tex_prefix : "$tex_prefix/$texlive_release");
 1800   #
 1801   set_standard_var('TEXMFSYSVAR', 'TEXLIVE_INSTALL_TEXMFSYSVAR',
 1802                    'texmfsysvar', "$vars{'TEXDIR'}/texmf-var");
 1803   #
 1804   set_standard_var('TEXMFSYSCONFIG', 'TEXLIVE_INSTALL_TEXMFSYSCONFIG',
 1805                    'texmfsysconfig', "$vars{'TEXDIR'}/texmf-config");
 1806   #
 1807   # TEXMFLOCAL is special because the default in texmf.cnf
 1808   #   TEXMFLOCAL = $SELFAUTOGRANDPARENT/texmf-local
 1809   # that is
 1810   #   ..../texlive/texmf-local
 1811   #
 1812   set_standard_var('TEXMFLOCAL', 'TEXLIVE_INSTALL_TEXMFLOCAL',
 1813                    'texmflocal', ($opt_texdir ? "$vars{'TEXDIR'}/texmf-local" :"$tex_prefix/texmf-local"));
 1814   #
 1815   set_standard_var('TEXMFHOME', 'TEXLIVE_INSTALL_TEXMFHOME',
 1816                    'texmfhome', "$homedir/texmf");
 1817   #
 1818   set_standard_var('TEXMFVAR', 'TEXLIVE_INSTALL_TEXMFVAR', 'texmfvar',
 1819     (platform() =~ m/darwin/) ? "$homedir/texlive/$yyyy/texmf-var"
 1820                               : "$homedir/.texlive$yyyy/texmf-var");
 1821   #
 1822   set_standard_var('TEXMFCONFIG', 'TEXLIVE_INSTALL_TEXMFCONFIG', 'texmfconfig',
 1823     (platform() =~ m/darwin/) ? "$homedir/texlive/$yyyy/texmf-config"
 1824                               : "$homedir/.texlive$yyyy/texmf-config");
 1825 
 1826   # for portable installation we want everything in one directory
 1827   if ($vars{'instopt_portable'}) {
 1828     $vars{'TEXMFHOME'}   = "\$TEXMFLOCAL";
 1829     $vars{'TEXMFVAR'}    = "\$TEXMFSYSVAR";
 1830     $vars{'TEXMFCONFIG'} = "\$TEXMFSYSCONFIG";
 1831   }
 1832 
 1833   if ($opt_debug_setup_vars) {
 1834     print "DV:final values from setup of paths:\n";
 1835     for my $i (qw/TEXDIR TEXMFSYSVAR TEXMFSYSCONFIG TEXMFHOME TEXMFVAR
 1836                   TEXMFCONFIG TEXMFLOCAL/) {
 1837       print "$i = $vars{$i}\n";
 1838     }
 1839   }
 1840 } # set_texlive_default_dirs
 1841 
 1842 
 1843 sub calc_depends {
 1844   # we have to reset the install hash EVERY TIME otherwise everything will
 1845   # always be installed since the default is scheme-full which selects
 1846   # all packages and never deselects.
 1847   %install=();
 1848   my $p;
 1849   my $a;
 1850 
 1851   # initialize the %install hash with what should be installed
 1852 
 1853   if ($vars{'selected_scheme'} ne "scheme-custom") {
 1854     # First look for packages in the selected scheme.
 1855     my $scheme=$tlpdb->get_package($vars{'selected_scheme'});
 1856     if (!defined($scheme)) {
 1857       if ($vars{'selected_scheme'}) {
 1858         # something is written in the selected scheme but not defined, that
 1859         # is strange, so warn and die
 1860         die ("Scheme $vars{'selected_scheme'} not defined, vars:\n");
 1861         dump_vars(\*STDOUT);
 1862       }
 1863     } else {
 1864       for my $scheme_content ($scheme->depends) {
 1865         $install{"$scheme_content"}=1 unless $scheme_content =~ /^collection-/;
 1866       }
 1867     }
 1868   }
 1869 
 1870   # Now look for collections in the %vars hash.  These are not
 1871   # necessarily the collections required by a scheme.  The final
 1872   # decision is made in the collections/languages menu.
 1873   foreach my $key (keys %vars) {
 1874     if ($key=~/^collection-/) {
 1875       $install{$key} = 1 if $vars{$key};
 1876     }
 1877   }
 1878 
 1879   # compute the list of archs to be installed
 1880   my @archs;
 1881   foreach (keys %vars) {
 1882     if (m/^binary_(.*)$/ ) {
 1883       if ($vars{$_}) { push @archs, $1; }
 1884     }
 1885   }
 1886 
 1887   #
 1888   # ensure that packages listed in InstallExtraRequiredPackages are installed
 1889   for my $p (@TeXLive::TLConfig::InstallExtraRequiredPackages) {
 1890     $install{$p} = 1;
 1891   }
 1892 
 1893   # if programs for arch=windows are installed we also have to install
 1894   # tlperl.windows which provides the "hidden" perl that will be used
 1895   # to run all the perl scripts.
 1896   # Furthermore we install tlgs.windows
 1897   if (grep(/^windows$/,@archs)) {
 1898     $install{"tlperl.windows"} = 1;
 1899     $install{"tlgs.windows"} = 1;
 1900     # tlpsv is gone
 1901   }
 1902 
 1903   # loop over all the packages until it is getting stable
 1904   my $changed = 1;
 1905   while ($changed) {
 1906     # set $changed to 0
 1907     $changed = 0;
 1908 
 1909     # collect the already selected packages
 1910     my @pre_selected = keys %install;
 1911     debug("calc_depends: number of packages to install: $#pre_selected\n");
 1912 
 1913     # loop over all the pre_selected and add them
 1914     foreach $p (@pre_selected) {
 1915       ddebug("pre_selected $p\n");
 1916       my $pkg = $tlpdb->get_package($p);
 1917       if (!defined($pkg)) {
 1918         tlwarn("$p is mentioned somewhere but not available, disabling it.\n");
 1919         $install{$p} = 0;
 1920         next;
 1921       }
 1922       foreach my $p_dep ($tlpdb->get_package($p)->depends) {
 1923         if ($p_dep =~ m/^(.*)\.ARCH$/) {
 1924           my $foo = "$1";
 1925           foreach $a (@archs) {
 1926             $install{"$foo.$a"} = 1 if defined($tlpdb->get_package("$foo.$a"));
 1927           }
 1928         } elsif ($p_dep =~ m/^(.*)\.windows$/) {
 1929           # a windows package should *only* be installed if we are installing
 1930           # the windows arch
 1931           if (grep(/^windows$/,@archs)) {
 1932             $install{$p_dep} = 1;
 1933           }
 1934         } else {
 1935           $install{$p_dep} = 1;
 1936         }
 1937       }
 1938     }
 1939 
 1940     # check for newly selected packages
 1941     my @post_selected = keys %install;
 1942     debug("calc_depends:   after resolution, #packages: $#post_selected\n");
 1943 
 1944     # set repeat condition
 1945     if ($#pre_selected != $#post_selected) {
 1946       $changed = 1;
 1947     }
 1948   }
 1949 
 1950   # after loop, now do the size computation.
 1951   my $size = 0;
 1952   foreach $p (keys %install) {
 1953     my $tlpobj = $tlpdb->get_package($p);
 1954     if (not(defined($tlpobj))) {
 1955       tlwarn("$p should be installed but "
 1956              . "is not in texlive.tlpdb; disabling.\n");
 1957       $install{$p} = 0;
 1958       next;
 1959     }
 1960     $size+=$tlpobj->docsize if $vars{'tlpdbopt_install_docfiles'};
 1961     $size+=$tlpobj->srcsize if $vars{'tlpdbopt_install_srcfiles'};
 1962     $size+=$tlpobj->runsize;
 1963     foreach $a (@archs) {
 1964       $size += $tlpobj->binsize->{$a} if defined($tlpobj->binsize->{$a});
 1965     }
 1966   }
 1967   $vars{'total_size'} =
 1968     sprintf "%d", ($size * $TeXLive::TLConfig::BlockSize)/1024**2;
 1969 } # calc_depends
 1970 
 1971 sub load_tlpdb {
 1972   my $master = $location;
 1973   info("Loading $master/$TeXLive::TLConfig::InfraLocation/$TeXLive::TLConfig::DatabaseName\n");
 1974   $tlpdb = TeXLive::TLPDB->new(
 1975     root => $master, 'verify' => $opt_verify_downloads);
 1976   if (!defined($tlpdb)) {
 1977     my $do_die = 1;
 1978     # if that failed, and:
 1979     # - we are installing from the network
 1980     # - the location string does not contain "tlnet"
 1981     # then we simply add "/systems/texlive/tlnet" in case someone just
 1982     # gave an arbitrary CTAN mirror address without the full path
 1983     if ($media eq "NET" && $location !~ m/tlnet/) {
 1984       tlwarn("First attempt for net installation failed;\n");
 1985       tlwarn("  repository url does not contain \"tlnet\",\n");
 1986       tlwarn("  retrying with \"/systems/texlive/tlnet\" appended.\n");
 1987       $location .= "/systems/texlive/tlnet";
 1988       $master = $location;
 1989       #
 1990       # since we change location, we reset the error count of the
 1991       # download object
 1992       $::tldownload_server->enable if defined($::tldownload_server);
 1993       #
 1994       $tlpdb = TeXLive::TLPDB->new(
 1995         root => $master, 'verify' => $opt_verify_downloads);
 1996       if (!defined($tlpdb)) {
 1997         tlwarn("Oh well, adding tlnet did not help.\n");
 1998         tlwarn(<<END_EXPLICIT_MIRROR);
 1999 
 2000 You may want to try specifying an explicit or different CTAN mirror;
 2001 see the information and examples for the -repository option at
 2002 https://tug.org/texlive/doc/install-tl.html
 2003 (or in the output of install-tl --help).
 2004 
 2005 You can also rerun the installer with -select-repository
 2006 to choose a mirror from a menu.
 2007 
 2008 END_EXPLICIT_MIRROR
 2009       } else {
 2010         # hurray, that worked out
 2011         info("Loading $master/$TeXLive::TLConfig::InfraLocation/$TeXLive::TLConfig::DatabaseName\n");
 2012         $do_die = 0;
 2013       }
 2014     }
 2015     #die "$0: Could not load TeX Live Database from $master, goodbye.\n"
 2016     return 0
 2017       if $do_die;
 2018   }
 2019   # set the defaults to what is specified in the tlpdb
 2020   # since we might have loaded values via -init-from-profile,
 2021   # make sure that we don't overwrite default values
 2022   for my $o (keys %TeXLive::TLConfig::TLPDBOptions) {
 2023     $vars{"tlpdbopt_$o"} = $tlpdb->option($o)
 2024       if (!defined($profiledata{"tlpdbopt_$o"}));
 2025   }
 2026   if (wndws()) {
 2027     # below, we really mean (start) menu integration.
 2028     # 2016: always menu shortcuts, never desktop shortcuts, whatever the setting
 2029     # 2017: new option value 2: launcher instead of menu.
 2030     # in portable case, shortcuts sanitized away elsewhere
 2031     $vars{'tlpdbopt_desktop_integration'} = 1;
 2032     # we have to make sure that this option is set to 0 in case
 2033     # that a non-admin is running the installations program
 2034     $vars{'tlpdbopt_w32_multi_user'} = 0 if (!admin());
 2035   }
 2036 
 2037   # select scheme: either $vars{'selected_scheme'} or $default_scheme
 2038   # check that the default scheme is actually present, otherwise switch to
 2039   # scheme-minimal.
 2040   my $selscheme;
 2041   if ($opt_scheme) {
 2042     $selscheme = $opt_scheme;
 2043   } elsif ($vars{"selected_scheme"}) {
 2044     $selscheme = $vars{"selected_scheme"};
 2045   } else {
 2046     $selscheme = $default_scheme;
 2047   }
 2048   if (!defined($tlpdb->get_package($selscheme))) {
 2049     # let us try scheme-minimal, and if also that is not available, scheme-infra
 2050     # which is required to be installed
 2051     if (!defined($tlpdb->get_package("scheme-minimal"))) {
 2052       if (!defined($tlpdb->get_package("scheme-infra"))) {
 2053         die("Aborting, cannot find either $selscheme or scheme-minimal or scheme-infra");
 2054       }
 2055       $default_scheme = "scheme-infra";
 2056     } else {
 2057       $default_scheme = "scheme-minimal";
 2058     }
 2059     tlwarn("$0: No $selscheme, switching to $default_scheme.\n");
 2060     $vars{'selected_scheme'} = $default_scheme;
 2061   } else {
 2062     $vars{'selected_scheme'} = $selscheme;
 2063   }
 2064   # make sure that we update %vars for collection_* if only selected_scheme
 2065   # is there, but no collection information
 2066   my $found_collection = 0;
 2067   for my $k (keys(%vars)) {
 2068     if ($k =~ m/^collection-/) {
 2069       $found_collection = 1;
 2070       last;
 2071     }
 2072   }
 2073   if (!$found_collection) {
 2074     for my $p ($tlpdb->get_package($vars{'selected_scheme'})->depends) {
 2075       $vars{$p} = 1 if ($p =~ m/^collection-/);
 2076     }
 2077   }
 2078   return 1;
 2079 } # load_tlpdb
 2080 
 2081 sub initialize_collections {
 2082   foreach my $pkg ($tlpdb->list_packages) {
 2083     my $tlpobj = $tlpdb->{'tlps'}{$pkg};
 2084     if ($tlpobj->category eq "Collection") {
 2085       $vars{"$pkg"} = 0 if (!defined($vars{$pkg}));
 2086       ++$vars{'n_collections_available'};
 2087       push (@collections_std, $pkg);
 2088     }
 2089   }
 2090   my $selscheme = ($vars{'selected_scheme'} || $default_scheme);
 2091   my $scheme_tlpobj = $tlpdb->get_package($selscheme);
 2092   if (defined ($scheme_tlpobj)) {
 2093     $vars{'n_collections_selected'}=0;
 2094     foreach my $dependent ($scheme_tlpobj->depends) {
 2095       if ($dependent=~/^(collection-.*)/) {
 2096         $vars{"$1"}=1;
 2097       }
 2098     }
 2099   }
 2100   for my $c (keys(%vars)) {
 2101     if ($c =~ m/^collection-/ && $vars{$c}) {
 2102       ++$vars{'n_collections_selected'};
 2103     }
 2104   }
 2105   if ($vars{"binary_windows"}) {
 2106     $vars{"collection-wintools"} = 1;
 2107     ++$vars{'n_collections_selected'};
 2108   }
 2109 } # initialize_collections
 2110 
 2111 sub set_install_platform {
 2112   my $detected_platform=platform;
 2113   if ($opt_custom_bin) {
 2114     $detected_platform = "custom";
 2115   }
 2116   my $warn_nobin;
 2117   my $warn_nobin_x86_64_linux;
 2118   my $nowarn="";
 2119   my $wp='***'; # warning prefix
 2120 
 2121   $warn_nobin="\n$wp WARNING: No binaries for your platform found.  ";
 2122   $warn_nobin_x86_64_linux="$warn_nobin" .
 2123       "$wp No binaries for x86_64-linux found, using i386-linux instead.\n";
 2124 
 2125   my $ret = $warn_nobin;
 2126   if (defined $vars{"binary_$detected_platform"}) {
 2127     $vars{"binary_$detected_platform"}=1;
 2128     $vars{'inst_platform'}=$detected_platform;
 2129     $ret = $nowarn;
 2130   } elsif ($detected_platform eq 'x86_64-linux') {
 2131     $vars{'binary_i386-linux'}=1;
 2132     $vars{'inst_platform'}='i386-linux';
 2133     $ret = $warn_nobin_x86_64_linux;
 2134   } else {
 2135     if ($opt_custom_bin) {
 2136       $ret = "$wp Using custom binaries from $opt_custom_bin.\n";
 2137     } else {
 2138       $ret = $warn_nobin;
 2139     }
 2140   }
 2141   foreach my $key (keys %vars) {
 2142     if ($key=~/^binary.*/) {
 2143        ++$vars{'n_systems_selected'} if $vars{$key}==1;
 2144     }
 2145   }
 2146   return($ret);
 2147 } # set_install_platform
 2148 
 2149 sub create_profile {
 2150   my $profilepath = shift;
 2151   # The file "TLprofile" is created at the beginning of the
 2152   # installation process and contains information about the current
 2153   # setup.  The purpose is to allow non-interactive installations.
 2154   my $fh;
 2155   if (ref($profilepath)) {
 2156     $fh = $profilepath;
 2157   } else {
 2158     open PROFILE, ">$profilepath";
 2159     $fh = \*PROFILE;
 2160   }
 2161   #
 2162   # determine whether the set of selected collections exactly 
 2163   # agrees with the selected scheme. In this case we do *not*
 2164   # save the actual collection setting but only the selected
 2165   # scheme, as reading the profile will load all collections
 2166   # if only the scheme is given.
 2167   my %instcols;
 2168   foreach my $key (sort keys %vars) {
 2169     $instcols{$key} = 1 if $key=~/^collection/ and $vars{$key}==1;
 2170   }
 2171   # for anything but "scheme-custom" we delete the contained
 2172   # collections from the list
 2173   if ($vars{'selected_scheme'} ne "scheme-custom") {
 2174     my $scheme=$tlpdb->get_package($vars{'selected_scheme'});
 2175     if (!defined($scheme)) {
 2176       die ("Scheme $vars{selected_scheme} not defined.\n");
 2177     }
 2178     for my $scheme_content ($scheme->depends) {
 2179       delete($instcols{"$scheme_content"}) if ($scheme_content=~/^collection-/);
 2180     }
 2181   }
 2182   # if there are still collection left, we keep all of them
 2183   my $save_cols = (keys(%instcols) ? 1 : 0);
 2184 
 2185   # start
 2186   my $tim = gmtime(time);
 2187   print $fh "# texlive.profile written on $tim UTC\n";
 2188   print $fh "# It will NOT be updated and reflects only the\n";
 2189   print $fh "# installation profile at installation time.\n";
 2190   print $fh "selected_scheme $vars{selected_scheme}\n";
 2191   foreach my $key (sort keys %vars) {
 2192     print $fh "$key $vars{$key}\n"
 2193         if $save_cols and $key=~/^collection/ and $vars{$key}==1;
 2194     # we don't save tlpdbopt_location
 2195     next if ($key eq "tlpdbopt_location");
 2196     print $fh "$key $vars{$key}\n" if $key =~ /^tlpdbopt_/;
 2197     print $fh "$key $vars{$key}\n" if $key =~ /^instopt_/;
 2198     print $fh "$key $vars{$key}\n" if defined($path_keys{$key});
 2199     print $fh "$key $vars{$key}\n" if (($key =~ /^binary_/) && $vars{$key});
 2200   }
 2201   if (!ref($profilepath)) {
 2202     close PROFILE;
 2203   }
 2204 } # create_profile
 2205 
 2206 sub read_profile {
 2207   my $profilepath = shift;
 2208   my %opts = @_;
 2209   my %keyrename = (
 2210     'option_doc'        => 'tlpdbopt_install_docfiles',
 2211     'option_fmt'        => 'tlpdbopt_create_formats',
 2212     'option_src'        => 'tlpdbopt_install_srcfiles',
 2213     'option_sys_bin'    => 'tlpdbopt_sys_bin',
 2214     'option_sys_info'   => 'tlpdbopt_sys_info',
 2215     'option_sys_man'    => 'tlpdbopt_sys_man',
 2216     'option_file_assocs' => 'tlpdbopt_file_assocs',
 2217     'option_backupdir'  => 'tlpdbopt_backupdir',
 2218     'option_w32_multi_user' => 'tlpdbopt_w32_multi_user',
 2219     'option_post_code'  => 'tlpdbopt_post_code',
 2220     'option_autobackup' => 'tlpdbopt_autobackup',
 2221     'option_desktop_integration' => 'tlpdbopt_desktop_integration',
 2222     'option_adjustrepo' => 'instopt_adjustrepo',
 2223     'option_letter'     => 'instopt_letter',
 2224     'option_path'       => 'instopt_adjustpath',
 2225     'option_symlinks'   => 'instopt_adjustpath',
 2226     'portable'          => 'instopt_portable',
 2227     'option_write18_restricted' => 'instopt_write18_restricted',
 2228   );
 2229   my %keylost = (
 2230     'option_menu_integration' => 1,
 2231     'in_place' => 1,
 2232   );
 2233 
 2234   open PROFILE, "<$profilepath"
 2235     or die "$0: Cannot open profile $profilepath for reading.\n";
 2236   # %pro is used to see whether there are non-recognized keys,
 2237   # while %profiledata is used to make sure that the values
 2238   # from the tlpdb do not overwrite -seed-profile values.
 2239   my %pro;
 2240   while (<PROFILE>) {
 2241     # don't use chomp here since we might use files written for Windows
 2242     # on Unix or the other way round.
 2243     # \R is a general line terminator, \z is end of string
 2244     s{\R\z}{};
 2245     next if m/^[[:space:]]*$/; # skip empty lines
 2246     next if m/^[[:space:]]*#/; # skip comment lines
 2247     s/^[[:space:]]+//;         # ignore leading (but not trailing) whitespace
 2248     my ($k,$v) = split (" ", $_, 2); # value might have spaces
 2249     # skip TEXDIRW, seems not used anymore, but might be around
 2250     # in some profiles
 2251     next if ($k eq "TEXDIRW");
 2252     # convert old keys to new keys
 2253     $k = $keyrename{$k} if ($keyrename{$k});
 2254     if ($keylost{$k}) {
 2255       tlwarn("Profile key `$k' is now ignored, please remove it.\n");
 2256       next;
 2257     }
 2258     $pro{$k} = $v;
 2259     $profiledata{$k} = $v;
 2260   }
 2261   foreach (keys %vars) {
 2262     # clear out collections from var, just to be sure
 2263     if (m/^collection-/) { $vars{$_} = 0; }
 2264   }
 2265   # initialize installer and tlpdb options
 2266   foreach (keys %pro) {
 2267     if (m/^instopt_/) {
 2268       if (defined($vars{$_})) {
 2269         $vars{$_} = $pro{$_};
 2270         delete($pro{$_});
 2271       }
 2272     } elsif (m/^tlpdbopt_/) {
 2273       my $o = $_;
 2274       $o =~ s/^tlpdbopt_//;
 2275       # we do not support setting the location in the profile
 2276       # could be done, but might be tricky ..
 2277       next if ($o eq 'location');
 2278       if (defined($TeXLive::TLConfig::TLPDBOptions{$o})) {
 2279         $vars{$_} = $pro{$_};
 2280         delete($pro{$_});
 2281       }
 2282 
 2283     } elsif (defined($path_keys{$_}) || m/^selected_scheme$/) {
 2284       if ($pro{$_}) {
 2285         $vars{$_} = $pro{$_};
 2286         delete($pro{$_});
 2287       } else {
 2288         tldie("$0: Quitting, profile key for path $_ must not be empty.\n");
 2289       }
 2290     
 2291     } elsif (m/^(binary|collection-)/) {
 2292       if ($pro{$_} =~ /^[01]$/) {
 2293         $vars{$_} = $pro{$_};
 2294         delete($pro{$_});
 2295       } else {
 2296         tldie("$0: Quitting, profile key for $_ must be 0 or 1, not: $pro{$_}\n");
 2297       }
 2298     }
 2299   }
 2300   #require Data::Dumper;
 2301   #$Data::Dumper::Indent = 1;
 2302   #print Data::Dumper->Dump([\%vars], [qw(vars)]);
 2303   #
 2304   # if there are still keys in the %pro array, some unknown keys have
 2305   # been written in the profile, bail out
 2306   if (my @foo = keys(%pro)) {
 2307     tlwarn("Unknown key(s) in profile $profilepath: @foo\n");
 2308     tlwarn("Stopping here.\n");
 2309     exit 1;
 2310   }
 2311 
 2312   # if a profile contains *only* the selected_scheme setting without
 2313   # any collection, we assume that exactely that scheme should be installed
 2314   my $coldefined = 0;
 2315   foreach my $k (keys %profiledata) {
 2316     if ($k =~ m/^collection-/) {
 2317       $coldefined = 1;
 2318       last;
 2319     }
 2320   }
 2321   # if we are in seed mode, do not try to load remote db as it is 
 2322   # not initialized by now
 2323   return if $opts{'seed'};
 2324   #
 2325   # check whether the collections are actually present in case of
 2326   # changes on the server
 2327   foreach my $k (keys %profiledata) {
 2328     if ($k =~ m/^collection-/) {
 2329       if (!defined($tlpdb->get_package($k))) {
 2330         tlwarn("The profile references a non-existing collection: $k\n");
 2331         tlwarn("Exiting.\n");
 2332         exit(1);
 2333       }
 2334     }
 2335   }
 2336   # Cmdline argument --scheme should override scheme selection in the profile
 2337   update_default_scheme();
 2338 
 2339   # if at least one collection has been defined return here
 2340   return if $coldefined;
 2341   # since no collections have been defined in the profile, we
 2342   # set those to be installed on which the scheme depends
 2343   my $scheme=$tlpdb->get_package($vars{'selected_scheme'});
 2344   if (!defined($scheme)) {
 2345     dump_vars(\*STDOUT);
 2346     die ("Scheme $vars{selected_scheme} not defined.\n");
 2347   }
 2348   for my $scheme_content ($scheme->depends) {
 2349     $vars{"$scheme_content"}=1 if ($scheme_content=~/^collection-/);
 2350   }
 2351 } # read_profile
 2352 
 2353 sub do_install_packages {
 2354   # We split installation of packages into two stages:
 2355   # - first critical packages, those absolutely necessary for working
 2356   # - all the other packages, that can be also installed afterwards
 2357   #   via tlmgr
 2358   # If something fails in the first group, we stop the installation.
 2359   # If something fails in the second group:
 2360   #   - if --continue is given, try to continue install
 2361   #   - if --continue is not given, terminate (behaviour till now)
 2362   #
 2363   my @criticalwhat = ();
 2364   my @what = ();
 2365   my @surely_fail_packages = ( @CriticalPackagesList, @TeXLive::TLConfig::InstallExtraRequiredPackages );
 2366   for my $package (keys %install) {
 2367     if (member($package, @surely_fail_packages)) {
 2368       push @criticalwhat, $package if ($install{$package} == 1);
 2369     } else {
 2370       push @what, $package if ($install{$package} == 1);
 2371     }
 2372   }
 2373   @criticalwhat = sort @criticalwhat;
 2374   @what = sort @what;
 2375   # determine retrial behavior
 2376   my $retry = $opt_debug_fakenet || ($media eq "NET");
 2377   # temporary unset the localtlpdb options responsible for
 2378   # running all kind of postactions, since install_packages
 2379   # would call them without the PATH already set up
 2380   # we are doing this anyway in do_postinstall_actions
 2381   $localtlpdb->option ("desktop_integration", "0");
 2382   $localtlpdb->option ("file_assocs", "0");
 2383   $localtlpdb->option ("post_code", "0");
 2384   if (!install_packages($tlpdb,$media,$localtlpdb,\@criticalwhat,
 2385                         $vars{'tlpdbopt_install_srcfiles'},
 2386                         $vars{'tlpdbopt_install_docfiles'},
 2387                         $retry, 0)
 2388       ||
 2389       !install_packages($tlpdb,$media,$localtlpdb,\@what,
 2390                         $vars{'tlpdbopt_install_srcfiles'},
 2391                         $vars{'tlpdbopt_install_docfiles'},
 2392                         $retry, $opt_continue)) {
 2393     my $profile_name = "installation.profile";
 2394     create_profile($profile_name);
 2395     tlwarn("Installation failed.\n");
 2396     tlwarn("Rerunning the installer will try to restart the installation.\n");
 2397     if (-r $profile_name) {
 2398       # only suggest rerunning with the profile if it exists.
 2399       tlwarn("Or you can restart by running the installer with:\n");
 2400       my $repostr = ($opt_location ? " --repository $location" : "");
 2401       my $args = "--profile $profile_name [YOUR-EXTRA-ARGS]";
 2402       if (wndws()) {
 2403         tlwarn("  install-tl-windows.bat$repostr $args\n");
 2404       } else {
 2405         tlwarn("  install-tl$repostr $args\n");
 2406       }
 2407     }
 2408     flushlog();
 2409     exit(1);
 2410   }
 2411   # restore options in tlpdb
 2412   $localtlpdb->option (
 2413     "desktop_integration", $vars{'tlpdbopt_desktop_integration'});
 2414   $localtlpdb->option ("file_assocs", $vars{'tlpdbopt_file_assocs'});
 2415   $localtlpdb->option ("post_code", $vars{'tlpdbopt_post_code'} ? "1" : "0");
 2416   $localtlpdb->save;
 2417 } # do_install_packages
 2418 
 2419 # for later complete removal we want to save some options and values
 2420 # into the local tlpdb:
 2421 # - should links be set, and if yes, the destination (bin,man,info)
 2422 #
 2423 sub save_options_into_tlpdb {
 2424   # if we are told to adjust the repository *and* we are *not*
 2425   # installing from the network already, we adjust the repository
 2426   # to the default mirror.ctan.org
 2427   if ($vars{'instopt_adjustrepo'} && ($media ne 'NET')) {
 2428     $localtlpdb->option ("location", $TeXLiveURL); 
 2429   } else {
 2430     my $final_loc = ($media eq 'NET' ? $location : abs_path($location));
 2431     $localtlpdb->option ("location", $final_loc);
 2432   }
 2433   for my $o (keys %TeXLive::TLConfig::TLPDBOptions) {
 2434     next if ($o eq "location"); # done above already
 2435     $localtlpdb->option ($o, $vars{"tlpdbopt_$o"});
 2436   }
 2437   my @archs;
 2438   foreach (keys %vars) {
 2439     if (m/^binary_(.*)$/ ) {
 2440       if ($vars{$_}) { push @archs, $1; }
 2441     }
 2442   }
 2443   if ($opt_custom_bin) {
 2444     push @archs, "custom";
 2445   }
 2446   if (! @archs) {
 2447     tldie("$0: Quitting, no binary platform specified/available.\n"
 2448          ."$0: See https://tug.org/texlive/custom-bin.html for\n"
 2449          ."$0: information on other precompiled binary sets.\n");
 2450   }
 2451   # only if we forced the platform we do save this option into the tlpdb
 2452   if (defined($opt_force_arch)) {
 2453     $localtlpdb->setting ("platform", $::_platform_);
 2454   }
 2455   $localtlpdb->setting("available_architectures", @archs);
 2456   $localtlpdb->save() unless $opt_in_place;
 2457 } # save_options_into_tlpdb
 2458 
 2459 sub import_settings_from_old_tlpdb {
 2460   my $dn = shift;
 2461   my $tlpdboldpath =
 2462     "$dn/$TeXLive::TLConfig::InfraLocation/$TeXLive::TLConfig::DatabaseName";
 2463   my $previoustlpdb;
 2464   if (-r $tlpdboldpath) {
 2465     # we found an old installation, so read that one in and save
 2466     # the list installed collections into an array.
 2467     info ("Trying to load old TeX Live Database,\n");
 2468     $previoustlpdb = TeXLive::TLPDB->new(root => $dn);
 2469     if ($previoustlpdb) {
 2470       info ("Importing settings from old installation in $dn\n");
 2471     } else {
 2472       tlwarn ("Cannot load old TLPDB, continuing with normal installation.\n");
 2473       return;
 2474     }
 2475   } else {
 2476     return;
 2477   }
 2478   ############# OLD CODE ###################
 2479   # in former times we sometimes didn't change from scheme-full
 2480   # to scheme-custom when deselecting some collections
 2481   # this is fixed now.
 2482   #
 2483   # # first import the collections
 2484   # # since the scheme is not the final word we select scheme-custom here
 2485   # # and then set the single collections by hand
 2486   # $vars{'selected_scheme'} = "scheme-custom";
 2487   # $vars{'n_collections_selected'} = 0;
 2488   # # remove the selection of all collections
 2489   # foreach my $entry (keys %vars) {
 2490   #   if ($entry=~/^(collection-.*)/) {
 2491   #     $vars{"$1"}=0;
 2492   #   }
 2493   # }
 2494   # for my $c ($previoustlpdb->collections) {
 2495   #   my $tlpobj = $tlpdb->get_package($c);
 2496   #   if ($tlpobj) {
 2497   #     $vars{$c} = 1;
 2498   #     ++$vars{'n_collections_selected'};
 2499   #   }
 2500   # }
 2501   ############ END OF OLD CODE ############
 2502 
 2503   ############ NEW CODE ###################
 2504   # we simply go through all installed schemes, install
 2505   # all depending collections
 2506   # if we find scheme-full we use this as 'selected_scheme'
 2507   # otherwise we use 'scheme_custom' as we don't know
 2508   # and there is no total order on the schemes.
 2509   #
 2510   # we cannot use select_scheme from tlmgr.pl, as this one clears
 2511   # previous selctions (hmm :-(
 2512   $vars{'selected_scheme'} = "scheme-custom";
 2513   $vars{'n_collections_selected'} = 0;
 2514   # remove the selection of all collections
 2515   foreach my $entry (keys %vars) {
 2516     if ($entry=~/^(collection-.*)/) {
 2517       $vars{"$1"}=0;
 2518     }
 2519   }
 2520   # now go over all the schemes *AND* collections and select them
 2521   foreach my $s ($previoustlpdb->schemes) {
 2522     my $tlpobj = $tlpdb->get_package($s);
 2523     if ($tlpobj) {
 2524       foreach my $e ($tlpobj->depends) {
 2525         if ($e =~ /^(collection-.*)/) {
 2526           # do not add collections multiple times
 2527           if (!$vars{$e}) {
 2528             $vars{$e} = 1;
 2529             ++$vars{'n_collections_selected'};
 2530           }
 2531         }
 2532       }
 2533     }
 2534   }
 2535   # Now do the same for collections:
 2536   for my $c ($previoustlpdb->collections) {
 2537     my $tlpobj = $tlpdb->get_package($c);
 2538     if ($tlpobj) {
 2539       if (!$vars{$c}) {
 2540         $vars{$c} = 1;
 2541         ++$vars{'n_collections_selected'};
 2542       }
 2543     }
 2544   }
 2545   ########### END NEW CODE #############
 2546 
 2547 
 2548   # now take over the path
 2549   my $oldroot = $previoustlpdb->root;
 2550   my $newroot = abs_path("$oldroot/..") . "/$texlive_release";
 2551   $vars{'TEXDIR'} = $newroot;
 2552   $vars{'TEXMFSYSVAR'} = "$newroot/texmf-var";
 2553   $vars{'TEXMFSYSCONFIG'} = "$newroot/texmf-config";
 2554   # only TEXMFLOCAL is treated differently, we use what is found by kpsewhich
 2555   # in 2008 and onward this is defined as
 2556   # TEXMFLOCAL = $SELFAUTOPARENT/../texmf-local
 2557   # so kpsewhich -var-value=TEXMFLOCAL returns
 2558   # ..../2008/../texmf-local
 2559   # TODO TODO TODO
 2560   chomp (my $tml = `kpsewhich -var-value=TEXMFLOCAL`);
 2561   $tml = abs_path($tml);
 2562   $vars{'TEXMFLOCAL'} = $tml;
 2563   #
 2564   # now for the settings
 2565   # set the defaults to what is specified in the tlpdb
 2566   $vars{'tlpdbopt_install_docfiles'}
 2567     = $previoustlpdb->option_pkg("00texlive.installation", "install_docfiles");
 2568   $vars{'tlpdbopt_install_srcfiles'}
 2569     = $previoustlpdb->option_pkg("00texlive.installation", "install_srcfiles");
 2570   $vars{'tlpdbopt_create_formats'}
 2571     = $previoustlpdb->option_pkg("00texlive.installation", "create_formats");
 2572   $vars{'tlpdbopt_desktop_integration'} = 1 if wndws();
 2573   $vars{'instopt_adjustpath'}
 2574     = $previoustlpdb->option_pkg("00texlive.installation", "path");
 2575   $vars{'instopt_adjustpath'} = 0 if !defined($vars{'instopt_adjustpath'});
 2576   $vars{'instopt_adjustpath'} = 1 if wndws();
 2577   $vars{'tlpdbopt_sys_bin'}
 2578     = $previoustlpdb->option_pkg("00texlive.installation", "sys_bin");
 2579   $vars{'tlpdbopt_sys_man'}
 2580     = $previoustlpdb->option_pkg("00texlive.installation", "sys_man");
 2581   $vars{'sys_info'}
 2582     = $previoustlpdb->option_pkg("00texlive.installation", "sys_info");
 2583   #
 2584   # import the set of selected architectures
 2585   my @aar = $previoustlpdb->setting_pkg("00texlive.installation",
 2586                                         "available_architectures");
 2587   if (@aar) {
 2588     for my $b ($tlpdb->available_architectures) {
 2589       $vars{"binary_$b"} = member( $b, @aar );
 2590     }
 2591     $vars{'n_systems_available'} = 0;
 2592     for my $key (keys %vars) {
 2593       ++$vars{'n_systems_available'} if ($key=~/^binary/);
 2594     }
 2595   }
 2596   #
 2597   # try to import paper settings
 2598   my $xdvi_paper;
 2599   if (!wndws()) {
 2600     $xdvi_paper = TeXLive::TLPaper::get_paper("xdvi");
 2601   }
 2602   my $pdftex_paper = TeXLive::TLPaper::get_paper("pdftex");
 2603   my $dvips_paper = TeXLive::TLPaper::get_paper("dvips");
 2604   my $dvipdfmx_paper = TeXLive::TLPaper::get_paper("dvipdfmx");
 2605   my $context_paper;
 2606   if (defined($previoustlpdb->get_package("context"))) {
 2607     $context_paper = TeXLive::TLPaper::get_paper("context");
 2608   }
 2609   my $common_paper = "";
 2610   if (defined($xdvi_paper)) {
 2611     $common_paper = $xdvi_paper;
 2612   }
 2613   $common_paper = 
 2614     ($common_paper ne $context_paper ? "no-agree-on-paper" : $common_paper)
 2615       if (defined($context_paper));
 2616   $common_paper = 
 2617     ($common_paper ne $pdftex_paper ? "no-agree-on-paper" : $common_paper)
 2618       if (defined($pdftex_paper));
 2619   $common_paper = 
 2620     ($common_paper ne $dvips_paper ? "no-agree-on-paper" : $common_paper)
 2621       if (defined($dvips_paper));
 2622   $common_paper = 
 2623     ($common_paper ne $dvipdfmx_paper ? "no-agree-on-paper" : $common_paper)
 2624       if (defined($dvipdfmx_paper));
 2625   if ($common_paper eq "no-agree-on-paper") {
 2626     tlwarn("Previous installation uses different paper settings.\n");
 2627     tlwarn("You will need to select your preferred paper sizes manually.\n\n");
 2628   } else {
 2629     if ($common_paper eq "letter") {
 2630       $vars{'instopt_letter'} = 1;
 2631     } elsif ($common_paper eq "a4") {
 2632       # do nothing
 2633     } else {
 2634       tlwarn(
 2635         "Previous installation has common paper setting of: $common_paper\n");
 2636       tlwarn("After installation has finished, you will need\n");
 2637       tlwarn("  to redo this setting by running:\n");
 2638     }
 2639   }
 2640   # update size information
 2641   $vars{'free_size'} = TeXLive::TLUtils::diskfree($vars{'TEXDIR'});
 2642 } # import_settings_from_old_tlpdb
 2643 
 2644 # do everything to select a scheme
 2645 #
 2646 sub select_scheme {
 2647   my $s = shift;
 2648   # set the selected scheme to $s
 2649   $vars{'selected_scheme'} = $s;
 2650   debug("setting selected scheme: $s\n");
 2651   # if we are working on scheme-custom simply return
 2652   return if ($s eq "scheme-custom");
 2653   # remove the selection of all collections
 2654   foreach my $entry (keys %vars) {
 2655     if ($entry=~/^(collection-.*)/) {
 2656       $vars{"$1"}=0;
 2657     }
 2658   }
 2659   # select the collections belonging to the scheme
 2660   my $scheme_tlpobj = $tlpdb->get_package($s);
 2661   if (defined ($scheme_tlpobj)) {
 2662     $vars{'n_collections_selected'}=0;
 2663     foreach my $dependent ($scheme_tlpobj->depends) {
 2664       if ($dependent=~/^(collection-.*)/) {
 2665         $vars{"$1"}=1;
 2666         ++$vars{'n_collections_selected'};
 2667       }
 2668     }
 2669   }
 2670   # we have first set all collection-* keys to zero and than
 2671   # set to 1 only those which are required by the scheme
 2672   # since now scheme asks for collection-wintools we set its vars value
 2673   # to 1 in case we are installing windows binaries
 2674   if ($vars{"binary_windows"}) {
 2675     $vars{"collection-wintools"} = 1;
 2676     ++$vars{'n_collections_selected'};
 2677   }
 2678   # for good measure, update the deps
 2679   calc_depends();
 2680 } # select_scheme
 2681 
 2682 # try to give a decent order of schemes, but be so general that
 2683 # if we change names of schemes nothing bad happnes (like forgetting one)
 2684 sub schemes_ordered_for_presentation {
 2685   my @scheme_order;
 2686   my %schemes_shown;
 2687   for my $s ($tlpdb->schemes) { $schemes_shown{$s} = 0 ; }
 2688   # first try the size-name-schemes in decreasing order
 2689   for my $sn (qw/full medium small basic minimal infraonly/) {
 2690     if (defined($schemes_shown{"scheme-$sn"})) {
 2691       push @scheme_order, "scheme-$sn";
 2692       $schemes_shown{"scheme-$sn"} = 1;
 2693     }
 2694   }
 2695   # now push all the other schemes if they are there and not already shown
 2696   for my $s (sort keys %schemes_shown) {
 2697     push @scheme_order, $s if !$schemes_shown{$s};
 2698   }
 2699   return @scheme_order;
 2700 } # schemes_ordered_for_presentation
 2701 
 2702 sub update_numbers {
 2703   $vars{'n_collections_available'}=0;
 2704   $vars{'n_collections_selected'} = 0;
 2705   $vars{'n_systems_available'} = 0;
 2706   $vars{'n_systems_selected'} = 0;
 2707   foreach my $key (keys %vars) {
 2708     if ($key =~ /^binary/) {
 2709       ++$vars{'n_systems_available'};
 2710       ++$vars{'n_systems_selected'} if $vars{$key} == 1;
 2711     }
 2712     if ($key =~ /^collection-/) {
 2713       ++$vars{'n_collections_available'};
 2714       ++$vars{'n_collections_selected'} if $vars{$key} == 1;
 2715     }
 2716   }
 2717 } # update_numbers
 2718 
 2719 # signal handler for interrupts SIGINT AND SIGTERM
 2720 sub signal_handler {
 2721   my ($sig) = @_;
 2722   flushlog();
 2723   print STDERR "$0: caught SIG$sig -- exiting\n";
 2724   exit(1);
 2725 }
 2726 
 2727 # to be called at exit when the installation did not complete
 2728 sub flushlog {
 2729   if (!defined($::LOGFILENAME)) {
 2730     my $fh;
 2731     my $logfile = "install-tl.log";
 2732     if (open (LOG, ">$logfile")) {
 2733       my $pwd = Cwd::getcwd();
 2734       $logfile = "$pwd/$logfile";
 2735       print "$0: Writing log in current directory: $logfile\n";
 2736       $fh = \*LOG;
 2737     } else {
 2738       $fh = \*STDERR;
 2739       print
 2740         "$0: Could not write to $logfile, so flushing messages to stderr.\n";
 2741     }
 2742     foreach my $l (@::LOGLINES) {
 2743       print $fh $l;
 2744     }
 2745   }
 2746 } # flushlog
 2747 
 2748 sub do_cleanup {
 2749   # remove temporary files from TEXDIR/temp
 2750   if (($media eq "local_compressed") or ($media eq "NET")) {
 2751     debug("Remove temporary downloaded containers...\n");
 2752     rmtree("$vars{'TEXDIR'}/temp") if (-d "$vars{'TEXDIR'}/temp");
 2753   }
 2754 
 2755   # write the profile out
 2756   if ($opt_in_place) {
 2757     create_profile("$vars{'TEXDIR'}/texlive.profile");
 2758     debug("Profile written to $vars{'TEXDIR'}/texlive.profile\n");
 2759   } else {
 2760     create_profile("$vars{'TEXDIR'}/$InfraLocation/texlive.profile");
 2761     debug("Profile written to $vars{'TEXDIR'}/$InfraLocation/texlive.profile\n");
 2762   }
 2763 
 2764   # now open the log file and write out the log lines if needed.
 2765   # the user could have given the -logfile option in which case all the
 2766   # stuff is already dumped to it and $::LOGFILE defined. So do not
 2767   # redefine it.
 2768   if (!defined($::LOGFILE)) {
 2769     # no -logfile option; nothing written yet
 2770     $::LOGFILENAME = "$vars{'TEXDIR'}/install-tl.log";
 2771     if (open(LOGF,">:utf8", $::LOGFILENAME)) {
 2772       $::LOGFILE = \*LOGF;
 2773       foreach my $line(@::LOGLINES) {
 2774         print $::LOGFILE "$line";
 2775       }
 2776     } else {
 2777       tlwarn("$0: Cannot create log file $::LOGFILENAME: $!\n"
 2778              . "Not writing out log lines.\n");
 2779     }
 2780   }
 2781 
 2782   # Close log file if present
 2783   close($::LOGFILE) if (defined($::LOGFILE));
 2784   if (!defined($::LOGFILENAME) and (-e "$vars{'TEXDIR'}/install-tl.log")) {
 2785     $::LOGFILENAME = "$vars{'TEXDIR'}/install-tl.log";
 2786   }
 2787   if (!(defined($::LOGFILENAME)) or !(-e $::LOGFILENAME)) {
 2788     $::LOGFILENAME = "";
 2789   }
 2790 } # do_cleanup
 2791 
 2792 sub check_env {
 2793   # check for tex-related envvars.
 2794   $::env_warns = "";
 2795   for my $evar (sort keys %origenv) {
 2796     next if $evar =~ /^(_.*
 2797                         |.*PWD
 2798                         |ARGS
 2799                         |GENDOCS_TEMPLATE_DIR
 2800                         |INSTROOT
 2801                         |INFOPATH
 2802                         |MANPATH
 2803                         |PATH
 2804                         |PERL5LIB
 2805                         |SHELLOPTS
 2806                         |WISH
 2807                        )$/x; # don't worry about these
 2808     if ("$evar $origenv{$evar}" =~ /tex/i) { # check both key and value
 2809       $::env_warns .= "    $evar=$origenv{$evar}\n";
 2810     }
 2811   }
 2812   if ($::env_warns) {
 2813     $::env_warns = <<"EOF";
 2814 
 2815  ----------------------------------------------------------------------
 2816  The following environment variables contain the string "tex"
 2817  (case-independent).  If you're doing anything but adding personal
 2818  directories to the system paths, they may well cause trouble somewhere
 2819  while running TeX.  If you encounter problems, try unsetting them.
 2820  
 2821  Please ignore spurious matches unrelated to TeX. (To omit this check,
 2822  set the environment variable TEXLIVE_INSTALL_ENV_NOCHECK.)
 2823 
 2824 $::env_warns ----------------------------------------------------------------------
 2825 EOF
 2826   }
 2827 }
 2828 
 2829 
 2830 # Create a welcome message.
 2831 sub create_welcome {
 2832   @::welcome_arr = ();
 2833   push @::welcome_arr, "\n";
 2834   push @::welcome_arr, __("Welcome to TeX Live!");
 2835   push @::welcome_arr, "\n";
 2836   push @::welcome_arr, __(
 2837     "See %s/index.html for links to documentation.\nThe TeX Live web site (https://tug.org/texlive/) contains any updates and corrections. TeX Live is a joint project of the TeX user groups around the world; please consider supporting it by joining the group best for you. The list of groups is available on the web at https://tug.org/usergroups.html.",
 2838     $::vars{'TEXDIR'});
 2839   if (wndws()
 2840       || ($vars{'instopt_adjustpath'}
 2841          && $vars{'tlpdbopt_desktop_integration'} != 2)) {
 2842      ; # don't tell them to make path adjustments on Windows,
 2843        # or if they chose to "create symlinks".
 2844    } else {
 2845     push @::welcome_arr, "\n";
 2846     push @::welcome_arr, __(
 2847       "Add %s/texmf-dist/doc/man to MANPATH.\nAdd %s/texmf-dist/doc/info to INFOPATH.\nMost importantly, add %s/bin/%s\nto your PATH for current and future sessions.",
 2848       $::vars{'TEXDIR'}, $::vars{'TEXDIR'}, $::vars{'TEXDIR'},
 2849       $::vars{'this_platform'});
 2850   }
 2851 }
 2852 
 2853 
 2854 # remember the warnings issued
 2855 sub install_warnlines_hook {
 2856   push @::warn_hook, sub { push @::WARNLINES, @_; };
 2857 }
 2858 
 2859 ## a summary of warnings if there were any
 2860 #sub warnings_summary {
 2861 #  return '' unless @::WARNLINES;
 2862 #  my $summary = <<EOF;
 2863 #
 2864 #Summary of warning messages during installation:
 2865 #EOF
 2866 #  $summary .= join ("", map { "  $_" } @::WARNLINES); # indent each warning
 2867 #  $summary .= "\n";  # extra blank line
 2868 #  return $summary;
 2869 #}
 2870 
 2871 
 2872 
 2873 # some helper functions
 2874 # 
 2875 sub select_collections {
 2876   my $varref = shift;
 2877   foreach (@_) {
 2878     $varref->{$_} = 1;
 2879   }
 2880 }
 2881 
 2882 sub deselect_collections {
 2883   my $varref = shift;
 2884   foreach (@_) {
 2885     $varref->{$_} = 0;
 2886   }
 2887 }
 2888 
 2889 
 2890   __END__
 2891 
 2892 =head1 NAME
 2893 
 2894 install-tl - TeX Live cross-platform installer
 2895 
 2896 =head1 SYNOPSIS
 2897 
 2898 install-tl [I<option>]...
 2899 
 2900 install-tl-windows.bat [I<option>]...
 2901 
 2902 =head1 DESCRIPTION
 2903 
 2904 This installer creates a runnable TeX Live installation from various
 2905 media, including over the network, from local hard disk, a DVD, etc. The
 2906 installer works on all platforms supported by TeX Live. For information
 2907 on initially downloading TeX Live, see
 2908 L<https://tug.org/texlive/acquire.html>.
 2909 
 2910 The basic idea of TeX Live installation is for you to choose one of the
 2911 top-level I<schemes>, each of which is defined as a different set of
 2912 I<collections> and I<packages>, where a collection is a set of packages,
 2913 and a package is what contains actual files. Each package is in exactly
 2914 one collection, while schemes can contain any combination of packages
 2915 and collections.
 2916 
 2917 Within the installer, you can choose a scheme, and further customize the
 2918 set of collections to install, but not the set of the packages.  To work
 2919 at the package level, use C<tlmgr> (reference just below) after the
 2920 initial installation is complete.
 2921 
 2922 The default is C<scheme-full>, which installs everything, and this is
 2923 highly recommended.
 2924 
 2925 =head1 REFERENCES
 2926 
 2927 Post-installation configuration, package updates, and more, are
 2928 handled through B<tlmgr>(1), the TeX Live Manager
 2929 (L<https://tug.org/texlive/tlmgr.html>).
 2930 
 2931 The most up-to-date version of this installer documentation is on the
 2932 Internet at L<https://tug.org/texlive/doc/install-tl.html>.
 2933 
 2934 For step-by-step instructions, see
 2935 L<https://tug.org/texlive/quickinstall.html>.
 2936 
 2937 For the full documentation of TeX Live, see
 2938 L<https://tug.org/texlive/doc>.
 2939 
 2940 =head1 EXAMPLES
 2941 
 2942 With no options, C<install-tl> drops you into an interactive menu where
 2943 essentially all default settings can be changed. With options, you can
 2944 initialize the settings in various ways, or perform the installation
 2945 without interaction. Some examples:
 2946 
 2947 =over 4
 2948 
 2949 =item C<install-tl --paper=letter>
 2950 
 2951 Initialize paper size setting. The only values allowed are C<letter> and
 2952 (the default) C<a4>.
 2953 
 2954 =item C<install-tl --scheme> I<scheme>
 2955 
 2956 Initialize the installation scheme; the default is C<full>.  For a list
 2957 of schemes, see the interactive C<S> menu.
 2958 
 2959 =item C<install-tl --no-interaction>
 2960 
 2961 Perform the installation immediately after parsing options, without
 2962 entering the interactive menu.
 2963 
 2964 =item C<install-tl --profile> I<texlive.profile>
 2965 
 2966 Install, without interaction, according to the given TL profile file;
 2967 see L</PROFILES> below. To initialize from the profile and then enter the
 2968 interactive menu, add C<--init-from-profile>.
 2969 
 2970 =back
 2971 
 2972 Full documentation follows.
 2973 
 2974 =head1 OPTIONS
 2975 
 2976 As usual, all options can be specified in any order, and with either a
 2977 leading C<-> or C<-->.  An argument value can be separated from its
 2978 option by either a space or C<=>.
 2979 
 2980 The options relating to customization of the installation can also be
 2981 selected in the interactive installation menus (GUI or text).
 2982 
 2983 =over 4
 2984 
 2985 =item B<-gui> [[=]I<module>]
 2986 
 2987 =item B<-no-gui>
 2988 
 2989 If no I<module> is given, starts the Tcl/Tk (see below) GUI installer.
 2990 
 2991 If I<module> is given loads the given installer module. Currently the
 2992 following modules are supported:
 2993 
 2994 =over 4
 2995 
 2996 =item C<text>
 2997 
 2998 The text mode user interface (default on Unix systems, including Macs).
 2999 Same as the C<-no-gui> option.
 3000 
 3001 =item C<tcl> (or "perltk" or "wizard" or "expert" or nothing)
 3002 
 3003 The Tcl/Tk user interface (default on Windows).  It starts
 3004 with a small number of configuration options, roughly equivalent
 3005 to what the former wizard option offers, but a button C<Advanced>
 3006 takes you to a screen with roughly the same options as the former
 3007 C<perltk> interface.
 3008 
 3009 =back
 3010 
 3011 The default GUI requires Tcl/Tk. This was standard on Macs, but has been
 3012 removed in the latest macOS releases. It's often already installed on
 3013 GNU/Linux, or can be easily installed through a distro package manager.
 3014 For Windows, TeX Live provides a Tcl/Tk runtime.
 3015 
 3016 =for comment Keep language list in sync with tlmgr.
 3017 
 3018 =item B<-lang> I<llcode>
 3019 
 3020 By default, the Tcl GUI uses the language detection built into
 3021 Tcl/Tk. If that fails you can select a different language by
 3022 giving this option with a language code (based on ISO 639-1).
 3023 Currently supported (but not necessarily completely translated) are:
 3024 English (en, default), Czech (cs), German (de), French (fr), Italian
 3025 (it), Japanese (ja), Dutch (nl), Polish (pl), Brazilian Portuguese
 3026 (pt_BR), Russian (ru), Slovak (sk), Slovenian (sl), Serbian (sr),
 3027 Ukrainian (uk), Vietnamese (vi), simplified Chinese (zh_CN), and
 3028 traditional Chinese (zh_TW).
 3029 
 3030 =item B<-repository> I<url|path>
 3031 
 3032 Specify the package repository to be used as the source of the
 3033 installation. In short, this can be a directory name or a url using
 3034 http(s), ftp, or scp. The documentation for C<tlmgr> has the details
 3035 (L<https://tug.org/texlive/doc/tlmgr.html#OPTIONS>).
 3036 
 3037 For installation, the default is to pick a mirror automatically, using
 3038 L<https://mirror.ctan.org/systems/texlive/tlnet>; the chosen mirror is
 3039 then used for the entire download. You can use the special argument
 3040 C<ctan> as an abbreviation for this. (See L<https://ctan.org> for more
 3041 about CTAN and its mirrors.)
 3042 
 3043 After installation is complete, you can use that installation as the
 3044 repository for another installation.  If you chose to install less than
 3045 the full scheme containing all packages, the list of available schemes
 3046 will be adjusted accordingly.
 3047 
 3048 =item B<-select-repository>
 3049 
 3050 This option allows you to choose a particular mirror from the current
 3051 list of active CTAN mirrors. This option is supported in the C<text>
 3052 and C<gui> installer modes, and will also offer to install
 3053 from local media if available, or from a repository specified on the
 3054 command line. It's useful when the (default) automatic redirection does
 3055 not choose a good host for you.
 3056 
 3057 =item B<-all-options>
 3058 
 3059 Normally options not relevant to the current platform are not shown
 3060 (e.g., when running on Unix, Windows-specific options are omitted).
 3061 Giving this command line option allows configuring such "foreign"
 3062 settings.
 3063 
 3064 =item B<-custom-bin> I<path>
 3065 
 3066 If you have built your own set of TeX Live binaries (e.g., because
 3067 precompiled binaries were not provided by TL for your platform), this
 3068 option allows you to specify the I<path> to a directory where the
 3069 binaries for the current system are present. The installation will
 3070 continue as usual, but at the end all files from I<path> are copied over
 3071 to C<bin/custom/> under your installation directory and this
 3072 C<bin/custom/> directory is what will be added to the path for the
 3073 post-install actions. To install multiple custom binary sets, manually
 3074 rename C<custom> before doing each.
 3075 
 3076 For more information on custom binaries, see
 3077 L<https://tug.org/texlive/custom-bin.html>.  For general information on
 3078 building TeX Live, see L<https://tug.org/texlive/build.html>.
 3079 
 3080 =item B<-debug-fakenet>
 3081 
 3082 Pretend we're doing a network install. This is for the sole purpose of
 3083 testing the code to handle broken downloads, via moving package files
 3084 aside in a tlnet mirror hierarchy.
 3085 
 3086 =item B<-debug-setup-vars>
 3087 
 3088 Print final values of directory variables; for more debugging
 3089 information on how they were set, also specify C<-v>.
 3090 
 3091 =item B<-debug-translation>
 3092 
 3093 In the former Perl/Tk GUI modes, this option reported any missing,
 3094 or more likely untranslated, messages to standard error. Not yet
 3095 implemented for the Tcl interface. Helpful for translators to see
 3096 what remains to be done.
 3097 
 3098 =item B<-force-platform> I<platform>
 3099 
 3100 Instead of auto-detecting the current platform, use I<platform>.
 3101 Binaries for this platform must be present in C<bin/>I<platform>C</> and
 3102 they must be runnable, or installation will fail. C<-force-arch> is a
 3103 synonym.
 3104 
 3105 =item B<-help>, B<--help>, B<-?>
 3106 
 3107 Display this help and exit. (This help is also on the web at
 3108 L<https://tug.org/texlive/doc/install-tl.html>). Sometimes the C<perldoc>
 3109 and/or C<PAGER> programs on the system have problems, possibly resulting
 3110 in control characters being literally output. This can't always be
 3111 detected, but you can set the C<NOPERLDOC> environment variable and
 3112 C<perldoc> will not be used.
 3113 
 3114 =item B<-in-place>
 3115 
 3116 This is a quick-and-dirty installation option in case you already have
 3117 an rsync or svn checkout of TeX Live.  It will use the checkout as-is
 3118 and will just do the necessary post-install.  Be warned that the file
 3119 C<tlpkg/texlive.tlpdb> may be rewritten, that removal has to be done
 3120 manually, and that the only realistic way to maintain this installation
 3121 is to redo it from time to time.  This option is not available via the
 3122 installer interfaces.  USE AT YOUR OWN RISK.
 3123 
 3124 =item B<-init-from-profile> I<profile_file>
 3125 
 3126 Similar to B<-profile> (see L</PROFILES> below), but only initializes
 3127 the installation configuration from I<profile_file> and then starts a
 3128 normal interactive session. Environment variables are not ignored.
 3129 
 3130 =item B<-logfile> I<file>
 3131 
 3132 Write both all messages (informational, debugging, warnings) to I<file>,
 3133 in addition to standard output or standard error.
 3134 
 3135 If this option is not given, the installer will create a log file
 3136 in the root of the writable installation tree,
 3137 for example, C</usr/local/texlive/YYYY/install-tl.log> for the I<YYYY>
 3138 release.
 3139 
 3140 =item B<-no-cls>
 3141 
 3142 For the text mode installer only: do not clear the screen when entering
 3143 a new menu. For debugging.
 3144 
 3145 =item B<-no-continue>
 3146 
 3147 Quit early on installation failure of a non-core package.
 3148 
 3149 By default, a few core packages are installed first; then, a failed
 3150 installation of any other (non-core) package is noted, but does not stop
 3151 the installation. Any such failed packages are retried, once.
 3152 
 3153 If the retry also fails, by default the installer proceeds to completion
 3154 anyway, with the idea that it was a transient network problem and
 3155 reinstallation will succeed later. If this option is specified, and the
 3156 retry fails, the installer aborts.
 3157 
 3158 =item B<-no-doc-install>
 3159 
 3160 =item B<-no-src-install>
 3161 
 3162 Do not install the documentation resp. source package files, both for
 3163 the immediate installation and for future updates. After installation,
 3164 inclusion of the doc/src files can be re-enabled via C<tlmgr>:
 3165 
 3166   tlmgr option docfiles 1
 3167   tlmgr option srcfiles 1
 3168 
 3169 If you later find that you want the doc/src files for a package that has
 3170 been installed without them, you can get them like this (using the
 3171 C<fontspec> package as the example):
 3172 
 3173   tlmgr install --reinstall --with-doc --with-src fontspec
 3174 
 3175 The source files mentioned here are those relating to TeX packages, such
 3176 as C<.dtx> files. The sources that are compiled to make the binaries are
 3177 available separately: see L<https://tug.org/texlive/svn/>.
 3178 
 3179 =item B<-no-installation>
 3180 
 3181 Do not perform any installation. This is for debugging the
 3182 initialization and setup routines without touching the disk.
 3183 
 3184 =item B<-no-interaction>
 3185 
 3186 Do not enter the interactive menu; immediately perform the installation
 3187 after initialization and option parsing. Also omit the check for a
 3188 previous installation and asking about importing previous settings.
 3189 
 3190 =item B<-no-persistent-downloads>
 3191 
 3192 =item B<-persistent-downloads>
 3193 
 3194 For network installs, activating this option makes the installer try to
 3195 set up a persistent connection using the C<LWP> Perl module.  This
 3196 opens only one connection between your computer and the server per
 3197 session and reuses it, instead of initiating a new download for each
 3198 package, which typically yields a significant speed-up.
 3199 
 3200 This option is turned on by default, and the installation program will
 3201 fall back to using C<wget> if this is not possible.  To disable usage of
 3202 LWP and persistent connections, use C<-no-persistent-downloads>.
 3203 
 3204 =item B<-no-verify-downloads>
 3205 
 3206 By default, if a GnuPG C<gpg> binary is found in PATH, downloads are
 3207 verified against a cryptographic signature. This option disables such
 3208 verification.  The full description is in the Crytographic Verification
 3209 section of the C<tlmgr> documentation, e.g.,
 3210 L<https://tug.org/texlive/doc/tlmgr.html#CRYPTOGRAPHIC-VERIFICATION>
 3211 
 3212 =item B<-non-admin>
 3213 
 3214 For Windows only: configure for the current user, not for all users.
 3215 
 3216 =item B<-paper> C<a4>B<|>C<letter>
 3217 
 3218 Set the default paper size for all TeX Live programs, as specified.
 3219 The default is C<a4>. The paper size can be set after installation with
 3220 the C<tlmgr paper> command.
 3221 
 3222 =item B<-portable>
 3223 
 3224 Install for portable use, e.g., on a USB stick.  See the
 3225 C<instopt_portable> description below for details.
 3226 
 3227 =item B<-print-platform>
 3228 
 3229 Print the TeX Live identifier for the detected platform
 3230 (hardware/operating system) combination to standard output, and exit.
 3231 C<-print-arch> is a synonym.
 3232 
 3233 =item B<-profile> I<profile_file>
 3234 
 3235 Load I<profile_file> and do the installation with no user interaction,
 3236 that is, a batch (unattended) install.  Environment variables are
 3237 ignored. See L</PROFILES> below.
 3238 
 3239 =item B<-q>
 3240 
 3241 Omit normal informational messages.
 3242 
 3243 =item B<-scheme> I<scheme>
 3244 
 3245 Schemes are the highest level of package grouping in TeX Live; the
 3246 default is to use the C<full> scheme, which includes everything. This
 3247 option overrides that default. The I<scheme> argument value may
 3248 optionally have a prefix C<scheme->. The list of supported scheme names
 3249 depends on what your package repository provides; see the interactive
 3250 menu list.
 3251 
 3252 =item B<-texdir> I<dir>
 3253 
 3254 Specify the system installation directory; the default is
 3255 C</usr/local/texlive/YYYY> for release YYYY. Specifying this option also
 3256 causes the C<TEXMFLOCAL>, C<TEXMFSYSCONFIG>, and C<TEXMFSYSVAR>
 3257 directories to be set as subdirectories of I<dir>, so they don't have to
 3258 be set individually.
 3259 
 3260 There is a brief summary of these directories trees at L</DIRECTORY
 3261 TREES> below; for details on the trees set up by default, and their
 3262 intended usage, see the main TeX Live documentation at
 3263 L<https://tug.org/texlive/doc>.
 3264 
 3265 =item B<-texuserdir> I<dir>
 3266 
 3267 Specify the user installation directory; the default is
 3268 C<~/.texliveYYYY> (except on Macs, where there is no leading dot).
 3269 Specifying this also causes the C<TEXMFHOME>, C<TEXMFCONFIG>, and
 3270 C<TEXMFVAR> directories to be set as subdirectories of I<dir>.
 3271 
 3272 =item B<-texmflocal> I<dir>
 3273 
 3274 Specify the C<TEXMFLOCAL> directory; the default is
 3275 C</usr/local/texlive/texmf-local>, that is, one level up from the main
 3276 installation. This is so locally-installed packages can be easily used
 3277 across releases, which is usually desirable. Specifying the C<-texdir>
 3278 option changes this, putting C<TEXMFLOCAL> under the main tree. The
 3279 C<-texmflocal> option can be used to specify an explicit directory.
 3280 
 3281 Anything installed here must follow the TeX directory structure (TDS),
 3282 e.g., C<TEXMFHOME/tex/latex/mypkg/mypkg.sty>. TDS reference:
 3283 L<https://tug.org/tds>.
 3284 
 3285 =item B<-texmfhome> I<dir>
 3286 
 3287 Specify the C<TEXMFHOME> directory; the default is C<~/texmf>, except on
 3288 Macs, where it is C<~/Library/texmf>. Analogously to C<TEXMFLOCAL>, the
 3289 C<-texuserdir> option changes this default.
 3290 
 3291 Also as with C<TEXMFLOCAL>, anything installed here must follow the TDS.
 3292 
 3293 =item B<-texmfsysconfig> I<dir>
 3294 
 3295 =item B<-texmfsysvar> I<dir>
 3296 
 3297 Specify the C<TEXMFSYSCONFIG> and C<TEXMFSYSVAR> system directories.
 3298 
 3299 =item B<-texmfconfig> I<dir>
 3300 
 3301 =item B<-texmfvar> I<dir>
 3302 
 3303 Specify the C<TEXMFCONFIG> and C<TEXMFVAR> user directories.
 3304 The defaults are C<~/.texliveYYYY/texmf-{config,var}>, except on Macs,
 3305 where the leading dot is omitted (C<~/texliveYYYY/...>).
 3306 
 3307 =item B<-v>
 3308 
 3309 Include verbose debugging messages; repeat for maximum debugging: C<-v
 3310 -v>.  (Further repeats are accepted but ignored.)
 3311 
 3312 =item B<-version>, B<--version>
 3313 
 3314 Output version information and exit.  If C<-v> is also given, the
 3315 versions of the TeX Live modules used are also reported.
 3316 
 3317 =back
 3318 
 3319 =head1 PROFILES
 3320 
 3321 A I<profile> file normally contains all the values needed to perform an
 3322 installation. After a normal installation has finished, a profile for
 3323 that exact installation is written to the file C<tlpkg/texlive.profile>.
 3324 In addition, from the text menu one can select C<P> to save the current
 3325 setup as a profile at any time. These are small text files; feel free to
 3326 peruse and edit them according to your needs.
 3327 
 3328 Such a profile file can be given as the argument to C<-profile>, for
 3329 example to redo the exact same installation on a different system.
 3330 Alternatively, you can use a custom profile, most easily created by
 3331 starting from a generated one and changing values. An empty profile
 3332 file will cause the installer to use the defaults.
 3333 
 3334 As mentioned above, the installer only supports selection by scheme and
 3335 collections, not individual packages, so packages cannot be specified in
 3336 profile files either. Use C<tlmgr> to work at the package level.
 3337 
 3338 Within a profile file, each line consists of
 3339 
 3340 I<variable> [I<value>]
 3341 
 3342 except for comment lines starting with C<#>.  The possible variable
 3343 names are listed below.  Values, when present, are either C<0> or C<1>
 3344 for booleans, or strings (which must be specified without any quote
 3345 characters).  Leading whitespace is ignored.
 3346 
 3347 If the variable C<selected_scheme> is defined and I<no> collection
 3348 variables at all are defined, then the collections required by the
 3349 specified scheme (which might change over time) are installed, without
 3350 explicitly listing them. This eases maintenance of profile files. If any
 3351 collections are specified in a profile, though, then the scheme is
 3352 ignored and all desired collections must be given explicitly.
 3353 
 3354 For example, a line 
 3355 
 3356   selected_scheme scheme-small
 3357 
 3358 along with definitions for the installation directories (given below
 3359 under "path options") suffices to install the "small" scheme with all
 3360 default options.  The schemes are described in the C<S> menu in the
 3361 text installer, or equivalent.
 3362 
 3363 In addition to C<selected_scheme>, here are the other variable names
 3364 supported in a profile:
 3365 
 3366 B<collection options> (prefix C<collection->)
 3367 
 3368 Collections are specified with a variable name with the prefix
 3369 C<collection-> followed by a collection name; there is no value.  For
 3370 instance, C<collection-basic>.  The collections are described in the
 3371 C<C> menu.
 3372 
 3373 Schemes and collections (and packages) are ultimately defined by the
 3374 files in the C<tlpkg/tlpsrc/> source directory.
 3375 
 3376 B<path options>
 3377 
 3378 It is best to define all of these, even though they may not be used in a
 3379 given installation, so as to avoid unintentionally getting a default
 3380 value that could cause problems later.
 3381 
 3382   TEXDIR
 3383   TEXMFLOCAL
 3384   TEXMFSYSCONFIG
 3385   TEXMFSYSVAR
 3386   TEXMFCONFIG
 3387   TEXMFVAR
 3388   TEXMFHOME
 3389 
 3390 B<installer options> (prefix C<instopt_>)
 3391 
 3392 =over 4
 3393 
 3394 =item C<instopt_adjustpath> (default 0 on Unix, 1 on Windows)
 3395 
 3396 Adjust C<PATH> environment variable.
 3397 
 3398 =item C<instopt_adjustrepo> (default 1)
 3399 
 3400 Set remote repository to a multiplexed CTAN mirror after installation;
 3401 see C<-repository> above.
 3402 
 3403 =item C<instopt_letter> (default 0)
 3404 
 3405 Set letter size paper as the default, instead of a4.
 3406 
 3407 =item C<instopt_portable> (default 0)
 3408 
 3409 Install for portable use, e.g., on a USB stick, without touching the
 3410 host system. Specifically, this forces the user directories
 3411 C<TEXMFHOME>, C<TEXMFCONFIG>, C<TEXMFVAR> to be identical to the system
 3412 directories C<TEXMFLOCAL>, C<TEXMFSYSCONFIG>, C<TEXMFSYSVAR>,
 3413 respectively (regardless of other options and environment variable.)
 3414 
 3415 In addition, on Windows, it disables the desktop integration, path
 3416 adjustment, and file associations actions usually performed.
 3417 
 3418 =item C<instopt_write18_restricted> (default 1)
 3419 
 3420 Enable C<\write18> for a restricted set of programs.
 3421 
 3422 =back
 3423 
 3424 B<tlpdb options> (prefix C<tlpdbopt_>)
 3425 
 3426 The definitive list is given in C<tlpkg/TeXLive/TLConfig.pm>, in the hash
 3427 C<%TeXLive::TLConfig::TLPDBOptions>, together with explanations.  All
 3428 items given there I<except> for C<tlpdbopt_location> can be specified.
 3429 Here is the current list:
 3430 
 3431   tlpdbopt_autobackup
 3432   tlpdbopt_backupdir
 3433   tlpdbopt_create_formats
 3434   tlpdbopt_desktop_integration
 3435   tlpdbopt_file_assocs
 3436   tlpdbopt_generate_updmap
 3437   tlpdbopt_install_docfiles
 3438   tlpdbopt_install_srcfiles
 3439   tlpdbopt_post_code
 3440   tlpdbopt_sys_bin
 3441   tlpdbopt_sys_info
 3442   tlpdbopt_sys_man
 3443   tlpdbopt_w32_multi_user
 3444 
 3445 B<platform options> (prefix C<binary_>)
 3446 
 3447 For each supported platform in TeX Live (directories under C<bin/>), the
 3448 variable C<binary_>I<PLATFORM> can be set with value 1.  For example:
 3449 
 3450   binary_x86_64-linux 1
 3451 
 3452 If no C<binary_> settings are made, the default is whatever the
 3453 current machine is running.
 3454 
 3455 In releases before 2017, many profile variables had different
 3456 names (not documented here; see the C<install-tl> source).  They are
 3457 accepted and transformed to the names given above.  When a profile is
 3458 written, the names above are always used.
 3459 
 3460 For more details on all of the above options, consult the TeX Live
 3461 installation manual, linked from L<https://tug.org/texlive/doc>.
 3462 
 3463 =head1 ENVIRONMENT VARIABLES
 3464 
 3465 For ease in scripting and debugging, C<install-tl> looks for the
 3466 following environment variables. They are not of interest for normal
 3467 user installations.
 3468 
 3469 =over 4
 3470 
 3471 =item C<NOPERLDOC>
 3472 
 3473 Don't try to run the C<--help> message through C<perldoc>.
 3474 
 3475 =item C<TEXLIVE_DOWNLOADER>
 3476 
 3477 =item C<TL_DOWNLOAD_PROGRAM>
 3478 
 3479 =item C<TL_DOWNLOAD_ARGS>
 3480 
 3481 These override the normal choice of a download program; see the C<tlmgr>
 3482 documentation, e.g.,
 3483 L<https://tug.org/texlive/doc/tlmgr.html#ENVIRONMENT-VARIABLES>.
 3484 
 3485 =item C<TEXLIVE_INSTALL_ENV_NOCHECK>
 3486 
 3487 Omit the check for environment variables containing the string C<tex>.
 3488 People developing TeX-related software are likely to have many such
 3489 variables.
 3490 
 3491 =item C<TEXLIVE_INSTALL_NO_CONTEXT_CACHE>
 3492 
 3493 Omit creating the ConTeXt cache.  This is useful for redistributors.
 3494 
 3495 =item C<TEXLIVE_INSTALL_NO_DISKCHECK>
 3496 
 3497 If set to 1, omit free disk space check. By default, if a
 3498 POSIX-compliant C<df> program (supporting C<-Pk>) is available, the
 3499 installer checks for available disk space in the selected installation
 3500 location, and will abort installation if there is insufficient disk
 3501 space, plus a margin of 100MB. An equivalent check is made on Windows
 3502 (not involving C<df>).
 3503 
 3504 =item C<TEXLIVE_INSTALL_NO_RESUME>
 3505 
 3506 Omit check for installing on top of a previous installation and then
 3507 asking about importing previous settings.
 3508 
 3509 =item C<TEXLIVE_INSTALL_NO_WELCOME>
 3510 
 3511 Omit printing the welcome message after successful installation, e.g.,
 3512 when testing.
 3513 
 3514 =item C<TEXLIVE_INSTALL_PAPER>
 3515 
 3516 Set the default paper size for all relevant programs; must be either
 3517 C<letter> or C<a4>. The default is C<a4>.
 3518 
 3519 =item C<TEXLIVE_INSTALL_PREFIX>
 3520 
 3521 =item C<TEXLIVE_INSTALL_TEXMFCONFIG>
 3522 
 3523 =item C<TEXLIVE_INSTALL_TEXMFVAR>
 3524 
 3525 =item C<TEXLIVE_INSTALL_TEXMFHOME>
 3526 
 3527 =item C<TEXLIVE_INSTALL_TEXMFLOCAL>
 3528 
 3529 =item C<TEXLIVE_INSTALL_TEXMFSYSCONFIG>
 3530 
 3531 =item C<TEXLIVE_INSTALL_TEXMFSYSVAR>
 3532 
 3533 Specify the respective directories. C<TEXLIVE_INSTALL_PREFIX> defaults
 3534 to C</usr/local/texlive>. All the defaults can be seen by running the
 3535 installer interactively and then typing C<D> for the directory menu.
 3536 
 3537 The various command line options for specifying directories override
 3538 these environment variables; since specifying both is usually
 3539 accidental, a warning is given if the values are different.
 3540 
 3541 =back
 3542 
 3543 =head1 DIRECTORY TREES
 3544 
 3545 There are a plethora of ways to specify the plethora of directory trees
 3546 used by TeX Live. By far the simplest, and recommended, approach is not
 3547 to change anything. The defaults suffice for the vast majority of
 3548 installations.
 3549 
 3550 But, for the sake of explanation, here is a table of the trees and the
 3551 command line options that change them. The first group of three are
 3552 system directories, and the second group of three are user directories;
 3553 the two groups are quite analogous.
 3554 
 3555   +----------------+--------------------------------------+--------------+------------------+
 3556   |    tree        | default                              | group change | single change    |
 3557   +----------------+--------------------------------------+--------------+------------------+
 3558   | TEXMFLOCAL     | /usr/local/texlive/texmf-local       | --texdir     | --texmflocal     |
 3559   | TEXMFSYSVAR    | /usr/local/texlive/YYYY/texmf-var    | --texdir     | --texmfsysvar    |
 3560   | TEXMFSYSCONFIG | /usr/local/texlive/YYYY/texmf-config | --texdir     | --texmfsysconfig |
 3561   +----------------+--------------------------------------+--------------+------------------+
 3562   | TEXMFHOME      | ~/texmf                              | --texuserdir | --texmfhome      |
 3563   | TEXMFVAR       | ~/.texliveYYYY/texmf-var             | --texuserdir | --texmfvar       |
 3564   | TEXMFCONFIG    | ~/.texliveYYYY/texmf-config          | --texuserdir | --texmfconfig    |
 3565   +----------------+--------------------------------------+--------------+------------------+
 3566 
 3567 In addition, as mentioned in the previous section, each tree has an
 3568 environment variable C<TEXLIVE_INSTALL_>I<tree> which overrides the
 3569 default; command line and profile settings both override environment
 3570 variable settings.
 3571 
 3572 The defaults vary slightly on Macs, as explained above in L</OPTIONS>.
 3573 
 3574 For the user trees, the default value uses C<~>, and this is left as a
 3575 literal C<~> in C<texmf.cnf>. That way, each user can have their own
 3576 C<TEXMFHOME>, etc., as intended. On the other hand, for the system
 3577 trees, if C<~> is used during the installation, this is assumed to
 3578 simply be a typing shorthand, and the expanded home directory is written
 3579 in C<texmf.cnf>, since it doesn't make sense to have user-specific
 3580 system directories.
 3581 
 3582 For more on the directory trees and their intended usage, see the main
 3583 TeX Live documentation at L<https://tug.org/texlive/doc>.
 3584 
 3585 =head1 BUGS
 3586 
 3587 The C<install-tl> script copies itself into the installed tree.
 3588 Usually, it can be run from there, using the installed tree as the
 3589 source for another installation.  Occasionally, however, there may be
 3590 incompatibilities in the code of the new C<install-tl> and the
 3591 infrastructure, resulting in (probably) inscrutable Perl errors.  The
 3592 way forward is to run C<install-tl> out of the installer package
 3593 (C<install-tl-unx.tar.gz> or C<install-tl.zip>) instead of the
 3594 installation. Feel free to also report the issue; usually the code
 3595 can be easily synced up again.
 3596 
 3597 By the way, do not try to use C<install-tl> to adjust options or
 3598 installed packages in an existing installed tree. Use C<tlmgr> instead.
 3599 
 3600 =head1 AUTHORS AND COPYRIGHT
 3601 
 3602 This script and its documentation were written for the TeX Live
 3603 distribution (L<https://tug.org/texlive>) and both are licensed under the
 3604 GNU General Public License Version 2 or later.
 3605 
 3606 $Id: install-tl 67839 2023-08-07 21:47:31Z preining $
 3607 =cut
 3608 
 3609 # to remake HTML version: pod2html --cachedir=/tmp install-tl >/tmp/itl.html
 3610 
 3611 ### Local Variables:
 3612 ### perl-indent-level: 2
 3613 ### tab-width: 2
 3614 ### indent-tabs-mode: nil
 3615 ### End:
 3616 # vim:set tabstop=2 expandtab: #