duplicity-team team mailing list archive
-
duplicity-team team
-
Mailing list archive
-
Message #02738
[Merge] lp:~angusgr/duplicity/exclude-older-than into lp:duplicity
Angus Gratton has proposed merging lp:~angusgr/duplicity/exclude-older-than into lp:duplicity.
Requested reviews:
duplicity-team (duplicity-team)
For more details, see:
https://code.launchpad.net/~angusgr/duplicity/exclude-older-than/+merge/247922
Hi,
I have a small change that I've been using for over a year now for my own backups, and I realised I should probably submit it back. I'm not sure if you'll want to include it, but it's been useful for me.
The change is an "--exclude-older-than" command line option, that allows you to only back up files with a modification date newer than a particular threshold.
How I personally use it is for my off-site backups. Every couple of months I swap a physical hard disk off-site which contains a full disk backup via duplicity. However every hour or so I run an incremental backup to S3 covering my most used directories. The S3 backup has the option --exclude-older-than 90D passed to it.
Provided I rotate the "large" off-site backup more regularly than every 90 days, I can expect that between the two backups I have a complete set of the data that matters to me. If I backuped everything up to S3 then it'd be expensive and clog up my poor low-bandwidth upstream ADSL link, but a lot of it is data that hasn't changed in months.
I don't know if this kind of configuration will work for anyone apart from just me, but I thought you might find the option interesting anyhow.
Thanks very much for duplicity btw, it's a great tool that has saved me several times now!
Angus
--
Your team duplicity-team is requested to review the proposed merge of lp:~angusgr/duplicity/exclude-older-than into lp:duplicity.
=== modified file 'bin/duplicity.1'
--- bin/duplicity.1 2015-01-26 16:08:57 +0000
+++ bin/duplicity.1 2015-01-29 01:01:26 +0000
@@ -510,6 +510,15 @@
come before any other include or exclude options.
.TP
+.BR "--exclude-older-than " time
+Exclude any files whose modification date is earlier than the specified
+.IR time .
+This can be used to produce a partial backup that contains only
+recently changed files. See the
+.B TIME FORMATS
+section for more information.
+
+.TP
.BI --exclude-other-filesystems
Exclude files on file systems (identified by device number) other than
the file system the root of the source directory is on.
=== modified file 'duplicity/commandline.py'
--- duplicity/commandline.py 2015-01-26 16:08:57 +0000
+++ duplicity/commandline.py 2015-01-29 01:01:26 +0000
@@ -316,6 +316,10 @@
parser.add_option("--exclude-regexp", metavar=_("regular_expression"),
dest="", type="string", action="callback", callback=add_selection)
+ # Exclude any files with modification dates older than this from the backup
+ parser.add_option("--exclude-older-than", type="time", metavar=_("time"),
+ dest="", action="callback", callback=add_selection)
+
# Whether we should be particularly aggressive when cleaning up
parser.add_option("--extra-clean", action="store_true")
=== modified file 'duplicity/selection.py'
--- duplicity/selection.py 2015-01-22 20:04:16 +0000
+++ duplicity/selection.py 2015-01-29 01:01:26 +0000
@@ -245,6 +245,8 @@
self.add_selection_func(self.other_filesystems_get_sf(0))
elif opt == "--exclude-regexp":
self.add_selection_func(self.regexp_get_sf(arg, 0))
+ elif opt == "--exclude-older-than":
+ self.add_selection_func(self.exclude_older_get_sf(arg))
elif opt == "--include":
self.add_selection_func(self.glob_get_sf(arg, 1))
elif opt == "--include-filelist":
@@ -644,6 +646,24 @@
else:
return exclude_sel_func
+ def exclude_older_get_sf(self, date):
+ """Return selection function based on files older than modification date """
+
+ def sel_func(path):
+ if not path.isreg():
+ return None
+ try:
+ if os.path.getmtime(path.name) < date:
+ return 0
+ except OSError, e:
+ pass # this is probably only on a race condition of file being deleted
+ return None
+
+ sel_func.exclude = True
+ sel_func.name = "Select older than %s" % (date,)
+ return sel_func
+
+
def glob_get_prefix_res(self, glob_str):
"""Return list of regexps equivalent to prefixes of glob_str"""
glob_parts = glob_str.split("/")
Follow ups