diff options
author | Norbert Preining <preining@logic.at> | 2009-12-10 05:16:49 +0000 |
---|---|---|
committer | Norbert Preining <preining@logic.at> | 2009-12-10 05:16:49 +0000 |
commit | f5059616ead85fc42ecaf002571d6554ae56cecf (patch) | |
tree | d5961d824a7c759d5b8c97db13b20894bdde90c8 /Master | |
parent | ddcb0adb20a8c66e23d6fca375fd698f9107ae34 (diff) |
add a first shot at TLDownload.pm
git-svn-id: svn://tug.org/texlive/trunk@16340 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master')
-rw-r--r-- | Master/tlpkg/dev/TLDownload.pm | 286 | ||||
-rwxr-xr-x | Master/tlpkg/dev/install-tl-using-TLDownload | 1994 |
2 files changed, 2280 insertions, 0 deletions
diff --git a/Master/tlpkg/dev/TLDownload.pm b/Master/tlpkg/dev/TLDownload.pm new file mode 100644 index 00000000000..66966e58d1f --- /dev/null +++ b/Master/tlpkg/dev/TLDownload.pm @@ -0,0 +1,286 @@ +# $Id$ +# TeXLive::TLDownload.pm - module for abstracting the download modes +# Copyright 2009 Norbert Preining +# +# This file is licensed under the GNU General Public License version 2 +# or any later version. + +package TeXLive::TLDownload; + +use TeXLive::TLUtils; + +my $svnrev = '$Revision$'; +my $_modulerevision; +if ($svnrev =~ m/: ([0-9]+) /) { + $_modulerevision = $1; +} else { + $_modulerevision = "unknown"; +} +sub module_revision { + return $_modulerevision; +} + +# since Net::HTTP and Net::FTP are shipped by the same packages +# we only test for Net::HTTP, if that fails, let us know ;-) +my $net_lib_avail = 0; +eval { require Net::HTTP; }; +if ($@) { + debug("Net::HTTP is not available, falling back to wget mode.\n"); + $net_lib_avail = 0; +} else { + require Net::HTTP; + require Net::FTP; + require HTTP::Status; + $net_lib_avail = 1; + debug("Net::HTTP available!\n"); +} + + +sub new +{ + my $class = shift; + my %params = @_; + my $self = { + server => $params{'server'}, + mode => defined($params{'mode'}) ? $params{'mode'} : "wget", + }; + if ($self->{'mode'} eq "http" || + $self->{'mode'} eq "ftp") { + die "Net::HTTP and Net::FTP is not available, cannot use http/ftp mode." + if (!$net_lib_avail); + } elsif ($self->{'mode'} eq "wget") { + # noting to be done + } else { + die "Unknown download mode: ", $self->{'mode'}; + } + bless $self, $class; + return $self; +} + + + +sub start_connection +{ + my $self = shift; + if ($self->mode eq "wget") { + debug("TLDownload::start_connection: no need to call start_connection in wget mode\n"); + return 1; + } + if (!defined($self->server)) { + die "TLDownload::start_connection: No server defined, cannot start connection."; + } + if ($self->mode eq "http") { + my $handle = Net::HTTP->new(Host => $self->server, KeepAlive => 1); + if (!$handle) { + tlwarn("TLDownload::start_connection: Could not connect to server " . $self->server . "\n"); + return 0; + } + # now we got a handle, save it simply into $self for later reuse + $self->{'handle'} = $handle; + return 1; + } + if ($self->mode eq "ftp") { + my $handle = Net::FTP->new($self->server, Debug => 0); + if (!$handle) { + tlwarn("TLDownload::start_connection: Could not connect to server " . $self->server . "\n"); + return 0; + } + if (!$handle->login("anonymous",'-texlive@')) { + tlwarn("TLDownload::start_connection: Cannot login to server: " . $handle->message . "\n"); + return 0; + } + if (!$handle->binary) { + tlwarn("TLDownload::start_connection: Cannot set transfer mode to binary: " . $handle->message . "\n"); + return 0; + } + # now we got a handle, save it simply into $self for later reuse + $self->{'handle'} = $handle; + return 1; + } + # we are still here, that cannot be + return 0; +} + + + +sub get_file +{ + my ($self, $url, $out, $size) = @_; + # + # first split the $url into components. we might get a full url + # or some relative path + my $protocol; + my $server; + my $path; + if ($url =~ m!^(http|ftp)://([^/]*)(/.*)$!i) { + $protocol = lc($1); + $server = lc($2); + $path = $3; + } elsif ($url =~ m!^/.*$!) { + $path = $url; + } else { + tlwarn("TLDownload::get_file: do not understand that url: $url\n"); + return 0; + } + # + # wget case + # simple fall back to TLUtils::_download_file + # + if ($self->mode eq "wget") { + if (!defined($protocol)) { + tlwarn("TLDownload::get_file: cannot download relative url $url in wget mode.\n"); + return 0; + } + my $wget; + if (defined($::progs{'wget'})) { + $wget = $progs->{'wget'}; + } else { + tlwarn ("TLDownload::get_file: programs not set up, trying literal wget\n"); + $wget = "wget"; + } + return TeXLive::TLUtils::_download_file($url, $out, $wget); + } + # + # check for incompatible server names or protocols + # + if (defined($protocol) && ($protocol ne $self->mode)) { + tlwarn("TLDownload::get_file: protocols mismatch, url uses $protocol, server " . $self->mode . ".\n"); + return 0; + } + if (defined($server) && ($server ne lc($self->server))) { + tlwarn("TLDownload::get_file: server mismatch, url uses $server, but current download server is " . $self->server . ".\n"); + return 0; + } + # + # ftp mode + # + if ($self->mode eq "ftp") { + if (!defined($self->{'handle'})) { + if (!$self->start_connection) { + # start_connection already warns ... + return 0; + } + } + # now we should have a $handle + my $handle = $self->{'handle'}; + if (!$handle->get($path, $out)) { + tlwarn("TLDownload::get_file: Cannot get $path: " . $handle->message . "\n"); + return 0; + } + return 1; + } + # + # http mode + # + if ($self->mode eq "http") { + if (!defined($self->{'handle'})) { + if (!$self->start_connection) { + # start_connection already warns ... + return 0; + } + } + # now we should have a $handle + my $handle = $self->{'handle'}; + if (! $handle->write_request(GET => $path, 'User-Agent' => 'texlive (net::http)')) { + tlwarn("TLDownload::get_file: Cannot send GET request.\n"); + return 0; + } + my ($code, $msg, %h) = $handle->read_response_headers; + if (HTTP::Status::is_error($code)) { + tlwarn("Problem downloading from server: $msg\n"); + return 0; + } + my $buffer = ""; + my $bytes_read = 0; + while (1) { + my $buf; + my $n = $handle->read_entity_body($buf, (defined($size) ? $size : 4096)); + if (!defined($n)) { + tlwarn("TLDownload::get_file: Cannot read file from server: $!\n"); + return 0; + } + last unless $n; + dddebug("- http read got $n bytes\n"); + $bytes_read += $n; + $buffer .= $buf; + } + if (defined($size) && ($bytes_read != $size)) { + tlwarn("TLDownload::get_file: didn't get $size bytes, expect breakage\n"); + } + if (!open (OUT, ">$out")) { + tlwarn("TLDownload::get_file: cannot open $out for writing: $!\n"); + return 0; + } + binmode(OUT); + print OUT $buffer; + if (!close(OUT)) { + tlwarn("TLDownload::get_file: strange, cannot close file handle ...\n"); + } + return 1; + } + # + # we are still here, strange + # + tlwarn("TLDownload::get_file: still around, strange, mode = " . $self->mode . "\n"); + return 0; +} + + + +sub mode +{ + my $self = shift; + if (@_) { $self->{'mode'} = shift } + return $self->{'mode'}; +} +sub server +{ + my $self = shift; + if (@_) { $self->{'server'} = shift } + return $self->{'server'}; +} + +1; +__END__ + + +=head1 NAME + +C<TeXLive::TLDownload> -- TeX Live Download abstraction module + +=head1 SYNOPSIS + + use TeXLive::TLDownload; + + $TeXLive::TLDownload::net_lib_avail + my $dl = TeXLive::TLDownload->new(server => "www.foo.com", mode => "http"); + my $dl = TeXLive::TLDownload->new(server => "www.foo.com", mode => "ftp"); + my $dl = TeXLive::TLDownload->new(server => "http://www.foo.com", mode => "wget"); + $dl->start_connection; + $dl->get_file($relpath, $output [, $expected_size ]); + +=head1 DESCRIPTION + +The C<TeXLive::TLDownload> module handles TeX Live Download abstractions +to make it possible to use persistent network connections instead of +calling wget for each single file. It depends on the modules Net::HTTP +and Net::FTP, and will check for these at loading time. If they are +not present only "wget" mode will be available. + +=head1 SEE ALSO + + +=head1 AUTHORS AND COPYRIGHT + +This script and its documentation were written for the TeX Live +distribution (L<http://tug.org/texlive>) and both are licensed under the +GNU General Public License Version 2 or later. + +=cut + +### Local Variables: +### perl-indent-level: 2 +### tab-width: 2 +### indent-tabs-mode: nil +### End: +# vim:set tabstop=2 expandtab: # diff --git a/Master/tlpkg/dev/install-tl-using-TLDownload b/Master/tlpkg/dev/install-tl-using-TLDownload new file mode 100755 index 00000000000..1731680dab8 --- /dev/null +++ b/Master/tlpkg/dev/install-tl-using-TLDownload @@ -0,0 +1,1994 @@ +#!/usr/bin/env perl +# $Id: install-tl 15740 2009-10-10 15:30:56Z karl $ +# +# Copyright 2007, 2008, 2009 Reinhard Kotucha, Norbert Preining +# This file is licensed under the GNU General Public License version 2 +# or any later version. +# +# Be careful when changing wording: Every normal informational message +# output here must be recognized by the long grep in tl-update-tlnet. +# +# TODO: +# - with -gui pop up a transient window showing: +# testing for compressed archive packages ... +# testing for uncompressed live system ... +# testing for network access ... +# loading tlpdb, this can take some time ... +# (that, and maybe some others can be done with the waitVariableX +# thingy as described in the Perl/Tk book in the chapter that can be +# found on the net) (Werner 28.10.08) +# - at the end of the installation after the welcome message if there +# was an error during installation (grep for Error in the logfile) +# then give a warning. (email hh tlbuild 2009-06-03) + +my $svnrev = '$Revision: 15740 $'; +$svnrev =~ m/: ([0-9]+) /; +$::installerrevision = $1; + +# taken from 00texlive.config: release, $tlpdb->config_release; +our $texlive_release; + +BEGIN { + $^W = 1; + my $Master; + my $me = $0; + $me =~ s!\\!/!g if $^O =~ /^MSWin(32|64)$/i; + if ($me =~ m!/!) { + ($Master = $me) =~ s!(.*)/[^/]*$!$1!; + } else { + $Master = "."; + } + $::installerdir = $Master; + + # All platforms: add the installer modules + unshift (@INC, "$::installerdir/tlpkg"); +} + +use Cwd 'abs_path'; +use Getopt::Long qw(:config no_autoabbrev); +use Pod::Usage; + +use TeXLive::TLUtils qw(platform platform_desc + which getenv win32 unix info log debug tlwarn ddebug tldie + get_system_tmpdir member process_logging_options rmtree + mkdirhier make_var_skeleton make_local_skeleton install_package copy + install_packages dirname setup_programs welcome welcome_paths); +#use TeXLive::TLMedia; +use TeXLive::TLPOBJ; +use TeXLive::TLPDB; +use TeXLive::TLConfig; +use TeXLive::TLDownload; + +if (win32) { + require TeXLive::TLWinGoo; + TeXLive::TLWinGoo->import( qw( + &win_version + &is_vista + &admin + &non_admin + ®_country + &expand_string + &global_tmpdir + &get_system_path + &get_user_path + &setenv_reg + &unsetenv_reg + &adjust_reg_path_for_texlive + ®ister_extension + &unregister_extension + ®ister_file_type + &unregister_file_type + &broadcast_env + &update_assocs + &add_desktop_shortcut + &add_menu_shortcut + &remove_desktop_shortcut + &remove_menu_shortcut + &create_uninstaller + )); +} + +use strict; + +# debugging/logging cmd lines options: +# -q shut up terminal output but warning messages +# -v do a bit of debugging to stdout and logfile +# repeated use increases the value of verbosity +# +@::LOGLINES = (); +# +# $install{$packagename} == 1 if it should be installed +my %install; + +# +# the different modules have to assign a code blob to this global variable +# which starts the installation. +# Example: In install-menu-text.pl there is +# $::run_menu = \&run_menu_text; +# +$::run_menu = sub { die "no UI defined." ; }; + +# the default scheme to be installed +my $default_scheme='scheme-full'; + +# some arrays where the lists of collections to be installed are saved +# our for menus +our @collections_std; +our @collections_lang; +our @collections_lang_doc; +# The global variable %vars is an associative list which contains all +# variables and their values which can be changed by the user. +# needs to be our since TeXLive::TLUtils uses it +# +# The following values are taken from the remote tlpdb using the +# $tlpdb->option_XXXXX +# settings (i.e., taken from tlpkg/tlpsrc/00texlive.installation.tlpsrc +# +# 'option_path' => 0, +# 'option_sys_bin' => '/usr/local/bin', +# 'option_sys_man' => '/usr/local/man', +# 'option_sys_info' => '/usr/local/info', +# 'option_doc' => 1, +# 'option_src' => 1, +# 'option_fmt' => 0, +# 'option_letter' => 0, +our %vars=( # 'n_' means 'number of'. + 'this_platform' => '', + 'n_systems_available' => 0, + 'n_systems_selected' => 0, + 'n_collections_selected' => 0, + 'n_collections_available' => 0, + 'total_size' => 0, + 'src_splitting_supported' => 1, + 'doc_splitting_supported' => 1, + 'selected_scheme' => $default_scheme, + 'from_dvd' => 0, + ); + +# option handling +my $opt_from_dvd = 0; +my $opt_gui = (win32() ? "wizard" : "text"); +my $opt_help = 0; +my $opt_location = ""; +my $opt_no_gui = 0; +my $opt_nonadmin = 0; +my $opt_portable = 0; +my $opt_print_arch = 0; +my $opt_profileseed = ""; +my $opt_profile = ""; +my $opt_scheme = ""; +my $opt_custom_bin; +my $opt_version = 0; +my $opt_force_arch; + +# show all options even those not relevant for that arch +$::opt_all_options = 0; + +# default language for GUI installer +$::lang = "en"; + +# use the fancy directory selector for TEXDIR +$::alternative_selector = 0; + +# do not debug translations by default +$::debug_translation = 0; + +# +# some strings to describe the different meanings of option_file_assoc +$::fileassocdesc[0] = "None"; +$::fileassocdesc[1] = "Only new"; +$::fileassocdesc[2] = "All"; + +# if we find a file installation.profile we ask the user whether we should +# continue with the installation +# note, we are in the installer directory. +if (-r "installation.profile") { + print "ABORTED INSTALLATION FOUND: installation.profile\n"; + print "Do you want to continue with the exact same settings as before (y/N): "; + my $answer = <STDIN>; + if ($answer =~ m/^y(es)?$/i) { + $opt_profile = "installation.profile"; + } +} + + +# first process verbosity/quiet options +process_logging_options(); +# now the others +GetOptions( + "custom-bin=s" => \$opt_custom_bin, + "fancyselector" => \$::alternative_selector, + "from_dvd" => \$opt_from_dvd, + "gui:s" => \$opt_gui, + "lang=s" => \$::opt_lang, + "location|url|repository|repo=s" => \$opt_location, + "no-cls", # $::opt_no_cls in install-menu-text-pl + "no-gui" => \$opt_no_gui, + "non-admin" => \$opt_nonadmin, + "portable" => \$opt_portable, + "print-arch" => \$opt_print_arch, + "force-arch=s" => \$opt_force_arch, + "debug-translation" => \$::debug_translation, + "profile-seed=s" => \$opt_profileseed, + "profile=s" => \$opt_profile, + "scheme=s" => \$opt_scheme, + "all-options" => \$::opt_all_options, + "version" => \$opt_version, + "help|?" => \$opt_help) or pod2usage(1); + +if ($opt_gui eq "") { + # the --gui option was given with an empty argument, set it to perltk + $opt_gui = "perltk"; +} +if ($opt_gui eq "expert") { + $opt_gui = "perltk"; +} + +if (win32()) { + pod2usage(-exitstatus => 0, + -verbose => 2, + -noperldoc => 1, + -output => \*STDOUT) if $opt_help; +} else { + pod2usage(-exitstatus => 0, -verbose => 2, -file => $0) if $opt_help; +} + +if ($opt_version) { + print "install-tl (TeX Live Cross Platform Installer)", + " revision $::installerrevision\n"; + if (open (REL_TL, "$::installerdir/release-texlive.txt")) { + # print first and last lines, which have the TL version info. + my @rel_tl = <REL_TL>; + print $rel_tl[0]; + print $rel_tl[$#rel_tl]; + close (REL_TL); + } + if ($::opt_verbosity > 0) { + print "Revision of modules:"; + print "\nTLConfig: " . TeXLive::TLConfig->module_revision(); + print "\nTLUtils: " . TeXLive::TLUtils->module_revision(); + print "\nTLPOBJ: " . TeXLive::TLPOBJ->module_revision(); + print "\nTLPDB: " . TeXLive::TLPDB->module_revision(); + print "\nTLWinGoo: " . TeXLive::TLWinGoo->module_revision() if win32(); + print "\n"; + } + exit 0; +} + +if ($#ARGV >= 0) { + # we still have arguments left, should only be gui, otherwise die + if ($ARGV[0] =~ m/^gui$/i) { + $opt_gui = "perltk"; + } else { + die "$0: Extra arguments `@ARGV'; try --help if you need it.\n"; + } +} + + +if (defined($::opt_lang)) { + $::lang = $::opt_lang; +} + +if ($opt_profile) { + if (-r $opt_profile) { + info("Automated TeX Live installation using profile: $opt_profile\n"); + } else { + $opt_profile = ""; + info("Profile $opt_profile not readable, continuing in interactive mode.\n"); + } +} + +if ($opt_nonadmin and win32()) { + non_admin(); +} + + +# the TLPDB instances we will use. $tlpdb is for the one from the installation +# media, while $localtlpdb is for the new installation +# $tlpdb must be our because it is used in install-menu-text.pl +our $tlpdb; +my $localtlpdb; +my $location; + +# $finished == 1 if the menu call already did the installation +my $finished = 0; +@::info_hook = (); + +my $system_tmpdir=get_system_tmpdir(); +my $media; + +# special uses of install-tl: +if ($opt_print_arch) { + print platform()."\n"; + exit 0; +} elsif ($opt_portable) { + &do_portable (); +} + + +# continuing with normal install + +# check as soon as possible for GUI functionality to give people a chance +# tp interrupt. +if (($opt_gui ne "text") && !$opt_no_gui && ($opt_profile eq "")) { + # try to load Tk.pm, but don't die if it doesn't work + eval { require Tk; }; + if ($@) { + # that didn't work out, so warn the user and continue with text mode + tlwarn("Cannot load Tk, maybe something is missing and\n"); + tlwarn("maybe http://tug.org/texlive/distro.html#perltk can help.\n"); + tlwarn("Error message from loading Tk:\n"); + tlwarn(" $@\n"); + tlwarn("Continuing in text mode...\n"); + $opt_gui = "text"; + } + eval { my $foo = Tk::MainWindow->new; $foo->destroy; }; + if ($@) { + tlwarn("perl/Tk unusable, cannot create main windows.\n"); + if (platform() eq "universal-darwin") { + tlwarn("That could be because X11 is not installed or started.\n"); + } + tlwarn("Error message from creating MainWindow:\n"); + tlwarn(" $@\n"); + tlwarn("Continuing in text mode...\n"); + $opt_gui = "text"; + } + if ($opt_gui eq "text") { + # we switched from GUI to non-GUI mode, tell the user and wait a bit + tlwarn("\nSwitching to text mode installer, if you want to cancel, do it now.\n"); + tlwarn("Waiting for 3 second\n"); + sleep(3); + } +} + +# +if (defined($opt_force_arch)) { + tlwarn("Overriding platform to $opt_force_arch\n"); + $::_platform_ = $opt_force_arch; +} + +# initialize the correct platform +platform(); +$vars{'this_platform'} = $::_platform_; + +# we do not support cygwin < 1.7, so check for that +if (!$opt_custom_bin && (platform() eq "i386-cygwin")) { + chomp( my $un = `uname -r`); + if ($un =~ m/^(\d+)\.(\d+)\./) { + if ($1 < 2 && $2 < 7) { + tldie("\nSorry, the TL binaries require at least cygwin 1.7.\n"); + } + } +} + +if (!setup_programs ("$::installerdir/tlpkg/installer", "$::_platform_")) { + tldie("$0: Goodbye.\n"); +} + +# determine where we will find the distribution to install from. +# +$location = $opt_location; +$location || ($location = "$::installerdir"); +if ($location =~ m!^(ctan$|(http|ftp)://)!i) { + $location =~ s,/(tlpkg|archive)?/*$,,; # remove any trailing tlpkg or / + if ($location =~ m/^ctan$/i) { + $location = TeXLive::TLUtils::give_ctan_mirror(); + } elsif ($location =~ m/^$TeXLiveServerURL/) { + my $mirrorbase = TeXLive::TLUtils::give_ctan_mirror_base(); + $location =~ s,^($TeXLiveServerURL|ctan$),$mirrorbase,; + } + $TeXLiveURL = $location; + $media = 'NET'; +} else { + # remove leading file:/+ part + $location =~ s!^file://*!/!i; + $location = abs_path($location); + # remove trailing \ or / (e.g. root of dvd drive on w32) + $location =~ s,[\\\/]$,,; + if (-d "$location/$Archive") { + $media='CD'; + } elsif (-d "$location/texmf/web2c") { + $media='DVD'; + } else { + if ($opt_location) { + # user gave a --location but nothing can be found there, so die + die "$0: cannot find installation source at $opt_location.\n"; + } + # no --location given, but NET installation + $TeXLiveURL = $location = TeXLive::TLUtils::give_ctan_mirror(); + $media = 'NET'; + } +} +info("Installing TeX Live $TeXLive::TLConfig::ReleaseYear from: $location\n"); + +info("Platform: ", platform(), " => \'", platform_desc(platform), "\'\n"); +if ($opt_custom_bin) { + if (-d $opt_custom_bin) { + info("Platform overridden, binaries taken from $opt_custom_bin\nand put into bin/custom!\n"); + } else { + tldie("Argument for -custom-bin needs to be directory with TeX Live binaries!\n"); + } +} +if ($media eq "DVD") { + info("Distribution: live (uncompressed)\n"); +} elsif ($media eq "CD") { + info("Distribution: inst (compressed)\n"); +} elsif ($media eq "NET") { + info("Distribution: net (downloading)\n"); + info("Using URL: $TeXLiveURL\n"); + my ($prot, $server, $subpath) = ($TeXLiveURL =~ m!(http|ftp)://([^/]*)(/.*)$!i); + if ($TeXLive::TLDownload::net_lib_avail) { + info("Trying to setup permanent connection to server using Net::$prot...\n"); + $::current_server = TeXLive::TLDownload->new(mode => $prot, + server => $server); + if ($::current_server->start_connection) { + info("... success\n"); + } else { + $::current_server = undef; + info("connection setup not successful, falling back to wget mode.\n"); + } + } +} else { + info("Distribution: $media\n"); +} +info("Directory for temporary files: $system_tmpdir\n"); + +if ($opt_from_dvd and ($media ne "DVD")) { + print "Not running from DVD; 'from_dvd' option not applicable\n"; + $opt_from_dvd = 0; +} +$vars{'from_dvd'} = $opt_from_dvd; + +load_tlpdb(); + +log("Installer revision: $::installerrevision\n"); +log("Database revision: " . $tlpdb->config_revision . "\n"); + +# correctly set the splitting support +# for DVD we always support splitting +if (($media eq "NET") || ($media eq "CD")) { + $vars{'src_splitting_supported'} = $tlpdb->config_src_container; + $vars{'doc_splitting_supported'} = $tlpdb->config_doc_container; +} +$texlive_release = $tlpdb->config_release; +# if the release from the remote TLPDB does not agree with the +# TLConfig::ReleaseYear in the first 4 places break out here. +# Why only the first four places: some optional network distributions +# might use +# release/2009-foobar +if ($media eq "NET" && + $texlive_release !~ m/^$TeXLive::TLConfig::ReleaseYear/) { + die "The release version of the installation source and\nthe installation media do not agree:\nsource: $texlive_release\nmedia: $TeXLive::TLConfig::ReleaseYear\nPlease report to tex-live\@tug.org"; +} +set_platforms_supported(); +set_texlive_default_dirs(); +set_install_platform(); +initialize_collections(); + +# initialize the scheme from the command line value, if given. +if ($opt_scheme) { + # add the scheme- prefix if they didn't give it. + $opt_scheme = "scheme-$opt_scheme" if $opt_scheme !~ /^scheme-/; + my $scheme = $tlpdb->get_package($opt_scheme); + if (defined($scheme)) { + select_scheme($opt_scheme); # select it + } else { + tlwarn("Scheme $opt_scheme not defined, ignoring it.\n"); + } +} + + +if ($opt_profile eq "") { + if ($opt_profileseed) { + read_profile("$opt_profileseed"); + } + # do the normal interactive installation. + # + # here we could load different menu systems. Currently several things + # are "our" so that the menu implementation can use it. The $tlpdb, the + # %var, and all the @collection* + # install-menu-*.pl have to assign a code ref to $::run_menu which is + # run, and should change ONLY stuff in %vars + # The allowed keys in %vars should be specified somewhere ... + # the menu implementation should return + # MENU_INSTALL do the installation + # MENU_ABORT abort every action immediately, no cleanup + # MENU_QUIT try to quit and clean up mess + our $MENU_INSTALL = 0; + our $MENU_ABORT = 1; + our $MENU_QUIT = 2; + our $MENU_ALREADYDONE = 3; + $opt_gui = "text" if ($opt_no_gui); + # finally do check for additional screens in the $opt_gui setting: + # format: + # --gui <plugin>:<a1>,<a2>,... + # which will passed to run_menu (<a1>, <a2>, ...) + # + my @runargs; + if ($opt_gui =~ m/^([^:]*):(.*)$/) { + $opt_gui = $1; + @runargs = split ",", $2; + } + if (-r "$::installerdir/tlpkg/installer/install-menu-${opt_gui}.pl") { + require("installer/install-menu-${opt_gui}.pl"); + } else { + tlwarn("UI plugin $opt_gui not found,\n"); + tlwarn("Using text mode installer.\n"); + require("installer/install-menu-text.pl"); + } + + # before we start the installation we check for the existence of + # a previous installation, and in case we ship inform the UI + { + my $tlmgrwhich = which("tlmgr"); + if ($tlmgrwhich) { + my $dn = dirname($tlmgrwhich); + $dn = abs_path("$dn/../.."); + # The "make Karl happy" case, check that we are not running install-tl + # from the same tree where tlmgr is hanging around + my $install_tl_root = abs_path($::installerdir); + my $tlpdboldpath = "$dn/$TeXLive::TLConfig::InfraLocation/$TeXLive::TLConfig::DatabaseName"; + if (-r $tlpdboldpath && $dn ne $install_tl_root) { + debug ("found old installation in $dn\n"); + push @runargs, "-old-installation-found=$dn"; + } + } + } + + my $ret = &{$::run_menu}(@runargs); + if ($ret == $MENU_QUIT) { + do_cleanup(); + flushlog(); + exit(1); + } + if ($ret == $MENU_ABORT) { + # omit do_cleanup(). + flushlog(); + exit(2); + } + if ($ret == $MENU_ALREADYDONE) { + debug("run_menu has already done the work ... cleaning up.\n"); + $finished = 1; + } + if (!$finished && ($ret != $MENU_INSTALL)) { + tlwarn("Unknown return value of run_menu: $ret\n"); + exit(3); + } +} else { + read_profile($opt_profile); +} + +if (!$finished) { + # do the actual installation + # win32: first, remove trailing slash from texdir[w] + # in case it is the root of a drive + $vars{'TEXDIR'} =~ s![/\\]$!!; + $vars{'TEXDIRW'} =~ s![/\\]$!!; + info("Installing to: $vars{TEXDIRW}\n"); + do_installation(); +} + +do_cleanup(); + +exit(0); + + +################################################################### +# +# FROM HERE ON ONLY SUBROUTINES +# NO VARIABLE DECLARATIONS +# +################################################################### + +sub do_installation { + if (win32()) { + non_admin() if !$vars{'option_w32_multi_user'}; + } + if ($vars{'n_collections_selected'} <= 0) { + tlwarn("Nothing selected, nothing to install, exiting!\n"); + exit 1; + } + # do the actual installation + my $h; + prepare_installation(); + if (!$vars{'from_dvd'}) { + calc_depends(); + save_options_into_tlpdb(); + do_install_packages(); + if ($opt_custom_bin) { + $vars{'this_platform'} = "custom"; + my $TEXDIR="$vars{'TEXDIR'}"; + mkdirhier("$TEXDIR/bin/custom"); + for my $f (<$opt_custom_bin/*>) { + copy($f, "$TEXDIR/bin/custom"); + } + } + } + # now we save every scheme that is fully covered by the stuff we have + # installed to the $localtlpdb + foreach my $s ($tlpdb->schemes) { + my $stlp = $tlpdb->get_package($s); + die ("That cannot happen, $s not defined in tlpdb") unless defined($stlp); + my $incit = 1; + foreach my $d ($stlp->depends) { + if (!defined($localtlpdb->get_package($d))) { + $incit = 0; + last; + } + } + if ($incit) { + $localtlpdb->add_tlpobj($stlp); + } + } + $localtlpdb->save unless $vars{'from_dvd'}; + do_postinst_stuff(); + if (win32()) { + print welcome(); + } else { + print welcome_paths(); + } +} + +# do_postinst_stuff has to fix up the texmf tree and install some missing +# files. The things to do are taken from the install-live.sh installer +# of former times, and should be critically checked. +sub do_postinst_stuff { + my $TEXDIR="$vars{'TEXDIR'}"; + my $TEXDIRW="$vars{'TEXDIRW'}"; + my $TEXMFSYSVAR="$vars{'TEXMFSYSVAR'}"; + my $TEXMFSYSCONFIG="$vars{'TEXMFSYSCONFIG'}"; + my $TEXMFLOCAL="$vars{'TEXMFLOCAL'}"; + my $tmv; + + do_texmf_cnf() unless ($opt_portable); + + # + # clean up useless files in texmf-dist/tlpkg as this is only + # created by the relocatable packages + if (-d "$TEXDIR/$TeXLive::TLConfig::RelocTree/tlpkg") { + rmtree("$TEXDIR/TeXLive::TLConfig::RelocTree/tlpkg"); + } + + # final program execution + # we have to do several things: + # - clean the environment from spurious TEXMF related variables + # - add the bin dir to the PATH + # - select perl interpreter and set the correct perllib + # - run the programs + + # Step 1: Clean the environment + my @TMFVARS0=qw(VARTEXFONTS + TEXMF SYSTEXMF VARTEXFONTS + TEXMFDBS WEB2C TEXINPUTS TEXFORMATS MFBASES MPMEMS TEXPOOL MFPOOL MPPOOL + PSHEADERS TEXFONTMAPS TEXPSHEADERS TEXCONFIG TEXMFCNF); + my @TMFVARS1=qw(TEXMFMAIN TEXMFDIST TEXMFLOCAL TEXMFSYSVAR TEXMFSYSCONFIG + TEXMFHOME TEXMFVAR TEXMFCONFIG); + + if (defined($ENV{'TEXMFCNF'}) and !$vars{'from_dvd'} and !$opt_portable) { + print "WARNING: environment variable TEXMFCNF is set. +You should know what you are doing. +We will remove that for the post install actions, but all further +operations might be disturbed.\n\n"; + } + foreach $tmv (@TMFVARS0) { + delete $ENV{$tmv} if (defined($ENV{$tmv})); + } + if (!$opt_portable) { + foreach $tmv (@TMFVARS1) { + delete $ENV{$tmv} if (defined($ENV{$tmv})); + } + } + if ($vars{'from_dvd'}) { + $ENV{'TEXMFSYSVAR'} = $vars{'TEXMFSYSVAR'}; + $ENV{'TEXMFCNF'} = $vars{'TEXMFSYSVAR'}."/web2c"; + } + + # Step 2: Setup the PATH, switch to the new Perl + + my $pathsep=(win32)? ';' : ':'; + my $plat_bindir="$TEXDIR/bin/$vars{'this_platform'}"; + my $perl_bindir="$TEXDIR/tlpkg/tlperl/bin"; + my $perl_libdir="$TEXDIR/tlpkg/tlperl/lib"; + +## This won't do any good; +## have to remove other tex directories in calling batchfile +# if (win32) { +# debug("Removing other TeXs from path\n"); +# my @newpt = (); +# foreach my $d (split (';', $ENV{'PATH'})) { +# push @newpt, $d unless TeXLive::TLWinGoo::is_a_texdir($d); +# } +# $ENV{'PATH'} = join($pathsep, @newpt); +# debug("Path after removals(s):\n $ENV{'PATH'}\n"); +# } + + debug("Prepending $plat_bindir to PATH\n"); + + $ENV{'PATH'}="$plat_bindir" . "$pathsep" . "$ENV{'PATH'}"; + + if (win32) { + debug("Prepending $perl_bindir to PATH\n"); + $ENV{'PATH'}="$perl_bindir" . "$pathsep" . "$ENV{'PATH'}"; + $ENV{'PATH'} =~ s!/!\\!g; + } + + debug("\nNew PATH is now:\n"); + foreach my $dir (split $pathsep, $ENV{'PATH'}) { + debug(" $dir\n"); + } + debug("\n"); + + if (win32) { + $ENV{'PERL5LIB'}="$perl_libdir"; + } + + # + # post install actions + # + + # in case we are running from DVD we use the tlpdb from the DVD, otherwise + # the one we have locally created, for all the further actions + my $usedtlpdb = $vars{'from_dvd'} ? $tlpdb : $localtlpdb; + + + if (win32()) { + debug "Actual environment:\n".`set`."\n\n"; + debug 'Effective TEXMFCNF: '.`kpsewhich -expand-path=\$TEXMFCNF`."\n"; + } + + # TODO: can the following two clauses be merged? + if (win32()) { + create_uninstaller($vars{'TEXDIR'}, $vars{'TEXDIRW'}, + $vars{'TEXMFSYSVAR'}, $vars{'TEXMFSYSCONFIG'}); + } + # (re-)initialize batchfile for uninstalling shortcuts + if (win32() and !$opt_portable) { + mkdirhier("$TEXDIRW/tlpkg/installer") if $vars{'from_dvd'}; + } + + # Step 4: run the programs + + if (!$opt_portable and !$vars{'from_dvd'}) { + info("running mktexlsr $TEXDIR/texmf-dist $TEXDIR/texmf\n"); + system('mktexlsr', "$TEXDIR/texmf-dist", "$TEXDIR/texmf"); + } + + # we have to generate the various config file. That could be done with + # texconfig generate * but Win32 does not have texconfig. But we have + # $localtlpdb and this is simple code, so do it directly, i.e., duplicate + # the code from the various generate-*.pl scripts + + info("writing fmtutil.cnf data to $TEXMFSYSVAR/web2c/fmtutil.cnf\n"); + TeXLive::TLUtils::create_fmtutil($usedtlpdb, + "$TEXMFSYSVAR/web2c/fmtutil.cnf", + "$TEXMFLOCAL/web2c/fmtutil-local.cnf"); + + mkdirhier "$vars{'TEXMFSYSCONFIG'}/web2c"; + info("writing updmap.cfg to $TEXMFSYSCONFIG/web2c/updmap.cfg\n"); + TeXLive::TLUtils::create_updmap ($usedtlpdb, + "$TEXMFSYSCONFIG/web2c/updmap.cfg", + "$TEXMFLOCAL/web2c/updmap-local.cfg"); + + info("writing language.dat data to $TEXMFSYSVAR/tex/generic/config/language.dat\n"); + TeXLive::TLUtils::create_language_dat($usedtlpdb, + "$TEXMFSYSVAR/tex/generic/config/language.dat", + "$TEXMFLOCAL/tex/generic/config/language-local.dat"); + + info("writing language.def data to $TEXMFSYSVAR/tex/generic/config/language.def\n"); + TeXLive::TLUtils::create_language_def($usedtlpdb, + "$TEXMFSYSVAR/tex/generic/config/language.def", + "$TEXMFLOCAL/tex/generic/config/language-local.def"); + + info("running mktexlsr $TEXMFSYSVAR\n"); + system('mktexlsr', "$TEXMFSYSVAR"); + + info("running updmap-sys... "); + # system('updmap-sys', '--nohash'); + log(`updmap-sys --nohash 2>&1`); + info("done\n"); + + info("re-running mktexlsr $TEXMFSYSVAR\n"); + system('mktexlsr', "$TEXMFSYSVAR"); + + # now work through the options if specified at all + + # letter instead of a4 + if ($vars{'option_letter'}) { + info("Setting default paper size to letter\n"); + system("tlmgr", "paper", "letter"); + } + + # all formats option + if ($vars{'option_fmt'}) { + info("pre-generating all format files (fmtutil-sys --all), be patient..."); + log(`fmtutil-sys --all 2>&1`); + info("done\n"); + } + + # + # do path adjustments: On Windows add/remove to PATH etc, on Unix + # set symlinks + do_path_adjustments() if $vars{'option_path'}; + + # no do the system integration: + # on unix this means setting up symlinks + # on w32 this means adding to path, settting registry values + # on both, we run the postaction directives of the tlp + do_tlpdb_postactions(); +} + + +sub do_tlpdb_postactions { + info ("running package specific postactions\n"); + # Run the post installation code in the postaction tlpsrc entries + my $usedtlpdb = $vars{'from_dvd'} ? $tlpdb : $localtlpdb; + foreach my $package (sort keys %install) { + if ($install{$package}) { + &TeXLive::TLUtils::do_postaction("install", + $usedtlpdb->get_package($package), + $vars{'option_file_assocs'}, + $vars{'option_desktop_integration'}, + $vars{'option_post_code'}); + } + } + info ("finished with package specific postactions\n"); +} + +sub do_path_adjustments { + info ("running path adjustment actions\n"); + if (win32()) { + TeXLive::TLUtils::w32_add_to_path($vars{'TEXDIR'}.'/bin/win32', + $vars{'option_w32_multi_user'}); + # + # from_dvd stuff + # setenv_reg('TEXMFSYSVAR', $vars{'TEXMFSYSVAR'}) if $vars{'from_dvd'}; + setenv_reg('TEXMFCNF', $vars{'TEXMFSYSVAR'}.'/web2c') if $vars{'from_dvd'}; + broadcast_env(); + } else { + TeXLive::TLUtils::add_symlinks($vars{'TEXDIR'}, $vars{'this_platform'}, + $vars{'option_sys_bin'}, $vars{'option_sys_man'}, + $vars{'option_sys_info'}); + } + info ("finished with path adjustment actions\n"); +} + + +# we have to adjust the texmf.cnf file to the paths set in the configuration! +sub do_texmf_cnf { + open(TMF,"<$vars{'TEXDIR'}/texmf/web2c/texmf.cnf") + or die "$vars{'TEXDIR'}/texmf/web2c/texmf.cnf not found: $!"; + my @texmfcnflines = <TMF>; + close(TMF); + my @newtmf; + my @changedtmf; + # we have to find TEXMFLOCAL TEXMFSYSVAR and TEXMFHOME + foreach my $line (@texmfcnflines) { + if ($line =~ m/^TEXMFLOCAL/) { + # by default TEXMFLOCAL = TEXDIR/../texmf-local, if this is the case + # we don't have to change anything from the default + my $deftmlocal = dirname($vars{'TEXDIR'}); + $deftmlocal .= "/texmf-local"; + if ("$vars{'TEXMFLOCAL'}" eq "$deftmlocal") { + push @newtmf, $line; + } else { + push @newtmf, "TEXMFLOCAL = $vars{'TEXMFLOCAL'}\n"; + push @changedtmf, "TEXMFLOCAL = $vars{'TEXMFLOCAL'}\n"; + } + } elsif ($line =~ m/^TEXMFSYSVAR/) { + # by default TEXMFSYSVAR = TEXDIR/texmf-var, if this is the case + # we don't have to change anything from the default + if ("$vars{'TEXMFSYSVAR'}" eq "$vars{'TEXDIR'}/texmf-var") { + push @newtmf, $line; + } else { + push @newtmf, "TEXMFSYSVAR = $vars{'TEXMFSYSVAR'}\n"; + push @changedtmf, "TEXMFSYSVAR = $vars{'TEXMFSYSVAR'}\n"; + } + } elsif ($line =~ m/^TEXMFSYSCONFIG/) { + # by default TEXMFSYSCONFIG = TEXDIR/texmf-config, if this is the case + # we don't have to change anything from the default + if ("$vars{'TEXMFSYSCONFIG'}" eq "$vars{'TEXDIR'}/texmf-config") { + push @newtmf, $line; + } else { + push @newtmf, "TEXMFSYSCONFIG = $vars{'TEXMFSYSCONFIG'}\n"; + push @changedtmf, "TEXMFSYSCONFIG = $vars{'TEXMFSYSCONFIG'}\n"; + } + } elsif ($line =~ m/^TEXMFHOME/) { + # kpse now expands ~ to USERPROFILE, so we don't treat win32 and + # unix differently + push @newtmf, "TEXMFHOME = $vars{'TEXMFHOME'}\n"; + if ("$vars{'TEXMFHOME'}" ne "~/texmf") { + push @changedtmf, "TEXMFHOME = $vars{'TEXMFHOME'}\n"; + } + } elsif ($line =~ m/^OSFONTDIR/) { + if (win32()) { + push @newtmf, "OSFONTDIR = \$SystemRoot/fonts//\n"; + push @changedtmf, "OSFONTDIR = \$SystemRoot/fonts//\n"; + } else { + push @newtmf, $line; + } + } else { + push @newtmf, $line; + } + } + my $TMF; + if (!$vars{'from_dvd'}) { + $TMF = ">$vars{'TEXDIR'}/texmf.cnf"; + open(TMF, $TMF) || die "open($TMF) failed: $!"; + print TMF <<EOF; +% This texmf.cnf file should contain only your personal changes from the +% main texmf.cnf. +% +% Do NOT change values in the main file (which is in +% .../texlive/YYYY/texmf/web2c/texmf.cnf), as YOUR CHANGES WILL BE LOST +% by later updates. +% +% If you need to make changes to texmf.cnf, put your custom settings in +% this file instead, which is YYYY/texmf.cnf. And insert *only* your +% changed values. +% +EOF +; + foreach (@changedtmf) { print TMF; } + # + # save the setting of shell_escape to the generated system texmf.cnf + # default in texmf/web2c/texmf.cnf is + # shell_escape = p + # so we write that only if the user *deselected* this option + if (!$vars{"option_write18_restricted"}) { + print TMF <<EOF; +% Disable system commands via \\write18{...}. Please see +% texmf/web2c/texmf.cnf +% for more details. +shell_escape = 0 +EOF +; + } + } else { + $TMF = ">$vars{'TEXMFSYSVAR'}/web2c/texmf.cnf"; + open (TMF, $TMF) || die "open($TMF) failed: $!\n"; + foreach (@newtmf) { print TMF; } + } + close(TMF) || warn "close($TMF) failed: $!"; +} + + +sub dump_vars { + my $filename=shift; + my $fh; + if (ref($filename)) { + $fh = $filename; + } else { + open VARS, ">$filename"; + $fh = \*VARS; + } + foreach my $key (keys %vars) { + print $fh "$key $vars{$key}\n"; + } + close VARS if (!ref($filename)); + debug("\n%vars dumped to '$filename'.\n"); +} + + +# Determine which platforms are supported. +sub set_platforms_supported { + my @binaries = $tlpdb->available_architectures; + for my $binary (@binaries) { + unless (defined $vars{"binary_$binary"}) { + $vars{"binary_$binary"}=0; + } + } + for my $key (keys %vars) { + ++$vars{'n_systems_available'} if ($key=~/^binary/); + } +} + +# Environment variables and default values on UNIX: +# TEXLIVE_INSTALL_PREFIX /usr/local/texlive => $tex_prefix +# TEXLIVE_INSTALL_TEXDIR $tex_prefix/2007 => $TEXDIR +# TEXLIVE_INSTALL_TEXMFSYSVAR $TEXDIR/texmf-var +# TEXLIVE_INSTALL_TEXMFSYSCONFIG $TEXDIR/texmf-config +# TEXLIVE_INSTALL_TEXMFLOCAL $tex_prefix/texmf-local +# TEXLIVE_INSTALL_TEXMFHOME '$HOME/texmf' + +sub set_texlive_default_dirs { + my $tex_prefix; + my $texmfsysvar; + my $texmfsysconfig; + my $texmflocal; + my $texmfhome; + + $tex_prefix=getenv('TEXLIVE_INSTALL_PREFIX'); + if (win32) { + $tex_prefix ||= getenv('SystemDrive') . '/texlive'; + # we use SystemDrive because ProgramFiles requires admin rights + # we don't use USERPROFILE here because that will be copied back and + # forth on roaming profiles + } else { + $tex_prefix||='/usr/local/texlive'; + } + $vars{'TEXDIRW'}="$tex_prefix/$texlive_release"; + + $texmfsysvar=getenv('TEXLIVE_INSTALL_TEXMFSYSVAR'); + $texmfsysvar||=$vars{'TEXDIRW'} . '/texmf-var'; + $vars{'TEXMFSYSVAR'}=$texmfsysvar; + + $texmfsysconfig=getenv('TEXLIVE_INSTALL_TEXMFSYSCONFIG'); + $texmfsysconfig||=$vars{'TEXDIRW'} . '/texmf-config'; + $vars{'TEXMFSYSCONFIG'}=$texmfsysconfig; + + $texmflocal=getenv('TEXLIVE_INSTALL_TEXMFLOCAL'); + $texmflocal||="$tex_prefix/texmf-local"; + $vars{'TEXMFLOCAL'}=$texmflocal; + + $vars{'TEXDIR'} = $vars{'from_dvd'} ? abs_path($::installerdir) : + $vars{'TEXDIRW'}; + + $texmfhome=getenv('TEXLIVE_INSTALL_TEXMFHOME'); + $texmfhome ||= "~"; + $vars{'TEXMFHOME'}="$texmfhome/texmf"; +} + +sub calc_depends { + # we have to reset the install hash EVERY TIME otherwise everything will + # always be installed since the default is scheme-full which selects + # all packages and never deselects it + %install=(); + my $p; + my $a; + + # initialize the %install hash with what should be installed + + if ($vars{'selected_scheme'} ne "scheme-custom") { + # First look for packages in the selected scheme. + my $scheme=$tlpdb->get_package($vars{'selected_scheme'}); + if (!defined($scheme)) { + if ($vars{'selected_scheme'}) { + # something is written in the selected scheme but not defined, that + # is strange, so warn and die + die ("Scheme $vars{'selected_scheme'} not defined, vars:\n"); + dump_vars(\*STDOUT); + } + } else { + for my $scheme_content ($scheme->depends) { + $install{"$scheme_content"}=1 unless ($scheme_content=~/^collection-/); + } + } + } + + # Now look for collections in the %vars hash. These are not + # necessarily the collections required by a scheme. The final + # decision is made in the collections/languages menu. + foreach my $key (keys %vars) { + if ($key=~/^collection-/) { + $install{$key} = 1 if $vars{$key}; + } + } + + # compute the list of archs to be installed + my @archs; + foreach (keys %vars) { + if (m/^binary_(.*)$/ ) { + if ($vars{$_}) { push @archs, $1; } + } + } + + # + # work through the addon settings in the %vars hash + #if ($vars{'addon_editor'}) { + # $install{"texworks"} = 1; + #} + + # if programs for arch=win32 are installed we also have to install + # tlperl.win32 which provides the "hidden" perl that will be used + # to run all the perl scripts. + # Furthermore we install tlgs.win32 and tlpsv.win32, too + if (grep(/^win32$/,@archs)) { + $install{"tlperl.win32"} = 1; + $install{"tlgs.win32"} = 1; + $install{"tlpsv.win32"} = 1; + } + + # loop over all the packages until it is getting stable + my $changed = 1; + while ($changed) { + # set $changed to 0 + $changed = 0; + + # collect the already selected packages + my @pre_selected = keys %install; + debug("initial number of installations: $#pre_selected\n"); + + # loop over all the pre_selected and add them + foreach $p (@pre_selected) { + ddebug("pre_selected $p\n"); + my $pkg = $tlpdb->get_package($p); + if (!defined($pkg)) { + tlwarn("$p is mentioned somewhere but not available, disabling it.\n"); + $install{$p} = 0; + next; + } + foreach my $p_dep ($tlpdb->get_package($p)->depends) { + if ($p_dep =~ m/^(.*)\.ARCH$/) { + my $foo = "$1"; + foreach $a (@archs) { + $install{"$foo.$a"} = 1 if defined($tlpdb->get_package("$foo.$a")); + } + } elsif ($p_dep =~ m/^(.*)\.win32$/) { + # a win32 package should *only* be installed if we are installing + # the win32 arch + if (grep(/^win32$/,@archs)) { + $install{$p_dep} = 1; + } + } else { + $install{$p_dep} = 1; + } + } + } + + # check for newly selected packages + my @post_selected = keys %install; + debug("number of post installations: $#post_selected\n"); + + # set repeat condition + if ($#pre_selected != $#post_selected) { + $changed = 1; + } + } + + # now do the size computation + my $size = 0; + foreach $p (keys %install) { + my $tlpobj = $tlpdb->get_package($p); + if (not(defined($tlpobj))) { + tlwarn("$p should be installed but " + . "is not in texlive.tlpdb; disabling.\n"); + $install{$p} = 0; + next; + } + $size+=$tlpobj->docsize if $vars{'option_doc'}; + $size+=$tlpobj->srcsize if $vars{'option_src'}; + $size+=$tlpobj->runsize; + foreach $a (@archs) { + $size += $tlpobj->binsize->{$a} if defined($tlpobj->binsize->{$a}); + } + } + $vars{'total_size'} = + sprintf "%d", ($size * $TeXLive::TLConfig::BlockSize)/1024**2; +} + +sub load_tlpdb { + my $master = $location; + info("Loading $master/$TeXLive::TLConfig::InfraLocation/$TeXLive::TLConfig::DatabaseName\n"); + $tlpdb=TeXLive::TLPDB->new(root => "$master"); + if (!defined($tlpdb)) { + die "$0: Could not load TeX Live Database from $master, goodbye.\n"; + } + # set the defaults to what is specified in the tlpdb + $vars{'option_doc'} = $tlpdb->option("install_docfiles"); + $vars{'option_src'} = $tlpdb->option("install_srcfiles"); + $vars{'option_fmt'} = $tlpdb->option("create_formats"); + $vars{'option_letter'} = defined($tlpdb->option("paper")) + && ($tlpdb->option("paper") eq "letter" ? 1 : 0); + $vars{'option_desktop_integration'} = $tlpdb->option("desktop_integration"); + $vars{'option_desktop_integration'} = 1 if win32(); + $vars{'option_path'} = $tlpdb->option("path"); + $vars{'option_path'} = 1 if win32(); + $vars{'option_w32_multi_user'} = $tlpdb->option("w32_multi_user"); + # we have to make sure that this option is set to 0 in case + # that a non-admin is running the installations program + $vars{'option_w32_multi_user'} = 0 if (win32() && !admin()); + $vars{'option_file_assocs'} = $tlpdb->option("file_assocs"); + $vars{'option_post_code'} = $tlpdb->option("post_code"); + $vars{'option_sys_bin'} = $tlpdb->option("sys_bin"); + $vars{'option_sys_man'} = $tlpdb->option("sys_man"); + $vars{'option_sys_info'} = $tlpdb->option("sys_info"); + $vars{'option_write18_restricted'} = $tlpdb->option("write18_restricted"); + + # check that the default scheme is actually present, otherwise switch to + # scheme-minimal + if (!defined($tlpdb->get_package($default_scheme))) { + if (!defined($tlpdb->get_package("scheme-minimal"))) { + die("Aborting, cannot find either $default_scheme or scheme_minimal"); + } + $default_scheme = "scheme-minimal"; + $vars{'selected_scheme'} = $default_scheme; + } +} + +sub initialize_collections { + foreach my $pkg ($tlpdb->list_packages) { + my $tlpobj = $tlpdb->{'tlps'}{$pkg}; + if ($tlpobj->category eq "Collection") { + $vars{"$pkg"}=0; + ++$vars{'n_collections_available'}; + if ($pkg=~/collection-lang/) { + push @collections_lang, $pkg; + } elsif ($pkg=~/documentation/) { + if ($pkg=~/documentation-base/) { + push @collections_std, $pkg; + } else { + push @collections_lang_doc, $pkg; + } + } else { + push @collections_std, $pkg; + } + } + } + my $scheme_tlpobj = $tlpdb->get_package($default_scheme); + if (defined ($scheme_tlpobj)) { + $vars{'n_collections_selected'}=0; + foreach my $dependent ($scheme_tlpobj->depends) { + if ($dependent=~/^(collection-.*)/) { + $vars{"$1"}=1; + ++$vars{'n_collections_selected'}; + } + } + } + if ($vars{"binary_win32"}) { + $vars{"collection-wintools"} = 1; + ++$vars{'n_collections_selected'}; + } +} + +sub set_install_platform { + my $detected_platform=platform; + if ($opt_custom_bin) { + $detected_platform = "custom"; + } + my $warn_nobin; + my $warn_nobin_x86_64_linux; + my $nowarn=""; + my $wp='***'; # warning prefix + + $warn_nobin="\n$wp WARNING: No binaries for your platform found. "; + $warn_nobin_x86_64_linux="$warn_nobin" . + "$wp No binaries for x86_64-linux found, using i386-linux instead.\n"; + + my $ret = $warn_nobin; + if (defined $vars{"binary_$detected_platform"}) { + $vars{"binary_$detected_platform"}=1; + $vars{'inst_platform'}=$detected_platform; + $ret = $nowarn; + } elsif ($detected_platform eq 'x86_64-linux') { + $vars{'binary_i386-linux'}=1; + $vars{'inst_platform'}='i386-linux'; + $ret = $warn_nobin_x86_64_linux; + } else { + if ($opt_custom_bin) { + $ret = "$wp Using custom binaries from $opt_custom_bin.\n"; + } else { + $ret = $warn_nobin; + } + } + foreach my $key (keys %vars) { + if ($key=~/^binary.*/) { + ++$vars{'n_systems_selected'} if $vars{$key}==1; + } + } + return($ret); +} + +sub create_profile { + my $profilepath = shift; + # The file "TLprofile" is created at the beginning of the + # installation process and contains information about the current + # setup. The purpose is to allow non-interactive installations. + my $fh; + if (ref($profilepath)) { + $fh = $profilepath; + } else { + open PROFILE, ">$profilepath"; + $fh = \*PROFILE; + } + my $tim = gmtime(time); + print $fh "# texlive.profile written on $tim UTC\n"; + print $fh "# It will NOT be updated and reflects only the\n"; + print $fh "# installation profile at installation time.\n"; + print $fh "selected_scheme $vars{selected_scheme}\n"; + foreach my $key (sort keys %vars) { + print $fh "$key $vars{$key}\n" + if $key=~/^collection/ and $vars{$key}==1; + print $fh "$key $vars{$key}\n" if $key =~ /^option_/; + print $fh "$key $vars{$key}\n" if (($key =~ /^binary_/) && $vars{$key}); + print $fh "$key $vars{$key}\n" if $key =~ /^TEXDIR/; # includes TEXDIRW + print $fh "$key $vars{$key}\n" if $key =~ /^TEXMFSYSVAR/; + print $fh "$key $vars{$key}\n" if $key =~ /^TEXMFSYSCONFIG/; + print $fh "$key $vars{$key}\n" if $key =~ /^TEXMFLOCAL/; + print $fh "$key $vars{$key}\n" if $key =~ /^TEXMFHOME/; + print $fh "$key $vars{$key}\n" if $key =~ /^from_dvd/; + } + if (!ref($profilepath)) { + close PROFILE; + } +} + +sub read_profile { + my $profilepath = shift; + open PROFILE, "<$profilepath" + or die "$0: Cannot open profile $profilepath for reading.\n"; + my %pro; + while (<PROFILE>) { + chomp; + next if m/^[[:space:]]*$/; # skip empty lines + next if m/^[[:space:]]*#/; # skip comment lines + my ($k,$v) = split (" ", $_, 2); # value might have spaces + $pro{$k} = $v; + } + foreach (keys %vars) { + # clear out collections from var + if (m/^collection-/) { $vars{$_} = 0; } + if (defined($pro{$_})) { $vars{$_} = $pro{$_}; } + } + # if a profile contains *only* the selected_scheme setting without + # any collection, we assume that exactely that scheme should be installed + my $coldefined = 0; + foreach my $k (keys %pro) { + if ($k =~ m/^collection-/) { + $coldefined = 1; + last; + } + } + # if at least one collection has been defined return here + return if $coldefined; + # since no collections have been defined in the profile, we + # set those to be installed on which the scheme depends + my $scheme=$tlpdb->get_package($vars{'selected_scheme'}); + if (!defined($scheme)) { + dump_vars(\*STDOUT); + die ("Scheme $vars{selected_scheme} not defined.\n"); + } + for my $scheme_content ($scheme->depends) { + $vars{"$scheme_content"}=1 if ($scheme_content=~/^collection-/); + } +} + +sub prepare_installation { + make_var_skeleton "$vars{'TEXMFSYSVAR'}"; + make_local_skeleton "$vars{'TEXMFLOCAL'}"; + mkdirhier "$vars{'TEXMFSYSCONFIG'}"; + + if ($vars{'from_dvd'}) { + $localtlpdb = $tlpdb; + } else { + $localtlpdb=new TeXLive::TLPDB; + $localtlpdb->root("$vars{'TEXDIR'}"); + } +} + + +sub do_install_packages { + my @what; + foreach my $package (sort keys %install) { + push @what, $package if ($install{$package} == 1); + } + if (!install_packages($tlpdb,$media,$localtlpdb,\@what, + $vars{'option_src'},$vars{'option_doc'})) { + my $profile_name = "installation.profile"; + create_profile($profile_name); + tlwarn("Installation failed.\n"); + tlwarn("Rerunning the installer will try to restart the installation.\n"); + tlwarn("Or you can restart by running the installer with:\n"); + if (win32()) { + tlwarn(" install-tl.bat --profile $profile_name [EXTRA-ARGS]\n"); + } else { + tlwarn(" install-tl --profile $profile_name [EXTRA-ARGS]\n"); + } + flushlog(); + exit(1); + } +} + +# for later complete removal we want to save some options and values +# into the local tlpdb: +# - should links be set, and if yes, the destination (bin,man,info) +sub save_options_into_tlpdb { + $localtlpdb->option ("location", $location); + $localtlpdb->option ("create_formats", $vars{'option_fmt'} ? "1" : "0"); + $localtlpdb->option ("desktop_integration", $vars{'option_desktop_integration'} ? "1" : "0"); + $localtlpdb->option ("file_assocs", $vars{'option_file_assocs'}); + $localtlpdb->option ("post_code", $vars{'option_post_code'} ? "1" : "0"); + $localtlpdb->option ("sys_bin", $vars{'option_sys_bin'}); + $localtlpdb->option ("sys_info", $vars{'option_sys_info'}); + $localtlpdb->option ("sys_man", $vars{'option_sys_man'}); + $localtlpdb->option ("install_docfiles", $vars{'option_doc'} ? "1" : "0"); + $localtlpdb->option ("install_srcfiles", $vars{'option_src'} ? "1" : "0"); + $localtlpdb->option ("w32_multi_user", $vars{'option_w32_multi_user'} ? "1" : "0"); + my @archs; + foreach (keys %vars) { + if (m/^binary_(.*)$/ ) { + if ($vars{$_}) { push @archs, $1; } + } + } + if ($opt_custom_bin) { + push @archs, "custom"; + } + + # only if we forced the platform we do save this option into the tlpdb + if (defined($opt_force_arch)) { + $localtlpdb->setting ("platform", $::_platform_); + } + $localtlpdb->setting("available_architectures", @archs); + $localtlpdb->save() unless $vars{'from_dvd'}; +} + + +sub import_settings_from_old_tlpdb { + my $dn = shift; + my $tlpdboldpath = "$dn/$TeXLive::TLConfig::InfraLocation/$TeXLive::TLConfig::DatabaseName"; + my $previoustlpdb; + if (-r $tlpdboldpath) { + # we found an old installation, so read that one in and save + # the list installed collections into an array. + info ("Trying to load old TeX Live Database,\n"); + info ("ignore warnings on unknown category Documentation\n"); + $previoustlpdb = TeXLive::TLPDB->new(root => $dn); + if ($previoustlpdb) { + info ("Importing settings from old installation in $dn\n"); + } else { + tlwarn ("Cannot load old TLPDB, continuing with normal installation.\n"); + return; + } + } else { + return; + } + # first import the collections + # since the scheme is not the final word we select scheme-custom here + # and then set the single collections by hand + $vars{'selected_scheme'} = "scheme-custom"; + $vars{'n_collections_selected'} = 0; + # remove the selection of all collections + foreach my $entry (keys %vars) { + if ($entry=~/^(collection-.*)/) { + $vars{"$1"}=0; + } + } + for my $c ($previoustlpdb->collections) { + my $tlpobj = $tlpdb->get_package($c); + if ($tlpobj) { + $vars{$c} = 1; + ++$vars{'n_collections_selected'}; + } + } + # now take over the path + my $oldroot = $previoustlpdb->root; + my $newroot = abs_path("$oldroot/..") . "/$texlive_release"; + $vars{'TEXDIR'} = $newroot; + $vars{'TEXDIRW'} = $newroot; + $vars{'TEXMFSYSVAR'} = "$newroot/texmf-var"; + $vars{'TEXMFSYSCONFIG'} = "$newroot/texmf-config"; + # only TEXMFLOCAL is treated differently, we use what is found by kpsewhich + # in 2008 and onward this is defined as + # TEXMFLOCAL = $SELFAUTOPARENT/../texmf-local + # so kpsewhich -var-value=TEXMFLOCAL returns + # ..../2008/../texmf-local + # TODO TODO TODO + chomp (my $tml = `kpsewhich -var-value=TEXMFLOCAL`); + $tml = abs_path($tml); + $vars{'TEXMFLOCAL'} = $tml; + # + # now for the settings + # set the defaults to what is specified in the tlpdb + $vars{'option_doc'} = + $previoustlpdb->option_pkg("00texlive-installation.config", + "install_docfiles"); + $vars{'option_src'} = + $previoustlpdb->option_pkg("00texlive-installation.config", + "install_srcfiles"); + $vars{'option_fmt'} = + $previoustlpdb->option_pkg("00texlive-installation.config", + "create_formats"); + $vars{'option_desktop_integration'} = 1 if win32(); + # option_path does not exist in older installation + $vars{'option_path'} = + $previoustlpdb->option_pkg("00texlive-installation.config", + "create_symlinks"); + $vars{'option_path'} = 1 if win32(); + $vars{'option_sys_bin'} = + $previoustlpdb->option_pkg("00texlive-installation.config", + "sys_bin"); + $vars{'option_sys_man'} = + $previoustlpdb->option_pkg("00texlive-installation.config", + "sys_man"); + $vars{'sys_info'} = + $previoustlpdb->option_pkg("00texlive-installation.config", + "sys_info"); + # + # import the set of selected architectures + my @aar = $previoustlpdb->setting_pkg("00texlive-installation.config", + "available_architectures"); + if (@aar) { + for my $b ($tlpdb->available_architectures) { + $vars{"binary_$b"} = member( $b, @aar ); + } + $vars{'n_systems_available'} = 0; + for my $key (keys %vars) { + ++$vars{'n_systems_available'} if ($key=~/^binary/); + } + } +} + +# do everything to select a scheme +# +sub select_scheme { + my $s = shift; + # set the selected scheme to $s + $vars{'selected_scheme'} = $s; + # if we are working on scheme-custom simply return + return if ($s eq "scheme-custom"); + # remove the selection of all collections + foreach my $entry (keys %vars) { + if ($entry=~/^(collection-.*)/) { + $vars{"$1"}=0; + } + } + # select the collections belonging to the scheme + my $scheme_tlpobj = $tlpdb->get_package($s); + if (defined ($scheme_tlpobj)) { + $vars{'n_collections_selected'}=0; + foreach my $dependent ($scheme_tlpobj->depends) { + if ($dependent=~/^(collection-.*)/) { + $vars{"$1"}=1; + ++$vars{'n_collections_selected'}; + } + } + } + # we have first set all collection-* keys to zero and than + # set to 1 only those which are required by the scheme + # since now scheme asks for collection-wintools we set its vars value + # to 1 in case we are installing win32 binaries + if ($vars{"binary_win32"}) { + $vars{"collection-wintools"} = 1; + ++$vars{'n_collections_selected'}; + } + # for good measure, update the deps + calc_depends(); +} + +sub update_numbers { + $vars{'n_collections_available'}=0; + $vars{'n_collections_selected'} = 0; + $vars{'n_systems_available'} = 0; + $vars{'n_systems_selected'} = 0; + foreach my $key (keys %vars) { + if ($key =~ /^binary/) { + ++$vars{'n_systems_available'}; + ++$vars{'n_systems_selected'} if $vars{$key} == 1; + } + if ($key =~ /^collection-/) { + ++$vars{'n_collections_available'}; + ++$vars{'n_collections_selected'} if $vars{$key} == 1; + } + } +} + +sub flushlog { + my $fh; + if (open(LOG,">install-tl.log")) { + printf "Writing log file to current working directory.\n"; + $fh = \*LOG; + } else { + $fh = \*STDERR; + printf "Not creating a log file but flushing messages to stderr.\n"; + } + + foreach my $l (@::LOGLINES) { + print $fh $l; + } +} + +sub check_on_lang_collection_installed { + # we check that at least one lang collection is installed: + foreach my $c (@collections_lang) { + return 1 if $vars{"$c"}; + } + if ($vars{"selected_scheme"} eq "scheme-context") { + # context + return 1; + } + return 0; +} + +sub do_cleanup +{ + # now open the log file and write out the log lines + # try to open a log file + # the user could have given the -logfile option in which case all the + # stuff is already dumped to it and $::LOGFILE defined. So do not + # redefine it + if (!defined($::LOGFILE)) { + if (open(LOGF,">$vars{'TEXDIRW'}/install-tl.log")) { + $::LOGFILE = \*LOGF; + foreach my $line(@::LOGLINES) { + print $::LOGFILE "$line"; + } + } else { + tlwarn("$0: Cannot create log file $vars{'TEXDIRW'}/install-tl.log: $!\n" + . "Not writing out log lines.\n"); + } + } + + # remove temporary files from TEXDIR/temp + if (($media eq "CD") or ($media eq "NET")) { + debug("Remove temporary downloaded containers...\n"); + rmtree("$vars{'TEXDIRW'}/temp") if (-d "$vars{'TEXDIRW'}/temp"); + } + + # dump various things to the log file + #if (defined($::LOGFILE)) { + # print $::LOGFILE "\nDump of vars:\n"; + # foreach my $key (keys %vars) { + # print $::LOGFILE "$key $vars{$key}\n"; + # } + # create_profile($::LOGFILE); + #} + + # should not be needed any more + #dump_vars("$system_tmpdir/texlive.vars"); + + # write the profile out + if ($vars{'from_dvd'}) { + create_profile("$vars{'TEXDIRW'}/texlive.profile"); + debug("Profile written to $vars{'TEXDIRW'}/texlive.profile\n"); + } else { + create_profile("$vars{'TEXDIR'}/$InfraLocation/texlive.profile"); + debug("Profile written to $vars{'TEXDIR'}/$InfraLocation/texlive.profile\n"); + } + # Close log file if present + close($::LOGFILE) if (defined($::LOGFILE)); + if (defined($::LOGFILENAME) and (-e $::LOGFILENAME)) { + print "Logfile: $::LOGFILENAME\n"; + } elsif (-e "$vars{'TEXDIRW'}/install-tl.log") { + print "Logfile: $vars{'TEXDIRW'}/install-tl.log\n"; + } else { + print "No logfile\n"; + } +} + + +# portable option, invoked from tl-portable script. +# +sub do_portable { + $::opt_verbosity = -1; + $::_platform_ = platform(); + $location = getenv('TEXDIR'); + die "$0: Don't use --portable directly; use tl-portable instead\n" + unless $location; + $vars{'TEXDIR'} = $location; + if (not -d $vars{'TEXDIR'}.'/bin/'.$::_platform_) { # shouldn't happen + die "$0: Platform ".$::_platform_." not supported."; + } + # set_platforms_supported(); + # set_texlive_default_dirs(); + $vars{'TEXDIRW'} = getenv('TEXDIRW'); + $vars{'TEXMFSYSVAR'} = getenv('TEXMFSYSVAR'); + $vars{'TEXMFSYSCONFIG'} = getenv('TEXMFSYSCONFIG'); + $vars{'TEXMFLOCAL'} = getenv('TEXMFLOCAL'); + $vars{'TEXMFHOME'} = getenv('TEXMFHOME'); + $vars{'TEXMFVAR'} = getenv('TEXMFVAR'); + $vars{'TEXMFCONFIG'} = getenv('TEXMFCONFIG'); + if (win32()) { + non_admin(); + my $winpath = "$vars{'TEXDIR'}/bin/win32"; + } + + our $PORTABLE_PROMPT_DONE = 0; # used in subroutine below + if (! -d "$vars{'TEXMFCONFIG'}" ) { + portable_prompt (); + mkdirhier "$vars{'TEXMFCONFIG'}"; + } + if (! -d "$vars{'TEXMFSYSCONFIG'}" ) { + portable_prompt (); + mkdirhier "$vars{'TEXMFSYSCONFIG'}"; + } + if (! -d "$vars{'TEXMFSYSVAR'}" ) { + portable_prompt (); + load_tlpdb(); + $localtlpdb = $tlpdb; + $texlive_release = $tlpdb->config_release; + make_var_skeleton "$vars{'TEXMFSYSVAR'}"; + # the usual option for pregenerating all formats doesn't apply + $vars{'option_fmt'} = 0; + do_postinst_stuff(); + } + + close($::LOGFILE) if defined($::LOGFILE); + print TeXLive::TLUtils::welcome; + exit 0; + + + # Give the user a chance to bail before changing anything. + # (Nested subroutine.) + sub portable_prompt + { + return if $PORTABLE_PROMPT_DONE; + $PORTABLE_PROMPT_DONE = 1; + print "About to generate some files, press Enter to continue:"; + <STDIN>; + } +} + +# +# some helper fucntion +sub select_collections { + my $varref = shift; + foreach (@_) { + $varref->{$_} = 1; + } +} + +sub deselect_collections { + my $varref = shift; + foreach (@_) { + $varref->{$_} = 0; + } +} + + +__END__ + +=head1 NAME + +install-tl - TeX Live cross-platform installer + +=head1 SYNOPSIS + +install-tl [OPTION]... + +install-tl.bat [OPTION]... + +=head1 DESCRIPTION + +The TeX Live installer works across all supported platforms and allows +to install TeX Live from various media, including the network. For +information on initially downloading TeX Live, see +L<http://tug.org/texlive/acquire.html>. + +The basic idea of TeX Live installation is to choose one of the +top-level I<schemes>, each of which is defined as a different set of +I<collections> and I<packages>, where a collection is a set of packages, +and a package is what contains actual files. + +Within the installer, you can choose a scheme, and further customize the +set of collections to install, but not the set of the packages. To do +that, remove the undesired packages after installation with C<tlmgr> +(see reference below). + +The default is C<scheme-full>, to install everything, and this is highly +recommended unless your disk space is severely limited. + +=head1 REFERENCES + +Post-installation configuration, packages updates, and more, are handled +through B<tlmgr>(1), the TeX Live Manager +(L<http://tug.org/texlive/tlmgr.html>). + +The most up-to-date version of this documentation is on the Internet at +L<http://tug.org/texlive/doc/install-tl.html>. + +For the full documentation of TeX Live, see +L<http://tug.org/texlive/doc>. + +=head1 OPTIONS + +=over 4 + +=item B<-gui> [[=]I<module>] + +If no I<module> is given starts the C<perltk> (see below) GUI installer. + +If I<module> is given loads the given installer module. Currently the +following modules are supported: + +=over 8 + +=item C<text> + +The text mode user interface which is the default on Unix systems, and +can be forced with by giving C<text> as I<module>, or with the C<-no-gui> +switch. + +=item C<wizard> + +The wizard mode user interface asking only a few questions before installing +all of TeX Live. This is the default on Windows systems. + +=item C<perltk> + +The all-in-one GUI installer. +It can also be selected by giving the C<-gui> option without any I<module>. + +=back + +The C<perltk> and C<wizard> modules, and thus also when calling with a +simple C<-gui> (without I<module>) requires +the Perl/Tk module (L<http://tug.org/texlive/distro.html#perltk>); if +Perl/Tk is not available, installation continues in text mode. + + +=item B<-no-gui> + +Use the text mode installer (default except on Windows). + +=item B<-lang> I<2-letter lang code> + +(only for GUI installer) If possible, start the installer translated into +the language specified by the 2-letter (ISO 639-1) language code (with +the exception for selecting simplified or traditional Chinese). +Currently supported +languages: English (en, default), Czech (cs), German (de), French (fr), +Italian (it), Dutch (nl), Polish (pl), Russian (ru), Slovak (sk), +Slovenian (sl), Vietnamese (vi), simplified Chinese (zh-cn), and +traditional Chinese (zh-tw). + +=item B<-repository> I<url|path> + +Specify the package repository to be used as the source of the +installation, either a local directory via C</path/to/directory> or a +C<file:/> url, or a network location via a C<http://> or C<ftp://> url. +(No other protocols are supported.) + +If the repository is local, the installation type (compressed or live) is +automatically determined, by checking for the presence of a +C<archive> directory relative to the root. Compressed is +preferred if both are available, since it is faster. Here's an example +of using a local directory: + + -repository /local/TL/repository + +If the repository is on the network, trailing C</> characters and/or +trailing C</tlpkg> and C</archive> components are ignored. For example, +you could choose a particular CTAN mirror with something like this: + + -repository http://ctan.example.org/its/ctan/dir/systems/texlive/tlnet + +Of course a real hostname and its particular top-level CTAN path +have to be specified. The list of CTAN mirrors is available at +L<http://ctan.org/mirrors>. + +The default is to pick a mirror automatically, using +L<http://mirror.ctan.org/systems/texlive/tlnet>; the chosen mirror is +used for the entire download. You can use the special repository name +C<ctan> as an abbreviation for this. See L<http://ctan.org> for more +about CTAN and its mirrors. + +After installation is complete, you can use that installation as the +repository for another installation. If you chose to install less than +the full scheme containing all packages, the list of available schemes +will be adjusted accordingly. + +For backward compatibility and convenience, C<--location> and C<--repo> +are accepted as aliases for this option. + +=item B<-no-cls> + +(only for text mode installer) do not clear the screen when entering +a new menu (for debugging purposes). + +=item B<-non-admin> + +For Windows only: configure for the current user, not for all users. + +=item B<-all-options> + +Normally options not regarding the current architecture are not shown. +Giving this cmd line option allows to configure settings in the +final tlpdb that do not have any immediate effect. + +=item B<-portable> + +Start the installer for portable use---but use the C<tl-portable> +scripts instead of this option. See below for details. + +=item B<-print-arch> + +Print the detected arch-os combination and exit. + +=item B<-force-arch> I<arch-os> + +Instead of auto-detecting the current platform use the one given on the +cmd line. Make sure that there are binaries for this platform and they +can actually be run. + +=item B<-profile> I<profile> + +Load the I<profile> file for repeated installations on different systems. +A I<profile> contains the values of all necessary variable for the +installation. After normal installation has finished a profile for that +exact installation is written into DEST/tlpkg/texlive.profile. That file +can be used to do the exact same installation on a different computer. + +You can also hand-craft such a profile starting from a generated one +by changing some values. Normally a profile has to contain the value 1 for +each collection that should be installed, even if the scheme is specified. +That follows from the logic of the installer that you first select a scheme +and then can change the actual collections being installed. + +There is one exception to this: If the profile contains a variable for +B<selected_scheme> and I<no> collection variable is defined in the +profile, then the collections which the specified scheme requires are +installed. Thus, a simple line C<selected_scheme scheme-medium> +together with the definitions of the paths (C<TEXDIR>, C<TEXDIRW>, +C<TEXMFHOME>, C<TEXMFLOCAL>, C<TEXMFSYSCONFIG>, C<TEXMFSYSVAR>) suffices +to install the medium scheme with all default options. + +=item B<-scheme> I<scheme> + +Schemes are the highest level of package grouping in TeX Live; the +default is to use the C<full> scheme, which includes everything. This +option overrides that default. You can change the scheme again before +the actual installation with the usual menu. The I<scheme> argument may +optionally have a prefix C<scheme->. The list of supported scheme names +depends on what your package repository provides; see the interactive +menu list. + +=item B<-custom-bin> I<path> + +In case your architecture is not supported by TeX Live out of the box +and you have built your own binaries for your system, this option allows +to give the I<path> to a directory where ready made binaries for your +system are present. The installation will continue as normally, but at +the end all files from I<path> are copied over to C<bin/custom> in your +installation folder and this directory will be added to the path for +the postinstall actions. + +=item B<-debug-translation> + +This switch will make install-tl report any missing or probably +untranslated messages in the GUI installers to STDERR. + +=item B<-q> + +Omit normal informational messages. + +=item B<-v> + +Include debugging messages; repeat for maximum debugging, as in C<-v +-v>. (Further repeats are accepted but ignored.) + +=item B<-logfile> I<file> + +Write both all messages (informational, debugging, warnings) to I<file>, +in addition to standard output or standard error. + +If this option is not given, the installer will create a log file +in the root of the writable installation tree, +for example, C</usr/local/texlive/YYYY/install-tl.log> for the I<YYYY> +release. + +=item B<--help>, B<-help>, B<-?> + +Display this help and exit. + +=item B<--version>, B<-version> + +Output version information and exit. +If C<-v> has been given the revisions of the used modules are reported, too. + +=back + +As usual, all options can be specified with either C<-> or C<-->, and +arguments can be separated from their options by either a space or C<=>. + +=head1 PORTABLE USE + +The TeX Live root directory contains a shell script C<tl-portable.sh> +and a DOS batch file C<tl-portable.bat> which start up a new shell and +command prompt in which TeX Live can be run with minimal impact on the +host system. These files start up C<install-tl> with the +C<-portable> option for some minimal preparation. Don't use this option +directly; it makes very specific assumptions about its environment. + +=head1 AUTHORS AND COPYRIGHT + +This script and its documentation were written for the TeX Live +distribution (L<http://tug.org/texlive>) and both are licensed under the +GNU General Public License Version 2 or later. + +=cut + +### Local Variables: +### perl-indent-level: 2 +### tab-width: 2 +### indent-tabs-mode: nil +### End: +# vim:set tabstop=2 expandtab: # |