From 9d19550c1a6fa44cd7a80b3d24ba79b2ab28d360 Mon Sep 17 00:00:00 2001 From: Dan Christensen Date: Sat, 8 Feb 2014 12:44:48 -0500 Subject: [PATCH] Add support for --exclude-from. --- attic/archiver.py | 13 ++++++++++++- attic/helpers.py | 13 +++++++++++++ attic/testsuite/archiver.py | 6 ++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/attic/archiver.py b/attic/archiver.py index 34eea0bdb..59daa9f59 100644 --- a/attic/archiver.py +++ b/attic/archiver.py @@ -13,7 +13,8 @@ from attic.cache import Cache from attic.key import key_creator from attic.helpers import Error, location_validator, format_time, \ format_file_mode, ExcludePattern, exclude_path, adjust_patterns, to_localtime, \ - get_cache_dir, get_keys_dir, format_timedelta, prune_split, Manifest, remove_surrogates, is_a_terminal + get_cache_dir, get_keys_dir, format_timedelta, prune_split, Manifest, remove_surrogates, \ + is_a_terminal, update_excludes from attic.remote import RepositoryServer, RemoteRepository @@ -403,6 +404,9 @@ class Archiver: subparser.add_argument('-e', '--exclude', dest='excludes', type=ExcludePattern, action='append', metavar="PATTERN", help='exclude paths matching PATTERN') + subparser.add_argument('--exclude-from', dest='exclude_files', + type=argparse.FileType('r'), action='append', + metavar='EXCLUDEFILE', help='read exclude patterns from EXCLUDEFILE, one per line') subparser.add_argument('-c', '--checkpoint-interval', dest='checkpoint_interval', type=int, default=300, metavar='SECONDS', help='write checkpoint every SECONDS seconds (Default: 300)') @@ -424,6 +428,9 @@ class Archiver: subparser.add_argument('-e', '--exclude', dest='excludes', type=ExcludePattern, action='append', metavar="PATTERN", help='exclude paths matching PATTERN') + subparser.add_argument('--exclude-from', dest='exclude_files', + type=argparse.FileType('r'), action='append', + metavar='EXCLUDEFILE', help='read exclude patterns from EXCLUDEFILE, one per line') subparser.add_argument('--numeric-owner', dest='numeric_owner', action='store_true', default=False, help='only obey numeric user and group identifiers') @@ -465,6 +472,9 @@ class Archiver: subparser.add_argument('-e', '--exclude', dest='excludes', type=ExcludePattern, action='append', metavar="PATTERN", help='exclude paths matching PATTERN') + subparser.add_argument('--exclude-from', dest='exclude_files', + type=argparse.FileType('r'), action='append', + metavar='EXCLUDEFILE', help='read exclude patterns from EXCLUDEFILE, one per line') subparser.add_argument('archive', metavar='ARCHIVE', type=location_validator(archive=True), help='archive to verity integrity of') @@ -512,6 +522,7 @@ class Archiver: help='repository to prune') args = parser.parse_args(args or ['-h']) self.verbose = args.verbose + update_excludes(args) return args.func(args) diff --git a/attic/helpers.py b/attic/helpers.py index 4e430d44a..401ff7f50 100644 --- a/attic/helpers.py +++ b/attic/helpers.py @@ -141,6 +141,19 @@ def to_localtime(ts): return datetime(*time.localtime((ts - datetime(1970, 1, 1, tzinfo=timezone.utc)).total_seconds())[:6]) +def update_excludes(args): + """Merge exclude patterns from files with those on command line. + Empty lines and lines starting with '#' are ignored, but whitespace + is not stripped.""" + if hasattr(args, 'exclude_files') and args.exclude_files: + if not hasattr(args, 'excludes') or args.excludes is None: + args.excludes = [] + for file in args.exclude_files: + patterns = [line.rstrip('\r\n') for line in file if not line.startswith('#')] + args.excludes += [ExcludePattern(pattern) for pattern in patterns if pattern] + file.close() + + def adjust_patterns(paths, excludes): if paths: return (excludes or []) + [IncludePattern(path) for path in paths] + [ExcludePattern('*')] diff --git a/attic/testsuite/archiver.py b/attic/testsuite/archiver.py index 891ec6008..1a0776f26 100644 --- a/attic/testsuite/archiver.py +++ b/attic/testsuite/archiver.py @@ -48,12 +48,15 @@ class ArchiverTestCase(AtticTestCase): self.output_path = os.path.join(self.tmpdir, 'output') self.keys_path = os.path.join(self.tmpdir, 'keys') self.cache_path = os.path.join(self.tmpdir, 'cache') + self.exclude_file_path = os.path.join(self.tmpdir, 'excludes') os.environ['ATTIC_KEYS_DIR'] = self.keys_path os.environ['ATTIC_CACHE_DIR'] = self.cache_path os.mkdir(self.input_path) os.mkdir(self.output_path) os.mkdir(self.keys_path) os.mkdir(self.cache_path) + with open(self.exclude_file_path, 'wb') as fd: + fd.write(b'input/file2\n# A commment line, then a blank line\n\n') self._old_wd = os.getcwd() os.chdir(self.tmpdir) @@ -157,6 +160,9 @@ class ArchiverTestCase(AtticTestCase): with changedir('output'): self.attic('extract', '--exclude=input/file2', self.repository_location + '::test') self.assert_equal(sorted(os.listdir('output/input')), ['file1', 'file3']) + with changedir('output'): + self.attic('extract', '--exclude-from=' + self.exclude_file_path, self.repository_location + '::test') + self.assert_equal(sorted(os.listdir('output/input')), ['file1', 'file3']) def test_path_normalization(self): self.attic('init', self.repository_location)