summaryrefslogtreecommitdiff
path: root/Master/texmf/scripts
diff options
context:
space:
mode:
authorNorbert Preining <preining@logic.at>2008-10-29 01:09:49 +0000
committerNorbert Preining <preining@logic.at>2008-10-29 01:09:49 +0000
commit672ba1882cfdcdf0740fa6cfcf3e02005edec1b6 (patch)
tree20a504022d78a896c84695fdf611bed02d3a299f /Master/texmf/scripts
parenta1b9b9d9ffe1042e576539790e757508b7cd5172 (diff)
commit the auto backup feature
git-svn-id: svn://tug.org/texlive/trunk@11102 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf/scripts')
-rwxr-xr-xMaster/texmf/scripts/texlive/tlmgr.pl332
1 files changed, 292 insertions, 40 deletions
diff --git a/Master/texmf/scripts/texlive/tlmgr.pl b/Master/texmf/scripts/texlive/tlmgr.pl
index 9063e9defe3..ef523703e61 100755
--- a/Master/texmf/scripts/texlive/tlmgr.pl
+++ b/Master/texmf/scripts/texlive/tlmgr.pl
@@ -22,18 +22,6 @@
# copy of the remote tlpdb
# -> if they are equal continue with that
# -> if they are unequal try to download the new one
-# - backup extensions (email from Manuel)
-# tlmgr option backupdir /some/fix/location
-# with default TLROOT/backups as default
-# In the longer term, I've heard demands for an auto-backup feature. The
-# obvious question would be hard disk space. On should probably set
-# options such as:
-# - never auto-backup (probably the default)
-# - keep only N backups per package (typically, one)
-# - only keep backups younger than M months (or weeks or)
-# - always do backups, let the user clean them up manually
-# Possibly, an operation like 'tlmgr clean' for cleaning old backup could
-# be great.
# - ordering or collections removal (see below for details)
# - (?) removal does not remove created format files from TEXMFSYSVAR
# - after install/update show the number of bytes transfered
@@ -112,7 +100,7 @@ GetOptions("location=s" => \$opt_location,
"gui-lang=s" => \$opt_gui_lang,
"package-logfile=s" => \$opt_packagelogfile,
"version" => \$opt_version,
- "pause" => \$opt_pause,
+ "pause" => \$opt_pause,
"h|help|?" => \$opt_help) or pod2usage(2);
my $action = shift;
@@ -657,9 +645,32 @@ sub action_restore {
GetOptions("backupdir=s" => \$opt_backupdir,
"n|dry-run" => \$opt_dry,
"force" => \$opt_force) or pod2usage(2);
- if (!defined($opt_backupdir)) {
- die "restore needs --backupdir\n";
+ # check the backup dir argument
+ if ($opt_backupdir) {
+ my $ob = abs_path($opt_backupdir);
+ $ob && ($opt_backupdir = $ob);
+ if (! -d $opt_backupdir) {
+ tlwarn ("backupdir argument $opt_backupdir is not a directory.\n");
+ tlwarn ("Don't know from where to restore backups, terminating.\n");
+ exit 1;
+ }
+ } else {
+ # no argument, check for presence in TLPDB
+ $opt_backupdir = $localtlpdb->option("backupdir");
+ if (!$opt_backupdir) {
+ tlwarn ("Don't know from where to restore backups, terminating.\n");
+ exit 1;
+ }
+ # we are stil here, there is something set in tlpdb
+ my $ob = abs_path($opt_backupdir);
+ $ob && ($opt_backupdir = $ob);
+ if (! -d $opt_backupdir) {
+ tlwarn ("backupdir as set in tlpdb $opt_backupdir is not a directory.\n");
+ tlwarn ("Don't know from where to restore backups, terminating.\n");
+ exit 1;
+ }
}
+
info("restore: dry run, no changes will be made\n") if $opt_dry;
# initialize the hash(packages) of hash(revisions)
@@ -731,30 +742,109 @@ sub action_backup {
my $opt_dry = 0;
my $opt_all = 0;
my $opt_backupdir;
+ # --clean argument
+ # can be either -1 ... don't clean
+ # 0 ... remove all backups
+ # N ... keep only N backups
+ # that parallels the value of autoclean in the configuration
+ # we have to be careful, because if simply --clean is given, we should
+ # check for the value saved in the tlpdb, and if that is not present
+ # do nothing. But Getopt::Long with clean:i leaves 0 in $opt_clean if
+ # it is present. So
+ # !defined($opt_clean) -> no --clean given
+ # $opt_clean = "" -> --clean without argument given, check tlpdb
+ # $opt_clean = -1, 0, N -> --clean=N given, check argument
+ #
+ my $opt_clean;
Getopt::Long::Configure(@getopt_configure_subopts);
GetOptions("all" => \$opt_all,
"backupdir=s" => \$opt_backupdir,
+ "clean:s" => \$opt_clean,
+ "n|dry-run" => \$opt_dry,
) or pod2usage(2);
+ my $clean_mode = 0;
+ $clean_mode = 1 if defined($opt_clean);
+ if ($clean_mode) {
+ if ($opt_clean eq "") {
+ # we need to check the tlpdb
+ $opt_clean = $localtlpdb->option("autobackup");
+ if (!$opt_clean) {
+ tlwarn ("--clean given without an argument, but no default clean\n");
+ tlwarn ("mode specified in the tlpdb, terminating.\n");
+ exit 1;
+ }
+ }
+ # now $opt_clean is something, but maybe not a number, check for
+ # validity
+ if ($opt_clean =~ m/^(-1|[0-9]+)$/) {
+ # get rid of leading zeros etc etc
+ $opt_clean = $opt_clean + 0;
+ } else {
+ tlwarn ("clean mode as specified on the command line or as given by default\n");
+ tlwarn ("must be an integer larger or equal than -1, terminating.\n");
+ exit 1;
+ }
+ }
+ # check the backup dir argument
+ if ($opt_backupdir) {
+ my $ob = abs_path($opt_backupdir);
+ $ob && ($opt_backupdir = $ob);
+ if (! -d $opt_backupdir) {
+ tlwarn ("backupdir argument $opt_backupdir is not a directory.\n");
+ if ($clean_mode) {
+ tlwarn ("Cannot clean a non existing directory, terminating.\n");
+ } else {
+ tlwarn ("Don't know where to save backups, terminating.\n");
+ }
+ exit 1;
+ }
+ } else {
+ # no argument, check for presence in TLPDB
+ $opt_backupdir = $localtlpdb->option("backupdir");
+ if (!$opt_backupdir) {
+ if ($clean_mode) {
+ tlwarn ("Cannot clean an unknown directory, terminating.\n");
+ } else {
+ tlwarn ("Don't know where to save backups, terminating.\n");
+ }
+ exit 1;
+ }
+ # we are stil here, there is something set in tlpdb
+ my $ob = abs_path($opt_backupdir);
+ $ob && ($opt_backupdir = $ob);
+ if (! -d $opt_backupdir) {
+ tlwarn ("backupdir as set in tlpdb $opt_backupdir is not a directory.\n");
+ if ($clean_mode) {
+ tlwarn ("Cannot clean a non existing directory, terminating.\n");
+ } else {
+ tlwarn ("Don't know where to save backups, terminating.\n");
+ }
+ exit 1;
+ }
+ }
+
my %ret;
my @todo;
- die ("tlmgr backup needs an obligatory argument --backupdir")
- unless (defined($opt_backupdir));
if ($opt_all) {
@todo = $localtlpdb->list_packages;
} else {
@todo = @ARGV;
+ @todo = $localtlpdb->expand_dependencies("-only-arch", $localtlpdb, @todo);
}
if (!@todo) {
printf "tlmgr backup takes either a list of packages or --all\n";
}
foreach my $pkg (@todo) {
- $opt_backupdir = abs_path($opt_backupdir);
- if (! -d $opt_backupdir) {
- printf STDERR "backupdir argument must be an existing directory!\n";
+ if ($clean_mode) {
+ clear_old_backups ($pkg, $opt_backupdir, $opt_clean, $opt_dry);
} else {
my $tlp = $localtlpdb->get_package($pkg);
- $tlp->make_container("lzma", $localtlpdb->root,
- $opt_backupdir, "${pkg}.r" . $tlp->revision);
+ info("saving current status of $pkg to $opt_backupdir${pkg}.r" .
+ $tlp->revision . ".\n");
+ if (!$opt_dry) {
+ $tlp->make_container("lzma", $localtlpdb->root,
+ $opt_backupdir, "${pkg}.r" . $tlp->revision);
+ }
}
}
return(\%ret);
@@ -928,6 +1018,7 @@ sub action_update {
my $opt_list = 0;
my $opt_noremove = 0;
my $opt_backupdir;
+ my $opt_backup = 0;
Getopt::Long::Configure(@getopt_configure_subopts);
GetOptions("no-depends" => \$opt_nodepends,
"no-depends-at-all" => \$opt_reallynodepends,
@@ -935,6 +1026,7 @@ sub action_update {
"list" => \$opt_list,
"no-remove" => \$opt_noremove,
"backupdir=s" => \$opt_backupdir,
+ "backup" => \$opt_backup,
"n|dry-run" => \$opt_dry) or pod2usage(2);
$opt_nodepends = 1 if $opt_reallynodepends;
my $nrupdated = 0;
@@ -944,6 +1036,70 @@ sub action_update {
my $mediatlpdb = $tlmediasrc->tlpdb;
info("update: dry run, no changes will be made\n") if $opt_dry;
+ # do backup dir checking now so that we don't run into troubles
+ # later, and exit if that doesn't work
+ if ($opt_backupdir) {
+ $opt_backupdir = abs_path($opt_backupdir);
+ if (! -d $opt_backupdir) {
+ tlwarn("Argument for --backupdir must be an existing directory. Terminating.\n");
+ exit 1;
+ }
+ }
+
+ my $autobackup = 0;
+ # check for the tlpdb option autobackup, and if present and true (!= 0)
+ # assume we are doing backups
+ if (!$opt_backup) {
+ $autobackup = $localtlpdb->option("autobackup");
+ if ($autobackup) {
+ # check the format, we currently allow only natural numbers, and -1
+ if ($autobackup eq "-1") {
+ debug ("Automatic backups activated, keeping \\infty backups.\n");
+ $opt_backup = 1;
+ } elsif ($autobackup eq "0") {
+ debug ("Automatic backups disabled.\n");
+ } elsif ($autobackup =~ m/^[0-9]+$/) {
+ debug ("Automatic backups activated, keeping $autobackup backups.\n");
+ $opt_backup = 1;
+ } else {
+ tlwarn ("Option autobackup can only be an integer >= -1.\n");
+ tlwarn ("Disabling auto backups.\n");
+ $localtlpdb->option("autobackup", 0);
+ $autobackup = 0;
+ }
+ }
+ }
+
+ # cmd line --backup, we check for --backupdir, and if that is not given
+ # we try to get the default from the tlpdb. If that doesn't work, exit.
+ if ($opt_backup) {
+ my $diebackupdir = 0;
+ if (!$opt_backupdir) {
+ $opt_backupdir = $localtlpdb->option("backupdir");
+ if ($opt_backupdir) {
+ # check again:
+ $opt_backupdir = abs_path($opt_backupdir);
+ $diebackupdir = 1 if (! -d $opt_backupdir);
+ } else {
+ # not set in the tlpdb, and not set on cmd line, but asked for
+ # --backup
+ $diebackupdir = 1;
+ }
+ }
+ # no else branch necessary, we already checked that --backupdir if
+ # given is ok, see above
+ if ($diebackupdir) {
+ tlwarn("You have asked for backups, but the backup directory as specified\n");
+ tlwarn("in the local TLPDB or the cmd line does not exists, exiting.\n");
+ exit 1;
+ }
+ }
+
+ # finally, if we have --backupdir, but no --backup, just enable it
+ $opt_backup = 1 if $opt_backupdir;
+
+ debug("Doing backups to $opt_backupdir\n") if $opt_backup;
+
# these two variables are used throughout this function
my $root = $localtlpdb->root;
my $temp = "$root/temp";
@@ -1122,19 +1278,18 @@ sub action_update {
if ($opt_list) {
info("$pkg: local: $rev, source: $mediarev\n");
} else {
- # first remove the package, then reinstall it
- # this way we get rid of useless files
- # force the deinstallation since we will reinstall it
- if ($opt_backupdir && !$opt_dry) {
- $opt_backupdir = abs_path($opt_backupdir);
- if (! -d $opt_backupdir) {
- tlwarn("backupdir argument must be an existing directory!\n");
- } else {
- $tlp->make_container("lzma", $root,
- $opt_backupdir, "${pkg}.r" . $tlp->revision);
- $unwind_package = "$opt_backupdir/${pkg}.r" . $tlp->revision . ".tar.lzma";
+ if ($opt_backup && !$opt_dry) {
+ $tlp->make_container("lzma", $root,
+ $opt_backupdir, "${pkg}.r" . $tlp->revision);
+ $unwind_package =
+ "$opt_backupdir/${pkg}.r" . $tlp->revision . ".tar.lzma";
+
+ if ($autobackup) {
+ # in case we do auto backups we remove older backups
+ clear_old_backups($pkg, $opt_backupdir, $autobackup);
}
}
+
if (win32() && ($pkg =~ m/$WinSpecialUpdatePackagesRegexp/)) {
add_w32_updater($mediatlp, $opt_dry);
} else {
@@ -1161,6 +1316,10 @@ sub action_update {
$remove_unwind_container = 1;
$unwind_package = "$fullname";
}
+ # first remove the package, then reinstall it
+ # this way we get rid of useless files
+ # force the deinstallation since we will reinstall it
+ #
# the remove_package should also remove empty dirs in case
# a dir is changed into a file
merge_into(\%ret, &remove_package($pkg, $localtlpdb, 1));
@@ -1176,7 +1335,7 @@ sub action_update {
# dirs from the new package before re-installing the old one.
# TODO
logpackage("failed update: $pkg ($rev -> $mediarev)");
- tlwarn("\n\nInstallation of new version of $pkg did fail, trying to unwind!\n");
+ tlwarn("\n\nInstallation of new version of $pkg did fail, trying to unwind.\n");
if (win32()) {
# w32 is notorious for not releasing a file immediately
# we experienced permission denied errors
@@ -1402,7 +1561,15 @@ sub action_option {
print "Install documentation files: ", ($localtlpdb->option_install_docfiles ? "yes": "no"), "\n";
print "Install source files: ", ($localtlpdb->option_install_srcfiles ? "yes": "no"), "\n";
} else {
- warn "Setting other options currently not supported, please edit texlive.tlpdb!";
+ my $val = shift @ARGV;
+ if (defined($val)) {
+ print "Setting option $what to $val.\n";
+ $localtlpdb->option($what,$val);
+ $localtlpdb->save;
+ } else {
+ print "Option $what = ", $localtlpdb->option($what), "\n";;
+ }
+ #warn "Setting other options currently not supported, please edit texlive.tlpdb!";
}
return;
}
@@ -1961,6 +2128,37 @@ sub finish {
}
+# clear the backup dir for $pkg and keep only $autobackup packages
+# mind that with $autobackup == 0 all packages are cleared
+sub clear_old_backups
+{
+ my ($pkg, $opt_backupdir, $autobackup, $opt_dry) = @_;
+
+ my $dryrun = 0;
+ $dryrun = 1 if ($opt_dry);
+ # keep arbitrary many backups
+ return if ($autobackup == -1);
+
+ opendir (DIR, $opt_backupdir) || die "opendir($opt_backupdir) failed: $!";
+ my @dirents = readdir (DIR);
+ closedir (DIR) || warn "closedir($opt_backupdir) failed: $!";
+ my @backups;
+ for my $dirent (@dirents) {
+ next if (-d $dirent);
+ next if ($dirent !~ m/^$pkg\.r([0-9]+)\.tar\.lzma$/);
+ push @backups, $1;
+ }
+ my $i = 1;
+ for my $e (reverse sort {$a <=> $b} @backups) {
+ if ($i > $autobackup) {
+ info ("Removing backup $opt_backupdir/$pkg.r$e.tar.lzma\n");
+ unlink("$opt_backupdir/$pkg.r$e.tar.lzma") unless $dryrun;
+ }
+ $i++;
+ }
+}
+
+
#
# return all the directories from which all content will be removed
#
@@ -2194,7 +2392,21 @@ Under normal circumstances tlmgr tries to remove packages which have
disappeared on the server when called with C<--all>, as described
above. This prevents any such removals.
-=item B<--backupdir> I<directory>
+=item B<--backup> and B<--backupdir> I<directory>
+
+These options control the creation of backups of packages before
+an update is started. If none of the two are given, no backup package
+will be saved. If B<--backupdir> is given specifying a (writable)
+directory then a back up will be made in that location. If only
+B<--backup> is given then the location for the backups has to be
+set in the tlpdb via the B<option> action (see below). If both are
+given then a backup will be made to the specified directory.
+
+By setting relevent options in the tlpdb via the B<option> action
+it is possible to automatically create backups for all packages, and
+keep only a certain number of backups. Please see the B<option>
+action for details. So if B<--backup> is not given, but the B<autobackup>
+option is set in the tlpdb, a backup will be made.
I<directory> specifies a directory where the package as installed will
be saved before updates are performed. Then you can restore later if
@@ -2223,10 +2435,22 @@ If the package on the server is older than the package already installed
downgrade. Also, packages for uninstalled platforms are not installed.
-=item B<backup> --backupdir I<dir> [B<--all>] [I<pkg>...]
+=item B<backup> [--clean[=I<N>]] [--backupdir I<dir>] [B<--all>] [I<pkg>...]
+
+The first mode without the B<--clean> switch is to make a backup of
+the given packages, or all packages with C<--all>. These backups are
+saved to the following place: If the B<--backupdir> option if given, to
+the directory I<dir>, which must exist and be writable.
+If the B<--backupdir> option is not given, the option setting in the
+tlpdb is used, if present. If both are missing, no backups are made.
-Makes a backup of the given packages, or all packages with C<--all>, to
-I<dir>, which must exist and be writable. Options:
+The second mode is when the B<--clean> switch is given, either with
+or without argument. If the value for the B<--clean> switch is missing, the
+option B<autobackup> from the tlpdb is used. If both are missing B<tlmgr>
+will terminate. For the meaning of the different values of that switch
+see below the B<option> action.
+
+Options:
=over 8
@@ -2240,6 +2464,16 @@ directory where backups are to be placed.
Make a backup of all packages in the TeX Live installation. This will
take quite a lot of space and time.
+=item B<--clean>
+
+Instead of making backups cleans up the backup directory from old
+backups.
+
+=item B<--dry-run>
+
+Nothing is actually backed up or removed; instead, the actions to be
+performed are written to the terminal.
+
=back
@@ -2322,7 +2556,9 @@ Possible values for I<key> are:
C<location> (default installation location),
C<formats> (create formats at installation time),
C<docfiles> (install documentation files),
-C<srcfiles> (install source files).
+C<srcfiles> (install source files),
+C<autobackup> (specify the number of backups to be kept),
+C<backupdir> (specify the default location for backups).
Perhaps the most common use for this is if you originally installed from
DVD, and want to permanently change the installation to get further
@@ -2332,6 +2568,22 @@ updates from the Internet. To do this, you can run
where YYYY is the TeX Live release year.
+The two options C<autobackup> and C<backupdir> can be used to specify
+defaults for the B<update>, B<backup> and B<restore> actions. These
+three actions normally need a directory to write to or read from the
+backups. If nothing is specified on the command line, the default taken
+from the C<backupdir> is taken.
+
+The C<autobackup> option (de)activates the automatical generation of
+backups. This option can be an integer larger or equal then -1. If
+C<autobackup> is -1, backups will not be removed (if you not ask for
+explicitely with B<tlmgr backup --clean=I<N> ...> specifying for I<N>
+something different then -1. If it any other integer, i.e., larger or
+equal than 0, it specifies the number of backups to be kept. That also
+includes that backups are disabled with 0 as argument.
+
+In the B<--clean> mode of the B<backup> action this option also specifies
+the number to be kept.
=item B<paper a4>