Explorar el Código

Merge branch 'merge' into merge-all

Thomas Waldmann hace 10 años
padre
commit
6164140fae
Se han modificado 3 ficheros con 66 adiciones y 4 borrados
  1. 20 4
      attic/archive.py
  2. 26 0
      attic/archiver.py
  3. 20 0
      attic/testsuite/archiver.py

+ 20 - 4
attic/archive.py

@@ -152,12 +152,16 @@ class Archive:
             info = self.manifest.archives[name]
             info = self.manifest.archives[name]
             self.load(info[b'id'])
             self.load(info[b'id'])
 
 
+    def _load_meta(self, id):
+        data = self.key.decrypt(id, self.repository.get(id))
+        metadata = msgpack.unpackb(data)
+        if metadata[b'version'] != 1:
+            raise Exception('Unknown archive metadata version')
+        return metadata
+
     def load(self, id):
     def load(self, id):
         self.id = id
         self.id = id
-        data = self.key.decrypt(self.id, self.repository.get(self.id))
-        self.metadata = msgpack.unpackb(data)
-        if self.metadata[b'version'] != 1:
-            raise Exception('Unknown archive metadata version')
+        self.metadata = self._load_meta(self.id)
         decode_dict(self.metadata, (b'name', b'hostname', b'username', b'time'))
         decode_dict(self.metadata, (b'name', b'hostname', b'username', b'time'))
         self.metadata[b'cmdline'] = [arg.decode('utf-8', 'surrogateescape') for arg in self.metadata[b'cmdline']]
         self.metadata[b'cmdline'] = [arg.decode('utf-8', 'surrogateescape') for arg in self.metadata[b'cmdline']]
         self.name = self.metadata[b'name']
         self.name = self.metadata[b'name']
@@ -344,6 +348,18 @@ class Archive:
             except OSError:
             except OSError:
                 pass
                 pass
 
 
+    def rename(self, name):
+        if name in self.manifest.archives:
+            raise self.AlreadyExists(name)
+        metadata = StableDict(self._load_meta(self.id))
+        metadata[b'name'] = name
+        data = msgpack.packb(metadata, unicode_errors='surrogateescape')
+        new_id = self.key.id_hash(data)
+        self.cache.add_chunk(new_id, data, self.stats)
+        self.manifest.archives[name] = {'id': new_id, 'time': metadata[b'time']}
+        self.cache.chunk_decref(self.id, self.stats)
+        del self.manifest.archives[self.name]
+
     def delete(self, stats):
     def delete(self, stats):
         unpacker = msgpack.Unpacker(use_list=False)
         unpacker = msgpack.Unpacker(use_list=False)
         for items_id, data in zip(self.metadata[b'items'], self.repository.get_many(self.metadata[b'items'])):
         for items_id, data in zip(self.metadata[b'items'], self.repository.get_many(self.metadata[b'items'])):

+ 26 - 0
attic/archiver.py

@@ -251,6 +251,18 @@ Type "Yes I am sure" if you understand this and want to continue.\n""")
                 archive.extract_item(dirs.pop(-1))
                 archive.extract_item(dirs.pop(-1))
         return self.exit_code
         return self.exit_code
 
 
+    def do_rename(self, args):
+        """Rename an existing archive"""
+        repository = self.open_repository(args.archive, exclusive=True)
+        manifest, key = Manifest.load(repository)
+        cache = Cache(repository, key, manifest)
+        archive = Archive(repository, key, manifest, args.archive.archive, cache=cache)
+        archive.rename(args.name)
+        manifest.write()
+        repository.commit()
+        cache.commit()
+        return self.exit_code
+
     def do_delete(self, args):
     def do_delete(self, args):
         """Delete an existing archive"""
         """Delete an existing archive"""
         repository = self.open_repository(args.archive, exclusive=True)
         repository = self.open_repository(args.archive, exclusive=True)
@@ -664,6 +676,20 @@ Type "Yes I am sure" if you understand this and want to continue.\n""")
         subparser.add_argument('paths', metavar='PATH', nargs='*', type=str,
         subparser.add_argument('paths', metavar='PATH', nargs='*', type=str,
                                help='paths to extract')
                                help='paths to extract')
 
 
+        rename_epilog = textwrap.dedent("""
+        This command renames an archive in the repository.
+        """)
+        subparser = subparsers.add_parser('rename', parents=[common_parser],
+                                          description=self.do_rename.__doc__,
+                                          epilog=rename_epilog,
+                                          formatter_class=argparse.RawDescriptionHelpFormatter)
+        subparser.set_defaults(func=self.do_rename)
+        subparser.add_argument('archive', metavar='ARCHIVE',
+                               type=location_validator(archive=True),
+                               help='archive to rename')
+        subparser.add_argument('name', metavar='NEWNAME', type=str,
+                               help='the new archive name to use')
+
         delete_epilog = textwrap.dedent("""
         delete_epilog = textwrap.dedent("""
         This command deletes an archive from the repository. Any disk space not
         This command deletes an archive from the repository. Any disk space not
         shared with any other existing archive is also reclaimed.
         shared with any other existing archive is also reclaimed.

+ 20 - 0
attic/testsuite/archiver.py

@@ -266,6 +266,26 @@ class ArchiverTestCase(ArchiverTestCaseBase):
         with changedir('output'):
         with changedir('output'):
             self.attic('extract', self.repository_location + '::test', exit_code=1)
             self.attic('extract', self.repository_location + '::test', exit_code=1)
 
 
+    def test_rename(self):
+        self.create_regular_file('file1', size=1024 * 80)
+        self.create_regular_file('dir2/file2', size=1024 * 80)
+        self.attic('init', self.repository_location)
+        self.attic('create', self.repository_location + '::test', 'input')
+        self.attic('create', self.repository_location + '::test.2', 'input')
+        self.attic('extract', '--dry-run', self.repository_location + '::test')
+        self.attic('extract', '--dry-run', self.repository_location + '::test.2')
+        self.attic('rename', self.repository_location + '::test', 'test.3')
+        self.attic('extract', '--dry-run', self.repository_location + '::test.2')
+        self.attic('rename', self.repository_location + '::test.2', 'test.4')
+        self.attic('extract', '--dry-run', self.repository_location + '::test.3')
+        self.attic('extract', '--dry-run', self.repository_location + '::test.4')
+        # Make sure both archives have been renamed
+        repository = Repository(self.repository_path)
+        manifest, key = Manifest.load(repository)
+        self.assert_equal(len(manifest.archives), 2)
+        self.assert_in('test.3', manifest.archives)
+        self.assert_in('test.4', manifest.archives)
+
     def test_delete(self):
     def test_delete(self):
         self.create_regular_file('file1', size=1024 * 80)
         self.create_regular_file('file1', size=1024 * 80)
         self.create_regular_file('dir2/file2', size=1024 * 80)
         self.create_regular_file('dir2/file2', size=1024 * 80)