diff options
-rw-r--r-- | gemato/recursiveloader.py | 64 | ||||
-rw-r--r-- | tests/test_recursiveloader.py | 42 |
2 files changed, 87 insertions, 19 deletions
diff --git a/gemato/recursiveloader.py b/gemato/recursiveloader.py index 52628ad..9008b65 100644 --- a/gemato/recursiveloader.py +++ b/gemato/recursiveloader.py @@ -704,7 +704,12 @@ class ManifestRecursiveLoader(object): entry_dict = self.get_deduplicated_file_entry_dict_for_update( path) - dir_manifest_stack = [] + manifest_stack = [] + for mpath, mrpath, m in (self + ._iter_manifests_for_path(path)): + manifest_stack.append(mpath) + break + it = os.walk(os.path.join(self.root_directory, path), onerror=gemato.util.throw_exception, followlinks=True) @@ -715,6 +720,11 @@ class ManifestRecursiveLoader(object): if relpath == '.': relpath = '' + # drop Manifest paths until we get to a common directory + while not gemato.util.path_starts_with(relpath, + os.path.dirname(manifest_stack[-1])): + manifest_stack.pop() + skip_dirs = [] for d in dirnames: # skip dotfiles @@ -766,7 +776,8 @@ class ManifestRecursiveLoader(object): entry_dict.update( self.get_deduplicated_file_entry_dict_for_update( relpath)) - dir_manifest = None + + new_entries = [] for f in filenames: # skip dotfiles @@ -778,6 +789,8 @@ class ManifestRecursiveLoader(object): if fe is not None: if fe.tag in ('IGNORE', 'OPTIONAL'): continue + if fe.tag == 'MANIFEST': + manifest_stack.append(fpath) else: # skip top-level Manifest, we obviously can't have # an entry for it @@ -785,34 +798,47 @@ class ManifestRecursiveLoader(object): continue if f in new_manifests: cls = gemato.manifest.ManifestEntryMANIFEST - # new Manifests go into the parent directory - for mpath, mrpath, m in (self - ._iter_manifests_for_path( - os.path.dirname(relpath))): - break + manifest_stack.append(fpath) else: cls = gemato.manifest.ManifestEntryDATA - # find appropriate Manifest for this directory - if dir_manifest is None: - for mpath, mrpath, m in (self - ._iter_manifests_for_path(fpath)): - dir_manifest = (mpath, mrpath, m) - break - else: - mpath, mrpath, m = dir_manifest - fe = cls(os.path.relpath(fpath, mrpath), 0, {}) - m.entries.append(fe) + # note: .path needs to be corrected below + fe = cls(fpath, 0, {}) + new_entries.append(fe) - # update the existing entry changed = gemato.verify.update_entry_for_path( os.path.join(dirpath, f), fe, hashes=hashes, expected_dev=self.manifest_device) - if changed: + if changed and mpath is not None: self.updated_manifests.add(mpath) + if new_entries: + mpath = manifest_stack[-1] + m = self.loaded_manifests[mpath] + mdirpath = os.path.dirname(mpath) + for fe in new_entries: + if fe.tag == 'MANIFEST': + # Manifest needs to go level up + mmpath = mpath + mm = m + mmdirpath = mdirpath + i = -1 + while gemato.util.path_starts_with(fe.path, mmpath): + i -= 1 + mmpath = manifest_stack[i] + mm = self.loaded_manifests[mmpath] + mmdirpath = os.path.dirname(mmpath) + + fe.path = os.path.relpath(fe.path, mmdirpath) + mm.entries.append(fe) + self.updated_manifests.add(mmpath) + else: + fe.path = os.path.relpath(fe.path, mdirpath) + m.entries.append(fe) + self.updated_manifests.add(mpath) + # check for removed files for relpath, me in entry_dict.items(): mpath, fe = me diff --git a/tests/test_recursiveloader.py b/tests/test_recursiveloader.py index cc4d3b9..c3263db 100644 --- a/tests/test_recursiveloader.py +++ b/tests/test_recursiveloader.py @@ -2555,3 +2555,45 @@ class CreateNewCompressedManifestTest(TempDirTestCase): os.path.join(self.dir, 'Manifest.gz'))) self.assertTrue(os.path.exists( os.path.join(self.dir, 'Manifest'))) + + +class MultipleDeepNestedManifestTest(TempDirTestCase): + DIRS = ['a', 'a/x', 'a/y', 'a/z', 'b'] + FILES = { + 'Manifest': u''' +MANIFEST a/Manifest 119 MD5 6956767cfbb3276adbdce86cca559719 +MANIFEST b/Manifest 0 MD5 d41d8cd98f00b204e9800998ecf8427e +''', + 'test': u'', + 'a/Manifest': u''' +MANIFEST x/Manifest 0 MD5 d41d8cd98f00b204e9800998ecf8427e +MANIFEST z/Manifest 0 MD5 d41d8cd98f00b204e9800998ecf8427e +''', + 'a/test': u'', + 'a/x/Manifest': u'', + 'a/x/test': u'', + 'a/y/test': u'', + 'a/z/Manifest': u'', + 'a/z/test': u'', + 'b/Manifest': u'', + 'b/test': u'', + } + + def test_update_entries_for_directory(self): + m = gemato.recursiveloader.ManifestRecursiveLoader( + os.path.join(self.dir, 'Manifest')) + m.update_entries_for_directory('', hashes=['SHA256', 'SHA512']) + m.save_manifests() + m.assert_directory_verifies() + + def test_update_entries_for_directory_without_manifests(self): + for dirpath, dirs, files in os.walk(self.dir): + if 'Manifest' in files: + os.unlink(os.path.join(dirpath, 'Manifest')) + + m = gemato.recursiveloader.ManifestRecursiveLoader( + os.path.join(self.dir, 'Manifest'), + allow_create=True) + m.update_entries_for_directory('', hashes=['SHA256', 'SHA512']) + m.save_manifests() + m.assert_directory_verifies() |