diff options
author | Norbert Preining <preining@logic.at> | 2013-04-13 05:32:44 +0000 |
---|---|---|
committer | Norbert Preining <preining@logic.at> | 2013-04-13 05:32:44 +0000 |
commit | 776874e7779ee459aecd4df8d2eddb68f492f17e (patch) | |
tree | 3365e588639069ebd6feab2ac8767ad53e4a1e33 | |
parent | bdcdba5ebfbf898456bac0a46f10458b602673b5 (diff) |
user mode for tlmgr
support a user mode for tlmgr that allows installation of
packages into user trees.
git-svn-id: svn://tug.org/texlive/trunk@29883 c570f23f-e606-0410-a88d-b1316a301751
-rwxr-xr-x | Master/texmf-dist/scripts/texlive/tlmgr.pl | 253 | ||||
-rw-r--r-- | Master/tlpkg/TeXLive/TLConfig.pm | 3 | ||||
-rw-r--r-- | Master/tlpkg/TeXLive/TLPDB.pm | 27 | ||||
-rw-r--r-- | Master/tlpkg/TeXLive/TLPOBJ.pm | 15 | ||||
-rw-r--r-- | Master/tlpkg/TeXLive/TLUtils.pm | 2 |
5 files changed, 267 insertions, 33 deletions
diff --git a/Master/texmf-dist/scripts/texlive/tlmgr.pl b/Master/texmf-dist/scripts/texlive/tlmgr.pl index 9252b732658..3dac77e69e5 100755 --- a/Master/texmf-dist/scripts/texlive/tlmgr.pl +++ b/Master/texmf-dist/scripts/texlive/tlmgr.pl @@ -133,6 +133,8 @@ sub main { "no-execute-actions" => 1, "pin-file" => "=s", "pause" => 1, + "usermode" => 1, + "usertree" => "=s", "print-platform|print-arch" => 1, "version" => 1, "help" => 1, @@ -387,13 +389,30 @@ for the full story.\n"; pod2usage(-msg => $msg, -exitstatus => 1, -verbose => 1, @noperldoc); } + # + # the main tree we will be working on + $::maintree = $Master; + if ($opts{"usermode"}) { + # we could also try to detect that we don't have write permissions + # and switch to user mode automatically + if (defined($opts{"usertree"})) { + $::maintree = $opts{"usertree"}; + } else { + chomp($::maintree = `kpsewhich -var-value TEXMFHOME`); + } + } + # besides doing normal logging if -logfile is specified, we try to log # package related actions (install, remove, update) to # the package-log file TEXMFSYSVAR/web2c/tlmgr.log $packagelogged = 0; # how many msgs we logged chomp (my $texmfsysvar = `kpsewhich -var-value=TEXMFSYSVAR`); $packagelogfile = $opts{"package-logfile"}; - $packagelogfile ||= "$texmfsysvar/web2c/tlmgr.log"; + if ($opts{"usermode"}) { + $packagelogfile ||= "$::maintree/web2c/tlmgr.log"; + } else { + $packagelogfile ||= "$texmfsysvar/web2c/tlmgr.log"; + } # # Try to open the packagelog file, but do NOT die when that does not work if (!open(PACKAGELOG, ">>$packagelogfile")) { @@ -575,6 +594,9 @@ sub execute_action { } elsif ($action =~ m/^info$/i) { action_info(@ARGV); finish(0); + } elsif ($action =~ m/^init-usertree$/i) { + action_init_usertree(); + finish(0); } elsif ($action =~ m/^remove$/i) { action_remove(); } elsif ($action =~ /^paper$/) { @@ -644,6 +666,8 @@ sub handle_execute_actions { my $errors = 0; + my $sysmode = ($opts{"usermode"} ? "" : "-sys"); + if ($::files_changed) { $errors += do_cmd_and_check("mktexlsr"); if (defined($localtlpdb->get_package('context'))) { @@ -671,7 +695,7 @@ sub handle_execute_actions my $dest = "$TEXMFDIST/web2c/updmap.cfg"; TeXLive::TLUtils::create_updmap($localtlpdb, $dest); } - $errors += do_cmd_and_check("updmap-sys") if $updmap_run_needed; + $errors += do_cmd_and_check("updmap$sysmode") if $updmap_run_needed; } # format relevant things @@ -769,7 +793,7 @@ sub handle_execute_actions # first regenerate all formats --byengine for my $e (keys %updated_engines) { log ("updating formats based on $e\n"); - $errors += do_cmd_and_check("fmtutil-sys --no-error-if-no-format --byengine $e"); + $errors += do_cmd_and_check("fmtutil$sysmode --no-error-if-no-format --byengine $e"); } # now rebuild all other formats for my $f (keys %do_enable) { @@ -777,7 +801,7 @@ sub handle_execute_actions # ignore disabled formats next if !$::execute_actions{'enable'}{'formats'}{$f}{'mode'}; log ("(re)creating format dump $f\n"); - $errors += do_cmd_and_check("fmtutil-sys --byfmt $f"); + $errors += do_cmd_and_check("fmtutil$sysmode --byfmt $f"); $done_formats{$f} = 1; } } @@ -797,7 +821,7 @@ sub handle_execute_actions } if ($localtlpdb->option("create_formats") && !$::regenerate_all_formats) { - $errors += do_cmd_and_check("fmtutil-sys --byhyphen $lang"); + $errors += do_cmd_and_check("fmtutil$sysmode --byhyphen $lang"); } } } @@ -806,7 +830,7 @@ sub handle_execute_actions # if ($::regenerate_all_formats) { info("Regenerating all formats, this may take some time ..."); - $errors += do_cmd_and_check("fmtutil-sys --all"); + $errors += do_cmd_and_check("fmtutil$sysmode --all"); info("done\n"); $::regenerate_all_formats = 0; } @@ -975,8 +999,13 @@ sub action_remove { # sub action_paper { init_local_db(); - chomp(my $texmfsysconfig = `kpsewhich -var-value=TEXMFSYSCONFIG`); - $ENV{"TEXMFCONFIG"} = $texmfsysconfig; + my $texmfconfig; + if ($opts{"usermode"}) { + chomp($texmfconfig = `kpsewhich -var-value=TEXMFCONFIG`); + } else { + chomp($texmfconfig = `kpsewhich -var-value=TEXMFSYSCONFIG`); + } + $ENV{"TEXMFCONFIG"} = $texmfconfig; my $action = shift @ARGV; if ($action =~ m/^paper$/i) { # generic paper @@ -988,7 +1017,7 @@ sub action_paper { "as in: tlmgr pdftex paper --list\n"); } elsif (!defined($newpaper)) { # tlmgr paper => show all current sizes. - TeXLive::TLPaper::paper_all($texmfsysconfig,undef); + TeXLive::TLPaper::paper_all($texmfconfig,undef); } elsif ($newpaper !~ /^(a4|letter)$/) { # tlmgr paper junk => complain. $newpaper = "the empty string" if !defined($newpaper); @@ -996,7 +1025,7 @@ sub action_paper { } else { # tlmgr paper {a4|letter} => do it. return if !check_on_writable(); - TeXLive::TLPaper::paper_all($texmfsysconfig,$newpaper); + TeXLive::TLPaper::paper_all($texmfconfig,$newpaper); } } else { # program-specific paper @@ -1013,7 +1042,7 @@ sub action_paper { return if !check_on_writable(); } unshift(@ARGV, "--list") if $opts{"list"}; - TeXLive::TLPaper::do_paper($prog,$texmfsysconfig,@ARGV); + TeXLive::TLPaper::do_paper($prog,$texmfconfig,@ARGV); } } @@ -1021,6 +1050,10 @@ sub action_paper { # PATH # sub action_path { + if ($opts{"usermode"}) { + tlwarn("action `path' not supported in usermode!\n"); + exit 1; + } my $what = shift @ARGV; if (!defined($what) || ($what !~ m/^(add|remove)$/i)) { $what = "" if ! $what; @@ -1277,6 +1310,7 @@ sub action_info { print "longdesc: ", $tlp->longdesc, "\n" if ($tlp->longdesc); print "installed: ", ($installed ? "Yes" : "No"), "\n"; print "revision: ", $tlp->revision, "\n" if ($installed); + print "relocatable: ", ($tlp->relocated ? "Yes" : "No"), "\n"; print "cat-version: ", $tlp->cataloguedata->{'version'}, "\n" if $tlp->cataloguedata->{'version'}; print "cat-date: ", $tlp->cataloguedata->{'date'}, "\n" @@ -2318,7 +2352,10 @@ sub action_update { # check for updates to tlmgr and die unless either --force or --list or --self # is given - my @critical = check_for_critical_updates($localtlpdb, $remotetlpdb); + my @critical; + if (!$opts{"usermode"}) { + @critical = check_for_critical_updates($localtlpdb, $remotetlpdb); + } my $dry_run_cont = $opts{"dry-run"} && ($opts{"dry-run"} < 0); if ( !$dry_run_cont && !$opts{"self"} && @critical) { critical_updates_warning(); @@ -3270,16 +3307,18 @@ sub action_install { init_tlmedia_or_die(); # check for updates to tlmgr itself, and die unless --force is given - if (check_for_critical_updates( $localtlpdb, $remotetlpdb)) { - critical_updates_warning(); - if ($opts{"force"}) { - tlwarn("Continuing due to --force\n"); - } else { - if ($::gui_mode) { - # return here and don't do any updates - return; + if (!$opts{"usermode"}) { + if (check_for_critical_updates( $localtlpdb, $remotetlpdb)) { + critical_updates_warning(); + if ($opts{"force"}) { + tlwarn("Continuing due to --force\n"); } else { - die "tlmgr: Not continuing, please see warning above!\n"; + if ($::gui_mode) { + # return here and don't do any updates + return; + } else { + die "tlmgr: Not continuing, please see warning above!\n"; + } } } } @@ -3298,7 +3337,7 @@ sub action_install { @packs = $remotetlpdb->expand_dependencies("-only-arch", $localtlpdb, @ARGV) unless $opts{"no-depends-at-all"}; # now expand all others unless $opts{"no-depends"} # if $opts{"reinstall"} do not collection->collection dependencies - if ($opts{"reinstall"}) { + if ($opts{"reinstall"} || $opts{"usermode"}) { @packs = $remotetlpdb->expand_dependencies("-no-collections", $localtlpdb, @packs) unless $opts{"no-depends"}; } else { @packs = $remotetlpdb->expand_dependencies($localtlpdb, @packs) unless $opts{"no-depends"}; @@ -3379,6 +3418,15 @@ sub action_install { foreach my $pkg (@todo) { my $flag = $FLAG_INSTALL; my $re = ""; + my $tlp = $remotetlpdb->get_package($pkg); + if (!defined($tlp)) { + info("Unknown package $pkg\n"); + next; + } + if (!$tlp->relocated && $opts{"usermode"}) { + info("Package $pkg is not relocatable, cannot install it in user mode!\n"); + next; + } if (defined($localtlpdb->get_package($pkg))) { if ($opts{"reinstall"}) { $re = "re"; @@ -3986,11 +4034,11 @@ sub action_option { # now also save the TLPOBJ of 00texlive.installation my $tlpo = $localtlpdb->get_package("00texlive.installation"); if ($tlpo) { - if (open(TOFD, ">$Master/tlpkg/tlpobj/00texlive.installation.tlpobj")) { + if (open(TOFD, ">$::maintree/tlpkg/tlpobj/00texlive.installation.tlpobj")) { $tlpo->writeout(\*TOFD); close(TOFD); } else { - tlwarn("Cannot save 00texlive.installation to $Master/tlpkg/tlpobj/00texlive.installation.tlpobj\n"); + tlwarn("Cannot save 00texlive.installation to $::maintree/tlpkg/tlpobj/00texlive.installation.tlpobj\n"); } } } else { @@ -4023,6 +4071,10 @@ sub action_platform { warn("action `platform' not supported on Windows\n"); return(); } + if ($opts{"usermode"}) { + tlwarn("action `platform' not supported in usermode\n"); + exit 1; + } my $what = shift @ARGV; init_local_db(1); info("platform: dry run, no changes will be made\n") if $opts{"dry-run"}; @@ -4174,6 +4226,10 @@ sub action_platform { # GENERATE # sub action_generate { + if ($opts{"usermode"}) { + tlwarn("action `generate' not supported in usermode!\n"); + exit 1; + } my $what = shift @ARGV; init_local_db(); @@ -5055,6 +5111,37 @@ sub action_postaction { } } +# INIT USER TREE +# sets up the user tree for tlmgr in user mode +sub action_init_usertree { + init_local_db(); + my $tlpdb = TeXLive::TLPDB->new; + my $usertree; + if ($opts{"usertree"}) { + $usertree = $opts{"usertree"}; + } else { + chomp($usertree = `kpsewhich -var-value TEXMFHOME`); + } + if (-r "$usertree/$InfraLocation/$DatabaseName") { + tldie("$prg: user mode database already set up in\n$prg: $usertree/$InfraLocation/$DatabaseName\n$prg: not overwriting it.\n"); + } + $tlpdb->root($usertree); + # copy values from main installation over + my $maininsttlp = $localtlpdb->get_package("00texlive.installation"); + my $inst = $maininsttlp->copy; + $tlpdb->add_tlpobj($inst); + # remove all available architectures + $tlpdb->setting( "available_architectures", ""); + # specify that we are in user mode + $tlpdb->setting( "usertree", 1 ); + $tlpdb->save; + # + # we need to create web2c dir for TLMedia to succeed setting up + # and for tlmgr.log file + mkdir ("$usertree/web2c"); + mkdir ("$usertree/tlpkg/tlpobj"); +} + # CONF # tries to mimic texconfig conf but can also set values for both tlmgr # and texmf conf files. @@ -5178,8 +5265,8 @@ sub init_local_db { # to make sure that the settings in the local tlpdb do not overwrite # stuff changed via the GUI return if defined $localtlpdb; - $localtlpdb = TeXLive::TLPDB->new ( root => $Master ); - die("cannot setup TLPDB in $Master") unless (defined($localtlpdb)); + $localtlpdb = TeXLive::TLPDB->new ( root => $::maintree ); + die("cannot setup TLPDB in $::maintree") unless (defined($localtlpdb)); # setup the programs, for w32 we need the shipped wget/xz etc, so we # pass the location of these files to setup_programs. if (!setup_programs("$Master/tlpkg/installer", $localtlpdb->platform)) { @@ -5747,6 +5834,7 @@ sub packagecmp { } sub check_on_writable { + return 1 if $opts{"usermode"}; if (!TeXLive::TLUtils::dir_writable("$Master/tlpkg")) { tlwarn("You don't have permission to change the installation in any way,\n"); tlwarn("specifically, the directory $Master/tlpkg/ is not writable.\n"); @@ -5921,6 +6009,15 @@ In GUI mode, this switch makes C<tlmgr> report any missing, or more likely untranslated, messages to standard error. This can help translators to see what remains to be done. +=item B<--usermode> + +Activates the user mode, see L<USER MODE> below. + +=item B<--usertree> I<dir> + +Uses I<dir> as user tree in user mode, seel L<USER MODE> below. + + =back The standard options for TeX Live programs are also accepted: @@ -6973,6 +7070,110 @@ If the package on the server is older than the package already installed downgrade. Also, packages for uninstalled platforms are not installed. + +=head2 init-usertree + +sets up the default user tree (C<TEXMFHOME>) or the one specified +on the command line using C<--usertree> for user mode management. +See L<USER MODE> below. + + +=head1 USER MODE + +B<WARNING> B<WARNING> B<WARNING> +This is very much work in progress +and experimental. Expect breakage, and the need to reinstall your +user tree a new. + +C<tlmgr> provides a restricted way to manage arbitrary texmf trees +in the same way as the installation. This allows a user without write +permissions to the installation location to update/install packages +into a user tree. + +C<tlmgr> is set into user mode by giving the command line option +C<--usermode>. It will not switch automatically, nor does it support +a config file by now. Thus, this option has to be given every time. + +This mode of C<tlmgr> works on a user tree, which by default will be +the value of C<TEXMFHOME>, but can be overridden with the command line +option C<--usertree>. In the following when we speak of the user tree +we mean either C<TEXMFHOME> or the one given on the command line. + +Not all actions are allowed in user mode, C<tlmgr> will warn you and +not carry out this action. The actions of C<tlmgr> can be classified into +those that don't need write permissions and thus are working the same +in user mode or normal mode. Currently these are +B<help>, B<version>, B<search>, B<show>, B<list>, B<check>, B<print-arch>. + +Most of the actions dealing with package management on the other hand +need write permissions, and behave differently: +B<install>, B<update>, B<remove>, B<option>, B<paper>, B<generate>, +B<backup>, B<restore>, B<uninstall>, B<symlinks>. + +Currently not supported (and probably will never be) is the B<arch> +action. + +As for the B<gui> action it is currently not supported, but might be +in future. + +Before using C<tlmgr> in user mode, you have to set up the user tree +with the B<init-usertree> action. This will create C<USERTREE/web2c>, +C<USERTREE/tlpkg/tlpobj> and set up a minimal C<USERTREE/tlpkg/texlive.tlpdb>. +From then on you can use the supported actions as normal by adding +the C<--usermode> command line switch. + +In user mode the file C<USERTREE/tlpkg/texlive.tlpdb> contains only the +packages that have been installed into the user tree C<USERTREE> using +C<tlmgr>, plus additional options in the virtual package +00texlive.installation (like with the main installation's texlive.tlpdb). + +All actions on packages in user mode can only be carried out on packages +that are marked as B<relocatable>. Basically that means that the contained +files all reside in the C<texmd-dist> tree. B<NOTE> That already excludes +all binary packages! Of the currently about 1900 packages the majority, +currently about 1750, are relocatable, i.e., they can be installed into +a user tree. + +Description of changes of actions in user mode: + +=head2 install + +in usermode the tlmgr action install will check that the package +and all depending packages are either all relocated, or those that +are not relocated are already installed in the system installation. +If this is true it will unpack all containers to be installed into +the user tree (TEXMFHOME or the value of --user-tree) and add the +respective packages to the user texlive.tlpdb (creating it if there +has non be created till now). + +Currently installing a collection installs all depending packages, +but in contrast to normal mode does not install depending collections. +So in *normal* mode tlmgr install collection-context would install +collection-metapost, c-basic, c-documentation-base, too. In *usermode* +only the packages mentioned in collection-context are installed. + +=head2 backup, restore, remove, update + +in usermode the tlmgr action update will check that all packages +to be updated are installed in the user tree, otherwise it behaves +exactely like the system tlmgr. + +=head2 option + +only acts upon the user's texlive.tlpdb + +=head2 paper + +changes configuration files in user tree + +=head2 generate + +creates configuration files in user tree + +B<WARNING WARNING WARNING> Be again warned that this is very experimental! + + + =head1 TLMGR CONFIGURATION FILE A small subset of the command line options can be set in a config file diff --git a/Master/tlpkg/TeXLive/TLConfig.pm b/Master/tlpkg/TeXLive/TLConfig.pm index d6da6a76fa9..c8a8319bda2 100644 --- a/Master/tlpkg/TeXLive/TLConfig.pm +++ b/Master/tlpkg/TeXLive/TLConfig.pm @@ -185,7 +185,8 @@ our %TLPDBOptions = ( our %TLPDBSettings = ( "platform" => [ "s", "Main platform for this computer" ], - "available_architectures" => [ "l", "All available/installed architectures" ] + "available_architectures" => [ "l", "All available/installed architectures" ], + "usertree" => [ "b", "This tree acts as user tree" ] ); our $WindowsMainMenuName = "TeX Live $ReleaseYear"; diff --git a/Master/tlpkg/TeXLive/TLPDB.pm b/Master/tlpkg/TeXLive/TLPDB.pm index a7c613ddf88..f0f1c25fc2c 100644 --- a/Master/tlpkg/TeXLive/TLPDB.pm +++ b/Master/tlpkg/TeXLive/TLPDB.pm @@ -283,6 +283,8 @@ sub from_file { $media = 'local_uncompressed'; } elsif (-d "$rootpath/texmf/web2c") { # older $media = 'local_uncompressed'; + } elsif (-d "$rootpath/web2c") { + $media = 'local_uncompressed'; } elsif (-d "$rootpath/$Archive") { $media = 'local_compressed'; } else { @@ -1401,8 +1403,12 @@ sub install_package_files { tlwarn("TLPDB::install_package_files: couldn't install $what!\n"); next; } - if ($tlpobj->relocated) { - $tlpobj->cancel_reloc_prefix; + if ($reloc) { + if ($totlpdb->setting("usertree")) { + $tlpobj->cancel_reloc_prefix; + } else { + $tlpobj->replace_reloc_prefix; + } $tlpobj->relocated(0); } my $tlpod = $self->root . "/tlpkg/tlpobj"; @@ -1652,7 +1658,11 @@ sub _install_package { $root = $self->root; } # if we are installing a reloc, add the RelocTree to the target - $target .= "/$TeXLive::TLConfig::RelocTree" if $reloc; + if ($reloc) { + if (!$totlpdb->setting("usertree")) { + $target .= "/$TeXLive::TLConfig::RelocTree"; + } + } foreach my $file (@$what) { # @what is taken, not @filelist! @@ -1664,7 +1674,11 @@ sub _install_package { # we always assume that copy will work return(1); } elsif ($what =~ m,\.tar(\.xz)?$,) { - $target .= "/$TeXLive::TLConfig::RelocTree" if $reloc; + if ($reloc) { + if (!$totlpdb->setting("usertree")) { + $target .= "/$TeXLive::TLConfig::RelocTree"; + } + } my $pkg = TeXLive::TLUtils::unpack($what, $target); if (!$pkg) { tlwarn("TLPDB::_install_package: couldn't unpack $what to $target\n"); @@ -1695,6 +1709,7 @@ sub remove_package { my ($self, $pkg, %opts) = @_; my $localtlpdb = $self; my $tlp = $localtlpdb->get_package($pkg); + my $usertree = $localtlpdb->setting("usertree"); if (!defined($tlp)) { tlwarn ("$pkg: package not present, cannot remove\n"); } else { @@ -1723,7 +1738,9 @@ sub remove_package { # since we don't have user mode if ($tlp->relocated) { for (@files) { - s:^$RelocPrefix/:$RelocTree/:; + if (!$usertree) { + s:^$RelocPrefix/:$RelocTree/:; + } } } # diff --git a/Master/tlpkg/TeXLive/TLPOBJ.pm b/Master/tlpkg/TeXLive/TLPOBJ.pm index 3d8d695a82c..c49214ff194 100644 --- a/Master/tlpkg/TeXLive/TLPOBJ.pm +++ b/Master/tlpkg/TeXLive/TLPOBJ.pm @@ -401,6 +401,21 @@ sub writeout_simple { sub cancel_reloc_prefix { my $self = shift; my @docfiles = $self->docfiles; + for (@docfiles) { s:^$RelocPrefix/::; } + $self->docfiles(@docfiles); + my @runfiles = $self->runfiles; + for (@runfiles) { s:^$RelocPrefix/::; } + $self->runfiles(@runfiles); + my @srcfiles = $self->srcfiles; + for (@srcfiles) { s:^$RelocPrefix/::; } + $self->srcfiles(@srcfiles); + # if there are bin files they have definitely NOT the + # texmf-dist prefix, so we cannot cancel it anyway +} + +sub replace_reloc_prefix { + my $self = shift; + my @docfiles = $self->docfiles; for (@docfiles) { s:^$RelocPrefix/:$RelocTree/:; } $self->docfiles(@docfiles); my @runfiles = $self->runfiles; diff --git a/Master/tlpkg/TeXLive/TLUtils.pm b/Master/tlpkg/TeXLive/TLUtils.pm index 8dcc0d603a5..9ee6549e364 100644 --- a/Master/tlpkg/TeXLive/TLUtils.pm +++ b/Master/tlpkg/TeXLive/TLUtils.pm @@ -1328,7 +1328,7 @@ sub install_packages { # if a package is relocatable we have to cancel the reloc prefix # before we save it to the local tlpdb if ($tlpobj->relocated) { - $tlpobj->cancel_reloc_prefix; + $tlpobj->replace_reloc_prefix; } $totlpdb->add_tlpobj($tlpobj); # we have to write out the tlpobj file since it is contained in the |