Index: tlpkg/TeXLive/TLConfig.pm =================================================================== --- tlpkg/TeXLive/TLConfig.pm (revision 15374) +++ tlpkg/TeXLive/TLConfig.pm (working copy) @@ -169,7 +169,8 @@ 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"; Index: tlpkg/TeXLive/TLPOBJ.pm =================================================================== --- tlpkg/TeXLive/TLPOBJ.pm (revision 15374) +++ tlpkg/TeXLive/TLPOBJ.pm (working copy) @@ -458,6 +458,21 @@ 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; Index: tlpkg/TeXLive/TLMedia.pm =================================================================== --- tlpkg/TeXLive/TLMedia.pm (revision 15374) +++ tlpkg/TeXLive/TLMedia.pm (working copy) @@ -60,6 +60,8 @@ } if (-d "$location/texmf/web2c") { $media = 'DVD'; + } elsif (-d "$location/web2c") { + $media = 'DVD'; } elsif (-d "$location/$Archive") { $media = 'CD'; } else { @@ -247,8 +249,12 @@ } # 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; + if ($reloc) { + if ($totlpdb->setting("usertree")) { + $tlpobj->cancel_reloc_prefix; + } else { + $tlpobj->replace_reloc_prefix; + } } # we have to write out the tlpobj file since it is contained in the # archives (.tar.xz) but at DVD install time we don't have them @@ -317,7 +323,11 @@ } elsif ($what =~ m,\.tar(\.xz)?$,) { my $type = defined($1) ? "xz" : "tar"; - $target .= "/$TeXLive::TLConfig::RelocTree" if $reloc; + if ($reloc) { + if (!$totlpdb->setting("usertree")) { + $target .= "/$TeXLive::TLConfig::RelocTree" if $reloc; + } + } # this is the case when we install from CD or the NET, or a backup # @@ -400,6 +410,7 @@ my ($self, $pkg, $nopostinstall) = @_; my $localtlpdb = $self->tlpdb; my $tlp = $localtlpdb->get_package($pkg); + my $usertree = $localtlpdb->setting("usertree"); if (!defined($tlp)) { tlwarn ("$pkg: package not present, cannot remove\n"); } else { @@ -426,9 +437,12 @@ # in user mode we just remove the prefix, in normal mode we # replace it with texmf-dist # since we don't have user mode + if ($tlp->relocated) { for (@files) { - s:^$RelocPrefix/:$RelocTree/:; + if (!$usertree) { + s:^$RelocPrefix/:$RelocTree/:; + } } } # Index: tlpkg/TeXLive/TLUtils.pm =================================================================== --- tlpkg/TeXLive/TLUtils.pm (revision 15374) +++ tlpkg/TeXLive/TLUtils.pm (working copy) @@ -1237,7 +1237,7 @@ # 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 Index: texmf/scripts/texlive/tlmgr.pl =================================================================== --- texmf/scripts/texlive/tlmgr.pl (revision 15374) +++ texmf/scripts/texlive/tlmgr.pl (working copy) @@ -123,6 +123,8 @@ "machine-readable" => 1, "package-logfiles" => "=s", "pause" => 1, + "usermode" => 1, + "usertree" => "=s", "version" => 1, "help|h|?" => 1); @@ -296,13 +298,30 @@ 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")) { @@ -438,6 +457,9 @@ } elsif ($action =~ m/^show$/i) { action_show(); finish(0); + } elsif ($action =~ m/^init-usertree$/i) { + action_init_usertree(); + finish(0); } elsif ($action =~ m/^remove$/i) { action_remove(); } elsif ($action =~ /^paper$/) { @@ -499,6 +521,8 @@ { my $errors = 0; + my $sysmode = ($opts{"usermode"} ? "" : "-sys"); + if ($::files_changed) { $errors += do_cmd_and_check("mktexlsr"); $::files_changed = 0; @@ -529,14 +553,14 @@ } } for my $m (keys %do_disable) { - $errors += do_cmd_and_check("updmap-sys --nomkmap --nohash --disable $m"); + $errors += do_cmd_and_check("updmap$sysmode --nomkmap --nohash --disable $m"); } for my $m (keys %do_enable) { - my $str = "updmap-sys --nomkmap --nohash --enable " . + my $str = "updmap$sysmode --nomkmap --nohash --enable " . $::execute_actions{'enable'}{'maps'}{$m} . "=$m"; $errors += do_cmd_and_check($str); } - $errors += do_cmd_and_check("updmap-sys") if $run_full; + $errors += do_cmd_and_check("updmap$sysmode") if $run_full; } @@ -581,13 +605,13 @@ # 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 --byengine $e"); + $errors += do_cmd_and_check("fmtutil$sysmode --byengine $e"); } # now rebuild all other formats for my $f (keys %do_enable) { next if defined($updated_engines{$format_to_engine{$f}}); 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; } } @@ -625,7 +649,7 @@ $lang = "$TEXMFSYSVAR/tex/generic/config/$lang"; } 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"); } } } @@ -634,7 +658,7 @@ # 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; } @@ -807,8 +831,13 @@ action_gui("config") if $opts{"gui"}; 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 @@ -820,7 +849,7 @@ "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); @@ -828,7 +857,7 @@ } 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 @@ -845,7 +874,7 @@ if (@ARGV) { return if !check_on_writable(); } - TeXLive::TLPaper::do_paper($prog,$texmfsysconfig,@ARGV); + TeXLive::TLPaper::do_paper($prog,$texmfconfig,@ARGV); } } @@ -886,13 +915,14 @@ # include arbitrary package in the list of collections, but # only collectons: @colls = grep {m;^collection-;} @colls; - print "package: ", $tlp->name, "\n"; - print "category: ", $tlp->category, "\n"; - print "shortdesc: ", $tlp->shortdesc, "\n" if ($tlp->shortdesc); - print "longdesc: ", $tlp->longdesc, "\n" if ($tlp->longdesc); - print "installed: ", ($installed ? "Yes" : "No"), "\n"; - print "revision: ", $tlp->revision, "\n" if ($installed); - print "collection: ", @colls, "\n" if (@colls); + print "package: ", $tlp->name, "\n"; + print "category: ", $tlp->category, "\n"; + print "shortdesc: ", $tlp->shortdesc, "\n" if ($tlp->shortdesc); + 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 "collection: ", @colls, "\n" if (@colls); if ($opts{"list"}) { if ($tlp->category eq "Collection" || $tlp->category eq "Scheme") { # in the case of collections of schemes we list the deps @@ -956,6 +986,10 @@ # 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)) { tlwarn("action path needs one argument, either add or remove\n"); @@ -1664,7 +1698,10 @@ # check for updates to tlmgr and die unless either --force or --list or --self # is given - my @critical = check_for_critical_updates($localtlpdb, $tlmediatlpdb); + my @critical; + if (!$opts{"usermode"}) { + @critical = check_for_critical_updates($localtlpdb, $tlmediatlpdb); + } my $dry_run_cont = $opts{"dry-run"} && ($opts{"dry-run"} < 0); if ( !$dry_run_cont && !$opts{"self"} && @critical) { critical_updates_warning(); @@ -2412,16 +2449,18 @@ init_tlmedia(); # check for updates to tlmgr itself, and die unless --force is given - if (check_for_critical_updates( $localtlpdb, $tlmediatlpdb)) { - 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, $tlmediatlpdb)) { + 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"; + } } } } @@ -2434,7 +2473,7 @@ @packs = $tlmediatlpdb->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 = $tlmediatlpdb->expand_dependencies("-no-collections", $localtlpdb, @packs) unless $opts{"no-depends"}; } else { @packs = $tlmediatlpdb->expand_dependencies($localtlpdb, @packs) unless $opts{"no-depends"}; @@ -2502,6 +2541,15 @@ foreach my $pkg (@todo) { my $flag = $FLAG_INSTALL; my $re = ""; + my $tlp = $tlmediasrc->tlpdb->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"; @@ -2730,11 +2778,11 @@ # 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 { @@ -2766,6 +2814,10 @@ if ($^O=~/^MSWin(32|64)$/i) { warn("action `arch' not supported on Windows\n"); } + if ($opts{"usermode"}) { + tlwarn("action `arch' not supported in usermode\n"); + exit 1; + } if ($opts{"gui"}) { action_gui("arch"); } @@ -2899,6 +2951,10 @@ # GENERATE # sub action_generate { + if ($opts{"usermode"}) { + tlwarn("action `generate' not supported in usermode!\n"); + exit 1; + } my $dest = defined($opts{"dest"}) ? $opts{"dest"} : ""; my $localconf = defined($opts{"localcfg"}) ? $opts{"localcfg"} : ""; my $what = shift @ARGV; @@ -3708,6 +3764,38 @@ # +# action init_user_tree +# sets up TEXMFHOME or --usertree argument for user mode tlmgr +# by creating a minimal tlpdb +# +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`); + } + $tlpdb->root($usertree); + my $inst = TeXLive::TLPOBJ->new; + $inst->name("00texlive.installation"); + $inst->category("TLCore"); + my @deps; + push @deps, "opt_location:$location"; + push @deps, "setting_available_architectures:"; + push @deps, "setting_usertree:1"; + $inst->depends(@deps); + $tlpdb->add_tlpobj($inst); + $tlpdb->save; + # + # we need to create web2c dir for TLMedia to succeed setting up + # and for tlmgr.log file + mkdir ("$usertree/web2c"); +} + + +# # action conf # tries to mimick texconfig conf but probably will add some more things # @@ -3771,10 +3859,10 @@ # stuff changed via the GUI return if defined $localtlmedia; return if defined $localtlpdb; - $localtlmedia = TeXLive::TLMedia->new ( $Master ); - die("cannot setup TLMedia in $Master") unless (defined($localtlmedia)); + $localtlmedia = TeXLive::TLMedia->new ( $::maintree ); + die("cannot setup TLMedia in $::maintree") unless (defined($localtlmedia)); $localtlpdb = $localtlmedia->tlpdb; - die("cannot find tlpdb in $Master") unless (defined($localtlpdb)); + die("cannot find 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", $localtlmedia->platform)) { @@ -4082,6 +4170,7 @@ } 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");