diff options
author | Siep Kroonenberg <siepo@cybercomm.nl> | 2011-03-23 17:48:43 +0000 |
---|---|---|
committer | Siep Kroonenberg <siepo@cybercomm.nl> | 2011-03-23 17:48:43 +0000 |
commit | af239484eb8ca0c0bec8804f054f7e482b9d6fe6 (patch) | |
tree | 74e4b1c2a606563741bbbecefb1d10fce82bf4a0 | |
parent | 161cc5508f7aa14ffe0713f3d3e4979b551ca6c4 (diff) |
Experimental installer with in-place and revised portable options
git-svn-id: svn://tug.org/texlive/trunk@21811 c570f23f-e606-0410-a88d-b1316a301751
-rwxr-xr-x | Master/install-tl-new | 2186 | ||||
-rwxr-xr-x | Master/install-tl-new.bat | 64 | ||||
-rw-r--r-- | Master/tlpkg/installer/install-menu-perltk-new.pl | 1054 | ||||
-rwxr-xr-x | Master/tlpkg/installer/install-menu-text-new.pl | 1070 |
4 files changed, 4374 insertions, 0 deletions
diff --git a/Master/install-tl-new b/Master/install-tl-new new file mode 100755 index 00000000000..db75ffbfc35 --- /dev/null +++ b/Master/install-tl-new @@ -0,0 +1,2186 @@ +#!/usr/bin/env perl +# $Id: install-tl 21776 2011-03-21 01:47:19Z reinhardk $ +# +# Copyright 2007, 2008, 2009, 2010 Reinhard Kotucha, Norbert Preining, +# Karl Berry. +# +# 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) + +my $svnrev = '$Revision: 21776 $'; +$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 native_slashify forward_slashify); +#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; + +# global list of lines that get logged (see TLUtils.pm::_logit). +@::LOGLINES = (); + +# global list of warnings +@::WARNLINES = (); + +# we play around with the environment, place to keep original +my %origenv = (); + +# $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, + 'in_place' => 0, + 'portable' => 0, + ); + +# option handling +my $opt_in_place = 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; +my $opt_persistent_downloads = 1; +my $opt_allow_ftp = 0; + +# 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, + "in-place" => \$opt_in_place, + "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-platform|print-arch" => \$opt_print_arch, + "force-platform|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, + "persistent-downloads!" => \$opt_persistent_downloads, + "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; +} + +die "Options custom-bin and in-place are incompatible." + if ($opt_in_place and $opt_custom_bin); + +die "Options profile and in-place are incompatible." + if ($opt_in_place and $opt_profile); + +die "Options profile-seed and in-place are incompatible." + if ($opt_in_place and $opt_profileseed); + +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) { # for now, not allowed if in_place + 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; +our @media_available; + +# special uses of install-tl: +if ($opt_print_arch) { + print platform()."\n"; + exit 0; +} + + +# continuing with normal install + +# check as soon as possible for GUI functionality to give people a chance +# to 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'; + @media_available = qw/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") { + push @media_available, 'local_compressed'; + } + + if (-d "$location/texmf/web2c") { + push @media_available, 'local_uncompressed'; + } + + if (member('local_compressed', @media_available)) { + $media = 'local_compressed'; + # for in_place option we want local_uncompressed media + $media = 'local_uncompressed' if $opt_in_place && + member('local_uncompressed', @media_available); + } elsif (member('local_uncompressed', @media_available)) { + $media = 'local_uncompressed'; + } 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 && (-r "$opt_custom_bin/kpsewhich" + || -r "$opt_custom_bin/kpsewhich.exe")) { + info("Platform overridden, binaries taken from $opt_custom_bin\n" + . "and will be installed into .../bin/custom.\n"); + } else { + tldie("$opt_custom_bin: Argument to -custom-bin must be a directory " + . "with TeX Live binaries.\n"); + } +} +if ($media eq "local_uncompressed") { + info("Distribution: live (uncompressed)\n"); +} elsif ($media eq "local_compressed") { + info("Distribution: inst (compressed)\n"); +} elsif ($media eq "NET") { + info("Distribution: net (downloading)\n"); + info("Using URL: $TeXLiveURL\n"); + TeXLive::TLUtils::setup_persistent_downloads() if $opt_persistent_downloads; +} else { + info("Distribution: $media\n"); +} +info("Directory for temporary files: $system_tmpdir\n"); + +if ($opt_in_place and ($media ne "local_uncompressed")) { + print "TeX Live not local or not decompressed; 'in_place' option not applicable\n"; + $opt_in_place = 0; +} elsif ($opt_in_place and (!TeXLive::TLUtils::texdir_check($::installerdir))) { + print "Installer dir not writable; 'in_place' option not applicable\n"; + $opt_in_place = 0; +} +$vars{'in_place'} = $opt_in_place; +$opt_scheme = "" if $opt_in_place; +$vars{'portable'} = $opt_portable; + +load_tlpdb(); + +log("Installer revision: $::installerrevision\n"); +log("Database revision: " . $tlpdb->config_revision . "\n"); + +# correctly set the splitting support +# for local_uncompressed we always support splitting +if (($media eq "NET") || ($media eq "local_compressed")) { + $vars{'src_splitting_supported'} = $tlpdb->config_src_container; + $vars{'doc_splitting_supported'} = $tlpdb->config_doc_container; +} +$texlive_release = $tlpdb->config_release; +if ($media eq "local_uncompressed") { + # existing installation may not have 00texlive.config metapackage + # so use TLConfig to establish what release we have + $texlive_release ||= $TeXLive::TLConfig::ReleaseYear; +} + +# 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 <<END_MISMATCH; +$0: The TeX Live versions of the local installation +and the repository being accessed are not compatible: + local: $TeXLive::TLConfig::ReleaseYear + repository: $texlive_release +Perhaps you need to use a different CTAN mirror? +END_MISMATCH +} + +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}-new.pl") { + require("installer/install-menu-${opt_gui}-new.pl"); + } else { + tlwarn("UI plugin $opt_gui not found,\n"); + tlwarn("Using text mode installer.\n"); + require("installer/install-menu-text-new.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); +} + +my $varsdump; +foreach my $key (sort keys %vars) { + $varsdump.=" $key: \"" . $vars{$key} . "\"\n"; +} + +log("Settings:\n" . $varsdump); + +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'} = $vars{'TEXDIR'}; # no longer used + sanitise_options(); + info("Installing to: $vars{TEXDIR}\n"); + do_installation(); +} + +do_cleanup(); + +exit(0); + + +################################################################### +# +# FROM HERE ON ONLY SUBROUTINES +# NO VARIABLE DECLARATIONS +# +################################################################### + +sub do_installation { + install_warnlines_hook(); + 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{'in_place'}) { + 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{'in_place'}; + do_postinst_stuff(); + if (win32() || $vars{'portable'}) { + print welcome(); + } else { + print welcome_paths(); + } + print warnings_summary(); +} + +# 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 $TEXMFSYSCONFIG="$vars{'TEXMFSYSCONFIG'}"; + my $TEXMFVAR="$vars{'TEXMFVAR'}"; + my $TEXMFCONFIG="$vars{'TEXMFCONFIG'}"; + my $TEXMFLOCAL="$vars{'TEXMFLOCAL'}"; + my $tmv; + + do_texmf_cnf(); + + # + # 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"); + } + + # + # create package backup directory for tlmgr autobackup to work + mkdirhier("$TEXDIR/$TeXLive::TLConfig::PackageBackupDir"); + + # 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. + %origenv = %ENV; + my @TMFVARS0=qw(VARTEXFONTS + TEXMF SYSTEXMF VARTEXFONTS + TEXMFDBS WEB2C TEXINPUTS TEXFORMATS MFBASES MPMEMS TEXPOOL MFPOOL MPPOOL + PSHEADERS TEXFONTMAPS TEXPSHEADERS TEXCONFIG TEXMFCNF + TEXMFMAIN TEXMFDIST TEXMFLOCAL TEXMFSYSVAR TEXMFSYSCONFIG + TEXMFVAR TEXMFCONFIG TEXMFHOME TEXMFCACHE); + + if (defined($ENV{'TEXMFCNF'})) { + 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})); + } + + # 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 local_uncompressed + # we use the tlpdb from the local_uncompressed, otherwise + # the one we have locally created, for all the further actions + my $usedtlpdb = $vars{'in_place'} ? $tlpdb : $localtlpdb; + + + if (win32()) { + debug "Actual environment:\n".`set`."\n\n"; + debug 'Effective TEXMFCNF: '.`kpsewhich -expand-path=\$TEXMFCNF`."\n"; + } + + if (win32() and !$vars{'portable'} and !$vars{'in_place'}) { + create_uninstaller($vars{'TEXDIR'}, $vars{'TEXDIR'}, + $vars{'TEXMFSYSVAR'}, $vars{'TEXMFSYSCONFIG'}); + # TODO: custom uninstaller for in_place + # (re-)initialize batchfile for uninstalling shortcuts + } + + # Step 4: run the programs + + if (!$vars{'in_place'}) { + 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("writing language.dat.lua data to $TEXMFSYSVAR/tex/generic/config/language.dat.lua\n"); + TeXLive::TLUtils::create_language_lua($usedtlpdb, + "$TEXMFSYSVAR/tex/generic/config/language.dat.lua", + "$TEXMFLOCAL/tex/generic/config/language-local.dat.lua"); + + info("running mktexlsr $TEXMFSYSVAR $TEXMFSYSCONFIG\n"); + system("mktexlsr", $TEXMFSYSVAR, $TEXMFSYSCONFIG); + + info("running updmap-sys..."); + # system('updmap-sys', '--nohash'); + log(`updmap-sys --nohash 2>&1`); + info("done\n"); + + # now work through the options if specified at all + + # letter instead of a4 + if ($vars{'option_letter'}) { + # set paper size, but do not execute any post actions, in this case + # it would be: + # - mktexlsr + # - fmtutil-sys -all + info("setting default paper size to letter\n"); + log(`tlmgr --no-execute-actions paper letter 2>&1`); + } + + # now rerun mktexlsr for updmap-sys and tlmgr paper letter updates. + info("re-running mktexlsr $TEXMFSYSVAR $TEXMFSYSCONFIG\n"); + system("mktexlsr", $TEXMFSYSVAR, $TEXMFSYSCONFIG); + + # luatex/context + # we only call luatools --generate once at installation time, the + # rest must be managed by the user, Taco email 2010-05-26 + # + # disabled since we are not multi user capable, email taco 2010-06-08 + #if (exists($install{"context"}) && $install{"context"} == 1) { + # info("making ConTeXt MkIV cache with luatools --generate, be patient..."); + # chomp (my $tmv = `kpsewhich -expand-braces="$vars{TEXMFVAR}"`); + # log("\n TEXMFVAR=$vars{TEXMFVAR}, expanded to $tmv for mkdirhier\n"); + # mkdirhier ($tmv); # don't be asked about making the dir + # log(`luatools --generate 2>&1`); + # info("done\n"); + #} + + # 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 + # for portable, this option should be unset + # it should not be necessary to test separately for portable + do_path_adjustments() if $vars{'option_path'}; + + # now 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 tlpdb + # no need to test for portable or in_place: + # the menus (or profile?) should have set the required options + do_tlpdb_postactions(); +} + + +sub do_tlpdb_postactions { + info ("running package specific postactions\n"); + # Run the post installation code in the postaction tlpsrc entries + # For now the option_desktop_integrations maps to both desktop + # and menu entries, but we can split that later + # option settings already reflect portable- and in_place options. + my $usedtlpdb = $vars{'in_place'} ? $tlpdb : $localtlpdb; + foreach my $package ($usedtlpdb->list_packages) { + &TeXLive::TLUtils::do_postaction("install", + $usedtlpdb->get_package($package), + $vars{'option_file_assocs'}, + $vars{'option_desktop_integration'}, + $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'}); + 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 @changedtmf = (); # install to disk: write only changed items + + my $yyyy = $TeXLive::TLConfig::ReleaseYear; + my $rewritetmflua = 0; # need a new texmfcnf.lua? + + # 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 write a new setting. + my $deftmlocal = dirname($vars{'TEXDIR'}); + $deftmlocal .= "/texmf-local"; + if ("$vars{'TEXMFLOCAL'}" ne "$deftmlocal") { + push @changedtmf, "TEXMFLOCAL = $vars{'TEXMFLOCAL'}\n"; + } + } elsif ($line =~ m/^TEXMFSYSVAR/) { + if ("$vars{'TEXMFSYSVAR'}" ne "$vars{'TEXDIR'}/texmf-var") { + push @changedtmf, "TEXMFSYSVAR = $vars{'TEXMFSYSVAR'}\n"; + } + } elsif ($line =~ m/^TEXMFSYSCONFIG/) { + if ("$vars{'TEXMFSYSCONFIG'}" ne "$vars{'TEXDIR'}/texmf-config") { + push @changedtmf, "TEXMFSYSCONFIG = $vars{'TEXMFSYSCONFIG'}\n"; + } + } elsif ($line =~ m/^TEXMFVAR/) { + if ($vars{"TEXMFVAR"} ne "~/.texlive$yyyy/texmf-var") { + push @changedtmf, "TEXMFVAR = $vars{'TEXMFVAR'}\n"; + $rewritetmflua = 1; # TEXMFVAR change -> new texmfcnf.lua + } + } elsif ($line =~ m/^TEXMFCONFIG/) { + if ("$vars{'TEXMFCONFIG'}" ne "~/.texlive$yyyy/texmf-config") { + push @changedtmf, "TEXMFCONFIG = $vars{'TEXMFCONFIG'}\n"; + } + } elsif ($line =~ m/^TEXMFHOME/) { + if ("$vars{'TEXMFHOME'}" ne "~/texmf") { + push @changedtmf, "TEXMFHOME = $vars{'TEXMFHOME'}\n"; + } + } elsif ($line =~ m/^OSFONTDIR/) { + if (win32()) { + push @changedtmf, "OSFONTDIR = \$SystemRoot/fonts//\n"; + } + } + } + + if ($vars{'portable'}) { + push @changedtmf, "ASYMPTOTE_HOME = \$TEXMFCONFIG/asymptote\n"; + } + + my ($TMF, $TMFLUA); + # we want to write only changes to texmf.cnf + # even for in_place installation + $TMF = ">$vars{'TEXDIR'}/texmf.cnf"; + open(TMF, $TMF) || die "open($TMF) failed: $!"; + print TMF <<EOF; +% (Public domain.) +% This texmf.cnf file should contain only your personal changes from the +% original texmf.cnf (for example, as chosen in the installer). +% +% That is, if you need to make changes to texmf.cnf, put your custom +% settings in this file, which is .../texlive/YYYY/texmf.cnf, rather than +% the distributed file (which is .../texlive/YYYY/texmf/web2c/texmf.cnf). +% And include *only* your changed values, not a copy of the whole thing! +% +EOF + foreach (@changedtmf) { + # avoid absolute paths for TEXDIR, use $SELFAUTOPARENT instead + s/^(TEXMF\w+\s*=\s*)\Q$vars{'TEXDIR'}\E/$1\$SELFAUTOPARENT/; + 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{...}. See texmf/web2c/texmf.cnf. +shell_escape = 0 +EOF +; + } + close(TMF) || warn "close($TMF) failed: $!"; + + if ($rewritetmflua) { + $TMFLUA = ">$vars{'TEXDIR'}/texmfcnf.lua"; + open(TMFLUA, $TMFLUA) || die "open($TMFLUA) failed: $!"; + + print TMFLUA <<EOF; +-- (Public domain.) +-- This texmfcnf.lua file should exist only if you have personal changes +-- from the distributed file; for example, if TEXMFVAR was changed in +-- the installer. +-- +return { TEXMFCACHE = '$vars{"TEXMFVAR"}' } +EOF + + close(TMFLUA) || warn "close($TMFLUA) 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/2010 => $TEXDIR +# TEXLIVE_INSTALL_TEXMFSYSVAR $TEXDIR/texmf-var +# TEXLIVE_INSTALL_TEXMFSYSCONFIG $TEXDIR/texmf-config +# TEXLIVE_INSTALL_TEXMFLOCAL $tex_prefix/texmf-local +# TEXLIVE_INSTALL_TEXMFVAR ~/.texlive2010/texmf-var +# TEXLIVE_INSTALL_TEXMFCONFIG ~/.texlive2010/texmf-config +# TEXLIVE_INSTALL_TEXMFHOME '$HOME/texmf' + +sub set_texlive_default_dirs { + my $tex_prefix = $vars{'in_place'} ? $::installerdir : + 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'; + } + # for portable and in_place installation we want everything in one directory + $vars{'TEXDIR'} = ($vars{'portable'} || $vars{'in_place'}) + ? $tex_prefix : "$tex_prefix/$texlive_release"; + + my $texmfsysvar = getenv('TEXLIVE_INSTALL_TEXMFSYSVAR'); + $texmfsysvar ||= $vars{'TEXDIR'} . '/texmf-var'; + $vars{'TEXMFSYSVAR'} = $texmfsysvar; + + my $texmfsysconfig = getenv('TEXLIVE_INSTALL_TEXMFSYSCONFIG'); + $texmfsysconfig ||= $vars{'TEXDIR'} . '/texmf-config'; + $vars{'TEXMFSYSCONFIG'}=$texmfsysconfig; + + my $texmflocal = getenv('TEXLIVE_INSTALL_TEXMFLOCAL'); + $texmflocal ||= "$tex_prefix/texmf-local"; + $vars{'TEXMFLOCAL'} = $texmflocal; + + $vars{'TEXDIR'} = $vars{'in_place'} + ? abs_path($::installerdir) : $vars{'TEXDIR'}; + + my $texmfhome = getenv('TEXLIVE_INSTALL_TEXMFHOME'); + $texmfhome ||= "~"; + $vars{'TEXMFHOME'}="$texmfhome/texmf"; + + # use the $texmfhome value just computed for these. + my $yyyy = $TeXLive::TLConfig::ReleaseYear; + my $texmfvar = getenv('TEXLIVE_INSTALL_TEXMFVAR'); + $texmfvar ||= "$texmfhome/.texlive$yyyy/texmf-var"; + $vars{'TEXMFVAR'} = $texmfvar; + + my $texmfconfig = getenv('TEXLIVE_INSTALL_TEXMFCONFIG'); + $texmfconfig ||= "$texmfhome/.texlive$yyyy/texmf-config"; + $vars{'TEXMFCONFIG'} = $texmfconfig; + + # for portable installation we want everything in one directory + if ($vars{'portable'}) { + $vars{'TEXMFHOME'} = "\$TEXMFLOCAL"; + $vars{'TEXMFVAR'} = "\$TEXMFSYSVAR"; + $vars{'TEXMFCONFIG'} = "\$TEXMFSYSCONFIG"; + } +} + +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)) { + my $do_die = 1; + # if that failed, and: + # - we are installing from the network + # - the location string does not contain "tlnet" + # then we simply add "/systems/texlive/tlnet" in case someone just + # gave an arbitrary CTAN mirror address without the full path + if ($media eq "NET" && $location !~ m/tlnet/) { + tlwarn("First attempt for net installation failed;\n"); + tlwarn(" repository url does not contain \"tlnet\",\n"); + tlwarn(" retrying with \"/systems/texlive/tlnet\" appended.\n"); + $location .= "/systems/texlive/tlnet"; + $master = $location; + # + # since we change location, we reset the error count of the + # download object + $::tldownload_server->enable if defined($::tldownload_server); + # + $tlpdb = TeXLive::TLPDB->new(root => $master); + if (!defined($tlpdb)) { + tlwarn("Oh well, adding tlnet did not help.\n"); + tlwarn(<<END_EXPLICIT_MIRROR); + +You may want to try specifying an explicit or different CTAN mirror; +see the information and examples for the -repository option at +http://tug.org/texlive/doc/install-tl.html +(or in the output of install-tl --help). + +END_EXPLICIT_MIRROR + } else { + # hurray, that worked out + info("Loading $master/$TeXLive::TLConfig::InfraLocation/$TeXLive::TLConfig::DatabaseName\n"); + $do_die = 0; + } + } + die "$0: Could not load TeX Live Database from $master, goodbye.\n" + if $do_die; + } + # 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_autobackup'} = $tlpdb->option("autobackup"); + $vars{'option_backupdir'} = $tlpdb->option("backupdir"); + $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'} = 0 if !defined($vars{'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"); + # this option is not stored in tlpdb if an existing installation is used + $vars{'option_write18_restricted'} ||= 1; + + # 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/; + 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 =~ /^TEXMFVAR/; + print $fh "$key $vars{$key}\n" if $key =~ /^TEXMFCONFIG/; + 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 =~ /^in_place/; + print $fh "$key $vars{$key}\n" if $key =~ /^portable/; + } + 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-/); + } +} + +# helper subroutine to do sanity check of options before installation +sub sanitise_options { + # portable option overrides any system integration options + $vars{'option_path'} &&= !$vars{'portable'}; + $vars{'option_file_assocs'} &&= !$vars{'portable'}; + $vars{'option_desktop_integration'} &&= !$vars{'portable'}; +} + +sub prepare_installation { + make_var_skeleton "$vars{'TEXMFSYSVAR'}"; + make_local_skeleton "$vars{'TEXMFLOCAL'}"; + mkdirhier "$vars{'TEXMFSYSCONFIG'}"; + + if ($vars{'in_place'}) { + $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); + } + my $media0 = $media; + $media0 = 'CD' if $media eq 'local_compressed'; + $media0 = 'DVD' if $media eq 'local_uncompressed'; + if (!install_packages($tlpdb,$media0,$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 ("autobackup", $vars{'option_autobackup'}); + $localtlpdb->option ("backupdir", $vars{'option_backupdir'}); + $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{'in_place'}; +} + +# this seems not to be used anymore + +#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"); +# $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{'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", +# "install_docfiles"); +# $vars{'option_src'} = +# $previoustlpdb->option_pkg("00texlive.installation", +# "install_srcfiles"); +# $vars{'option_fmt'} = +# $previoustlpdb->option_pkg("00texlive.installation", +# "create_formats"); +# $vars{'option_desktop_integration'} = 1 if win32(); +# $vars{'option_path'} = +# $previoustlpdb->option_pkg("00texlive.installation", +# "path"); +# $vars{'option_path'} = 0 if !defined($vars{'option_path'}); +# $vars{'option_path'} = 1 if win32(); +# $vars{'option_sys_bin'} = +# $previoustlpdb->option_pkg("00texlive.installation", +# "sys_bin"); +# $vars{'option_sys_man'} = +# $previoustlpdb->option_pkg("00texlive.installation", +# "sys_man"); +# $vars{'sys_info'} = +# $previoustlpdb->option_pkg("00texlive.installation", +# "sys_info"); +# # +# # import the set of selected architectures +# my @aar = $previoustlpdb->setting_pkg("00texlive.installation", +# "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{'TEXDIR'}/install-tl.log")) { + $::LOGFILE = \*LOGF; + foreach my $line(@::LOGLINES) { + print $::LOGFILE "$line"; + } + } else { + tlwarn("$0: Cannot create log file $vars{'TEXDIR'}/install-tl.log: $!\n" + . "Not writing out log lines.\n"); + } + } + + # remove temporary files from TEXDIR/temp + if (($media eq "local_compressed") or ($media eq "NET")) { + debug("Remove temporary downloaded containers...\n"); + rmtree("$vars{'TEXDIR'}/temp") if (-d "$vars{'TEXDIR'}/temp"); + } + + # write the profile out + if ($vars{'in_place'}) { + create_profile("$vars{'TEXDIR'}/texlive.profile"); + debug("Profile written to $vars{'TEXDIR'}/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{'TEXDIR'}/install-tl.log") { + print "Logfile: $vars{'TEXDIR'}/install-tl.log\n"; + } else { + print "No logfile\n"; + } +} + + +# Return the basic welcome message. + +sub welcome { + my $welcome = <<"EOF"; + + See + $::vars{'TEXDIR'}/index.html + for links to documentation. The TeX Live web site (http://tug.org/texlive/) + contains updates and corrections. + + TeX Live is a joint project of the TeX user groups around the world; + please consider supporting it by joining the group best for you. The + list of groups is available on the web at http://tug.org/usergroups.html. + + Welcome to TeX Live! +EOF + return $welcome; +} + + +# The same welcome message as above but with hints about C<PATH>, +# C<MANPATH>, and C<INFOPATH>. + +sub welcome_paths { + my $welcome = welcome (); + + # ugly, remove welcome msg; better than repeating the whole text, though. + $welcome =~ s/\n Welcome to TeX Live!\n//; + + $welcome .= <<"EOF"; + + Add $::vars{'TEXDIR'}/texmf/doc/man to MANPATH, if not dynamically determined. + Add $::vars{'TEXDIR'}/texmf/doc/info to INFOPATH. +EOF + + if ($::vars{'in_place'} and !win32()) { + $welcome .= <<"EOF"; + Set TEXMFCNF to $::vars{'TEXMFSYSVAR'}/web2c. +EOF + } + + $welcome .= <<"EOF"; + + Most importantly, add $::vars{'TEXDIR'}/bin/$::vars{'this_platform'} + to your PATH for current and future sessions. +EOF + + unless ($ENV{"TEXLIVE_INSTALL_ENV_NOCHECK"}) { + # check for tex-related envvars. + my $texenvs = ""; + for my $evar (sort keys %origenv) { + next if $evar =~ /^(_ + |.*PWD + |GENDOCS_TEMPLATE_DIR|PATH|SHELLOPTS + )$/x; # don't worry about these + if ("$evar $origenv{$evar}" =~ /tex/i) { # check both key and value + $texenvs .= " $evar=$origenv{$evar}\n"; + } + } + if ($texenvs) { + $welcome .= <<"EOF"; + + ---------------------------------------------------------------------- + The following environment variables contain the string "tex" + (case-independent). If you're doing anything but adding personal + directories to the system paths, they may well cause trouble with + some parts of running TeX. If you encounter problems, try unsetting + them. Please ignore any spurious matches that are unrelated to TeX. + +$texenvs ---------------------------------------------------------------------- +EOF + } + } + + $welcome .= <<"EOF"; + + Welcome to TeX Live! +EOF + + return $welcome; +} + + +# +# remember the warnings issued +sub install_warnlines_hook { + push @::warn_hook, sub { push @::WARNLINES, @_; }; +} + +# +# a summary of warnings if there were any +sub warnings_summary { + return '' unless @::WARNLINES; + my $summary = <<EOF; + + There were some warnings during the installation process. + Here is a summary of warning messages: +EOF + $summary .= ' ' . join(' ', @::WARNLINES) . "\n"; + return $summary; +} + + +# +# 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 [I<option>]... + +install-tl.bat [I<option>]... + +=head1 DESCRIPTION + +This installer creates a runnable TeX Live installation from various +media, including over the network. The installer works across all +platforms supported by TeX Live. For information on initially +downloading the 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, use C<tlmgr> (reference below) after the initial installation is +completely. + +The default is C<scheme-full>, to install everything, and this is highly +recommended. + +=head1 REFERENCES + +Post-installation configuration, package updates, and much 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<llcode> + +(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), Serbian (sr), 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.) + +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 argument C<ctan> +as an abbreviation for this. See L<http://ctan.org> for more about CTAN +and its mirrors. + +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>. + +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 + +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<-all-options> + +Normally options not regarding the current platform 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<-custom-bin> I<path> + +If you have built your own binaries for your system (probably because +your platform was not supported by TeX Live out of the box), this option +allows you to give the I<path> to a directory where the binaries for the +current system are present. The installation will continue as usual, 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 post-install actions. + +=item B<-debug-translation> + +In GUI mode, this switch makes C<tlmgr> report any missing, or more +likely untranslated, messages to standard error. Helpful for +translators to see what remains to be done. + +=item B<--help>, B<-help>, B<-?> + +Display this help and exit. + +=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<-force-platform> I<platform> + +Instead of auto-detecting the current platform, use I<platform>. +Binaries for this platform must be present and they must actually be +runnable, or installation will fail. C<-force-arch> is a synonym. + +=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<--persistent-downloads> + +=item B<--no-persistent-downloads> + +For net installs, activating this option makes the installer try to set up a +persistent connection using the Net::LWP Perl module. +This opens only one connection between your computer and the server +per session and reuses it, instead of initiating a new download for +each package. + +This option is turned on by default, and the installation program will +fall back to using C<wget> if this is not possible. To disable usage of +LWP and persistent connections, use C<--no-persistent-downloads>. + +=item B<-portable> + +Install for portable use. This option minimazes the impact on the host +system making TeX Live self-contained in a single directory and +usable from portable drives. See section B<PORTABLE USE> below. + +=item B<-print-platform> + +Print the TeX Live identifier for the detected platform +(hardware/operating system) combination to standard output, and exit. +C<-print-arch> is a synonym. + +=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 +C<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<TEXMFHOME>, C<TEXMFLOCAL>, C<TEXMFSYSCONFIG>, C<TEXMFSYSVAR>) suffices +to install the medium scheme with all default options. + +=item B<-q> + +Omit normal informational messages. + +=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<-v> + +Include debugging messages; repeat for maximum debugging, as in C<-v +-v>. (Further repeats are accepted but ignored.) + +=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 root directory of a TeX Live installation contains a shell script +C<tl-portable> and a DOS batch file C<tl-portable.bat> which start up a +new shell (command prompt), in which TeX Live can be run self-contained. + +When running these scripts from a non-writable medium, some preparation +of the host system is done on the first run, in the host directory +C<~/.tlportableYYYY>. Otherwise, the host system is not touched. + +=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/install-tl-new.bat b/Master/install-tl-new.bat new file mode 100755 index 00000000000..37541572781 --- /dev/null +++ b/Master/install-tl-new.bat @@ -0,0 +1,64 @@ +@echo off
+rem $Id: install-tl.bat 15942 2009-11-06 23:54:05Z trzeciak $
+rem Wrapper script to set up environment for installer
+rem
+rem Public domain.
+rem Originally written 2009 by Tomasz M. Trzeciak.
+
+rem First, check if this is DOS based system
+rem in DOS '^' is just a normal character
+if not ^x==x goto DOS
+
+rem Abort if we are running from UNC path
+if %~d0==\\ goto UNC
+
+rem Localize environment changes
+setlocal enableextensions
+
+rem Do we really need to cd to the batch location?
+cd /d %~dp0
+
+rem Break search path into dir list and rebuild w/o tex dirs
+call :rebuildpath ";" "%path:;=" "%"
+if "%path:~0,1%"==";" set path=%path:~1%
+
+rem Use TL Perl
+set path=%~dp0tlpkg\tlperl\bin;%path%
+set PERL5LIB=%~dp0tlpkg\tlperl\lib
+
+rem Start installer
+path
+perl "%~dpn0" %*
+pause
+goto :eof
+
+rem Subroutine to build search path without tex directories
+rem any dir containing pdftex.exe is considered a tex dir
+:rebuildpath ";" dir list ...
+shift
+rem The first argument (";") serves as a marker to reset the path
+if "%~0"==";" set path=
+rem Finish if no more arguments to process
+if [%1]==[] goto :eof
+rem Continue if tex dir
+if exist "%~1\pdftex.exe" goto :rebuildpath
+rem Add dir to path
+set path=%path%;%~1
+goto :rebuildpath
+
+rem About install-tl.bat.manifest:
+rem Vista assumes that a file with install in the name is
+rem an installer and therefore requires administrative privileges.
+rem The manifest file tells Vista otherwise.
+
+:UNC
+echo Cannot run from UNC path.
+echo Map network drive to a drive letter and rerun the installer.
+echo You can use pushd/popd commands for temporary mapping.
+pause
+exit /b 1
+
+:DOS
+echo DOS and Windows 9x systems are not supported. Sorry.
+echo Windows 2000 or newer is required.
+pause
diff --git a/Master/tlpkg/installer/install-menu-perltk-new.pl b/Master/tlpkg/installer/install-menu-perltk-new.pl new file mode 100644 index 00000000000..6cb806fbb92 --- /dev/null +++ b/Master/tlpkg/installer/install-menu-perltk-new.pl @@ -0,0 +1,1054 @@ +#!/usr/bin/env perl +# $Id: install-menu-perltk.pl 20268 2010-10-31 07:26:14Z preining $ +# +# Copyright 2008, 2009, 2010 Norbert Preining +# Copyright 2008 Reinhard Kotucha +# This file is licensed under the GNU General Public License version 2 +# or any later version. +# +# TODO: +# - make the fancy selector the default, at least on unix +# - for w32 find out the necessary files for the fancy selector and move +# them to the installer perl package + +use strict; +$^W = 1; + +my $svnrev = '$Revision: 20268 $'; +$svnrev =~ m/: ([0-9]+) /; +$::menurevision = $1; + +require Tk; +require Tk::Dialog; +require Tk::DialogBox; +require Tk::PNG; +require Tk::ROText; +require Tk::ProgressBar; +require Tk::BrowseEntry; + +if ($::alternative_selector) { + require Tk::DirTree; +} + +use utf8; +no utf8; + +our %vars; +our $tlpdb; +our @collections_std; +our @collections_lang; +our @collections_lang_doc; +our $texlive_release; + +our $MENU_INSTALL = 0; +our $MENU_ABORT = 1; +our $MENU_QUIT = 2; +our $MENU_ALREADYDONE = 3; + +my $return = $MENU_INSTALL; + +our $LANG; +our %TRANS; +require("TeXLive/trans.pl"); + +$::fileassocdesc[0] = __("None"); +$::fileassocdesc[1] = __("Only new"); +$::fileassocdesc[2] = __("All"); + +$::letterdesc[0] = __('A4'); +$::letterdesc[1] = __('letter'); + +my $mw; +my $subframe; +my $mainwindow; +my $bintextbutton; +my $schemebutton; +my $tmflocalbutton; +my $tmfsysvarbutton; +my $tmfsysconfigbutton; +my $tmfhomebutton; +my $pathbutton; +my $deskintbutton; +my $assocbutton; +my $adminbutton; +my $collectionstext; +my $texmflocaltext; +my $texmfsysvartext; +my $texmfsysconfigtext; +my $texmfhometext; +my $texdirtext; +my $langcoltext; +my $optletterstate; +my $optfmtstate; +my $optsrcstate; +my $optdocstate; +my $portableyesno = ( $vars{'portable'} ? __("Yes") : __("No") ); +my $letteryesno = $::letterdesc[$vars{'option_letter'}]; +my $fmtyesno = ( $vars{'option_fmt'} ? __("Yes") : __("No") ); +my $srcyesno = ( $vars{'option_src'} ? __("Yes") : __("No") ); +my $deskintyesno = ( $vars{'option_desktop_integration'} ? __("Yes") : __("No") ); +my $pathadjyesno = ( $vars{'option_path'} ? __("Yes") : __("No") ); +my $fileassocyesno = $::fileassocdesc[$vars{'option_file_assocs'}]; +my $editoryesno = ( $vars{'collection-texworks'} ? __("Yes") : __("No") ); +my $adminallyesno = ( $vars{'option_w32_multi_user'} ? __("Yes") : __("No") ); +my $docyesno = ( $vars{'option_doc'} ? __("Yes") : __("No") ); +my $restrictedyesno = ( $vars{'option_write18_restricted'} ? __("Yes") : __("No") ); + +$::run_menu = \&run_menu_perltk; + + +#################################################################### +# From here on only function definitions +# ################################################################## + + +sub menu_abort { + $return = $MENU_ABORT; + $mainwindow->destroy; +} + +sub setup_hooks_perltk { + @::info_hook = (); + push @::info_hook, + sub { + return unless defined $mainwindow; + update_status(join(" ",@_)); + $mainwindow->update; + }; + push @::warn_hook, + sub { + return unless defined $mainwindow ; + update_status(join(" ",@_)); + $mainwindow->update; + }; + @::install_packages_hook = (); + push @::install_packages_hook, \&update_progressbar; + push @::install_packages_hook, + sub { + return unless defined $mainwindow; + return unless defined $::sww; + $mainwindow->update; + $::sww->update; + }; +} + +sub update_status { + my ($p) = @_; + return unless defined $::progressw; + $::progressw->insert("end", "$p"); + $::progressw->see("end"); +} +sub update_progressbar { + my ($n,$total) = @_; + return unless defined $::progress; + if (defined($n) && defined($total)) { + $::progress->value(int($n*100/$total)); + } +} + + +sub run_menu_perltk { + calc_depends(); + $mainwindow = Tk::MainWindow->new; + $mainwindow->protocol('WM_DELETE_WINDOW' => \&menu_abort); + setup_hooks_perltk(); + + if (!win32()) { + require Tk::Pane; + $subframe = $mainwindow->Scrolled("Frame", -scrollbars => "oe"); + } else { + $subframe = $mainwindow->Frame; + } + $mw = $subframe->Frame; + + # image frame on the left + my $fl = $mw->Frame(-background => "#0078b8"); + my $img = $fl->Photo(-format => 'png', -file => "$::installerdir/tlpkg/installer/texlive.png"); + $fl->Label(-image => $img, -background => "#0078b8")->pack(-expand => 1, -fill => "y"); + $fl->Label(-text => "v$::installerrevision/$::menurevision", -background => "#0078b8")->pack; + + # data frame on the right + my $fr = $mw->Frame; + $fl->pack(-side => 'left', -expand => 1, -fill => "y"); + $fr->pack(-side => 'right'); + + + my $row = 1; + $fr->Label(-text => __("TeX Live %s Installation", $TeXLive::TLConfig::ReleaseYear))->grid(-row => $row, -column => 1, -columnspan => 3); + + if (!$vars{'in_place'}) { + + $row++; + $fr->Label(-text => "------- " . __("Basic Information") . " -------")->grid(-row => $row, -column => 1, -columnspan => 3); + + # binary system line + if (!win32()) { + $row++; + $fr->Label(-text => __('Binary system(s)'), -anchor => 'w')->grid(-row => $row, -column => 1, -sticky => 'w'); + $bintextbutton = $fr->Label(-anchor => 'w'); + $bintextbutton->grid(-row => $row, -column => 2, -padx => "2m"); + $fr->Button(-text => __("Change"), -command => sub { menu_select_binsystems(); })->grid(-row => $row, -column => 3, -sticky => "ew", -padx => "2m"); + } + + $row++; + + # scheme line + $fr->Label(-text => __('Selected scheme'), -anchor => 'w')->grid(-row => $row, -column => 1, -sticky => 'w'); + $schemebutton = $fr->Label(-anchor => 'w'); + $schemebutton->grid(-row => $row, -column => 2, -padx => "2m"); + $fr->Button(-text => __("Change"), -command => sub { menu_select_scheme(); })->grid(-row => $row, -column => 3, -sticky => "ew", -padx => "2m"); + + $row++; + + # further customization + $fr->Label(-text => "------- " . __("Further Customization") . " -------")->grid(-row => $row, -column => 1,-columnspan => 3); + + $row++; + # standard collection line + $fr->Label(-text => __('Standard collections'), -anchor => 'w')->grid(-row => $row, -column => 1, -sticky => 'w'); + $fr->Button(-text => __("Change"), -command => sub { menu_select_standard_collections(); })->grid(-row => $row, -column => 3, -sticky => "ew", -padx => "2m"); + + $row++; + # lang collection line + $fr->Label(-text => __('Language collections'), -anchor => 'w')->grid(-row => $row, -column => 1, -sticky => 'w'); + $langcoltext = $fr->Label(-anchor => 'w')->grid(-row => $row, -column => 2, -padx => "2m"); + $fr->Button( -text => __("Change"), -command => sub { menu_select_lang_collections(); })->grid(-row => $row, -column => 3, -sticky => "ew", -padx => "2m"); + + $row++; + $collectionstext = $fr->Label(); + $collectionstext->grid(-row => $row, -column => 1, -columnspan => 3); + } + + $row++; + # further customization + $fr->Label(-text => "------- " . __("Directory setup") . " -------")->grid(-row => $row, -column => 1, -columnspan => 3); + + $row++; + $fr->Label(-text => __('Portable setup'), -anchor => 'w')->grid(-row => $row, -column => 1, -sticky => 'w'); + $fr->Label(-anchor => 'w', -textvariable => \$portableyesno)->grid(-row => $row, -column => 2, -padx => "2m"); + $fr->Button(-text => __("Toggle"), -command => sub { toggle_portable(); })->grid(-row => $row, -column => 3, -sticky => "ew", -padx => "2m"); + + $row++; + # texdir line + $fr->Label(-text => __('TEXDIR (the main TeX directory)'), -anchor => 'w')->grid(-row => $row, -column => 1, -sticky => 'w'); + $texdirtext = $fr->Label(-anchor => 'w')->grid(-row => $row, -column => 2, -padx => "2m"); + if (!$vars{'in_place'}) { + if ($::alternative_selector) { + $fr->Button(-text => __("Change"), -command => sub { menu_edit_texdir("TEXDIR"); })->grid(-row => $row, -column => 3, -sticky => "ew", -padx => "2m"); + } else { + $fr->Button(-text => __("Change"), -command => sub { menu_edit_vars_value("TEXDIR"); })->grid(-row => $row, -column => 3, -sticky => "ew", -padx => "2m"); + } + } + + + $row++; + # texmflocal line + $fr->Label(-text => __('TEXMFLOCAL (directory for site-wide local files)'), -anchor => 'w')->grid(-row => $row, -column => 1, -sticky => 'w'); + $texmflocaltext = $fr->Label(-anchor => 'w')->grid(-row => $row, -column => 2, -padx => "2m"); + $tmflocalbutton = $fr->Button(-text => __("Change"), -command => sub { menu_edit_vars_value("TEXMFLOCAL"); }); + $tmflocalbutton -> grid(-row => $row, -column => 3, -sticky => "ew", -padx => "2m"); + + $row++; + # texmfsysvar line + $fr->Label(-text => __('TEXMFSYSVAR (directory for autogenerated data)'), -anchor => 'w')->grid(-row => $row, -column => 1, -sticky => 'w'); + $texmfsysvartext = $fr->Label(-anchor => 'w')->grid(-row => $row, -column => 2, -padx => "2m"); + $tmfsysvarbutton = $fr->Button(-text => __("Change"), -command => sub { menu_edit_vars_value("TEXMFSYSVAR"); }); + $tmfsysvarbutton->grid(-row => $row, -column => 3, -sticky => "ew", -padx => "2m"); + + $row++; + # texmfsysconfig line + $fr->Label(-text => __('TEXMFSYSCONFIG (directory for local config)'), -anchor => 'w')->grid(-row => $row, -column => 1, -sticky => 'w'); + $texmfsysconfigtext = $fr->Label(-anchor => 'w')->grid(-row => $row, -column => 2, -padx => "2m"); + $tmfsysconfigbutton = $fr->Button(-text => __("Change"), -command => sub { menu_edit_vars_value("TEXMFSYSCONFIG"); }); + $tmfsysconfigbutton->grid(-row => $row, -column => 3, -sticky => "ew", -padx => "2m"); + + $row++; + # texmfhome line + $fr->Label(-text => __('TEXMFHOME (directory for user-specific files)'), -anchor => 'w')->grid(-row => $row, -column => 1, -sticky => 'w'); + $texmfhometext = $fr->Label(-anchor => 'w')->grid(-row => $row, -column => 2, -padx => "2m"); + $tmfhomebutton = $fr->Button(-text => __("Change"), -command => sub { menu_edit_vars_value("TEXMFHOME"); }); + $tmfhomebutton->grid(-row => $row, -column => 3, -sticky => "ew", -padx => "2m"); + + if ($vars{'portable'}) { + for my $b ($tmflocalbutton, $tmfsysvarbutton, $tmfsysconfigbutton, $tmfhomebutton) { + $b->configure(-state => 'disabled') + } + } + + $row++; + # Options + $fr->Label(-text => "------- " . __("Options") . " -------")->grid(-row => $row, -column => 1, -columnspan => 3); + + $row++; + # optpaper + $fr->Label(-text => __('Default paper size'), -anchor => 'w')->grid(-row => $row, -column => 1, -sticky => 'w'); + $fr->Label(-anchor => 'w', -textvariable => \$letteryesno)->grid(-row => $row, -column => 2, -padx => "2m"); + $fr->Button(-text => __("Toggle"), -command => sub { toggle_and_set_opt_variable(\$vars{'option_letter'}, \$letteryesno, \@::letterdesc); })->grid(-row => $row, -column => 3, -sticky => "ew", -padx => "2m"); + + $row++; + $fr->Label(-text => __('Allow execution of restricted list of programs via \write18'), -anchor => 'w')->grid(-row => $row, -column => 1, -sticky => 'w'); + $fr->Label(-anchor => 'w', -textvariable => \$restrictedyesno)->grid(-row => $row, -column => 2, -padx => "2m"); + $fr->Button(-text => __("Toggle"), -command => sub { toggle_and_set_opt_variable(\$vars{'option_write18_restricted'}, \$restrictedyesno); })->grid(-row => $row, -column => 3, -sticky => "ew", -padx => "2m"); + + $row++; + $fr->Label(-text => __('Create all format files'), -anchor => 'w')->grid(-row => $row, -column => 1, -sticky => 'w'); + $fr->Label(-anchor => 'w', -textvariable => \$fmtyesno)->grid(-row => $row, -column => 2, -padx => "2m"); + $fr->Button(-text => __("Toggle"), -command => sub { toggle_and_set_opt_variable(\$vars{'option_fmt'}, \$fmtyesno); })->grid(-row => $row, -column => 3, -sticky => "ew", -padx => "2m"); + + if ($vars{'doc_splitting_supported'} and !$vars{'in_place'}) { + $row++; + $fr->Label(-text => __('Install font/macro doc tree'), -anchor => 'w')->grid(-row => $row, -column => 1, -sticky => 'w'); + $fr->Label(-anchor => 'w', -textvariable => \$docyesno)->grid(-row => $row, -column => 2, -padx => "2m"); + $fr->Button(-text => __("Toggle"), -command => sub { toggle_and_set_opt_variable(\$vars{'option_doc'}, \$docyesno); })->grid(-row => $row, -column => 3, -sticky => "ew", -padx => "2m"); + } + + if ($vars{'src_splitting_supported'} and !$vars{'in_place'}) { + $row++; + $fr->Label(-text => __('Install font/macro source tree'), -anchor => 'w')->grid(-row => $row, -column => 1, -sticky => 'w'); + $fr->Label(-anchor => 'w', -textvariable => \$srcyesno)->grid(-row => $row, -column => 2, -padx => "2m"); + $fr->Button(-text => __("Toggle"), -command => sub { toggle_and_set_opt_variable(\$vars{'option_src'}, \$srcyesno); })->grid(-row => $row, -column => 3, -sticky => "ew", -padx => "2m"); + } + + $row++; + $fr->Label(-text => (win32()) ? __('Adjust PATH setting in registry') : + __('Create symlinks in system directories'), + -anchor => 'w')->grid(-row => $row, -column => 1, -sticky => 'w'); + $fr->Label(-anchor => 'w', -textvariable => \$pathadjyesno)->grid(-row => $row, -column => 2, -padx => "2m"); + if (unix()) { + $pathbutton = $fr->Button(-text => __("Change"), -command => sub { menu_select_symlink(); }); + } else { + $pathbutton = $fr->Button(-text => __("Toggle"), -command => sub { toggle_and_set_opt_variable(\$vars{'option_path'}, \$pathadjyesno); }); + } + $pathbutton->grid(-row => $row, -column => 3, -sticky => "ew", -padx => "2m"); + + if ($::opt_all_options || win32()) { + $row++; + $fr->Label(-text => __('Add shortcuts to menu and desktop'), -anchor => 'w')->grid(-row => $row, -column => 1, -sticky => 'w'); + $fr->Label(-anchor => 'w', -textvariable => \$deskintyesno)->grid(-row => $row, -column => 2, -padx => "2m"); + $deskintbutton = $fr->Button(-text => __("Toggle"), -command => sub { toggle_and_set_opt_variable(\$vars{'option_desktop_integration'}, \$deskintyesno); }); + $deskintbutton->grid(-row => $row, -column => 3, -sticky => "ew", -padx => "2m"); + + $row++; + $fr->Label(-text => __('Change file associations'), -anchor => 'w')->grid(-row => $row, -column => 1, -sticky => 'w'); + $fr->Label(-anchor => 'w', -textvariable => \$fileassocyesno)->grid(-row => $row, -column => 2, -padx => "2m"); + $assocbutton = $fr->Button(-text => __("Change"), -command => sub { menu_edit_file_assocs(); }); + $assocbutton->grid(-row => $row, -column => 3, -sticky => "ew", -padx => "2m"); + + if ($::opt_all_options || admin()) { + $row++; + $fr->Label(-text => __('Installation for all users'), -anchor => 'w')->grid(-row => $row, -column => 1, -sticky => 'w'); + $fr->Label(-anchor => 'w', -textvariable => \$adminallyesno)->grid(-row => $row, -column => 2, -padx => "2m"); + $adminbutton = $fr->Button(-text => __("Toggle"), -command => sub { toggle_and_set_opt_variable(\$vars{'option_w32_multi_user'}, \$adminallyesno); }); + $adminbutton->grid(-row => $row, -column => 3, -sticky => "ew", -padx => "2m"); + } + + $row++; + $fr->Label(-text => __('Install TeXworks front end'), -anchor => 'w')->grid(-row => $row, -column => 1, -sticky => 'w'); + $fr->Label(-anchor => 'w', -textvariable => \$editoryesno)->grid(-row => $row, -column => 2, -padx => "2m"); + if (!$vars{'in_place'}) { + $fr->Button(-text => __("Toggle"), -command => sub { toggle_and_set_opt_variable(\$vars{'collection-texworks'}, \$editoryesno); })->grid(-row => $row, -column => 3, -sticky => "ew", -padx => "2m"); + } + } + if ($vars{'portable'}) { + for $b ($pathbutton, $deskintbutton, $assocbutton, $adminbutton) { + $b->configure(-state => 'disabled') if $b; + } + } + + # install/cancel buttons + my $f3 = $fr->Frame; + $f3->Button( + -text => __("Install TeX Live"), + -command => sub { installation_window(); } + )->pack(-side => 'left', -padx => "2m", -pady => "2m")->focus(); + my $quitbutton = $f3->Button( + -text => __("Quit"), + -command => \&menu_abort, + )->pack(-side => 'right', -padx => "2m", -pady => "2m"); + $mw->bind('<Escape>', [ $quitbutton, 'Invoke' ]); + #my $wizardbutton = $f3->Button( + # -text => __("Wizard"), + # -command => sub { + # $mainwindow->destroy; + # require("installer/install-menu-wizard.pl"); + # setup_hooks_wizard(); + # $return = run_menu_wizard(); + # })->pack(-side => 'right', -padx => "2m", -pady => "2m"); + $row++; + $f3->grid(-row => $row, -column => 1, -columnspan => 3); + menu_update_texts(); + $fr->gridColumnconfigure(2, -minsize => 300); + $mw->pack(-expand => 1, -fill => "both"); + $mw->update; + my $rh = $mw->reqheight; + my $rw = $mw->reqwidth; + my $maxheight = $mainwindow->screenheight() - 20; + debug("Requested height: $rh, requested width: $rw, max height: $maxheight\n"); + if ($rh > $maxheight) { + $rh = $maxheight; + $rw += 20; # for the scrollbar = = + } + $subframe->configure(-height => $rh, -width=>$rw); + $subframe->pack(-expand => 1, -fill => "both"); + $mainwindow->configure(-height => $rh, -width=>$rw); + #$mw->pack(-expand => 1, -fill => "both"); + Tk::MainLoop(); + return($return); +} + +sub installation_window { + # create a progress bar window + $::sww = $mainwindow->Toplevel(-title => __("Installation process"), + -width => 400); + $::sww->transient($mainwindow); + $::sww->grab(); + $::sww->Label(-text => __("Installation process"))->pack; + $::progressw = $::sww->Scrolled("ROText", -scrollbars => "e", -height => 16); + $::progressw->pack(-expand => 1, -fill => "both"); + my $percent_done = 0; + $::progress = $::sww->ProgressBar(-variable => \$percent_done, + -width => 20, -length => 400, -from => 0, -to => 100, -blocks => 10, + -colors => [ 0, '#0078b8' ]); + $::progress->pack(-fill => "x"); + my $f = $::sww->Frame; + my $b = $f->Button(-text => __("Cancel"), + -command => sub { $::sww->destroy; $mainwindow->destroy; + do_cleanup(); exit(1); } + )->pack(-pady => "2m"); + $b->focus(); + $f->pack; + do_installation(); + $return = $MENU_ALREADYDONE; + my $t = __("See %s/index.html for links to documentation.\nThe TeX Live web site (http://tug.org/texlive/) contains any updates and corrections. TeX Live is a joint project of the TeX user groups around the world; please consider supporting it by joining the group best for you. The list of groups is available on the web at http://tug.org/usergroups.html.", $::vars{'TEXDIR'}); + if (!win32()) { + $t .= "\n\n" . __("Add %s/texmf/doc/man to MANPATH.\nAdd %s/texmf/doc/info to INFOPATH.\nMost importantly, add %s/bin/%s\nto your PATH for current and future sessions.", $::vars{'TEXDIR'}, $::vars{'TEXDIR'}, $::vars{'TEXDIR'}, $::vars{'this_platform'}); + } + if (@::WARNLINES) { + $t .= "\n\n" . __("There were some warnings during the installation process.\nHere is the list of warning messages:") . "\n"; + $t .= join('', @::WARNLINES); + $t =~ s/\n\z//; + } + + $t .= "\n\n" . __("Welcome to TeX Live!"); + #$t =~ s/\\n/\n/g; + $::progressw->insert("end", "\n"); + my $linechar = $::progressw->index("end"); + $::progressw->markSet("finaltext", $linechar); + $::progressw->markGravity("finaltext", "left"); + $::progressw->insert("end", "\n$t"); + $::progressw->see("end"); + $::progressw->tagAdd("centered", $linechar, "end"); + $::progressw->tagConfigure("centered", -justify => "center"); + $b->configure(-text => __("Finish"), + -command => sub { $mainwindow->destroy; }); +} + +# this sub will not be called if $vars{'in_place'} +sub menu_edit_texdir { + my $key = shift; + our $addyear = 1; + our $addtexlive = 1; + my $val = $vars{$key}; + our $currsel; + our $entry; + sub update_label { + my $t = $currsel; + $t .= "/texlive" if ($addtexlive); + $t .= "/$texlive_release" if ($addyear); + $entry->configure(-text => "$t"); + } + my $hint_var; + if ($key ne 'TEXMFHOME') { + $hint_var = win32() ? $ENV{'USERPROFILE'} : $ENV{'HOME'}; + } else { + $hint_var = win32() ? '%USERPROFILE%' : '$HOME'; + } + if ($val =~ m!^(.*)/texlive/$texlive_release$!) { + $currsel = "$1"; + $addyear = 1; + $addtexlive = 1; + } elsif ($val =~ m!^(.*)/$texlive_release$!) { + $currsel = "$1"; + $addyear = 1; + $addtexlive = 0; + } elsif ($val =~ m!^(.*)/texlive$!) { + $currsel = "$1"; + $addyear = 0; + $addtexlive = 1; + } else { + $addyear = 0; + $addtexlive = 0; + $currsel = $val; + } + my $sw = $mainwindow->Toplevel(-title => __("Change variable value")); + $sw->transient($mainwindow); + $sw->grab(); + $sw->Label(-text => __("Enter path for %s (use ~ for %s)", $key, $hint_var))->pack(-padx => "2m", -pady => "2m"); + $entry = $sw->Entry(-width => 60)->pack(-padx => "2m", -pady => "2m"); + my $f = $sw->Frame; + my $c1 = $f->Checkbutton(-text => 'Add "texlive"', -variable => \$addtexlive, + -command => \&update_label); + my $c2 = $f->Checkbutton(-text => "Add \"$texlive_release\"", -variable => \$addyear, + -command => \&update_label); + my $foo = $sw->Scrolled("DirTree", -scrollbars => "osoe", + -browsecmd => sub { my ($d) = @_; $currsel = $d; update_label(); }, + -directory => "$currsel"); + my $ff = $sw->Frame; + my $ok = $ff->Button(-text => __("Ok"), -command => sub { $val = $entry->get; callback_edit_directories($key,$val); $sw->destroy; }); + my $cancel = $ff->Button(-text => __("Cancel"), -command => sub { $sw->destroy; }); + update_label(); + $c1->pack(-side => "left", -padx => "2m", -pady => "2m"); + $c2->pack(-side => "right", -padx => "2m", -pady => "2m"); + $f->pack; + $foo->pack(-fill => "both", -expand => 1); + $ok->pack(-side => 'left' , -padx => "2m", -pady => "2m"); + $cancel->pack(-side => 'right', -padx => "2m", -pady => "2m"); + $ff->pack; + # bindings + $sw->bind('<Return>' => [ $ok, 'Invoke']); + $sw->bind('<Escape>' => [ $cancel, 'Invoke']); +} + +sub menu_edit_vars_value { + my $key = shift; + my $sw = $mainwindow->Toplevel(-title => __("Change variable value")); + $sw->transient($mainwindow); + $sw->grab(); + my $val = $vars{$key}; + my $hint_var; + if ($key ne 'TEXMFHOME') { + $hint_var = win32() ? $ENV{'USERPROFILE'} : $ENV{'HOME'}; + } else { + $hint_var = win32() ? '%USERPROFILE%' : '$HOME'; + } + $sw->Label(-text => __("Enter path for %s (use ~ for %s)", $key, $hint_var))->pack(-padx => "2m", -pady => "2m"); + my $entry = $sw->Entry(-text => native_slashify($val), -width => 60); + $entry->pack(-padx => "2m", -pady => "2m")->focus(); + my $f = $sw->Frame; + my $okbutton = $f->Button(-text => __("Ok"), + -command => sub { $val = forward_slashify($entry->get); callback_edit_directories($key,$val) ; $sw->destroy })->pack(-side => 'left', -padx => "2m", -pady => "2m"); + my $cancelbutton = $f->Button(-text => __("Cancel"), + -command => sub { $sw->destroy })->pack(-side => 'right', -padx => "2m", -pady => "2m"); + $f->pack(-expand => 'x'); + # bindings + $sw->bind('<Return>' => [ $okbutton, 'Invoke']); + $sw->bind('<Escape>' => [ $cancelbutton, 'Invoke']); +} + +sub menu_edit_file_assocs { + my $sw = $mainwindow->Toplevel(-title => __('Change file associations')); + $sw->transient($mainwindow); + $sw->grab(); + my $key = 'option_file_assocs'; + my $var = $::fileassocdesc[$vars{$key}]; + $sw->Label(-text => __("Change file associations"))->pack(-padx => "2m", -pady => "2m"); + my $opt = $sw->BrowseEntry(-autolistwidth => 1, + -variable => \$var); + for my $i (0..2) { + $opt->insert("end", $::fileassocdesc[$i]); + } + + $opt->pack(-padx => "2m", -pady => "2m")->focus(); + my $f = $sw->Frame; + my $okbutton = $f->Button(-text => __("Ok"), + -command => sub { + my $idx; + if ($var eq $::fileassocdesc[0]) { + $idx = 0; + } elsif ($var eq $::fileassocdesc[1]) { + $idx = 1; + } elsif ($var eq $::fileassocdesc[2]) { + $idx = 2; + } else { + die "How that could happen!\n"; + } + $vars{$key} = $idx; + $fileassocyesno = $::fileassocdesc[$idx]; + $sw->destroy; })->pack(-side => "left", -padx => "2m", -pady => "2m"); + my $cancelbutton = $f->Button(-text => __("Cancel"), -command => sub { $sw->destroy; })->pack(-side => "left", -padx => "2m", -pady => "2m"); + $f->pack; + $sw->bind('<Return>', [ $okbutton, 'Invoke' ]); + $sw->bind('<Escape>', [ $cancelbutton, 'Invoke' ]); +} + + +sub menu_select_scheme { + my $sw = $mainwindow->Toplevel(-title => __('Selected scheme')); + $sw->transient($mainwindow); + $sw->grab(); + my @schemes; + foreach my $pkg ($tlpdb->list_packages) { + my $tlpobj = $tlpdb->{'tlps'}{$pkg}; + if ($tlpobj->category eq "Scheme") { + push @schemes, $pkg; + $vars{"$pkg"}=($vars{'selected_scheme'} eq $pkg)? 1:0; + } + } + @schemes=sort @schemes; + push @schemes, "scheme-custom"; + my $selected = $vars{'selected_scheme'}; + $sw->Label(-text => __("Selected scheme"))->pack(-padx => "2m", -pady => "2m"); + my $f2 = $sw->Frame; + my $f2l = $f2->Frame; + my $f2r = $f2->Frame; + my $nrfh = $#schemes / 2; + my $i = 0; + foreach my $scheme (@schemes) { + my $desc; + if ($scheme ne "scheme-custom") { + my $tlpobj = $tlpdb->get_package("$scheme"); + $desc = $tlpobj->shortdesc; + } else { + $desc = "custom selection of collections"; + } + my $b; + if ($i < $nrfh) { + $b = $f2l->Radiobutton(-variable => \$selected, -value => $scheme, + -text => __($desc))->pack(-anchor => 'w'); + } else { + $b = $f2r->Radiobutton(-variable => \$selected, -value => $scheme, + -text => __($desc))->pack(-anchor => 'w'); + } + if ($selected eq $scheme) { + $b->focus(); + } + $i++; + } + $f2l->pack(-side => 'left', -padx => "2m", -pady => "2m"); + $f2r->pack(-side => 'right', -padx => "2m", -pady => "2m"); + $f2->pack; + my $f3 = $sw->Frame; + my $okbutton = $f3->Button(-text => __("Ok"), + -command => sub { callback_select_scheme($selected) ; $sw->destroy })->pack(-side => 'left', -padx => "2m", -pady => "2m"); + my $cancelbutton = $f3->Button(-text => __("Cancel"), + -command => sub { $sw->destroy })->pack(-side => 'left', -padx => "2m", -pady => "2m"); + $f3->pack(-expand => 'x'); + $sw->bind('<Return>' => [ $okbutton, 'Invoke']); + $sw->bind('<Escape>' => [ $cancelbutton, 'Invoke']); +} + +sub menu_select_standard_collections { + my $sw = $mainwindow->Toplevel(-title => __('Standard collections')); + $sw->transient($mainwindow); + $sw->grab(); + my $fb = $sw->Frame; + my $fc = $sw->Frame; + my $fd = $sw->Frame; + my $f1 = $fb->Frame; + my $f2 = $fb->Frame; + my %lvars = %vars; + $sw->Label(-text => __("Select the collections to be installed"))->pack(-padx => "2m", -pady => "2m"); + my $halfcol = $#collections_std / 2; + my $i = 0; + foreach my $coll (sort @collections_std) { + my $tlpobj = $tlpdb->get_package("$coll"); + if ($i < $halfcol) { + $f1->Checkbutton(-variable => \$lvars{$coll}, -text => __($tlpobj->shortdesc))->pack(-anchor => 'w'); + } else { + $f2->Checkbutton(-variable => \$lvars{$coll}, -text => __($tlpobj->shortdesc))->pack(-anchor => 'w'); + } + $i++; + } + $f1->pack(-side => 'left', -padx => "2m", -pady => "2m"); + $f2->pack(-side => 'right', -padx => "2m", -pady => "2m"); + $fb->pack(-padx => "2m", -pady => "2m"); + $fc->pack(); + $fc->Button(-text => __("Select All"), + -command => sub { select_collections(\%lvars, @collections_std) })->pack(-side => 'left', -padx => "2m", -pady => "2m")->focus(); + $fc->Button(-text => __("Deselect All"), + -command => sub { deselect_collections(\%lvars, @collections_std) })->pack(-side => 'right', -padx => "2m", -pady => "2m"); + $fd->pack(-expand => 'x', -padx => "2m", -pady => "2m"); + my $okbutton = $fd->Button(-text => __("Ok"), + -command => sub { + # we call the update only if something has changed + my $changed = 0; + for my $k (keys %lvars) { + if ($vars{$k} ne $lvars{$k}) { + $changed = 1; + last; + } + } + if ($changed) { + %vars = %lvars; + callback_select_collection(); + } + $sw->destroy; + })->pack(-side => 'left', -padx => "2m", -pady => "2m"); + my $cancelbutton = $fd->Button(-text => __("Cancel"), + -command => sub { $sw->destroy })->pack(-side => 'right', -padx => "2m", -pady => "2m"); + $sw->bind('<Return>' => [ $okbutton, 'Invoke']); + $sw->bind('<Escape>' => [ $cancelbutton, 'Invoke']); +} + +sub menu_select_lang_collections { + my $sw = $mainwindow->Toplevel(-title => __('Language collections')); + $sw->transient($mainwindow); + $sw->grab(); + my $f1 = $sw->Frame; + $f1->pack; + my $f1lang = $f1->Labelframe(-text => __("Select language support")); + my $f1doc = $f1->Labelframe(-text => __("Select language-specific documentation")); + $f1lang->pack(-side => 'left', -padx => "2m", -pady => "2m", -ipadx => "2m", -ipady => "2m"); + $f1doc->pack(-side => 'right', -padx => "2m", -pady => "2m", -ipadx => "2m", -ipady => "2m", -expand => 1, -fill => "y"); + my $f1langT = $f1lang->Frame; $f1langT->pack; + my $f1langL = $f1lang->Frame; $f1langL->pack; + my $f1langLa = $f1langL->Frame; $f1langLa->pack(-side => 'left'); + my $f1langLb = $f1langL->Frame; $f1langLb->pack(-side => 'right'); + my $langh = $#collections_lang / 2; + my $i = 0; + my %lvars = %vars; + foreach my $coll (sort @collections_lang) { + my $tlpobj = $tlpdb->get_package("$coll"); + if ($i < $langh) { + $f1langLa->Checkbutton(-variable => \$lvars{$coll}, -text => __($tlpobj->shortdesc))->pack(-anchor => 'w'); + } else { + $f1langLb->Checkbutton(-variable => \$lvars{$coll}, -text => __($tlpobj->shortdesc))->pack(-anchor => 'w'); + } + $i++; + } + my $f1langB = $f1lang->Frame; + $f1langB->pack(-expand => 'x'); + $f1langB->Button(-text => __("Select All"), + -command => sub { select_collections(\%lvars, @collections_lang) })->pack(-side => 'left', -padx => "2m", -pady => "2m")->focus(); + $f1langB->Button(-text => __("Deselect All"), + -command => sub { deselect_collections(\%lvars, @collections_lang) })->pack(-side => 'right', -padx => "2m", -pady => "2m"); + + my $f1docT = $f1doc->Frame; $f1docT->pack; + my $f1docL = $f1doc->Frame; $f1docL->pack; + my $f1docLa = $f1docL->Frame; $f1docLa->pack(-side => 'left'); + my $f1docLb = $f1docL->Frame; $f1docLb->pack(-side => 'right'); + my $doch = $#collections_lang_doc / 2; + $i = 0; + foreach my $coll (sort @collections_lang_doc) { + my $tlpobj = $tlpdb->get_package("$coll"); + if ($i < $doch) { + $f1docLa->Checkbutton(-variable => \$lvars{$coll}, -text => __($tlpobj->shortdesc))->pack(-anchor => 'w'); + } else { + $f1docLb->Checkbutton(-variable => \$lvars{$coll}, -text => __($tlpobj->shortdesc))->pack(-anchor => 'w'); + } + $i++; + } + my $f1docB = $f1doc->Frame; + $f1docB->pack(-expand => 1, -side => "bottom"); + $f1docB->Button(-text => __("Select All"), + -command => sub { select_collections(\%lvars, @collections_lang_doc) })->pack(-side => 'left', -padx => "2m", -pady => "2m"); + $f1docB->Button(-text => __("Deselect All"), + -command => sub { deselect_collections(\%lvars, @collections_lang_doc) })->pack(-side => 'left', -padx => "2m", -pady => "2m"); + my $f2 = $sw->Frame; $f2->pack(-expand => 'x'); + my $okbutton = $f2->Button(-text => __("Ok"), + -command => sub { + # we call the update only if something has changed + my $changed = 0; + for my $k (keys %lvars) { + if ($vars{$k} ne $lvars{$k}) { + $changed = 1; + last; + } + } + if ($changed) { + %vars = %lvars; + callback_select_collection(); + } + $sw->destroy; + })->pack(-side => 'left', -padx => "2m", -pady => "2m"); + my $cancelbutton = $f2->Button(-text => __("Cancel"), + -command => sub { $sw->destroy })->pack(-side => 'right', -padx => "2m", -pady => "2m"); + $sw->bind('<Return>' => [ $okbutton, 'Invoke']); + $sw->bind('<Escape>' => [ $cancelbutton, 'Invoke']); +} + +sub menu_select_symlink { + our ($lbin,$lman,$linfo); + our $osym = $vars{'option_path'}; + our ($binlab,$binb,$manlab,$manb,$infolab,$infob); + sub set_unset_buttons { + $lbin = ($osym ? $vars{'option_sys_bin'} : ''); + $linfo = ($osym ? $vars{'option_sys_info'} : ''); + $lman = ($osym ? $vars{'option_sys_man'} : ''); + if ($osym) { + $binb->configure (-state => 'normal'); + $manb->configure (-state => 'normal'); + $infob->configure(-state => 'normal'); + } else { + $infob->configure(-state => 'disabled'); + $manb->configure (-state => 'disabled'); + $binb->configure (-state => 'disabled'); + } + } + sub return_callback { + if ($osym) { + my $home = getenv('HOME'); + $home = getenv('USERPROFILE') if (win32()); + $home ||= '~'; + $lbin =~ s/^~/$home/; + $linfo =~ s/^~/$home/; + $lman =~ s/^~/$home/; + $vars{'option_sys_bin'} = $lbin; + $vars{'option_sys_info'} = $linfo; + $vars{'option_sys_man'} = $lman; + } + $vars{'option_path'} = $osym; + toggle_and_set_opt_variable(\$vars{'option_path'}, \$pathadjyesno); + } + my $sw = $mainwindow->Toplevel(-title => __('Create symlinks in system directories')); + $sw->transient($mainwindow); + $sw->grab(); + $sw->Checkbutton(-variable => \$osym, + -text => __("create symlinks in standard directories"), + -command => sub { set_unset_buttons(); } )->grid(-column => 1, + -row => 1, + -columnspan => 2, + -padx => "2m"); + $binlab = $sw->Label(-text => __("binaries to")); + $binb = $sw->Entry(-textvariable => \$lbin); + $manlab = $sw->Label(-text => __("manpages to")); + $manb = $sw->Entry(-textvariable => \$lman); + $infolab = $sw->Label(-text => __("info to")); + $infob = $sw->Entry(-textvariable => \$linfo); + $binlab->grid(-row => 2, -column => 1, -sticky => "w", -padx => "2m"); + $binb->grid(-row => 2, -column => 2, -sticky => "ew", -padx => "2m"); + $manlab->grid(-row => 3, -column => 1, -sticky => "w", -padx => "2m"); + $manb->grid(-row => 3, -column => 2, -sticky => "ew", -padx => "2m"); + $infolab->grid(-row => 4, -column => 1, -sticky => "w", -padx => "2m"); + $infob->grid(-row => 4, -column => 2, -sticky => "ew", -padx => "2m"); + set_unset_buttons(); + my $f2 = $sw->Frame; $f2->grid(-column => 1, -columnspan => 2, -row => 5); + my $okbutton = $f2->Button(-text => __("Ok"), + -command => sub { return_callback(); $sw->destroy })->pack(-side => 'left'); + my $cancelbutton = $f2->Button(-text => __("Cancel"), + -command => sub { $sw->destroy })->pack(-side => 'right'); + $sw->bind('<Return>' => [ $okbutton, 'Invoke']); + $sw->bind('<Escape>' => [ $cancelbutton, 'Invoke']); +} + +sub menu_select_binsystems { + my $f2r; + my $f2; + my $sw = $mainwindow->Toplevel(-title => __('Binary system(s)')); + $sw->transient($mainwindow); + $sw->grab(); + my @diskarchs = (); + foreach my $key (keys %vars) { + if ($key=~/binary_(.*)/) { + push @diskarchs, $1; + } + } + $sw->Label(-text => __("Select arch-os"))->pack(-padx => "2m", -pady => "2m"); + $f2 = $sw->Frame; + my $f2l = $f2->Frame; + foreach my $sys (sort @diskarchs) { + $f2l->Checkbutton(-variable => \$vars{"binary_$sys"}, -text => platform_desc($sys))->pack(-anchor => 'w'); + } + $f2l->pack(-side => 'left'); + $f2->pack(-padx => "2m", -pady => "2m"); + my $f3 = $sw->Frame; + my $okbutton = $f3->Button(-text => __("Ok"), + -command => sub { callback_select_systems() ; $sw->destroy })->pack(-side => 'left', -padx => "2m", -pady => "2m"); + my $cancelbutton = $f3->Button(-text => __("Cancel"), + -command => sub { $sw->destroy })->pack(-side => 'right', -padx => "2m", -pady => "2m"); + $f3->pack(-expand => 'x'); + $sw->bind('<Return>' => [ $okbutton, 'Invoke']); + $sw->bind('<Escape>' => [ $cancelbutton, 'Invoke']); +} + + +sub menu_set_text { + my $w = shift; + my $t = shift; + # if in_place or portable not a complete interface + $w->configure(-text => $t, @_) if $w; +} + +sub menu_set_schemebutton_text { + menu_set_text($schemebutton, "$vars{'selected_scheme'}"); +} + +sub menu_set_binbutton_text { + if (!win32()) { + menu_set_text($bintextbutton, __("%s out of %s", $vars{'n_systems_selected'}, $vars{'n_systems_available'})); + } +} + +sub menu_set_collections_text { + menu_set_text($collectionstext, __("%s collections out of %s", + $vars{'n_collections_selected'}, $vars{'n_collections_available'}) + . " (" . __("disk space required:") . " $vars{'total_size'} MB)"); +} + +sub menu_set_pathes_text { + if (check_on_lang_collection_installed()) { + # good + menu_set_text($langcoltext, ""); + } else { + # bad + menu_set_text($langcoltext, __("(no language collection selected!)"), -foreground => "red"); + } + if (TeXLive::TLUtils::texdir_check($vars{'TEXDIR'})) { + menu_set_text($texdirtext, native_slashify($vars{'TEXDIR'}), -foreground => "black"); + } else { + menu_set_text($texdirtext, __("(default not writable - please change!)"), -foreground => "red"); + } + menu_set_text($texmflocaltext, native_slashify($vars{'TEXMFLOCAL'})); + if ((-w $vars{'TEXMFSYSVAR'}) || (-w dirname($vars{'TEXMFSYSVAR'}))) { + menu_set_text($texmfsysvartext, native_slashify($vars{'TEXMFSYSVAR'}), -foreground => "black"); + } elsif ("$vars{'TEXMFSYSVAR'}" =~ m;^$vars{'TEXDIR'};) { + if (TeXLive::TLUtils::texdir_check($vars{'TEXDIR'})) { + menu_set_text($texmfsysvartext, native_slashify($vars{'TEXMFSYSVAR'}), -foreground => "black"); + } else { + menu_set_text($texmfsysvartext, __("(please change TEXDIR first!)"), -foreground => "red"); + } + } else { + menu_set_text($texmfsysvartext, __("(default not writable - please change!)")); + } + if ((-w $vars{'TEXMFSYSCONFIG'}) || (-w dirname($vars{'TEXMFSYSCONFIG'}))) { + menu_set_text($texmfsysconfigtext, native_slashify($vars{'TEXMFSYSCONFIG'}), -foreground => "black"); + } elsif ("$vars{'TEXMFSYSCONFIG'}" =~ m;^$vars{'TEXDIR'};) { + if (TeXLive::TLUtils::texdir_check($vars{'TEXDIR'})) { + menu_set_text($texmfsysconfigtext, native_slashify($vars{'TEXMFSYSCONFIG'}), -foreground => "black"); + } else { + menu_set_text($texmfsysconfigtext, __("(please change TEXDIR first!)"), -foreground => "red"); + } + } else { + menu_set_text($texmfsysconfigtext, __("(default not writable - please change!)")); + } + menu_set_text($texmfhometext, native_slashify($vars{'TEXMFHOME'})); +} + + +sub menu_update_texts { + menu_set_pathes_text; + menu_set_collections_text; + menu_set_binbutton_text; + menu_set_schemebutton_text; + $optletterstate = $::letterdesc[$vars{'option_letter'}]; + $optfmtstate = ($vars{'option_fmt'} ? __("Yes") : __("No")); + $optsrcstate = ($vars{'option_src'} ? __("Yes") : __("No")); + $optdocstate = ($vars{'option_doc'} ? __("Yes") : __("No")); +} + +sub callback_select_scheme { + my $s = shift; + select_scheme($s); + $editoryesno = ($vars{'collection-texworks'} ? __("Yes") : __("No")); + menu_update_texts(); +} + +sub callback_select_collection { + # special case for collection-texworks: + $editoryesno = ($vars{'collection-texworks'} ? __("Yes") : __("No")); + calc_depends(); + select_scheme("scheme-custom"); + update_numbers(); + menu_update_texts(); +} + +sub callback_select_systems() { + if ($vars{"binary_win32"}) { + $vars{"collection-wintools"} = 1; + } else { + $vars{"collection-wintools"} = 0; + } + calc_depends(); + update_numbers(); + menu_update_texts(); +} + +sub callback_edit_directories { + my ($key,$val) = @_; + my $home = getenv('HOME'); + if (win32()) { + $home = getenv('USERPROFILE'); + $home =~ s!\\!/!g; + } + $home ||= '~'; + $val =~ s!\\!/!g; + $vars{$key} = $val; + $vars{'TEXDIR'} =~ s/^~/$home/; + $vars{'TEXMFLOCAL'} =~ s/^~/$home/; + $vars{'TEXMFSYSVAR'} =~ s/^~/$home/; + $vars{'TEXMFSYSCONFIG'} =~ s/^~/$home/; + # only if we set TEXDIR we set the others in parallel + if ($key eq "TEXDIR") { + if ($vars{'TEXDIR'}=~/^(.*)\/$texlive_release$/) { + $vars{'TEXMFLOCAL'}="$1/texmf-local"; + $vars{'TEXMFSYSVAR'}="$1/$texlive_release/texmf-var"; + $vars{'TEXMFSYSCONFIG'}="$1/$texlive_release/texmf-config"; + } elsif ($vars{'TEXDIR'}=~/^(.*)$/) { + $vars{'TEXMFLOCAL'}="$1/texmf-local"; + $vars{'TEXMFSYSVAR'}="$1/texmf-var"; + $vars{'TEXMFSYSCONFIG'}="$1/texmf-config"; + } + $vars{'TEXDIRW'}=$vars{'TEXDIR'} + } + menu_update_texts(); +} + +sub callback_edit_var() { + my ($key,$val) = @_; + $vars{$key} = $val; + menu_update_texts(); +} + +sub dump_vars_stdout { + foreach my $k (keys %vars) { + print "DEBUG: vars{$k} = $vars{$k}\n"; + } +} + +sub toggle_portable { + my $td = $vars{'TEXDIR'}; + my $b; + if ($vars{'portable'}) { + $vars{'portable'} = 0; + $portableyesno = __('No'); + # enable some buttons + for $b ($tmflocalbutton, $tmfsysvarbutton, $tmfsysconfigbutton, $tmfhomebutton) { + $b->configure(-state => 'normal'); + } + for $b ($pathbutton, $deskintbutton, $assocbutton, $adminbutton) { + $b->configure(-state => 'normal') if $b; + } + } else { + $vars{'portable'} = 1; + $portableyesno = __('Yes'); + # disable some buttons. These should get a name first. + for $b ($tmflocalbutton, $tmfsysvarbutton, $tmfsysconfigbutton, $tmfhomebutton) { + $b->configure(-state => 'disabled'); + } + $vars{'option_path'} = 0; + $vars{'option_desktop_integration'} = 0; + $vars{'option_file_assocs'} = 0; + $vars{'option_w32_multi_user'} = 0; + $deskintyesno = __("No"); + $pathadjyesno = __("No"); + $fileassocyesno = __("None"); + $adminallyesno = __("No"); + for $b ($pathbutton, $deskintbutton, $assocbutton, $adminbutton) { + $b->configure(-state => 'disabled') if $b; + } + } + set_texlive_default_dirs(); # this sub tests for portable and in_place + menu_set_pathes_text(); + # same for some options +} + +sub toggle_and_set_opt_variable { + my ($varsref, $toggleref, $choicesref) = @_; + my ($no, $yes) = $choicesref ? @$choicesref : (__('No'), __('Yes')); + $$toggleref = ($$toggleref eq $yes) ? $no : $yes; + $$varsref = 0; + $$varsref = 1 if ($$toggleref eq $yes); + calc_depends(); + menu_update_texts(); +} + +1; + +__END__ + +### Local Variables: +### perl-indent-level: 2 +### tab-width: 2 +### indent-tabs-mode: nil +### End: +# vim:set tabstop=2 expandtab: # diff --git a/Master/tlpkg/installer/install-menu-text-new.pl b/Master/tlpkg/installer/install-menu-text-new.pl new file mode 100755 index 00000000000..092226643ab --- /dev/null +++ b/Master/tlpkg/installer/install-menu-text-new.pl @@ -0,0 +1,1070 @@ +#!/usr/bin/env perl +# $Id: install-menu-text.pl 20268 2010-10-31 07:26:14Z preining $ +# install-menu-txt.pl +# +# Copyright 2007, 2008, 2009, 2010 Norbert Preining, Karl Berry +# Copyright 2007, 2008 Reinhard Kotucha +# This file is licensed under the GNU General Public License version 2 +# or any later version. +# +# This file implements the text based menu system for the TeX Live installer. + +use vars qw(@::end_install_hook $::opt_no_cls); + +our %vars; +our $tlpdb; +our @media_available; +our $previoustlpdb; +our @collections_std; +our @collections_lang; +our @collections_lang_doc; +our $texlive_release; + +my $MENU_CONTINUE = -1; +our $MENU_INSTALL = 0; +our $MENU_ABORT = 1; +our $MENU_QUIT = 2; + + +my $RETURN = $MENU_CONTINUE; + +# issue welcome message on end of installation +push @::end_install_hook, + sub { if (win32()) { print TeXLive::TLUtils::welcome(); } + else { print TeXLive::TLUtils::welcome_paths(); } }; + +sub clear_screen { + return 0 if ($::opt_no_cls); + system (unix() ? 'clear' : 'cls'); +} + +sub string_to_list { + my $string=shift; + return split(//, $string); +} + +sub button { + my $val=shift; + return ($val)? '[X]':'[ ]'; +} + +sub hbar { + return '=' x79, "\n"; +} + +sub toggle { + my $var=shift; + $vars{$var} = ($vars{$var} ? 0 : 1); +} + +sub menu_head { + my $text = shift; + clear_screen; + print hbar(), "$text\n\n"; +} + +sub other_options { + my @options=@_; + my %opts=( + '-' => 'deselect all', + '+' => 'select all', + 'H' => 'help', + 'R' => 'return to main menu', + 'Q' => 'quit' + ); + + $opts{'I'}=$vars{'portable'} ? 'start portable installation' : 'start hd installation'; + + print "\nActions:"; + if ($options[$#options] eq 'diskspace') { + pop @options; + calc_depends (); + print " (disk space required: $vars{'total_size'} MB)"; + } + print "\n"; + + for my $option (@options) { + if (defined $opts{"$option"}) { + printf " <%s> %s\n", $option, $opts{$option}; + } else { + die "other_options: $opts{$option} undefined.\n"; + } + } +} + +sub prompt { + my $prompt = shift; + print "\n$prompt: "; + my $answer = <STDIN>; + $answer = "q" if !defined($answer); + chomp($answer); + return "$answer"; +} + +# The menu loop. A menu is a function. Its return value is a +# reference to another menu or to itself. +sub run_menu_text { + my (@args) = @_; + # the text mode installer does not take interest in any argument + # but the -old-installation-found + while (@args) { + my $f = shift @args; + if ($f =~ m/^-old-installation-found=(.*)$/) { + my $dn = $1; + print "\nAn old installation of TeX Live has been found in $dn\n"; + print " +If you want the selection of collections and various options being taken +over press `y', otherwise anything else. + +Import settings from previous TeX Live installation: (y/n): "; + chomp(my $yn = <STDIN>); + if ($yn =~ m/^y$/i) { + import_settings_from_old_tlpdb($dn); + } + } + } + my $menu=\&main_menu; + while ($RETURN == $MENU_CONTINUE) { + $menu=$menu->(); + } + return($RETURN); +} +$::run_menu = \&run_menu_text; + +sub binary_menu { + my %command=( + 'self' => \&binary_menu, + 'R' => \&main_menu, + 'Q' => \&quit + ); + + my @binaries; + my @keys=string_to_list "abcdefghijklmopstuvwxyz"; + my $index=0; + my %keyval; + my $selected_platform; + + menu_head "Available platforms:"; + + foreach my $key (keys %vars) { + if ($key =~ /binary_(.*)/) { + push @binaries, $1; + } + } + @binaries=sort(@binaries); + + foreach my $binary (@binaries) { + printf " %s %s %-16s %s\n", $keys[$index], + button($vars{"binary_$binary"}), + "$binary", + platform_desc($binary); + $keyval{"$keys[$index]"} = "binary_$binary"; + ++$index; + } + other_options qw(- + R Q diskspace); + + my $answer = prompt 'Enter letter(s) to select platforms'; + + my @keystrokes=string_to_list $answer; + + foreach my $keystroke (@keystrokes) { + if ($keystroke eq '-') { + for my $binary (@binaries) { + $vars{"binary_$binary"}=0 if defined $vars{"binary_$binary"}; + } + } + if ($keystroke eq '+') { + for my $binary (@binaries) { + $vars{"binary_$binary"}=1 if defined $vars{"binary_$binary"}; + } + } + if (defined $keyval{$keystroke}) { + toggle "$keyval{$keystroke}"; + } elsif (!defined $command{"\u$answer"}) { + print "Unknown command: $keystroke\n\n"; + } + } + if ($vars{"binary_win32"}) { + $vars{"collection-wintools"} = 1; + } else { + $vars{"collection-wintools"} = 0; + } + if (defined $command{"\u$answer"}) { + return $command{"\u$answer"}->(); + } else { + return $command{'self'}->(); + } +} + + +sub scheme_menu { + my %command=( + 'self' => \&scheme_menu, + 'R' => \&main_menu, + 'Q' => \&quit + ); + + my @schemes; + my @keys=string_to_list "abcdefghijklmnopstuvwxyz"; + my %keyval; + my $index=0; + + menu_head 'Select scheme:'; + + foreach my $pkg ($tlpdb->schemes) { + push @schemes, $pkg; + $vars{"$pkg"}=($vars{'selected_scheme'} eq $pkg)? 1:0; + } + @schemes=sort @schemes; + push @schemes, "scheme-custom"; + + foreach my $scheme (@schemes) { + $keyval{$keys[$index]}="$scheme"; + if ($scheme ne "scheme-custom") { + my $tlpobj = $tlpdb->get_package("$scheme"); + printf " %s %s %s\n", $keys[$index], button($vars{"$scheme"}), + $tlpobj->shortdesc; + } else { + printf " %s %s custom selection of collections\n", + $keys[$index], button($vars{'selected_scheme'} eq "scheme-custom"); + } + ++$index; + } + + select_scheme($vars{'selected_scheme'}); + + if ($vars{"binary_win32"}) { + $vars{"collection-wintools"} = 1; + } else { + $vars{"collection-wintools"} = 0; + } + + other_options qw(R Q diskspace); + my $answer = prompt 'Enter letter to select scheme'; + + if (defined $keyval{"$answer"}) { + $vars{'selected_scheme'}=$keyval{"$answer"}; + select_scheme($vars{'selected_scheme'}); + return $command{'self'}->(); + } + if (defined $command{"\u$answer"}) { + return $command{"\u$answer"}->(); + } else { + print "Unknown command: $answer\n\n"; + return $command{'self'}->(); + } +} + + +sub collection_menu { + my %command=( + 'self' => \&collection_menu, + 'R' => \&main_menu, + 'Q' => \&quit + ); + + my @collections; + my @keys=string_to_list "abcdefghijklmnopstuvwxyzABCDEFGHIJKLMNOPSTUVWXYZ"; + my %keyval; + my $index=0; + my @coll_short_desc; + my @coll_long_desc; + + menu_head 'Select collections:'; + + @collections=sort @collections_std; + + foreach my $collection (@collections) { + next if ($collection eq 'collection-perl'); + my $tlpobj = $tlpdb->get_package("$collection"); + if (length $tlpobj->shortdesc>30) { + push @coll_long_desc, $collection; + } else { + push @coll_short_desc, $collection; + } + } + my $singlecolumn_index=@coll_short_desc-1; + +##<cols=2> + my $lines=@coll_short_desc/2; + ++$lines if (@coll_short_desc%2); + for (0..$lines-1) { + $index=$_; + my $collection=$coll_short_desc[$index]; + my $tlpobj = $tlpdb->get_package("$collection"); + $keyval{$keys[$index]}="$collection"; + printf " %s %s %-33s", $keys[$index], button($vars{"$collection"}), + substr($tlpobj->shortdesc,0,33); + if (defined $coll_short_desc[$index+$lines]) { + my $collection=$coll_short_desc[$index+$lines]; + my $tlpobj=$tlpdb->get_package("$collection"); + $keyval{$keys[$index+$lines]}="$collection"; + printf " %s %s %-32s\n", $keys[$index+$lines], + button($vars{"$collection"}), substr($tlpobj->shortdesc,0,32); + } else { + print "\n"; + } + } +##</cols=2> + $index=$singlecolumn_index; +# print "\n$index\n\n"; + foreach my $collection (@coll_long_desc) { + my $tlpobj=$tlpdb->get_package("$collection"); + $keyval{$keys[$index+1]}="$collection"; + printf " %s %s %s\n", $keys[$index+1], button($vars{"$collection"}), + $tlpobj->shortdesc; + ++$index; + } +##</cols=1> + + other_options qw(- + R Q diskspace); + my $answer = prompt 'Enter letter(s) to select collection(s)'; + + my @keystrokes=string_to_list $answer; + + foreach my $keystroke (@keystrokes) { + if ($keystroke eq '-') { + for my $collection (@collections) { + $vars{"$collection"}=0 if defined $vars{"$collection"}; + } + } + if ($keystroke eq '+') { + for my $collection (@collections) { + $vars{"$collection"}=1 if defined $vars{"$collection"}; + } + } + if (defined $keyval{$keystroke}) { + toggle "$keyval{$keystroke}"; + } elsif (!defined $command{"\u$answer"}) { + print "Unknown command: $keystroke\n\n"; + } + } + + if (defined $command{"\u$answer"}) { + # if we play around with collections we also select custom-scheme + # but we do not switch back to originally afterwards, too complicated + # to be done + select_scheme("scheme-custom"); + return $command{"\u$answer"}->(); + } else { + return $command{'self'}->(); + } +} + +sub language_menu { + my %command=( + 'self' => \&language_menu, + 'R' => \&main_menu, + 'Q' => \&quit + ); + + my @languages; + my @lang_docs; + my @lang_keys=string_to_list "abcdefghijklmnopstuvwxyz0123456789"; + my @lang_doc_keys=string_to_list "ABCDEFGHIJKLMNOPSTUVWXYZ"; + my %keyval; + my $lang_index=0; + my $lang_doc_index=0; + my $lines; + + menu_head 'Language support:'; + + @languages=sort @collections_lang; + @lang_docs=sort @collections_lang_doc; + + $lines=@languages/2; + ++$lines if (@languages%2); + for my $index (0..$lines-1) { + my $language=$languages[$index]; + my $tlpobj = $tlpdb->get_package("$language"); + $keyval{$lang_keys[$index]}="$language"; + printf " %s %s %-33s", $lang_keys[$index], button($vars{"$language"}), + substr($tlpobj->shortdesc,0,33); + if (defined $languages[$index+$lines]) { + my $language=$languages[$index+$lines]; + my $tlpobj = $tlpdb->get_package("$language"); + $keyval{$lang_keys[$index+$lines]}="$language"; + printf " %s %s %-32s\n", $lang_keys[$index+$lines], + button($vars{"$language"}), substr($tlpobj->shortdesc,0,32); + } else { + print "\n"; + } + } + + print "\nLanguage-specific documentation:\n\n"; + + $lines=@lang_docs/2; + ++$lines if (@lang_docs%2); + for my $index (0..$lines-1) { + my $lang_doc=$lang_docs[$index]; + my $tlpobj = $tlpdb->get_package("$lang_doc"); + $keyval{$lang_doc_keys[$index]}="$lang_doc"; + printf " %s %s %-33s", $lang_doc_keys[$index], button($vars{"$lang_doc"}), + substr($tlpobj->shortdesc,0,33); + if (defined $lang_docs[$index+$lines]) { + my $lang_doc=$lang_docs[$index+$lines]; + my $tlpobj = $tlpdb->get_package("$lang_doc"); + $keyval{$lang_doc_keys[$index+$lines]}="$lang_doc"; + printf " %s %s %-32s\n", $lang_doc_keys[$index+$lines], + button($vars{"$lang_doc"}), substr($tlpobj->shortdesc,0,32); + } else { + print "\n"; + } + } + + other_options qw (+ - R Q diskspace); + my $answer = prompt 'Enter letter(s) to select language(s)'; + + my @keystrokes=string_to_list $answer; + + foreach my $keystroke (@keystrokes) { + if ($keystroke eq '-') { + for my $collection (@languages,@lang_docs) { + $vars{"$collection"}=0 if defined $vars{"$collection"}; + } + } + if ($keystroke eq '+') { + for my $collection (@languages,@lang_docs) { + $vars{"$collection"}=1 if defined $vars{"$collection"}; + } + } + if (defined $keyval{$keystroke}) { + toggle "$keyval{$keystroke}"; + } elsif (!defined $command{"\u$answer"}) { + print "Unknown command: $keystroke\n\n"; + } + } + + if (defined $keyval{"$answer"}) { + return $command{'self'}->(); + } + if (defined $command{"\u$answer"}) { + select_scheme("scheme-custom"); + return $command{"\u$answer"}->(); + } else { + return $command{'self'}->(); + } +} + + +sub directories_menu +{ + my %command=( + 'self' => \&directories_menu, + 'R' => \&main_menu, + 'Q' => \&quit + ); + + my $maindir = 'TEXDIR'; + + menu_head "Directories setup:"; + if (!TeXLive::TLUtils::texdir_check($vars{$maindir})) { + print "!! The default location as given below can't be written to. +!! Either change the destination directory using <1> or create it +!! outside this script. +"; + } + if (!$vars{'in_place'}) { + print <<"EOF"; + <1> TEXDIR: $vars{'TEXDIR'} + support tree: $vars{'TEXDIR'}/texmf +EOF + } else { + print <<"EOF"; + TEXDIR: $vars{'TEXDIR'} + support tree: $vars{'TEXDIR'}/texmf +EOF + } + if (!$vars{'portable'}) { + print <<"EOF"; + + <2> TEXMFLOCAL: $vars{'TEXMFLOCAL'} + <3> TEXMFSYSVAR: $vars{'TEXMFSYSVAR'} + <4> TEXMFSYSCONFIG: $vars{'TEXMFSYSCONFIG'} + + <5> TEXMFVAR: $vars{'TEXMFVAR'} + <6> TEXMFCONFIG: $vars{'TEXMFCONFIG'} + <7> TEXMFHOME: $vars{'TEXMFHOME'} + +EOF + + if (win32) { + print " Note: ~ will expand to %USERPROFILE%\n"; + } else { + print " Note: ~ will expand to \$HOME (or to %USERPROFILE% on Windows)\n"; + } + } + + other_options qw(R Q); + my $answer = prompt 'Enter command'; + + if ("\u$answer" eq '1' and !$vars{'in_place'}) { + print "New value for $maindir [$vars{$maindir}]: "; + $answer = &input_dirname (); + $vars{$maindir} = $answer if $answer ne ""; + if ($vars{$maindir}=~/^(.*)\/$texlive_release$/) { + $vars{'TEXMFLOCAL'}="$1/texmf-local"; + $vars{'TEXMFSYSVAR'}="$1/$texlive_release/texmf-var"; + $vars{'TEXMFSYSCONFIG'}="$1/$texlive_release/texmf-config"; + } elsif ($vars{$maindir}=~/^(.*)$/) { + $vars{'TEXMFLOCAL'}="$1/texmf-local"; + $vars{'TEXMFSYSVAR'}="$1/texmf-var"; + $vars{'TEXMFSYSCONFIG'}="$1/texmf-config"; + } + return $command{'self'}; + + } elsif ("\u$answer" eq '2' and !$vars{'portable'}) { + print "New value for TEXMFLOCAL [$vars{'TEXMFLOCAL'}]: "; + $answer = &input_dirname (); + $vars{'TEXMFLOCAL'} = $answer if $answer ne ""; + return $command{'self'}; + + } elsif ("\u$answer" eq '3' and !$vars{'portable'}) { + print "New value for TEXMFSYSVAR [$vars{'TEXMFSYSVAR'}]: "; + $answer = &input_dirname (); + $vars{'TEXMFSYSVAR'} = $answer if $answer ne ""; + return $command{'self'}; + + } elsif ("\u$answer" eq '4' and !$vars{'portable'}) { + print "New value for TEXMFSYSCONFIG [$vars{'TEXMFSYSCONFIG'}]: "; + $answer = &input_dirname (); + $vars{'TEXMFSYSCONFIG'} = $answer if $answer ne ""; + return $command{'self'}; + + } elsif ("\u$answer" eq '5' and !$vars{'portable'}) { + print "New value for TEXMFVAR [$vars{'TEXMFVAR'}]: "; + $answer = &input_dirname ("noexpansion"); + $vars{'TEXMFVAR'} = $answer if $answer ne ""; + return $command{'self'}; + + } elsif ("\u$answer" eq '6' and !$vars{'portable'}) { + print "New value for TEXMFCONFIG [$vars{'TEXMFCONFIG'}]: "; + $answer = &input_dirname ("noexpansion"); + $vars{'TEXMFCONFIG'} = $answer if $answer ne ""; + return $command{'self'}; + + } elsif ("\u$answer" eq '7' and !$vars{'portable'}) { + print "New value for TEXMFHOME [$vars{'TEXMFHOME'}]: "; + $answer = &input_dirname ("noexpansion"); + $vars{'TEXMFHOME'} = $answer if $answer ne ""; + return $command{'self'}; + } + + if (defined $command{"\u$answer"}) { + return $command{"\u$answer"}->(); + } else { + print "Unknown command: $answer\n\n"; + return $command{'self'}->(); + } +} + + +# Helper function to read a directory name and clean it up. +# Unless NO_EXPANSION is true, convert to absolute path. +# +sub input_dirname +{ + my $noexpansion = shift; + chomp (my $answer = <STDIN>); + return "" if $answer eq ""; + + $answer =~ s!\\!/!g if win32(); # switch to forward slashes + + if (!$noexpansion) { + my $home = getenv('HOME'); + $home = getenv('USERPROFILE') if win32(); + $home ||= '~'; + $answer =~ s/^~/$home/; # $home expansion + } + + if ($answer !~ m/^~/) { + # relative paths are unlikely to work in texmf.cnf, et al., + # and don't have any apparent practical use. Convert to absolute. + if (! File::Spec->file_name_is_absolute($answer)) { + $answer = Cwd::abs_path($answer); + } + } + return $answer; +} + + +$vars{'page'}=0; + +sub html2text { + my $filename=shift; + my @text; + open IN, "$filename"; + @all_lines=<IN>; + close IN; + chomp @all_lines; + + my $itemcnt; + my $ordered_list=0; + my $h1_indent=25; + my $h2_indent=3; + my $h3_indent=6; + + for (@all_lines) { + next if /DOCTYPE/; + next if /<!--/; + next if /<title/i; + next if /<\/?body/i; + next if /<\/?html/i; + next if /<\/?head/i; + next if /<\/?meta/i; + next if /^\s*$/; # ignore empty lines + + s/<i>/"/gi; s/<\/i>/"/gi; # italics + s/<tt>/'/gi; s/<\/tt>/'/gi; # typewriter + s/<p>.*//gi; # paragraphs + s/<\/ul>.*//gi; # unsorted lists + s/<\/ol>.*//gi; # ordered lists + s/—/--/gi; # mdash + s/</</gi; s/>/>/gi; # < and > + if (/<h1>(.*?)<\/h1>/i) { + push @text, " " x $h1_indent. "$1\n"; + push @text, " " x $h1_indent. "=" x (length $1). "\n"; + push @text, "\n"; + } elsif (/<h2>(.*?)<\/h2>/i) { + push @text, "\n"; + push @text, " " x $h2_indent. "$1\n"; + push @text, " " x $h2_indent. "~" x (length $1). "\n"; + push @text, "\n"; + } elsif (/<h3>(.*?)<\/h3>/i) { + push @text, "\n"; + push @text, " " x $h3_indent. "$1\n"; + push @text, " " x $h3_indent. "-" x (length $1). "\n"; + push @text, "\n"; + } elsif (/<ol>/i) { + $ordered_list=1; + $itemcnt=1; + } elsif (/<ul>/i) { + $ordered_list=0; + } elsif (/^\s*<li>\s*(.*)/) { + if ($ordered_list) { + push @text, "\n"; + push @text, " $itemcnt. $1\n"; + ++$itemcnt; + } else { + push @text, "\n"; + push @text, " * $1\n"; + } + } else { + push @text, "$_\n"; + } + } + return @text; +} + + +sub help_menu { + my %command=( + 'self' => \&help_menu, + 'R' => \&main_menu, + 'Q' => \&quit + ); + my $installer_help="$installerdir/tlpkg/installer/install-tl.html"; + + clear_screen; + + my @text=html2text "$installer_help"; + my $lines=(@text); + my $overlap=3; + my $lps=32; # lines per screen - overlap + my $firstline=$vars{'page'}*$lps; + my $lastline=$firstline+$lps+$overlap; + my $line=0; +# print "<<<$firstline>>> <<<$lastline>>>\n"; + for (@text) { + print "$_" if ($line>=$firstline and $line<=$lastline); + ++$line; + } + print "\n", hbar, + " <T> top <N> next page <P> previous page <R> return" + . " <Q> quit --", $vars{'page'}+1, "--\n"; + + my $answer = prompt 'Enter command'; + + if ("\u$answer" eq 'T') { + $vars{'page'}=0; + return $command{'self'}; + + } elsif ("\u$answer" eq 'N') { + $vars{'page'}+=1 unless $lastline>$lines; + return $command{'self'}; + + } elsif ("\u$answer" eq 'P') { + $vars{'page'}-=1 if $vars{'page'}>=1; + return $command{'self'}; + + } elsif (defined $command{"\u$answer"}) { + return $command{"\u$answer"}; + + } else { + print "Unknown command: $answer\n\n"; + return $command{'self'}; + } +} + + +sub options_menu { + my $b_path=button($vars{'option_path'}); + my $b_doc=button($vars{'option_doc'}); + my $b_src=button($vars{'option_src'}); + my $b_fmt=button($vars{'option_fmt'}); + my $b_letter=button($vars{'option_letter'}); + my $b_deskint=button($vars{'option_desktop_integration'}); + my $b_admin=button($vars{'option_w32_multi_user'}); + my $b_addoneditor=button($vars{'collection-texworks'}); + my $b_restricted=button($vars{'option_write18_restricted'}); + + my $sys_bin=$vars{'option_sys_bin'}; + my $sys_man=$vars{'option_sys_man'}; + my $sys_info=$vars{'option_sys_info'}; + + my $t_sys_bin=($vars{'option_path'})? $vars{'option_sys_bin'}:''; + my $t_sys_man=($vars{'option_path'})? $vars{'option_sys_man'}:''; + my $t_sys_info=($vars{'option_path'})? $vars{'option_sys_info'}:''; + + my %command=( + 'self' => \&options_menu, + 'R' => \&main_menu, + 'Q' => \&quit + ); + + clear_screen; + menu_head "Options setup:"; + + print <<"EOF"; + <P> use letter size instead of A4 by default: $b_letter + <E> execution of restricted list of programs: $b_restricted + <F> create format files: $b_fmt +EOF +; + if ($vars{'doc_splitting_supported'} and !$vars{'in_place'}) { + print " <D> install font/macro doc tree: $b_doc\n"; + } + if ($vars{'src_splitting_supported'} and !$vars{'in_place'}) { + print " <S> install font/macro source tree: $b_src\n"; + } + if (!$vars{'portable'}) { + if (unix() || $::opt_all_options) { + print <<"EOF"; + <L> create symlinks in standard directories: $b_path + binaries to: $t_sys_bin + manpages to: $t_sys_man + info to: $t_sys_info +EOF +; + } else { + print <<"EOF"; + <L> adjust registry entry for path: $b_path +EOF +; + } + if (win32() || $::opt_all_options) { + print " <M> install menu items, shortcuts, etc: $b_deskint\n"; + print " <N> update file associations: [$::fileassocdesc[$vars{'option_file_assocs'}]]\n"; + if ($::opt_all_options || TeXLive::TLWinGoo::admin()) { + # if we are admin we allow normal user installation, too + print " <U> make installation available to all users: $b_admin\n"; + } + } + } + if (win32() || $::opt_all_options) { + print " <W> install TeXworks front end: $b_addoneditor\n"; + } + other_options qw(R Q diskspace); + my $answer = prompt 'Enter command'; + + # option_path + + if (unix()) { + if (("\u$answer" eq 'L') and !$vars{'portable'}) { + my $home = getenv('HOME'); + $home = getenv('USERPROFILE') if (win32()); + $home ||= '~'; + toggle 'option_path'; + if ($vars{'option_path'}) { + print "New value for binary directory [$sys_bin]: "; + chomp($answer=<STDIN>); + $vars{'option_sys_bin'} = "$answer" if (length $answer); + $vars{'option_sys_bin'} =~ s@\\@/@g if (win32()); + $vars{'option_sys_bin'} =~ s/^~/$home/; + if ($vars{'option_sys_bin'}=~/^(.*)\/bin$/) { + $vars{'option_sys_man'}="$1/man"; + $vars{'option_sys_info'}="$1/info"; + } + print "New value for man directory [$vars{'option_sys_man'}]: "; + chomp($answer=<STDIN>); + $vars{'option_sys_man'}="$answer" if (length $answer); + $vars{'option_sys_man'} =~ s@\\@/@g if (win32()); + $vars{'option_sys_man'} =~ s/^~/$home/; + + print "New value for info directory [$vars{'option_sys_info'}]: "; + chomp($answer=<STDIN>); + $vars{'option_sys_info'}="$answer" if (length $answer); + $vars{'option_sys_info'} =~ s@\\@/@g if (win32()); + $vars{'option_sys_info'} =~ s/^~/$home/; + } + return $command{'self'}; + } + } else { + if (("\u$answer" eq 'L') and !$vars{'portable'}) { + my $home = getenv('HOME'); + $home = getenv('USERPROFILE') if (win32()); + $home ||= '~'; + toggle 'option_path'; + return $command{'self'}; + } + } + + # option_desktop_integration, option_file_assocs + + if (win32() || $::opt_all_options) { + if ("\u$answer" eq 'M' and !$vars{'portable'}) { + toggle 'option_desktop_integration'; + return $command{'self'}; + + } elsif ("\u$answer" eq 'N' and !$vars{'portable'}) { + print "New value for file_assocs:\n"; + print " 0 -- don't tweak the file associations\n"; + print " 1 -- only add new file associations, don't overwrite old ones\n"; + print " 2 -- always create file associations to TeX Live programs\n"; + print "New value for file_assocs [$vars{'option_file_assocs'}]: "; + chomp (my $a = <STDIN>); + if ($a eq "0" || $a eq "1" || $a eq "2") { + $vars{'option_file_assocs'} = $a; + } + return $command{'self'}; + + } elsif ("\u$answer" eq 'U' and !$vars{'portable'}) { + toggle 'option_w32_multi_user'; + return $command{'self'}; + } + } + + # other options + + if ("\u$answer" eq 'P') { + toggle 'option_letter'; + return $command{'self'}; + + } elsif ("\u$answer" eq 'F') { + toggle 'option_fmt'; + return $command{'self'}; + + } elsif ("\u$answer" eq 'E') { + toggle 'option_write18_restricted'; + return $command{'self'}; + + } elsif ("\u$answer" eq 'S' and !$vars{'in_place'}) { + toggle 'option_src'; + return $command{'self'}; + + } elsif ("\u$answer" eq 'D' and !$vars{'in_place'}) { + toggle 'option_doc'; + return $command{'self'}; + + } elsif (defined $command{"\u$answer"}) { + return $command{"\u$answer"}; + + } elsif (("\u$answer" eq 'W') && ($::opt_all_options || win32()) && + !$vars{'in_place'} ) { + toggle 'collection-texworks'; + return $command{'self'}; + + } else { + print "Unknown or unsupported command: $answer\n\n"; + return $command{'self'}; + } +} + + +sub quit { + exit 0; + $RETURN = $MENU_QUIT; +} + +sub do_install { + $RETURN = $MENU_INSTALL; +} + +sub toggle_portable { + if ($vars{'portable'}) { + $vars{'portable'} = 0; + $vars{'option_desktop_integration'} = 0; + $vars{'option_path'} = 0; + $vars{'option_file_assocs'} = 0; + $vars{'option_w32_multi_user'} = 0; + } else { + $vars{'portable'} = 1; + $vars{'option_desktop_integration'} = 1; + $vars{'option_path'} = 1; + $vars{'option_file_assocs'} = 1; + $vars{'option_w32_multi_user'} = 1; + } + set_texlive_default_dirs(); # this sub tests for portable and in_place + main_menu; +} + +sub main_menu { + my $this_platform=platform_desc($vars{'this_platform'}); + + my $b_path=button($vars{'option_path'}); + my $b_doc=button($vars{'option_doc'}); + my $b_src=button($vars{'option_src'}); + my $b_fmt=button($vars{'option_fmt'}); + my $b_letter=button($vars{'option_letter'}); + my $b_deskint=button($vars{'option_desktop_integration'}); + my $b_admin=button($vars{'option_w32_multi_user'}); + my $b_addoneditor=button($vars{'collection-texworks'}); + my $b_restricted=button($vars{'option_write18_restricted'}); + + my $warn_nobin; + + $warn_nobin=set_install_platform; + + my $maindir = 'TEXDIR'; + + $vars{'n_systems_selected'}=0; + $vars{'n_collections_selected'}=0; + foreach my $key (keys %vars) { + if ($key=~/^binary.*/) { + ++$vars{'n_systems_selected'} if $vars{$key}==1; + } + if ($key=~/^collection/) { + ++$vars{'n_collections_selected'} if $vars{$key}==1; + } + } + calc_depends(); + + my %command = ( + 'self' => \&main_menu, + 'D' => \&directories_menu, + 'H' => \&help_menu, + 'I' => \&do_install, + 'O' => \&options_menu, + 'Q' => \&quit, + 'V' => \&toggle_portable, + ); + if (!$vars{'in_place'}) { + $command{'B'} = \&binary_menu if unix(); + $command{'C'} = \&collection_menu; + $command{'L'} = \&language_menu; + $command{'S'} = \&scheme_menu; + } + + clear_screen; + print <<"EOF"; +======================> TeX Live installation procedure <===================== + +=======> Note: Letters/digits in <angle brackets> indicate menu items <======= +=======> for commands or configurable options <======= + + Detected platform: $this_platform + $warn_nobin +EOF + + if (!$vars{'in_place'}) { + print <<"EOF"; + <B> platforms: $vars{'n_systems_selected'} out of $vars{'n_systems_available'} + + <S> installation scheme ($vars{'selected_scheme'}) + $vars{'n_collections_selected'} collections out of $vars{'n_collections_available'}, disk space required: $vars{'total_size'} MB + + Customizing installation scheme: + <C> standard collections + <L> language collections +EOF + + if (!check_on_lang_collection_installed()) { + print " !! No language specific collection selected!\n"; + print " !! If you only write American English documents that is fine!\n"; + } + } + print <<"EOF"; + + <D> directories: + TEXDIR (the main TeX directory): +EOF + + if (TeXLive::TLUtils::texdir_check($vars{$maindir})) { + print " $vars{$maindir}\n"; + } else { + print " !! default location: $vars{$maindir}\n"; + print " !! is not writable, please select a different one!\n"; + } + print <<"EOF"; + TEXMFLOCAL (directory for site-wide local files): + $vars{'TEXMFLOCAL'} + TEXMFSYSVAR (directory for variable and automatically generated data): + $vars{'TEXMFSYSVAR'} + TEXMFSYSCONFIG (directory for local config): + $vars{'TEXMFSYSCONFIG'} + TEXMFVAR (personal directory for variable and automatically generated data): + $vars{'TEXMFVAR'} + TEXMFCONFIG (personal directory for local config): + $vars{'TEXMFCONFIG'} + TEXMFHOME (directory for user-specific files): + $vars{'TEXMFHOME'} + +EOF + +print <<"EOF"; + <O> options: + $b_letter use letter size instead of A4 by default + $b_restricted allow execution of restricted list of programs via \\write18 + $b_fmt create all format files +EOF + + if (!$vars{'in_place'}) { + if ($vars{'doc_splitting_supported'}) { + print " $b_doc install macro/font doc tree\n"; + } + if ($vars{'src_splitting_supported'}) { + print " $b_src install macro/font source tree\n"; + } + } + if (win32()) { + if (!$vars{'portable'}) { + print " $b_path adjust search path\n"; + print " $b_deskint add menu items, shortcuts, etc.\n"; + print " [$vars{'option_file_assocs'}] update file associations\n"; + if (admin()) { + print " $b_admin make installation available to all users\n"; + } + } + print " $b_addoneditor install TeXworks front end\n"; + print " $b_path create symlinks to standard directories\n" unless + ($vars{'portable'} || win32()); + } + + if ($vars{'portable'}) { + print "\n <V> set up for regular hd installation\n"; + } else { + print "\n <V> set up for portable installation\n"; + } + + other_options qw(I H Q); + my $answer = prompt 'Enter command'; + + if (defined $command{"\u$answer"}) { + return $command{"\u$answer"}; + } else { + print "Unknown command: $answer\n\n"; + return $command{'self'}; + } +} + +# needs a terminal 1 for require to succeed! +1; + +__END__ + +### Local Variables: +### perl-indent-level: 2 +### tab-width: 2 +### indent-tabs-mode: nil +### End: +# vim:set tabstop=2 expandtab: # |