summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gemato/profile.py49
-rw-r--r--gemato/recursiveloader.py32
-rw-r--r--tests/test_profile.py131
3 files changed, 206 insertions, 6 deletions
diff --git a/gemato/profile.py b/gemato/profile.py
new file mode 100644
index 0000000..2b551a6
--- /dev/null
+++ b/gemato/profile.py
@@ -0,0 +1,49 @@
+# gemato: Profile support
+# vim:fileencoding=utf-8
+# (c) 2017 Michał Górny
+# Licensed under the terms of 2-clause BSD license
+
+import os.path
+
+
+class DefaultProfile(object):
+ """
+ Profile is a class describing the specific properties of a directory
+ tree. It is used when updating Manifests to determine the most
+ correct behavior for a given use case.
+ """
+
+ def get_entry_type_for_path(self, path):
+ """
+ Get Manifest entry type appropriate for the specified path.
+ Must return an appropriate Manifest tag for file-style entry
+ (i.e. one of DATA, MISC, EBUILD, AUX).
+ """
+ return 'DATA'
+
+
+class EbuildRepositoryProfile(DefaultProfile):
+ """
+ A profile suited for a modern ebuild repository.
+ """
+ pass
+
+
+class BackwardsCompatEbuildRepositoryProfile(EbuildRepositoryProfile):
+ """
+ A profile for ebuild repository that maintains compatibility
+ with Manifest2 format.
+ """
+
+ def get_entry_type_for_path(self, path):
+ spl = path.split(os.path.sep)
+ if len(spl) == 3:
+ if path.endswith('.ebuild'):
+ return 'EBUILD'
+ elif spl[2] == 'metadata.xml':
+ return 'MISC'
+ if spl[2:3] == ['files']:
+ return 'AUX'
+
+ return (super(BackwardsCompatEbuildRepositoryProfile, self)
+ .get_entry_type_for_path(path))
diff --git a/gemato/recursiveloader.py b/gemato/recursiveloader.py
index cb6d247..fd926c5 100644
--- a/gemato/recursiveloader.py
+++ b/gemato/recursiveloader.py
@@ -9,6 +9,7 @@ import os.path
import gemato.compression
import gemato.exceptions
import gemato.manifest
+import gemato.profile
import gemato.util
import gemato.verify
@@ -22,12 +23,14 @@ class ManifestRecursiveLoader(object):
__slots__ = ['root_directory', 'loaded_manifests', 'verify_openpgp',
'openpgp_env', 'sign_openpgp', 'openpgp_keyid', 'hashes',
- 'openpgp_signed', 'updated_manifests', 'manifest_device']
+ 'openpgp_signed', 'updated_manifests', 'manifest_device',
+ 'profile']
def __init__(self, top_manifest_path,
verify_openpgp=True, openpgp_env=None,
sign_openpgp=None, openpgp_keyid=None,
- hashes=None, allow_create=False):
+ hashes=None, allow_create=False,
+ profile=gemato.profile.DefaultProfile()):
"""
Instantiate the loader for a Manifest tree starting at top-level
Manifest @top_manifest_path.
@@ -53,6 +56,8 @@ class ManifestRecursiveLoader(object):
If @allow_create is True and @top_manifest_path does not exist,
a new Manifest tree will be initialized. Otherwise, opening
a non-existing file will cause an exception.
+
+ @profile can be used to provide the profile for the repository.
"""
self.root_directory = os.path.dirname(top_manifest_path)
@@ -61,6 +66,7 @@ class ManifestRecursiveLoader(object):
self.sign_openpgp = sign_openpgp
self.openpgp_keyid = openpgp_keyid
self.hashes = hashes
+ self.profile = profile
self.loaded_manifests = {}
self.updated_manifests = set()
@@ -859,14 +865,16 @@ class ManifestRecursiveLoader(object):
if fpath in manifest_filenames:
continue
if fpath in new_manifests:
- cls = gemato.manifest.ManifestEntryMANIFEST
+ ftype = 'MANIFEST'
manifest_stack.append((fpath, relpath,
self.loaded_manifests[fpath]))
else:
- cls = gemato.manifest.ManifestEntryDATA
+ ftype = self.profile.get_entry_type_for_path(
+ fpath)
# note: .path needs to be corrected below
- fe = cls(fpath, 0, {})
+ fe = gemato.manifest.new_manifest_entry(ftype,
+ fpath, 0, {})
new_entries.append(fe)
changed = gemato.verify.update_entry_for_path(
@@ -894,7 +902,19 @@ class ManifestRecursiveLoader(object):
mm.entries.append(fe)
self.updated_manifests.add(mmpath)
else:
- fe.path = os.path.relpath(fe.path, mdirpath)
+ if ftype == 'AUX':
+ # AUX has implicit files/ prefix in .path
+ # but for now, we've shoved our path
+ # into .aux_path
+ fe.path = os.path.relpath(fe.aux_path,
+ mdirpath)
+ assert gemato.util.path_inside_dir(
+ fe.path, 'files')
+ # drop files/ prefix for the entry
+ fe.aux_path = os.path.relpath(fe.path,
+ 'files')
+ else:
+ fe.path = os.path.relpath(fe.path, mdirpath)
m.entries.append(fe)
self.updated_manifests.add(mpath)
diff --git a/tests/test_profile.py b/tests/test_profile.py
new file mode 100644
index 0000000..ebc9406
--- /dev/null
+++ b/tests/test_profile.py
@@ -0,0 +1,131 @@
+# gemato: Profile behavior tests
+# vim:fileencoding=utf-8
+# (c) 2017 Michał Górny
+# Licensed under the terms of 2-clause BSD license
+
+import os.path
+
+import gemato.profile
+
+from tests.testutil import TempDirTestCase
+
+
+class EbuildRepositoryTests(TempDirTestCase):
+ """
+ Tests for ebuild repository profiles.
+ """
+
+ PROFILE = gemato.profile.EbuildRepositoryProfile
+ DIRS = [
+ 'dev-foo',
+ 'dev-foo/bar',
+ 'dev-foo/bar/files',
+ 'eclass',
+ 'eclass/tests',
+ 'licenses',
+ 'metadata',
+ 'metadata/dtd',
+ 'metadata/glsa',
+ 'metadata/install-qa-check.d',
+ 'metadata/md5-cache',
+ 'metadata/md5-cache/dev-foo',
+ 'metadata/news',
+ 'metadata/news/2020-01-01-foo',
+ 'metadata/xml-schema',
+ 'profiles',
+ 'profiles/arch',
+ 'profiles/arch/foo',
+ 'profiles/desc',
+ 'profiles/updates',
+ ]
+ EXPECTED_TYPES = {
+ 'header.txt': 'DATA',
+ 'skel.ebuild': 'DATA',
+ 'skel.metadata.xml': 'DATA',
+ 'dev-foo/metadata.xml': 'DATA',
+ 'dev-foo/bar/bar-1.ebuild': 'DATA',
+ 'dev-foo/bar/metadata.xml': 'DATA',
+ 'dev-foo/bar/files/test.patch': 'DATA',
+ 'eclass/foo.eclass': 'DATA',
+ 'eclass/tests/foo.sh': 'DATA',
+ 'licenses/foo': 'DATA',
+ 'metadata/layout.conf': 'DATA',
+ 'metadata/projects.xml': 'DATA',
+ 'metadata/pkg_desc_index': 'DATA',
+ 'metadata/timestamp': 'DATA',
+ 'metadata/timestamp.chk': 'DATA',
+ 'metadata/timestamp.commit': 'DATA',
+ 'metadata/timestamp.x': 'DATA',
+ 'metadata/dtd/foo.dtd': 'DATA',
+ 'metadata/glsa/glsa-202001-01.xml': 'DATA',
+ 'metadata/install-qa-check.d/50foo': 'DATA',
+ 'metadata/md5-cache/dev-foo/bar-1': 'DATA',
+ 'metadata/news/2020-01-01-foo/2020-01-01-foo.en.txt': 'DATA',
+ 'metadata/news/2020-01-01-foo/2020-01-01-foo.en.txt.asc': 'DATA',
+ 'metadata/xml-schema/foo.xsd': 'DATA',
+ 'profiles/arch.desc': 'DATA',
+ 'profiles/categories': 'DATA',
+ 'profiles/eapi': 'DATA',
+ 'profiles/info_pkgs': 'DATA',
+ 'profiles/info_vars': 'DATA',
+ 'profiles/license_groups': 'DATA',
+ 'profiles/package.mask': 'DATA',
+ 'profiles/profiles.desc': 'DATA',
+ 'profiles/repo_name': 'DATA',
+ 'profiles/thirdpartymirrors': 'DATA',
+ 'profiles/use.desc': 'DATA',
+ 'profiles/use.local.desc': 'DATA',
+ 'profiles/arch/foo/eapi': 'DATA',
+ 'profiles/arch/foo/parent': 'DATA',
+ 'profiles/desc/foo.desc': 'DATA',
+ 'profiles/updates/1Q-2020': 'DATA',
+ }
+ FILES = dict.fromkeys(EXPECTED_TYPES, u'')
+
+ def test_get_entry_type_for_path(self):
+ p = self.PROFILE()
+ for f, expt in self.EXPECTED_TYPES.items():
+ self.assertEqual(
+ p.get_entry_type_for_path(f),
+ expt,
+ "type mismatch for {}".format(f))
+
+ def test_update_entries_for_directory(self):
+ m = gemato.recursiveloader.ManifestRecursiveLoader(
+ os.path.join(self.dir, 'Manifest'),
+ hashes=['SHA256', 'SHA512'],
+ allow_create=True,
+ profile=self.PROFILE())
+ m.update_entries_for_directory('')
+ for f, expt in self.EXPECTED_TYPES.items():
+ self.assertEqual(
+ m.find_path_entry(f).tag,
+ expt,
+ "type mismatch for {}".format(f))
+ return m
+
+class BackwardsCompatEbuildRepositoryTests(EbuildRepositoryTests):
+ PROFILE = gemato.profile.BackwardsCompatEbuildRepositoryProfile
+
+ def __init__(self, *args, **kwargs):
+ self.EXPECTED_TYPES = self.EXPECTED_TYPES.copy()
+ self.EXPECTED_TYPES.update({
+ 'dev-foo/bar/bar-1.ebuild': 'EBUILD',
+ 'dev-foo/bar/metadata.xml': 'MISC',
+ 'dev-foo/bar/files/test.patch': 'AUX',
+ })
+ # TODO: this is only temporary until we have API to create
+ # the Manifest at this level automatically
+ self.FILES['dev-foo/bar/Manifest'] = u''
+ super(BackwardsCompatEbuildRepositoryTests, self).__init__(
+ *args, **kwargs)
+
+ def test_update_entries_for_directory(self):
+ m = (super(BackwardsCompatEbuildRepositoryTests, self)
+ .test_update_entries_for_directory())
+ self.assertEqual(
+ m.find_path_entry('dev-foo/bar/files/test.patch').path,
+ 'files/test.patch')
+ self.assertEqual(
+ m.find_path_entry('dev-foo/bar/files/test.patch').aux_path,
+ 'test.patch')