summaryrefslogtreecommitdiff
path: root/Master/tlpkg/archive/applied.auto-backup-feature.patch
blob: aa01f1d13816af2e23f4a53fae807cae516d3eed (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
Implement automatic backups
Current status:
  tlmgr option backupdir .....
sets the defalt backup dir. Now tlmgr update can take another argument
  tlmgr update --backup ....
which creates backups in the default backupdir as specified in the TLPDB.

Furthermore, if the tlpdb opion autobackup is set to a integer >= -1 the 
following happens (all of them need the option backupdir set to an
existing directory)
  tlmgr option autobackup -1
    always make backups, keep infinitely many
  tlmgr option autobackup 0
    disable automatic backups
  tlmgr option autobackup N
    for N > 0 keep N backups


So if you want to set up automatic backups, do:
  mkdir /var/cache/texlive-backups
  tlmgr option backupdir /var/cache/texlive-backups/
  tlmgr option autobackup 5


Cleaning mode:
	tlmgr backup --clean[=ARG] [--backupdir=dir] [--all] [packs]

if NO --clean is given, a backup is made.

if --clean is given without any argument, then the value of "autobackup"
in the tlpdb is used (should we change the name?)

if --clean=ARG is given it must be either -1, 0, 1, ... with the following
meaning:
	-1:	do nothing, keep all backups (not very useful, but ...
	N>=0	keep only N backups (that means for N == 0 all backups
		will be removed)

If --backupdir is NOT given we will try to initialize it from TLPDB 
option "backupdir".


TODO:
. testing on windows
. documentation in POD format
. testing with .doc/.src args, and with .ARCH packages, no idea
  what is going on there

---

Index: texmf/scripts/texlive/tlmgr.pl
===================================================================
--- texmf/scripts/texlive/tlmgr.pl	(revision 11087)
+++ texmf/scripts/texlive/tlmgr.pl	(working copy)
@@ -34,6 +34,16 @@
 #   - always do backups, let the user clean them up manually
 #   Possibly, an operation like 'tlmgr clean' for cleaning old backup could
 #   be great.
+#   format for the options:
+#     option backupdir
+#     option autobackup/TIME
+#       where TIME = natural number N -> keep N backups per package
+#               or = 0 -> don't do auto backups
+#               or = -1 (= +\infty) keep backup indefinitely
+#               or = Nd | Nw | Nm -> keeping backups younger then
+#                                    Nd  N days
+#                                    Nw  N weeks
+#                                    Nm  N months
 # - 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 +122,7 @@
            "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;
@@ -731,14 +741,90 @@
   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
+  my $die_backupdir = 0;
+  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 {
@@ -748,13 +834,16 @@
     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 +1017,7 @@
   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 +1025,7 @@
              "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 +1035,70 @@
   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 +1277,18 @@
       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 +1315,10 @@
             $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 +1334,7 @@
             # 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 +1560,15 @@
     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 +2127,37 @@
 }
 
 
+# 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
 #
Index: tlpkg/TeXLive/TLPDB.pm
===================================================================
--- tlpkg/TeXLive/TLPDB.pm	(revision 11087)
+++ tlpkg/TeXLive/TLPDB.pm	(working copy)
@@ -49,6 +49,7 @@
   $tlpdb->config_container_format;
   $tlpdb->config_release;
   $tlpdb->config_revision;
+  $tlpdb->option($key, [$value]);
 
   TeXLive::TLPDB->listdir([$dir]);
   $tlpdb->generate_listfiles([$destdir]);
@@ -955,6 +956,14 @@
   return;
 }
 
+sub option {
+  my $self = shift;
+  my $key = shift;
+  if (@_) { $self->_set_option_value($key, shift); }
+  return $self->_option_value($key);
+}
+# TODO the above function should be used in the functions below as
+# far as possible ...
 sub option_available_architectures {
   my $self = shift;
   if (@_) { $self->_set_option_value("available_architectures","@_"); }