summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gemato/recursiveloader.py144
-rw-r--r--tests/test_recursiveloader.py73
2 files changed, 156 insertions, 61 deletions
diff --git a/gemato/recursiveloader.py b/gemato/recursiveloader.py
index f403b7a..e5e9fdc 100644
--- a/gemato/recursiveloader.py
+++ b/gemato/recursiveloader.py
@@ -56,6 +56,7 @@ class ManifestRecursiveLoader(object):
# TODO: allow catching OpenPGP exceptions somehow?
m = self.load_manifest(os.path.basename(top_manifest_path))
self.openpgp_signed = m.openpgp_signed
+ self.updated_manifests = set()
def load_manifest(self, relpath, verify_entry=None):
"""
@@ -365,11 +366,64 @@ class ManifestRecursiveLoader(object):
return ret
+ def save_manifests(self, hashes=None):
+ """
+ Save the Manifests modified since the last save_manifests()
+ call.
+
+ @hashes specifies the requested hash set. If specified,
+ it overrides the hash set used in Manifest. If None, the set
+ specified in ManifestLoader constructor is used. If that one
+ is None as well, the routine reuses the existing hash set
+ in the entry.
+ """
+
+ if hashes is None:
+ hashes = self.hashes
+
+ fixed_manifests = set()
+ for mpath, relpath, m in self._iter_manifests_for_path('',
+ recursive=True):
+ for e in m.entries:
+ if not isinstance(e, gemato.manifest
+ .ManifestEntryMANIFEST):
+ continue
+
+ fullpath = os.path.join(relpath, e.path)
+ if fullpath not in self.updated_manifests:
+ continue
+
+ gemato.verify.update_entry_for_path(
+ os.path.join(self.root_directory, fullpath),
+ e,
+ hashes=hashes,
+ expected_dev=self.manifest_device)
+
+ # do not remove it from self.updated_manifests
+ # immediately as we may have to deal with multiple
+ # entries
+ fixed_manifests.add(fullpath)
+ self.updated_manifests.add(mpath)
+
+ # we've apparently modified this Manifest, so store it now
+ if mpath in self.updated_manifests:
+ self.save_manifest(mpath)
+
+ # now, discard all the Manifests whose entries we've updated
+ self.updated_manifests -= fixed_manifests
+ # ...and top-level Manifest which has no entries
+ self.updated_manifests -= set(gemato.compression
+ .get_potential_compressed_names('Manifest'))
+ # at this point, the list should be empty
+ assert not self.updated_manifests
+
def update_entry_for_path(self, path, new_entry_type='DATA',
hashes=None):
"""
- Update the Manifest entries for @path and the appropriate
- MANIFEST entries. @path must not be covered by IGNORE.
+ Update the Manifest entries for @path and queue the containing
+ Manifests for update. @path must not be covered by IGNORE.
+ You need to invoke save_manifests() to store the Manifest
+ updates afterwards.
If the path exists and has a matching Manifest entry, the most
specific existing entry will be updated. If the path has more
@@ -399,7 +453,6 @@ class ManifestRecursiveLoader(object):
"""
had_entry = False
- manifests_to_update = set()
if hashes is None:
hashes = self.hashes
@@ -424,15 +477,12 @@ class ManifestRecursiveLoader(object):
# we update either file at the specified path
# or any relevant Manifests
fullpath = os.path.join(relpath, e.path)
- if fullpath == path:
- if had_entry:
- # duplicate entry!
- entries_to_remove.append(e)
- continue
- # pass through
- elif fullpath in manifests_to_update:
- pass
- else:
+ if fullpath != path:
+ continue
+
+ if had_entry:
+ # duplicate entry!
+ entries_to_remove.append(e)
continue
try:
@@ -451,61 +501,35 @@ class ManifestRecursiveLoader(object):
else:
raise err
else:
- manifests_to_update.add(mpath)
+ self.updated_manifests.add(mpath)
had_entry = True
if entries_to_remove:
for e in entries_to_remove:
m.entries.remove(e)
- manifests_to_update.add(mpath)
-
- # we've apparently added this Manifest, so store it now
- if mpath in manifests_to_update:
- self.save_manifest(mpath)
+ self.updated_manifests.add(mpath)
if not had_entry:
assert hashes is not None
for mpath, relpath, m in self._iter_manifests_for_path(path):
# add to the first relevant Manifest
- if not had_entry:
- assert new_entry_type not in (
- 'DIST', 'IGNORE', 'OPTIONAL')
- newpath = os.path.relpath(path, relpath)
- if new_entry_type == 'AUX':
- # AUX has implicit files/ prefix
- assert gemato.util.path_inside_dir(newpath,
- 'files')
- # drop files/ prefix
- newpath = os.path.relpath(newpath, 'files')
- e = gemato.manifest.new_manifest_entry(
- new_entry_type, newpath, 0, {})
- gemato.verify.update_entry_for_path(
- os.path.join(self.root_directory, path),
- e,
- hashes=hashes,
- expected_dev=self.manifest_device)
- m.entries.append(e)
- manifests_to_update.add(mpath)
- had_entry = True
- else:
- for e in m.entries:
- if not isinstance(e, gemato.manifest.ManifestEntryMANIFEST):
- continue
-
- # we update either file at the specified path
- # or any relevant Manifests
- fullpath = os.path.join(relpath, e.path)
- if fullpath not in manifests_to_update:
- continue
-
- gemato.verify.update_entry_for_path(
- os.path.join(self.root_directory,
- fullpath),
- e,
- hashes=hashes,
- expected_dev=self.manifest_device)
- manifests_to_update.add(mpath)
-
- # we've apparently added this Manifest, so store it now
- if mpath in manifests_to_update:
- self.save_manifest(mpath)
+ assert new_entry_type not in (
+ 'DIST', 'IGNORE', 'OPTIONAL')
+ newpath = os.path.relpath(path, relpath)
+ if new_entry_type == 'AUX':
+ # AUX has implicit files/ prefix
+ assert gemato.util.path_inside_dir(newpath,
+ 'files')
+ # drop files/ prefix
+ newpath = os.path.relpath(newpath, 'files')
+ e = gemato.manifest.new_manifest_entry(
+ new_entry_type, newpath, 0, {})
+ gemato.verify.update_entry_for_path(
+ os.path.join(self.root_directory, path),
+ e,
+ hashes=hashes,
+ expected_dev=self.manifest_device)
+ m.entries.append(e)
+ self.updated_manifests.add(mpath)
+ had_entry = True
+ break
diff --git a/tests/test_recursiveloader.py b/tests/test_recursiveloader.py
index d017ef1..a8b7384 100644
--- a/tests/test_recursiveloader.py
+++ b/tests/test_recursiveloader.py
@@ -301,6 +301,7 @@ DATA test 0 MD5 d41d8cd98f00b204e9800998ecf8427e
m.update_entry_for_path('sub/stray', hashes=['SHA256', 'SHA512'])
self.assertIsInstance(m.find_path_entry('sub/stray'),
gemato.manifest.ManifestEntryDATA)
+ m.save_manifests()
# relevant Manifests should have been updated
with io.open(os.path.join(self.dir, 'sub/Manifest'),
'r', encoding='utf8') as f:
@@ -317,6 +318,7 @@ DATA test 0 MD5 d41d8cd98f00b204e9800998ecf8427e
new_entry_type='MANIFEST')
self.assertIsInstance(m.find_path_entry('sub/stray'),
gemato.manifest.ManifestEntryMANIFEST)
+ m.save_manifests()
# relevant Manifests should have been updated
with io.open(os.path.join(self.dir, 'sub/Manifest'),
'r', encoding='utf8') as f:
@@ -334,6 +336,7 @@ DATA test 0 MD5 d41d8cd98f00b204e9800998ecf8427e
new_entry_type='MISC')
self.assertIsInstance(m.find_path_entry('sub/stray'),
gemato.manifest.ManifestEntryMISC)
+ m.save_manifests()
# relevant Manifests should have been updated
with io.open(os.path.join(self.dir, 'sub/Manifest'),
'r', encoding='utf8') as f:
@@ -350,6 +353,7 @@ DATA test 0 MD5 d41d8cd98f00b204e9800998ecf8427e
new_entry_type='EBUILD')
self.assertIsInstance(m.find_path_entry('sub/stray'),
gemato.manifest.ManifestEntryEBUILD)
+ m.save_manifests()
# relevant Manifests should have been updated
with io.open(os.path.join(self.dir, 'sub/Manifest'),
'r', encoding='utf8') as f:
@@ -381,6 +385,7 @@ DATA test 0 MD5 d41d8cd98f00b204e9800998ecf8427e
self.assertListEqual(
sorted(m.find_path_entry('sub/stray').checksums),
['SHA256', 'SHA512'])
+ m.save_manifests()
# relevant Manifests should have been updated
with io.open(os.path.join(self.dir, 'sub/Manifest'),
'r', encoding='utf8') as f:
@@ -398,6 +403,7 @@ DATA test 0 MD5 d41d8cd98f00b204e9800998ecf8427e
self.assertListEqual(
sorted(m.find_path_entry('sub/stray').checksums),
['MD5'])
+ m.save_manifests()
# relevant Manifests should have been updated
with io.open(os.path.join(self.dir, 'sub/Manifest'),
'r', encoding='utf8') as f:
@@ -407,6 +413,25 @@ DATA test 0 MD5 d41d8cd98f00b204e9800998ecf8427e
self.assertNotEqual(f.read(), self.FILES['Manifest'])
m.assert_directory_verifies()
+ def test_update_entry_for_path_discard(self):
+ """
+ Test that files are not modified if save_manifests()
+ is not called.
+ """
+ m = gemato.recursiveloader.ManifestRecursiveLoader(
+ os.path.join(self.dir, 'Manifest'))
+ m.update_entry_for_path('sub/stray', hashes=['SHA256', 'SHA512'])
+ self.assertIsInstance(m.find_path_entry('sub/stray'),
+ gemato.manifest.ManifestEntryDATA)
+ del m
+ # relevant Manifests should not have been touched
+ with io.open(os.path.join(self.dir, 'sub/Manifest'),
+ 'r', encoding='utf8') as f:
+ self.assertEqual(f.read(), self.FILES['sub/Manifest'])
+ with io.open(os.path.join(self.dir, 'Manifest'),
+ 'r', encoding='utf8') as f:
+ self.assertEqual(f.read(), self.FILES['Manifest'])
+
class MultipleManifestTest(TempDirTestCase):
DIRS = ['sub']
@@ -459,6 +484,7 @@ TIMESTAMP 2017-01-01T01:01:01Z
m = gemato.recursiveloader.ManifestRecursiveLoader(
os.path.join(self.dir, 'Manifest'))
m.update_entry_for_path('sub/foo')
+ m.save_manifests()
# relevant Manifests should have been updated
# but sub/Manifest.b should be left intact
with io.open(os.path.join(self.dir, 'sub/Manifest.a'),
@@ -480,10 +506,45 @@ TIMESTAMP 2017-01-01T01:01:01Z
self.assertListEqual(
sorted(m.find_path_entry('sub/foo').checksums),
['SHA256', 'SHA512'])
+ m.save_manifests()
+ self.assertListEqual(
+ sorted(m.find_path_entry('sub/Manifest.a').checksums),
+ ['MD5'])
+ self.assertListEqual(
+ sorted(m.find_path_entry('sub/Manifest.b').checksums),
+ ['MD5'])
+ # relevant Manifests should have been updated
+ # but sub/Manifest.b should be left intact
+ with io.open(os.path.join(self.dir, 'sub/Manifest.a'),
+ 'r', encoding='utf8') as f:
+ self.assertNotEqual(f.read(), self.FILES['sub/Manifest.a'])
+ with io.open(os.path.join(self.dir, 'sub/Manifest.b'),
+ 'r', encoding='utf8') as f:
+ self.assertEqual(f.read(), self.FILES['sub/Manifest.b'])
+ with io.open(os.path.join(self.dir, 'Manifest'),
+ 'r', encoding='utf8') as f:
+ self.assertNotEqual(f.read(), self.FILES['Manifest'])
+ m.assert_directory_verifies()
+
+ def test_update_entry_for_path_hashes_plus_manifest(self):
+ m = gemato.recursiveloader.ManifestRecursiveLoader(
+ os.path.join(self.dir, 'Manifest'))
+ m.update_entry_for_path('sub/foo', hashes=['SHA256', 'SHA512'])
+ # check for checksums
+ self.assertListEqual(
+ sorted(m.find_path_entry('sub/foo').checksums),
+ ['SHA256', 'SHA512'])
self.assertListEqual(
sorted(m.find_path_entry('sub/Manifest.a').checksums),
+ ['MD5'])
+ m.save_manifests(hashes=['SHA1'])
+ self.assertListEqual(
+ sorted(m.find_path_entry('sub/foo').checksums),
['SHA256', 'SHA512'])
self.assertListEqual(
+ sorted(m.find_path_entry('sub/Manifest.a').checksums),
+ ['SHA1'])
+ self.assertListEqual(
sorted(m.find_path_entry('sub/Manifest.b').checksums),
['MD5'])
# relevant Manifests should have been updated
@@ -510,6 +571,10 @@ TIMESTAMP 2017-01-01T01:01:01Z
['SHA256', 'SHA512'])
self.assertListEqual(
sorted(m.find_path_entry('sub/Manifest.a').checksums),
+ ['MD5'])
+ m.save_manifests()
+ self.assertListEqual(
+ sorted(m.find_path_entry('sub/Manifest.a').checksums),
['SHA256', 'SHA512'])
self.assertListEqual(
sorted(m.find_path_entry('sub/Manifest.b').checksums),
@@ -536,9 +601,10 @@ TIMESTAMP 2017-01-01T01:01:01Z
self.assertListEqual(
sorted(m.find_path_entry('sub/foo').checksums),
['SHA1'])
+ m.save_manifests()
self.assertListEqual(
sorted(m.find_path_entry('sub/Manifest.a').checksums),
- ['SHA1'])
+ ['SHA256', 'SHA512'])
self.assertListEqual(
sorted(m.find_path_entry('sub/Manifest.b').checksums),
['MD5'])
@@ -767,6 +833,7 @@ AUX test.patch 0 MD5 d41d8cd98f00b204e9800998ecf8427e
os.path.join(self.dir, 'Manifest'))
m.update_entry_for_path('files/test.patch')
self.assertIsNone(m.find_path_entry('files/test.patch'))
+ m.save_manifests()
with io.open(os.path.join(self.dir, 'Manifest'),
'r', encoding='utf8') as f:
self.assertNotEqual(f.read(), self.FILES['Manifest'])
@@ -793,6 +860,7 @@ class AUXTypeFileAdditionTest(TempDirTestCase):
hashes=['MD5'], new_entry_type='AUX')
self.assertIsInstance(m.find_path_entry('files/test.txt'),
gemato.manifest.ManifestEntryAUX)
+ m.save_manifests()
with io.open(os.path.join(self.dir, 'Manifest'),
'r', encoding='utf8') as f:
self.assertNotEqual(f.read(), self.FILES['Manifest'])
@@ -858,6 +926,7 @@ DATA test 0 SHA1 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12
self.assertIn(
tuple(m.find_path_entry('test').checksums),
(('MD5',), ('SHA1',)))
+ m.save_manifests()
with io.open(os.path.join(self.dir, 'Manifest'),
'r', encoding='utf8') as f:
self.assertNotEqual(f.read(), self.FILES['Manifest'])
@@ -1083,6 +1152,7 @@ MISC foo 0 MD5 d41d8cd98f00b204e9800998ecf8427e
os.path.join(self.dir, 'Manifest'))
m.update_entry_for_path('foo')
self.assertIsNone(m.find_path_entry('foo'))
+ m.save_manifests()
with io.open(os.path.join(self.dir, 'Manifest'),
'r', encoding='utf8') as f:
self.assertNotEqual(f.read(), self.FILES['Manifest'])
@@ -1134,6 +1204,7 @@ OPTIONAL foo
os.path.join(self.dir, 'Manifest'))
m.update_entry_for_path('foo')
self.assertIsNotNone(m.find_path_entry('foo'))
+ m.save_manifests()
with io.open(os.path.join(self.dir, 'Manifest'),
'r', encoding='utf8') as f:
self.assertEqual(f.read(), self.FILES['Manifest'])