#!/usr/bin/env perl # $Id$ # # Copyright 2007, 2008 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. my $svnrev = '$Revision$'; $svnrev =~ m/: ([0-9]+) /; $::installerrevision = $1; # taken from 00texlive.config: release, $tlpdb->config_release; our $texlive_release; my $localpath; BEGIN { $^W = 1; my $me=$0; $me=~s!\\!/!g if $^O=~/^MSWin(32|64)$/i; if ($me=~m!/!) { ($localpath=$me)=~s!(.*)/.*$!$1!; # we have to chdir to the Master ... chdir($localpath); } else { $localpath = '.'; } $::installerdir='.'; # Windows: The installer uses a minimal subset of Perl. 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. The batchfile wrapper takes care of this. #if ($^O=~/^MSWin(32|64)$/i) { # @INC="$::installerdir/tlpkg/installer/perllib"; #} # All platforms: add the installer modules unshift (@INC, "$::installerdir/tlpkg"); } use Getopt::Long qw(:config no_autoabbrev); use TeXLive::TLUtils qw(platform platform_desc which getenv win32 unix program_exists info log debug tlwarn ddebug 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::TLPOBJ; use TeXLive::TLPDB; use TeXLive::TLConfig; use TeXLive::TLPostActions; use Pod::Usage; use Cwd 'abs_path'; 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 &add_texbindir_to_path &remove_texbindirs_from_path ®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 &init_unshortbat &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 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_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, 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, 'src_splitting_supported' => 1, 'doc_splitting_supported' => 1, 'selected_scheme' => $default_scheme, 'from_dvd' => 0, ); # option handling my $opt_from_dvd = ""; my $opt_gui = 0; 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_version = 0; $opt_gui = 1 if (win32); # default language for GUI installer $::lang = "en"; # use the fancy directory selector for TEXDIR $::alternative_selector = 0; # 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: $localpath/installation.profile\n"; print "Do you want to continue with the exact same settings as before (y/N): "; my $answer = ; if ($answer =~ m/^y(es)?$/i) { $opt_profile = "installation.profile"; } } # first process verbosity/quiet options process_logging_options(); # now the others GetOptions( "fancyselector" => \$::alternative_selector, "from_dvd" => \$opt_from_dvd, "gui" => \$opt_gui, "lang=s" => \$::opt_lang, "location|url=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, "profile-seed=s" => \$opt_profileseed, "profile=s" => \$opt_profile, "scheme=s" => \$opt_scheme, "version" => \$opt_version, "help|?" => \$opt_help) or pod2usage(1); 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 "TeX Live Cross Platform Installer, revision $::installerrevision\n"; if (-r "release-texlive.txt") { # more version info if we can get it. print `sed -n '1p;\$p' release-texlive.txt`; } exit 0; } if ($#ARGV >= 0) { # we still have arguments left, should only be gui, otherwise die if ($ARGV[0] =~ m/^gui$/i) { $opt_gui = 1; } 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; @::start_install_hook = (); @::end_install_hook = (); @::start_postinst_hook = (); @::start_install_hook = (); my $system_tmpdir=get_system_tmpdir(); my $media; # a couple of special uses of install-tl: if ($opt_print_arch) { print platform()."\n"; exit 0; } elsif ($opt_portable) { $::opt_verbosity = -1; $::_platform_ = platform(); $location = getenv('TEXDIR'); die "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 print "Platform ".$::_platform_." not supported\n"; exit 1; } # 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'); # 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'}"; mkdirhier "$vars{'TEXMFSYSCONFIG'}"; if (not -d "$vars{'TEXMFSYSVAR'}" ) { print "About to generate some files... Press "; ; load_tlpdb(); $localtlpdb = $tlpdb; $texlive_release = $tlpdb->config_release; make_var_skeleton "$vars{'TEXMFSYSVAR'}"; #$localtlpdb=new TeXLive::TLPDB; #$localtlpdb->root("$vars{'TEXDIR'}"); # the usual argument 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; } # continuing with normal install # initialize the correct platform platform(); if (!setup_programs ("$::installerdir/tlpkg/installer", "$::_platform_")) { tlwarn("Couldn't set up the necessary programs.\nCannot continue with installation.\nPlease report to texlive\@tug.org.\n"); exit 1; } $ENV{'WGETRC'}="$::installerdir/tlpkg/installer/wgetrc"; # # determine from where we do install # $location = $opt_location; $location || ($location = "$::installerdir"); if ($location =~ m!^(http|ftp)://!i) { $location =~ s,/(tlpkg|archive)?/*$,,; # remove any trailing tlpkg or / $TeXLiveURL = $location; $media = 'NET'; } else { # remove leading file:/+ part $location =~ s!^file://*!/!i; $location = abs_path($location); 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 "Cannot find installation source at $opt_location!"; } # no --location given, but NET installation $TeXLiveURL = $location = TeXLive::TLUtils::give_ctan_mirror(); $media = 'NET'; } } info("Installing from: $location\n"); info("Platform: ", platform, " => \'", platform_desc(platform), "\'\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"); } 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; set_platforms_supported(); set_texlive_default_dirs(); initialize_collections(); set_install_platform(); # 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 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_no_gui) { # 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 = 0; } 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 a consequence of not having X Windows installed or started!\n"); } tlwarn("Error message from creating MainWindow:\n"); tlwarn(" $@\n"); tlwarn("Continuing in text mode...\n"); $opt_gui = 0; } } if ($opt_gui && !$opt_no_gui) { 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) { debug("run_menu has already done the work ... cleaning up!\n"); $finished = 1; } if (!$finished && ($ret != $MENU_INSTALL)) { warn("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{TEXDIR}\n"); do_installation(); } do_cleanup(); exit(0); ################################################################### # # FROM HERE ON ONLY SUBROUTINES # NO VARIABLE DECLARATIONS # ################################################################### sub do_installation { # do the actual installation my $h; foreach $h (@::start_install_hook) { &$h(); } prepare_installation(); if (!$vars{'from_dvd'}) { calc_depends(); save_options_into_tlpdb(); do_install_packages(); } if (win32()) { my $path = TeXLive::TLWinGoo::get_system_env() -> {'/Path'}; $path =~ s/[\s\x00]+$//; log("Old system path: $path\n"); $path = TeXLive::TLWinGoo::get_user_env() -> {'/Path'}; if ($path) { $path =~ s/[\s\x00]+$//; log("Old user path: $path\n"); } else { log("Old user path: none\n"); } add_texbindir_to_path($vars{'TEXDIR'}.'/bin/win32'); $path = TeXLive::TLWinGoo::get_system_env() -> {'/Path'}; $path =~ s/[\s\x00]+$//; log("New system path: $path\n"); $path = TeXLive::TLWinGoo::get_user_env() -> {'/Path'}; if ($path) { $path =~ s/[\s\x00]+$//; log("New user path: $path\n"); } else { log("New user path: none\n"); } # setenv_reg('TEXMFSYSVAR', $vars{'TEXMFSYSVAR'}) if $vars{'from_dvd'}; setenv_reg('TEXMFCNF', $vars{'TEXMFSYSVAR'}.'/web2c') if $vars{'from_dvd'}; broadcast_env(); create_uninstaller($vars{'TEXDIR'}, $vars{'TEXDIRW'}, $vars{'TEXMFSYSVAR'}, $vars{'TEXMFSYSCONFIG'}); } foreach $h (@::start_postinst_hook) { &$h(); } do_postinst_stuff(); $localtlpdb->save unless $vars{'from_dvd'}; foreach $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)); 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) { 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{'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 # First look for packages in the selected scheme. my $scheme=$tlpdb->get_package($vars{'selected_scheme'}); if (!defined($scheme)) { die ("Scheme $vars{'selected_scheme'} not defined, vars:\n"); dump_vars(\*STDOUT); } 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 and bin-tlpsv.win32, too if (grep(/^win32$/,@archs)) { $install{"bin-tlperl.win32"} = 1; $install{"bin-tlgs.win32"} = 1; $install{"bin-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; ddebug("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; 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 $p (keys %install) { my $tlpobj = $tlpdb->get_package($p); if (not(defined($tlpobj))) { tlwarn("$p should be installed but cannot be found in texlive.tlpdb, disabling it!\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("Cannot load TeX Live Database from $master"); } # 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' } = ( $tlpdb->option_paper eq "letter" ? 1 : 0 ); $vars{'option_symlinks'} = $tlpdb->option_create_symlinks; $vars{'sys_bin'} = $tlpdb->option_sys_bin; $vars{'sys_man'} = $tlpdb->option_sys_man; $vars{'sys_info'} = $tlpdb->option_sys_info; # 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; 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 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_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/; if ($vars{'option_symlinks'}) { print $fh "sys_bin ", $vars{'sys_bin'}, "\n" if $key =~ /^sys_bin/; print $fh "sys_man ", $vars{'sys_man'}, "\n" if $key =~ /^sys_man/; print $fh "sys_info ", $vars{'sys_info'}, "\n" if $key =~ /^sys_info/; } 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/; } 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 () { 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{$_}; } } # 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); } install_packages($tlpdb,$media,$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 { $localtlpdb->option_platform($::_platform_); $localtlpdb->option_location($location); $localtlpdb->option_paper($vars{'option_letter'} ? "letter" : "a4"); $localtlpdb->option_create_formats($vars{'option_fmt'} ? "1" : "0"); $localtlpdb->option_create_symlinks($vars{'option_symlinks'} ? "1" : "0"); $localtlpdb->option_sys_bin($vars{'sys_bin'}); $localtlpdb->option_sys_info($vars{'sys_info'}); $localtlpdb->option_sys_man($vars{'sys_man'}); $localtlpdb->option_install_docfiles($vars{'option_doc'} ? "1" : "0"); $localtlpdb->option_install_srcfiles($vars{'option_doc'} ? "1" : "0"); my @archs; foreach (keys %vars) { if (m/^binary_(.*)$/ ) { if ($vars{$_}) { push @archs, $1; } } } $localtlpdb->option_available_architectures(@archs); $localtlpdb->save() unless $vars{'from_dvd'}; } # 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); # 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})); } } $ENV{'TEXMFSYSVAR'} = $vars{'TEXMFSYSVAR'} if $vars{'from_dvd'}; # 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"; 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'}"; } 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 # # (re-)initialize batchfile for uninstalling shortcuts if (win32() and !$opt_portable) { mkdirhier("$TEXDIRW/tlpkg/installer") if $vars{'from_dvd'}; init_unshortbat($TEXDIRW); } foreach my $package (sort keys %install) { if ($install{$package} && defined($PostInstall{$package})) { info("running post install action for $package\n"); &{$PostInstall{$package}}($TEXDIR, $TEXDIRW, $TEXMFSYSVAR, $TEXMFLOCAL); } } # $opt_portable: no %install but we still want xetex postinstall &{$PostInstall{'xetex'}}($TEXDIR, $TEXDIRW, $TEXMFSYSVAR, $TEXMFLOCAL) if $opt_portable; update_assocs() if win32(); # 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"); my $tlp = $vars{'from_dvd'} ? $tlpdb : $localtlpdb; TeXLive::TLUtils::create_fmtutil($tlp, #$localtlpdb, "$TEXMFSYSVAR/web2c/fmtutil.cnf", "$TEXMFLOCAL/web2c/fmtutil-local.cnf"); info("writing updmap.cfg to $TEXMFSYSVAR/web2c/updmap.cfg\n"); TeXLive::TLUtils::create_updmap ($tlp, #$localtlpdb, "$TEXMFSYSVAR/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($tlp, #$localtlpdb, "$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($tlp, #$localtlpdb, "$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"); if (platform() eq "hppa-hpux") { # we didn't get a texlua binary for hppa-hpux, so try texconfig system("texconfig", "paper", "letter"); } else { system("texlua", "$TEXDIR/texmf/scripts/texlive/texconf.tlu", "--sys", "--noformat", "paper", "letter"); } } # all formats option if ($vars{'option_fmt'}) { info("pre-generating all format files (fmtutil-sys --all), be patient..."); #system('fmtutil-sys', '--all'); # try to capture that output log(`fmtutil-sys --all 2>&1`); info("done\n"); } # option_links if ($vars{'option_symlinks'}) { # bin files my @files; mkdirhier $vars{'sys_bin'}; if (-w $vars{'sys_bin'}) { info("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 { info("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'}) { info("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 { info("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'}) { info("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 { info("destination of man symlink $vars{'sys_man'} not writable, no linking of man files done!\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: $!\n"); my @texmfcnflines = ; 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: $!\n"; print TMF <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")) { 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; } } 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 { warn("Cannot create log file $vars{'TEXDIRW'}/install-tl.log: $!\nNot 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"; } #print "Don't forget to set TEXMFSYSVAR to ".$vars{'TEXMFSYSVAR'}."!!!\n" #print "Don't forget to set TEXMFCNF to\n ". $vars{'TEXMFSYSVAR'}."/web2c !!!\n" # if ($vars{'from_dvd'} and !win32()); } __END__ =head1 NAME install-tl - the 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. Post-installation configuration, packages updates, and more, are now available through B(1), the TeX Live Manager (L). The most up-to-date version of this documentation is on the Internet at L. =head1 OPTIONS =over 4 =item B<-gui> If possible, use the GUI installer (default on Windows). This requires the Perl/Tk module (L; 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 language code. Currently supported languages: English (en, default), German (de), French (fr), Dutch (nl), Polish (pl) and Slovenian (sl). =item B<-location> I Provide an installation source, either a local directory via C or a C url, or a network location via a C or C url. If the location is local, the installation type (compressed or live) is automatically determined, by checking for the presence of a C 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: -location /local/TL/repository/copy If the location is on the network, trailing C characters and/or trailing C and C components are ignored. For example, you could choose a particular CTAN mirror with something like: -location http://ctan.example.org/tex-archive/texlive/tlnet/2008 Of course a proper hostname and its particular top-level CTAN path have to be specified. (The list of CTAN mirrors is maintained at L.) The default is to pick a mirror automatically, using L; the chosen mirror is used for the entire download. (See L for more about the CTAN mirror services.) =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<-portable> Start the installer for portable use---but use the C scripts instead of this option. See below for details. =item B<-print-arch> Print the detected arch-os combination and exit. =item B<-profile> I Load the I file for repeated installations on different systems. A I 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 and I collection variable is defined in the profile, then the collections which the specified scheme requires are installed. Thus, a simple line C together with the definitions of the paths (C, C, C, C, C, C) suffices to install the medium scheme with all default options. =item B<-scheme> I Schemes are the highest level of package grouping in TeX Live; the default is to use the C 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 argument may optionally have a prefix C. The list of supported scheme names depends on what your installation location provides; see the interactive menu list. =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 Write both all messages (informational, debugging, warnings) to I, 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 for the I release. =item B<--help>, B<-help>, B<-?> Display this help and exit. =item B<--version>, B<-version> Output version information and exit. =back As usual, all options can be specified with either C<-> or C<-->, and arguments can be be separated from their options by either a space or C<=>. =head1 PORTABLE USE The TeX Live root directory contains a shell script C and a DOS batch file C 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 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) 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: #