diff options
Diffstat (limited to 'Master/install-tl')
-rwxr-xr-x | Master/install-tl | 1203 |
1 files changed, 1203 insertions, 0 deletions
diff --git a/Master/install-tl b/Master/install-tl new file mode 100755 index 00000000000..83973e7d867 --- /dev/null +++ b/Master/install-tl @@ -0,0 +1,1203 @@ +#!/usr/bin/env perl + +# $Id$ +# install-tl.pl +# +# Copyright 2007 2008 Reinhard Kotucha, Norbert Preining +# This file is licensed under the GNU General Public License version 2 +# or any later version. +# +# TODO: +# - support option_paper (paper instead of A4) +# missing + +my $svnrev = '$Revision$'; +$svnrev =~ m/: ([0-9]+) /; +$::installerrevision = $1; + +# is now taken from 00texlive.config: release, $tlpdb->config_release; +our $texlive_release; + +BEGIN { + $^W = 1; + my $me=$0; + $me=~s!\\!/!g if $^O=~/^MSWin(32|64)$/i; + + if ($me=~m!/!) { + ($::installerdir=$me)=~s!(.*)/.*$!$1!; + # we have to chdir to the Master ... + chdir($::installerdir); + } else { + $::installerdir='.'; + } +# The installer uses a minimal subset of Perl for Windows. In order +# to avoid conflicts with other versions of Perl already installed on +# the system, we simply ignore them. The installer has to execute +# $::installerdir/tlpkg/bin/perl.exe and should not rely on any other +# Perl executable. + + if ($^O=~/^MSWin(32|64)$/i) { + @INC="$::installerdir/tlpkg/installer/perllib"; + } + unshift (@INC, "$::installerdir/tlpkg"); +} + +use TeXLive::TLUtils qw(initialize_installer media platform platform_desc + which getenv win32 unix program_exists + get_system_tmpdir member + mkdirhier make_var_skeleton make_local_skeleton install_package copy + install_packages dirname tllog setup_programs); +use TeXLive::TLPOBJ; +use TeXLive::TLPDB; +use TeXLive::TLConfig; +use Pod::Usage; +use Cwd 'abs_path'; + +if (win32) { + require TeXLive::TLWinGoo; + TeXLive::TLWinGoo->import( qw( + &wg_error + &win_version + &is_vista + &admin + &non_admin + ®_country + &dir_writable + &expand_string + &global_tmpdir + &get_system_path + &get_user_path + &setenv_reg + &unsetenv_reg + &add_texbindir_to_path + &remove_texbindirs_from_path + ®ister_script_type + &unregister_script_type + &broadcast_env + &update_assocs + ®ister_uninstaller + )); +} +use Getopt::Long; +$Getopt::Long::autoabbrev=0; + +use strict; + +# debugging/logging cmd lines options: +# -q shut up terminal output +# -qq shut up also log file output +# -d set $::LOGLEVELFILE to $::LOG_DEBUG +# -dd set $::LOGLEVELFILE to $::LOG_DDEBUG +# -ddd set $::LOGLEVELFILE to $::LOG_DDDEBUG +# +$::LOGLEVELFILE = $::LOG_NORMAL; +$::LOGLEVELTERMINAL = $::LOG_NORMAL; +@::LOGLINES = (); +# +# $install{$packagename} == 1 if it should be installed +my %install; + +# 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; +# for win dealing +#our $Registry; +# 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 +our %vars=( # 'n_' means 'number of'. + 'this_platform' => platform(), + 'n_systems_available' => 0, + 'n_systems_selected' => 0, + 'n_collections_selected' => 0, + 'n_collections_available' => 0, + 'total_size' => 0, + 'option_symlinks' => 0, + 'sys_bin' => '/usr/local/bin', + 'sys_man' => '/usr/local/man', + 'sys_info' => '/usr/local/info', + 'option_doc' => 1, + 'option_src' => 1, + 'option_fmt' => 0, + 'option_letter' => 0, + 'selected_scheme' => $default_scheme, + ); + +# option handling +my $opt_media = ""; +my $opt_url = ""; +my $opt_profile = ""; +my $opt_no_cls=0; +my $opt_nogui = 0; +my $opt_debug = 0; +my $opt_ddebug = 0; +my $opt_dddebug = 0; +my $opt_quiet = 0; +my $opt_qquiet = 0; +my $opt_nonadmin = 0; +my $opt_arch = 0; +our $opt_portable = 0; +my $opt_help = 0; +my $opt_version = 0; +my $opt_gui = 0; +$opt_gui = 1 if (win32); + +# default language for GUI installer +$::lang = "en"; + +GetOptions("media=s" => \$opt_media, + "profile=s"=> \$opt_profile, + "no-cls", + "gui", \$opt_gui, + "no-gui", \$opt_nogui, + "netarchive=s" => \$NetArchive, + "diskarchive=s" => \$DiskArchive, + "lang=s" => \$::opt_lang, + "print-arch" => \$opt_arch, + "portable" => \$opt_portable, + "d" => \$opt_debug, + "dd" => \$opt_ddebug, + "ddd" => \$opt_dddebug, + "q" => \$opt_quiet, + "qq" => \$opt_qquiet, + "url=s" => \$opt_url, + "version" => \$opt_version, + "help|?" => \$opt_help) or pod2usage(1); + +if (win32()) { + pod2usage(-exitstatus => 0, -verbose => 2, -noperldoc => 1) if $opt_help; +} else { + pod2usage(-exitstatus => 0, -verbose => 2) if $opt_help; +} + +if ($opt_version) { + print "TeX Live Cross Platform Installer, Revision $::installerrevision\n"; + exit 0; +} + +if (defined($::opt_lang)) { + $::lang = $::opt_lang; +} + +if ($opt_quiet) { + $::LOGLEVELTERMINAL = $::LOG_ZERO; +} +if ($opt_qquiet) { + $::LOGLEVELTERMINAL = $::LOG_ZERO; + $::LOGLEVELFILE = $::LOG_ZERO; +} +if ($opt_debug) { + $::LOGLEVELFILE = $::LOG_DEBUG; +} +if ($opt_ddebug) { + $::LOGLEVELFILE = $::LOG_DDEBUG; +} +if ($opt_dddebug) { + $::LOGLEVELFILE = $::LOG_DDDEBUG; +} +if ("$opt_media" =~ m/^CD/i) { + $::_media_ = "CD"; +} elsif ("$opt_media" =~ m/^NET/i) { + $::_media_ = "NET"; +} elsif ("$opt_media" =~ m/^DVD/i) { + $::_media_ = "DVD"; +} + +if ("$opt_profile" ne "") { + if (-r "$opt_profile") { + tllog($::LOG_NORMAL, "Using automated installation using $opt_profile!"); + } else { + $opt_profile = ""; + tllog($::LOG_NORMAL, "Profile $opt_profile not readable, continuing in interactive mode!"); + } +} + +if ($opt_nonadmin and win32()) { non_admin(); } + +if ("$opt_url" ne "") { + $TeXLiveURL = "$opt_url"; +} + +# 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; + +# $finished == 1 if the menu call already did the installation +my $finished = 0; +@::start_install_hook = (); +@::end_install_hook = (); +@::start_postinst_hook = (); +@::start_install_hook = (); + +my $system_tmpdir=get_system_tmpdir(); + +if ($opt_arch) { + print platform; + exit 0; +} elsif ($opt_portable) { + $::LOGLEVELTERMINAL = $::LOG_ZERO; + # initialize_installer: + $::_media_ = "DVD"; + $::_platform_ = platform(); + $vars{'TEXDIR'} = getenv('TEXDIR'); + if (not -d $vars{'TEXDIR'}.'/bin/'.$::_platform_) { # shouldn't happen + print "Platform ".$::_platform_." not supported\n"; + exit 1; + } + # set_platforms_supported(); + # set_texlive_default_dirs(); + $vars{'TEXMFSYSVAR'} = getenv('TEXMFSYSVAR'); + $vars{'TEXMFSYSCONFIG'} = getenv('TEXMFSYSCONFIG'); + $vars{'TEXMFLOCAL'} = getenv('TEXMFLOCAL'); + $vars{'TEXMFHOME'} = getenv('TEXMFHOME'); + $vars{'TEXMFVAR'} = getenv('TEXMFVAR'); + $vars{'TEXMFCONFIG'} = getenv('TEXMFCONFIG'); + # initialize_collections(); + # set_install_platform(); + $vars{'this_platform'} = platform(); + # do_installation(); + # prepare_installation(); + if (win32()) { + non_admin(); + my $winpath = "$vars{'TEXDIR'}/bin/win32"; + register_script_type(".texlua", "%TEXBINDIR%/texlua.exe"); + update_assocs(); + } + mkdirhier "$vars{'TEXMFCONFIG'}"; + if (not -d "$vars{'TEXMFSYSVAR'}" ) { + print "About to generate some files... Press <enter>"; + <STDIN>; + load_tlpdb(); + $localtlpdb = $tlpdb; + $texlive_release = $tlpdb->config_release; + make_var_skeleton "$vars{'TEXMFSYSVAR'}"; + #$localtlpdb=new TeXLive::TLPDB; + #$localtlpdb->root("$vars{'TEXDIR'}"); + do_postinst_stuff(); + } + close($::LOGFILE) if defined($::LOGFILE); + exit 0; +} + +tllog($::LOG_NORMAL, "Platform: ", platform, " => \'", platform_desc(platform), "\'\n"); +if (media() eq "DVD") { + tllog($::LOG_NORMAL, "Distribution: live (uncompressed)\n"); +} elsif (media() eq "CD") { + tllog($::LOG_NORMAL, "Distribution: inst (compressed)\n"); +} elsif (media() eq "NET") { + tllog($::LOG_NORMAL, "Distribution: net (downloading)\n"); +} else { + tllog($::LOG_NORMAL, "Distribution: ", media(), "\n"); +} +tllog($::LOG_NORMAL, "Directory for Temporary Files: '", $system_tmpdir, "\'\n"); +tllog($::LOG_NORMAL, "Installer Directory: '$::installerdir'\n"); + +initialize_installer(); +setup_programs("$::installerdir/tlpkg/installer", "$::_platform_"); +load_tlpdb(); +$texlive_release = $tlpdb->config_release; +set_platforms_supported(); +set_texlive_default_dirs(); +initialize_collections(); +set_install_platform(); +if ($opt_profile eq "") { + # 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 should implement a function run_menu() 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; + if ($opt_gui && !$opt_nogui) { + # 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 + tllog($::LOG_NORMAL, "Cannot load Tk, maybe something is missing!\n"); + tllog($::LOG_NORMAL, "Error message from loading Tk:\n"); + tllog($::LOG_NORMAL, "$@\n"); + tllog($::LOG_NORMAL, "Continuing in Text Mode...\n"); + $opt_gui = 0; + } + } + if ($opt_gui && !$opt_nogui) { + require("installer/install-menu-perltk.pl"); + } else { + require("installer/install-menu-text.pl"); + } + my $ret = run_menu(); + if ($ret == $MENU_QUIT) { + # do_cleanup(); MISSING + flushlog(); + exit(1); + } + if ($ret == $MENU_ABORT) { + # NO do_cleanup()! + flushlog(); + exit(2); + } + if ($ret == $MENU_ALREADYDONE) { + tllog($::LOG_DEBUG, "run_menu has already done the work ... cleaning up!\n"); + $finished = 1; + } + if (!$finished && ($ret != $MENU_INSTALL)) { + tllog($::LOG_NORMAL, "Unknown return value of run_menu: $ret\n"); + exit(3); + } +} else { + read_profile("$opt_profile"); +} + +if (!$finished) { + # do the actual installation + do_installation(); +} + +# now open the log file and write out the log lines +# try to open a log file +if ($::LOGLEVELFILE > $::LOG_ZERO) { + if (open(LOGF,">$vars{'TEXDIR'}/install-tl.log")) { + $::LOGFILE = \*LOGF; + foreach my $line(@::LOGLINES) { + print $::LOGFILE "$line"; + } + } else { + warn("Cannot create log file $vars{'TEXDIR'}/install-tl.log: $!\nNot writing out log lines!\n"); + $::LOGLEVELFILE = $::LOG_ZERO; + } +} + +# 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); +} + +dump_vars("$system_tmpdir/texlive.vars"); + +# write the profile out +create_profile("$vars{'TEXDIR'}/$InfraLocation/texlive.profile"); +tllog($::LOG_DEBUG, "Profile written to $vars{'TEXDIR'}/$InfraLocation/texlive.profile\n"); + +# Close log file if present +close($::LOGFILE) if defined($::LOGFILE); + + +exit(0); + +################################################################### +# +# FROM HERE ON ONLY SUBROUTINES +# NO VARIABLE DECLARATIONS +# +################################################################### + +sub do_installation { + # do the actual installation + foreach my $h (@::start_install_hook) { + &$h(); + } + calc_depends(); + prepare_installation(); + save_options_into_tlpdb(); + do_install_packages(); + if (win32()) { + do_win_registry_magic(); + } + foreach my $h (@::start_postinst_hook) { + &$h(); + } + do_postinst_stuff(); + $localtlpdb->save; + foreach my $h (@::end_install_hook) { + &$h(); + } +} + +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)); + tllog($::LOG_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_TEXMFLOCAL $tex_prefix/texmf-local +# TEXLIVE_INSTALL_TEXMFHOME '$HOME/texmf' + +sub set_texlive_default_dirs { + my $tex_prefix; + my $texmfsysvar; + my $texmflocal; + my $texmfhome; + + $tex_prefix=getenv('TEXLIVE_INSTALL_PREFIX'); + if (win32) { + my $prog = getenv('ProgramFiles'); + $tex_prefix ||= $prog . '/texlive'; + # $tex_prefix ||= $prog . '/texlive' if TeXLive::TLWinGoo::dir_writable($prog); + # $tex_prefix||=getenv('USERPROFILE') . '/texlive'; + } else { + $tex_prefix||='/usr/local/texlive'; + } + $vars{'TEXDIR'}="$tex_prefix/$texlive_release"; + + $texmfsysvar=getenv('TEXLIVE_INSTALL_TEXMFSYSVAR'); + $texmfsysvar||=$vars{'TEXDIR'} . '/texmf-var'; + $vars{'TEXMFSYSVAR'}="$texmfsysvar"; + + $texmflocal=getenv('TEXLIVE_INSTALL_TEXMFLOCAL'); + $texmflocal||="$tex_prefix/texmf-local"; + $vars{'TEXMFLOCAL'}="$texmflocal"; + + $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=(); + + # initialize the %install hash with what should be installed + + # First look for packages in the selected scheme. + 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) { + $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; } + } + } + + # if programs for arch=win32 are installed we also have to install + # bin-tlperl.win32 which provides the "hidden" perl that will be used + # to run all the perl scripts. + # Furthermore we install bin-tlgs.win32, too + if (grep(/^win32$/,@archs)) { + $install{"bin-tlperl.win32"} = 1; + $install{"bin-tlgs.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; + tllog($::LOG_DDEBUG, "initial number of installations: $#pre_selected\n"); + + # loop over all the pre_selected and add them + foreach my $p (@pre_selected) { + tllog($::LOG_DDEBUG, "pre_selected $p\n"); + foreach my $p_dep ($tlpdb->get_package($p)->depends) { + if ($p_dep =~ m/^(.*)\.ARCH$/) { + my $foo = "$1"; + foreach my $a (@archs) { + $install{"$foo.$a"} = 1; + } + } 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; + tllog($::LOG_DDEBUG, "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 my $p (keys %install) { + my $tlpobj = $tlpdb->get_package($p); + if (not(defined($tlpobj))) { + die "Cannot find $p in texlive.tlpdb, strange!\n"; + } + $size+=$tlpobj->docsize if $vars{'option_doc'}; + $size+=$tlpobj->srcsize if $vars{'option_src'}; + $size+=$tlpobj->runsize; + foreach my $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; + if (media eq 'NET') { + $master="$TeXLiveURL"; + } else { + $master="$::installerdir"; + } + tllog($::LOG_NORMAL, "Loading $master/$TeXLive::TLConfig::InfraLocation/$TeXLive::TLConfig::DatabaseName ...\n"); + $tlpdb=TeXLive::TLPDB->new(root => "$master"); +} + +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'}; + } + } + } +} + +sub set_install_platform { + my @available_platforms; + my $detected_platform=platform; + 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 { + $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 overwritten and reflects only the\n"; + print $fh "# installation profile at installation time\n"; + print $fh "selected_scheme $vars{selected_scheme}\n"; + foreach my $key (keys %vars) { + print $fh "$key $vars{$key}\n" + if $key=~/^collection/ and $vars{$key}==1; + print $fh "$key $vars{$key}\n" if $key=~/^option_letter/; + print $fh "$key $vars{$key}\n" if $key=~/^option_doc/; + print $fh "$key $vars{$key}\n" if $key=~/^option_fmt/; + print $fh "$key $vars{$key}\n" if $key=~/^option_src/; + print $fh "$key $vars{$key}\n" if $key=~/^option_symlinks/; + print $fh "$key $vars{$key}\n" if $key=~/^TEXDIR/; + print $fh "$key $vars{$key}\n" if $key=~/^TEXMFSYSVAR/; + print $fh "$key $vars{$key}\n" if $key=~/^TEXMFLOCAL/; + print $fh "$key $vars{$key}\n" if $key=~/^TEXMFHOME/; + } + if (!ref($profilepath)) { + close PROFILE; + } +} + +sub read_profile { + my $profilepath = shift; + open PROFILE, "<$profilepath" + or die "Cannot open profile $profilepath for reading!\n"; + my %pro; + while (<PROFILE>) { + next if m/^[[:space:]]*$/; # skip empty lines + next if m/^[[:space:]]*#/; # skip comment lines + my ($k,$v) = split; + $pro{$k} = $v; + } + foreach (keys %vars) { + # clear out collections from var + if (m/^collection-/) { $vars{$_} = 0; } + if (defined($pro{$_})) { $vars{$_} = $pro{$_}; } + } +} + +sub prepare_installation { + make_var_skeleton "$vars{'TEXMFSYSVAR'}"; + make_local_skeleton "$vars{'TEXMFLOCAL'}"; + mkdirhier "$vars{'TEXDIR'}/texmf-config"; + + $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); + } + install_packages($tlpdb,$localtlpdb,\@what,$vars{'option_src'},$vars{'option_doc'}); +} + +# 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 { + my $tlp = new TeXLive::TLPOBJ; + $tlp->name("00texlive-installation.config"); + $tlp->category("TLCore"); + my @deps; + push @deps, "platform/$::_platform_"; + if ($::_media_ eq 'NET') { + push @deps, "location/$TeXLiveURL"; + } else { + push @deps, "location/" . abs_path($::installerdir); + } + if ($vars{'option_letter'}) { + push @deps, "letter"; + } + if ($vars{'option_fmt'}) { + push @deps, "formats"; + } + if ($vars{'option_symlinks'}) { + push @deps, "symlinks"; + push @deps, "sys_bin/$vars{'sys_bin'}"; + push @deps, "sys_info/$vars{'sys_info'}"; + push @deps, "sys_man/$vars{'sys_man'}"; + } + if ($vars{'option_doc'}) { + push @deps, "docfiles"; + } + if ($vars{'option_src'}) { + push @deps, "srcfiles"; + } + $tlp->depends(@deps); + $localtlpdb->add_tlpobj($tlp); + $localtlpdb->save(); +} + +# 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 $TEXMFSYSVAR="$vars{'TEXMFSYSVAR'}"; + my $TEXMFLOCAL="$vars{'TEXMFLOCAL'}"; + + # install some copies from texmf(-dist) into texmf-var + copy ("$TEXDIR/texmf-dist/tex/plain/config/language.def", + "$TEXMFSYSVAR/tex/plain/config") + if (-f "$TEXDIR/texmf-dist/tex/plain/config/language.def"); + copy ("$TEXDIR/texmf/xdvi/XDvi", + "$TEXMFSYSVAR/xdvi") + if (-f "$TEXDIR/texmf/xdvi/XDvi"); + + # those files must exist + copy ("$TEXDIR/texmf/dvips/config/config.ps", + "$TEXMFSYSVAR/dvips/config"); + copy ("$TEXDIR/texmf/dvipdfm/config/config", + "$TEXMFSYSVAR/dvipdfm/config"); + copy ("$TEXDIR/texmf/web2c/mktex.cnf", + "$TEXMFSYSVAR/web2c"); + + # the old installer copied from CDDIR, but shouldn't this be installed + # in ANY case since it is in bin-pdftex??? + copy ("$TEXDIR/texmf/tex/generic/config/pdftexconfig.tex", + "$TEXMFSYSVAR/tex/generic/config"); + + # old installer did this, should we do this, TOO???? + #cp $CDDIR/texmf-dist/tex/context/config/cont-usr.tex $TEXMFSYSVAR/tex/context/config/cont-usr.tex + + do_texmf_cnf() unless $opt_portable; + + + # 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 @TMFVARS=qw(VARTEXFONTS TEXMFMAIN TEXMFDIST TEXMFLOCAL TEXMFSYSVAR + # TEXMFSYSCONFIG TEXMFHOME TEXMFVAR TEXMFCONFIG TEXMF SYSTEXMF VARTEXFONTS + # TEXMFDBS WEB2C TEXINPUTS TEXFORMATS MFBASES MPMEMS TEXPOOL MFPOOL MPPOOL + # PSHEADERS TEXFONTMAPS TEXPSHEADERS TEXCONFIG TEXMFCNF); + 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); + + foreach my $tmv (@TMFVARS0) { + delete $ENV{$tmv} if (defined($ENV{$tmv})); + } + if (!$opt_portable) { foreach my $tmv (@TMFVARS1) { + delete $ENV{$tmv} if (defined($ENV{$tmv})); + }} + + # Step 2: Setup the PATH, PATHEXT, 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"; + + tllog($::LOG_DEBUG, "Prepending $plat_bindir to PATH\n"); + + $ENV{'PATH'}="$plat_bindir" . "$pathsep" . "$ENV{'PATH'}"; + + if (win32) { + tllog($::LOG_DEBUG, "Prepending $perl_bindir to PATH\n"); + $ENV{'PATH'}="$perl_bindir" . "$pathsep" . "$ENV{'PATH'}"; + } + + tllog($::LOG_DEBUG, "\nNew PATH is now:\n"); + foreach my $dir (split $pathsep, $ENV{'PATH'}) { + tllog($::LOG_DEBUG, " $dir\n"); + } + tllog($::LOG_DEBUG, "\n"); + + if (win32) { + $ENV{'PATHEXT'}=".texlua;" . "$ENV{'PATHEXT'}"; + $ENV{'TEXBINDIR'}=$TEXDIR . "\\bin\\win32"; + $ENV{'TEXBINDIR'} =~ s!/!\\!g; + $ENV{'PERL5LIB'}="$perl_libdir"; + } + + + # Step 4: run the programs + + if (!$opt_portable) { + tllog($::LOG_NORMAL, "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 + tllog($::LOG_NORMAL, "writing fmtutil.cnf data to $TEXMFSYSVAR/web2c/fmtutil.cnf\n"); + TeXLive::TLUtils::create_fmtutil($localtlpdb, + "$TEXMFSYSVAR/web2c/fmtutil.cnf", + "$TEXMFLOCAL/web2c/fmtutil-local.cnf"); + + tllog($::LOG_NORMAL, "writing updmap.cfg to $TEXMFSYSVAR/web2c/updmap.cfg\n"); + TeXLive::TLUtils::create_updmap ($localtlpdb, + "$TEXMFSYSVAR/web2c/updmap.cfg", + "$TEXMFLOCAL/web2c/updmap-local.cfg"); + + tllog($::LOG_NORMAL, "writing language.dat data to $TEXMFSYSVAR/tex/generic/config/language.dat\n"); + TeXLive::TLUtils::create_language($localtlpdb, + "$TEXMFSYSVAR/tex/generic/config/language.dat", + "$TEXMFLOCAL/tex/generic/config/language-local.dat"); + + tllog($::LOG_NORMAL, "running updmap-sys\n"); + system('updmap-sys', '--nohash'); + + tllog($::LOG_NORMAL, "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'}) { + tllog($::LOG_NORMAL, "letter option not implemented yet, please wait\n"); + } + + # all formats option + if ($vars{'option_fmt'}) { + tllog($::LOG_NORMAL, "pre-generation all format file (fmtutil-sys --all)\n"); + system('fmtutil-sys','--all'); + } + + # option_links + if ($vars{'option_symlinks'}) { + # bin files + my @files; + mkdirhier $vars{'sys_bin'}; + if (-w $vars{'sys_bin'}) { + tllog($::LOG_NORMAL, "linking binaries to $vars{'sys_bin'}\n"); + @files = `ls $plat_bindir`; + chomp(@files); + `cd "$vars{'sys_bin'}" && rm -f @files`; + `ln -s "$plat_bindir/"* "$vars{'sys_bin'}"`; + } else { + tllog($::LOG_NORMAL, "destination of bin symlink $vars{'sys_bin'} not writable, no linking of bin files done!\n"); + } + if ($vars{'option_doc'}) { + # info files + mkdirhier $vars{'sys_info'}; + if (-w $vars{'sys_info'}) { + tllog($::LOG_NORMAL, "linking info pages to $vars{'sys_info'}\n"); + @files = `ls "$TEXDIR/texmf/doc/info"`; + chomp(@files); + `cd "$vars{'sys_info'}" && rm -f @files`; + `ln -s "$TEXDIR/texmf/doc/info/"*info* "$vars{'sys_info'}"`; + } else { + tllog($::LOG_NORMAL, "destination of info symlink $vars{'sys_info'} not writable, no linking of info files done!\n"); + } + # man files + mkdirhier $vars{'sys_man'}; + if (-w $vars{'sys_man'}) { + tllog($::LOG_NORMAL, "linking man pages to $vars{'sys_man'}\n"); + my $foo = `(cd "$TEXDIR/texmf/doc/man" && echo *)`; + my @mans = split ' ', $foo; + chomp(@mans); + foreach my $m (@mans) { + my $mandir = "$TEXDIR/texmf/doc/man/$m"; + next unless -d $mandir; + mkdirhier "$vars{'sys_man'}/$m"; + next unless -w "$vars{'sys_man'}/$m"; + @files = `ls "$mandir"`; + chomp(@files); + `cd "$vars{'sys_man'}/$m" && rm -f @files`; + `ln -s "$mandir/"* "$vars{'sys_man'}/$m"`; + } + } else { + tllog($::LOG_NORMAL, "destination of man symlink $vars{'sys_man'} not writable, no linking of man files done!\n"); + } + } + } + + # old installer: + #$config && texconfig-sys init + #$config || echo "PLEASE RUN texconfig or texconfig-sys to make new formats." +} + + +# 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: $!\n"); + my @texmfcnflines = <TMF>; + close(TMF); + my @newtmf; + # 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"; + } + } 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"; + } + } elsif ($line =~ m/^TEXMFHOME/) { + # kpse now expands ~ to USERPROFILE, so we don't treat win32 and + # unix differently + push @newtmf, "TEXMFHOME = $vars{'TEXMFHOME'}\n"; + } elsif ($line =~ m/^OSFONTDIR/) { + if (win32()) { + push @newtmf, "OSFONTDIR = \$SystemRoot/fonts//\n"; + } else { + push @newtmf, $line; + } + } else { + push @newtmf, $line; + } + } + open(TMF,">$vars{'TEXDIR'}/texmf/web2c/texmf.cnf") + or die("Can't open $vars{'TEXDIR'}/texmf/web2c/texmf.cnf for writing: $!\n"); + foreach (@newtmf) { print TMF; } + close(TMF); +} + +# register texlua handlers etc etc +sub do_win_registry_magic { + # we are called under if (win32()) !! + my $texbindir = $vars{'TEXDIR'}."\\bin\\win32"; + $texbindir =~ s!/!\\!g; + add_texbindir_to_path($texbindir); + setenv_reg('TEXBINDIR', $texbindir); + register_script_type(".texlua", "%TEXBINDIR%/texlua.exe"); + broadcast_env(); + update_assocs(); + register_uninstaller("$vars{'TEXDIR'}") unless $opt_portable; +} + +# +# do everything to select a scheme +# +sub select_scheme { + my $s = shift; + # set the selected scheme to $s + $vars{'selected_scheme'} = $s; + # 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'}; + } + } + } + # for good measure, update the deps + calc_depends(); +} + +sub update_numbers { + $vars{'n_collections_selected'}=0; + $vars{'n_systems_available'} = 0; + $vars{'n_collections_selected'} = 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")) { + warn "Writing log file to current working directory!\n"; + $fh = \*LOG; + } else { + $fh = \*STDERR; + warn "Not creating a log file but flushing messages to stderr:\n"; + } + + foreach my $l (@::LOGLINES) { + print $fh $l; + } +} + +__END__ + +=head1 NAME + +install-tl.pl - the TeX Live Cross Platform Installer + +=head1 SYNOPSIS + +install-tl.pl [OPTION] ... + +install-tl.bat [OPTION] ... + +=head1 OPTIONS + +=over 8 + +=item B<-gui> + +Tries to load the GUI installer using Perl/Tk. If Perl/Tk is not +available continue with the text mode installer. + +=item B<-lang> I<2-letter lang code> + +(only for GUI installer) tries to start the installer translated into +the language specified by the 2-letter language code. Currently supported +languages are English (en, default), Polish (pl), and German (de). + +=item B<-media> I<[CD|DVD|NET]> + +Overrides the autodetection of the media. + +=item B<-profile> I<profile> + +Preloads a TeX Live profile for equal installations on different systems. + +=item B<-url> I<url> + +Overrides the default URL for network installs. Should start with +either ftp:// or http:// + +=item B<-netarchive> I<dir> + +Overrides the default settings for netarchive. Should be used with care. + +=item B<-diskarchive> I<dir> + +Overrides the default settings for diskarchive. Should be used with care. + +=item B<-no-cls> + +(only for text mode installer) do not clear the screen when entering +a new menu. For debugging purposes. + +=item B<-print-arch> + +Print the detected arch-os combination and exit. + +=item B<-portable> + +Starts the installer for portable use. See below for details. + +=item B<-d>, B<-dd>, B<-ddd> + +Debugging levels. + +=item B<-q>, B<-qq> + +B<-q> disables output to the terminal, while B<-qq> also disables output +to the logfile. + +=item B<-help>, B<-h>, B<-?> + +print a help message. + +=back + +=head1 DESCRIPTION + +The TeX Live installer works across all supported platforms and allows +to install TeX Live from various media including the network. + +=head1 PORTABLE USE + +The TeXLive root directory contains a shell script tl-portable.sh +and a DOS batch file tl-portable.bat which start up a new shell and +command prompt in which TeXLive can be run with minimal impact on +the host system. These files start up install-tl.pl with the +-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: # |