Ver código fonte

Added support for stripping leading path segments

closes #95
Jonas Borgström 11 anos atrás
pai
commit
193fb1fcd5
4 arquivos alterados com 36 adições e 3 exclusões
  1. 2 0
      CHANGES
  2. 13 3
      attic/archiver.py
  3. 7 0
      attic/testsuite/__init__.py
  4. 14 0
      attic/testsuite/archiver.py

+ 2 - 0
CHANGES

@@ -7,6 +7,8 @@ Version 0.14
 ------------
 
 (feature release, released on X)
+- Added support for stripping leading path segments (#95)
+  "attic extract --strip-segments X"
 - Add workaround for old Linux systems without acl_extended_file_no_follow (#96)
 - Add MacPorts' path to the default openssl search path (#101)
 - HashIndex improvements, eliminates unnecessary IO on low memory systems.

+ 13 - 3
attic/archiver.py

@@ -191,14 +191,21 @@ Type "Yes I am sure" if you understand this and want to continue.\n""")
         archive = Archive(repository, key, manifest, args.archive.archive,
                           numeric_owner=args.numeric_owner)
         patterns = adjust_patterns(args.paths, args.excludes)
+        dry_run = args.dry_run
+        strip_components = args.strip_components
         dirs = []
         for item in archive.iter_items(lambda item: not exclude_path(item[b'path'], patterns), preload=True):
+            orig_path = item[b'path']
+            if strip_components:
+                item[b'path'] = os.sep.join(orig_path.split(os.sep)[strip_components:])
+                if not item[b'path']:
+                    continue
             if not args.dry_run:
                 while dirs and not item[b'path'].startswith(dirs[-1][b'path']):
                     archive.extract_item(dirs.pop(-1))
-            self.print_verbose(remove_surrogates(item[b'path']))
+            self.print_verbose(remove_surrogates(orig_path))
             try:
-                if args.dry_run:
+                if dry_run:
                     archive.extract_item(item, dry_run=True)
                 else:
                     if stat.S_ISDIR(item[b'mode']):
@@ -207,7 +214,7 @@ Type "Yes I am sure" if you understand this and want to continue.\n""")
                     else:
                         archive.extract_item(item)
             except IOError as e:
-                self.print_error('%s: %s', remove_surrogates(item[b'path']), e)
+                self.print_error('%s: %s', remove_surrogates(orig_path), e)
 
         if not args.dry_run:
             while dirs:
@@ -572,6 +579,9 @@ Type "Yes I am sure" if you understand this and want to continue.\n""")
         subparser.add_argument('--numeric-owner', dest='numeric_owner',
                                action='store_true', default=False,
                                help='only obey numeric user and group identifiers')
+        subparser.add_argument('--strip-components', dest='strip_components',
+                               type=int, default=0, metavar='NUMBER',
+                               help='Remove the specified number of leading path elements. Pathnames with fewer elements will be silently skipped.')
         subparser.add_argument('archive', metavar='ARCHIVE',
                                type=location_validator(archive=True),
                                help='archive to extract')

+ 7 - 0
attic/testsuite/__init__.py

@@ -1,3 +1,4 @@
+from contextlib import contextmanager
 import filecmp
 import os
 import posix
@@ -41,6 +42,12 @@ class AtticTestCase(unittest.TestCase):
     assert_raises = unittest.TestCase.assertRaises
     assert_true = unittest.TestCase.assertTrue
 
+    @contextmanager
+    def assert_creates_file(self, path):
+        self.assert_true(not os.path.exists(path), '{} should not exist'.format(path))
+        yield
+        self.assert_true(os.path.exists(path), '{} should exist'.format(path))
+
     def assert_dirs_equal(self, dir1, dir2):
         diff = filecmp.dircmp(dir1, dir2)
         self._assert_dirs_equal_cmp(diff)

+ 14 - 0
attic/testsuite/archiver.py

@@ -165,6 +165,20 @@ class ArchiverTestCase(ArchiverTestCaseBase):
         # end the same way as info_output
         assert info_output2.endswith(info_output)
 
+    def test_strip_components(self):
+        self.attic('init', self.repository_location)
+        self.create_regular_file('dir/file')
+        self.attic('create', self.repository_location + '::test', 'input')
+        with changedir('output'):
+            self.attic('extract', self.repository_location + '::test', '--strip-components', '3')
+            self.assert_true(not os.path.exists('file'))
+            with self.assert_creates_file('file'):
+                self.attic('extract', self.repository_location + '::test', '--strip-components', '2')
+            with self.assert_creates_file('dir/file'):
+                self.attic('extract', self.repository_location + '::test', '--strip-components', '1')
+            with self.assert_creates_file('input/dir/file'):
+                self.attic('extract', self.repository_location + '::test', '--strip-components', '0')
+
     def test_extract_include_exclude(self):
         self.attic('init', self.repository_location)
         self.create_regular_file('file1', size=1024 * 80)