diff options
-rw-r--r-- | lib/portage/dbapi/bintree.py | 21 | ||||
-rw-r--r-- | lib/portage/exception.py | 4 | ||||
-rw-r--r-- | lib/portage/gpkg.py | 6 | ||||
-rw-r--r-- | lib/portage/tests/gpkg/test_gpkg_metadata_update.py | 2 | ||||
-rw-r--r-- | lib/portage/tests/update/test_move_ent.py | 108 | ||||
-rw-r--r-- | lib/portage/tests/update/test_move_slot_ent.py | 148 | ||||
-rw-r--r-- | lib/portage/tests/update/test_update_dbentry.py | 152 |
7 files changed, 436 insertions, 5 deletions
diff --git a/lib/portage/dbapi/bintree.py b/lib/portage/dbapi/bintree.py index 6446fde95..a6e1f9773 100644 --- a/lib/portage/dbapi/bintree.py +++ b/lib/portage/dbapi/bintree.py @@ -291,6 +291,24 @@ class bindbapi(fakedbapi): elif binpkg_format == "gpkg": mybinpkg = portage.gpkg.gpkg(self.settings, cpv_str, binpkg_path) mydata = mybinpkg.get_metadata() + if mybinpkg.signature_exist: + writemsg( + colorize( + "WARN", + f"Binpkg update ignored for signed package: {binpkg_path}, " + "the file will be removed.", + ) + ) + try: + os.remove(binpkg_path) + except OSError as err: + writemsg( + colorize( + "WARN", + f"Failed to remove moved signed package: {binpkg_path} {str(err)}", + ) + ) + return encoding_key = False else: raise InvalidBinaryPackageFormat( @@ -687,7 +705,6 @@ class binarytree: ) continue - moves += 1 binpkg_format = get_binpkg_format(binpkg_path) if binpkg_format == "xpak": mytbz2 = portage.xpak.tbz2(binpkg_path) @@ -708,6 +725,8 @@ class binarytree: else: continue + moves += 1 + updated_items = update_dbentries([mylist], mydata, parent=mycpv) mydata.update(updated_items) if decode_metadata_name: diff --git a/lib/portage/exception.py b/lib/portage/exception.py index 505e920de..153a9f9a5 100644 --- a/lib/portage/exception.py +++ b/lib/portage/exception.py @@ -197,6 +197,10 @@ class CompressorOperationFailed(PortagePackageException): """An error occurred during external operation""" +class SignedPackage(PortagePackageException): + """Unable to update a signed package""" + + class InvalidAtom(PortagePackageException): """Malformed atom spec""" diff --git a/lib/portage/gpkg.py b/lib/portage/gpkg.py index c56076ab9..2e1130857 100644 --- a/lib/portage/gpkg.py +++ b/lib/portage/gpkg.py @@ -34,6 +34,7 @@ from portage.exception import ( DigestException, MissingSignature, InvalidSignature, + SignedPackage, ) from portage.output import colorize, EOutput from portage.util._urlopen import urlopen @@ -991,7 +992,7 @@ class gpkg: finally: image_tar.kill() - def update_metadata(self, metadata, new_basename=None): + def update_metadata(self, metadata, new_basename=None, force=False): """ Update metadata in the gpkg file. """ @@ -999,6 +1000,9 @@ class gpkg: self.checksums = [] old_basename = self.prefix + if self.signature_exist and not force: + raise SignedPackage("Cannot update a signed gpkg file") + if new_basename is None: new_basename = old_basename else: diff --git a/lib/portage/tests/gpkg/test_gpkg_metadata_update.py b/lib/portage/tests/gpkg/test_gpkg_metadata_update.py index d2da630f3..51ad8b404 100644 --- a/lib/portage/tests/gpkg/test_gpkg_metadata_update.py +++ b/lib/portage/tests/gpkg/test_gpkg_metadata_update.py @@ -16,7 +16,7 @@ class test_gpkg_metadata_case(TestCase): def test_gpkg_update_metadata(self): playground = ResolverPlayground( user_config={ - "make.conf": ('BINPKG_COMPRESS="gzip"',), + "make.conf": ('BINPKG_COMPRESS="gzip"', 'FEATURES="-binpkg-signing"'), } ) tmpdir = tempfile.mkdtemp() diff --git a/lib/portage/tests/update/test_move_ent.py b/lib/portage/tests/update/test_move_ent.py index 22d0c8feb..436b846cf 100644 --- a/lib/portage/tests/update/test_move_ent.py +++ b/lib/portage/tests/update/test_move_ent.py @@ -122,3 +122,111 @@ class MoveEntTestCase(TestCase): finally: playground.cleanup() + + def testMoveEntWithSignature(self): + ebuilds = { + "dev-libs/A-2::dont_apply_updates": { + "EAPI": "4", + "SLOT": "2", + }, + } + + installed = { + "dev-libs/A-1::test_repo": { + "EAPI": "4", + }, + "dev-libs/A-2::dont_apply_updates": { + "EAPI": "4", + "SLOT": "2", + }, + } + + binpkgs = { + "dev-libs/A-1::test_repo": { + "EAPI": "4", + }, + "dev-libs/A-2::dont_apply_updates": { + "EAPI": "4", + "SLOT": "2", + }, + } + + updates = textwrap.dedent( + """ + move dev-libs/A dev-libs/A-moved + """ + ) + + for binpkg_format in ("gpkg",): + with self.subTest(binpkg_format=binpkg_format): + print(colorize("HILITE", binpkg_format), end=" ... ") + sys.stdout.flush() + playground = ResolverPlayground( + binpkgs=binpkgs, + ebuilds=ebuilds, + installed=installed, + user_config={ + "make.conf": (f'BINPKG_FORMAT="{binpkg_format}"',), + }, + ) + + settings = playground.settings + trees = playground.trees + eroot = settings["EROOT"] + test_repo_location = settings.repositories["test_repo"].location + portdb = trees[eroot]["porttree"].dbapi + vardb = trees[eroot]["vartree"].dbapi + bindb = trees[eroot]["bintree"].dbapi + + updates_dir = os.path.join(test_repo_location, "profiles", "updates") + + try: + ensure_dirs(updates_dir) + with open(os.path.join(updates_dir, "1Q-2010"), "w") as f: + f.write(updates) + + # Create an empty updates directory, so that this + # repo doesn't inherit updates from the main repo. + ensure_dirs( + os.path.join( + portdb.getRepositoryPath("dont_apply_updates"), + "profiles", + "updates", + ) + ) + + global_noiselimit = portage.util.noiselimit + portage.util.noiselimit = -2 + try: + _do_global_updates(trees, {}) + finally: + portage.util.noiselimit = global_noiselimit + + # Workaround for cache validation not working + # correctly when filesystem has timestamp precision + # of 1 second. + vardb._clear_cache() + + # A -> A-moved + self.assertRaises(KeyError, vardb.aux_get, "dev-libs/A-1", ["EAPI"]) + vardb.aux_get("dev-libs/A-moved-1", ["EAPI"]) + # The original package should still exist because a binary + # package move is a copy on write operation. + bindb.aux_get("dev-libs/A-1", ["EAPI"]) + print(bindb.aux_get("dev-libs/A-1", "PF")) + self.assertRaises( + KeyError, bindb.aux_get, "dev-libs/A-moved-1", ["EAPI"] + ) + + # dont_apply_updates + self.assertRaises( + KeyError, vardb.aux_get, "dev-libs/A-moved-2", ["EAPI"] + ) + vardb.aux_get("dev-libs/A-2", ["EAPI"]) + self.assertRaises( + KeyError, bindb.aux_get, "dev-libs/A-moved-2", ["EAPI"] + ) + bindb.aux_get("dev-libs/A-2", ["EAPI"]) + + finally: + playground.cleanup() diff --git a/lib/portage/tests/update/test_move_slot_ent.py b/lib/portage/tests/update/test_move_slot_ent.py index 88d9802cf..caefdb4c9 100644 --- a/lib/portage/tests/update/test_move_slot_ent.py +++ b/lib/portage/tests/update/test_move_slot_ent.py @@ -86,7 +86,10 @@ class MoveSlotEntTestCase(TestCase): ebuilds=ebuilds, installed=installed, user_config={ - "make.conf": (f'BINPKG_FORMAT="{binpkg_format}"',), + "make.conf": ( + f'BINPKG_FORMAT="{binpkg_format}"', + 'FEATURES="-binpkg-signing"', + ), }, ) @@ -154,3 +157,146 @@ class MoveSlotEntTestCase(TestCase): finally: playground.cleanup() + + def testMoveSlotEntWithSignature(self): + ebuilds = { + "dev-libs/A-2::dont_apply_updates": { + "EAPI": "5", + "SLOT": "0/2.30", + }, + "dev-libs/B-2::dont_apply_updates": { + "SLOT": "0", + }, + "dev-libs/C-2.1::dont_apply_updates": { + "EAPI": "5", + "SLOT": "0/2.1", + }, + } + + installed = { + "dev-libs/A-1::test_repo": { + "EAPI": "5", + "SLOT": "0/2.30", + }, + "dev-libs/B-1::test_repo": { + "SLOT": "0", + }, + "dev-libs/C-1::test_repo": { + "EAPI": "5", + "SLOT": "0/1", + }, + } + + binpkgs = { + "dev-libs/A-1::test_repo": { + "EAPI": "5", + "SLOT": "0/2.30", + }, + "dev-libs/A-2::dont_apply_updates": { + "EAPI": "5", + "SLOT": "0/2.30", + }, + "dev-libs/B-1::test_repo": { + "SLOT": "0", + }, + "dev-libs/B-2::dont_apply_updates": { + "SLOT": "0", + }, + "dev-libs/C-1::test_repo": { + "EAPI": "5", + "SLOT": "0/1", + }, + "dev-libs/C-2.1::dont_apply_updates": { + "EAPI": "5", + "SLOT": "0/2.1", + }, + } + + updates = textwrap.dedent( + """ + slotmove dev-libs/A 0 2 + slotmove dev-libs/B 0 1 + slotmove dev-libs/C 0 1 + """ + ) + + for binpkg_format in ("gpkg",): + with self.subTest(binpkg_format=binpkg_format): + print(colorize("HILITE", binpkg_format), end=" ... ") + sys.stdout.flush() + playground = ResolverPlayground( + binpkgs=binpkgs, + ebuilds=ebuilds, + installed=installed, + user_config={ + "make.conf": ( + f'BINPKG_FORMAT="{binpkg_format}"', + 'FEATURES="binpkg-signing"', + ), + }, + ) + + settings = playground.settings + trees = playground.trees + eroot = settings["EROOT"] + test_repo_location = settings.repositories["test_repo"].location + portdb = trees[eroot]["porttree"].dbapi + vardb = trees[eroot]["vartree"].dbapi + bindb = trees[eroot]["bintree"].dbapi + + updates_dir = os.path.join(test_repo_location, "profiles", "updates") + + try: + ensure_dirs(updates_dir) + with open(os.path.join(updates_dir, "1Q-2010"), "w") as f: + f.write(updates) + + # Create an empty updates directory, so that this + # repo doesn't inherit updates from the main repo. + ensure_dirs( + os.path.join( + portdb.getRepositoryPath("dont_apply_updates"), + "profiles", + "updates", + ) + ) + + global_noiselimit = portage.util.noiselimit + portage.util.noiselimit = -2 + try: + _do_global_updates(trees, {}) + finally: + portage.util.noiselimit = global_noiselimit + + # Workaround for cache validation not working + # correctly when filesystem has timestamp precision + # of 1 second. + vardb._clear_cache() + + # 0/2.30 -> 2/2.30 + self.assertEqual( + "2/2.30", vardb.aux_get("dev-libs/A-1", ["SLOT"])[0] + ) + self.assertEqual( + "0/2.30", bindb.aux_get("dev-libs/A-1", ["SLOT"])[0] + ) + + # 0 -> 1 + self.assertEqual("1", vardb.aux_get("dev-libs/B-1", ["SLOT"])[0]) + self.assertEqual("0", bindb.aux_get("dev-libs/B-1", ["SLOT"])[0]) + + # 0/1 -> 1 (equivalent to 1/1) + self.assertEqual("1", vardb.aux_get("dev-libs/C-1", ["SLOT"])[0]) + self.assertEqual("0/1", bindb.aux_get("dev-libs/C-1", ["SLOT"])[0]) + + # dont_apply_updates + self.assertEqual( + "0/2.30", bindb.aux_get("dev-libs/A-2", ["SLOT"])[0] + ) + self.assertEqual("0", bindb.aux_get("dev-libs/B-2", ["SLOT"])[0]) + self.assertEqual( + "0/2.1", bindb.aux_get("dev-libs/C-2.1", ["SLOT"])[0] + ) + + finally: + playground.cleanup() diff --git a/lib/portage/tests/update/test_update_dbentry.py b/lib/portage/tests/update/test_update_dbentry.py index a473cd937..4e6554496 100644 --- a/lib/portage/tests/update/test_update_dbentry.py +++ b/lib/portage/tests/update/test_update_dbentry.py @@ -235,7 +235,10 @@ class UpdateDbentryTestCase(TestCase): installed=installed, world=world, user_config={ - "make.conf": (f'BINPKG_FORMAT="{binpkg_format}"',), + "make.conf": ( + f'BINPKG_FORMAT="{binpkg_format}"', + 'FEATURES="-binpkg-signing"', + ), }, ) @@ -307,3 +310,150 @@ class UpdateDbentryTestCase(TestCase): finally: playground.cleanup() + + def testUpdateDbentryDbapiTestCaseWithSignature(self): + ebuilds = { + "dev-libs/A-2::dont_apply_updates": { + "RDEPEND": "dev-libs/M dev-libs/N dev-libs/P", + "EAPI": "4", + "SLOT": "2", + }, + "dev-libs/B-2::dont_apply_updates": { + "RDEPEND": "dev-libs/M dev-libs/N dev-libs/P", + "EAPI": "4", + "SLOT": "2", + }, + } + + installed = { + "dev-libs/A-1::test_repo": { + "RDEPEND": "dev-libs/M dev-libs/N dev-libs/P", + "EAPI": "4", + }, + "dev-libs/A-2::dont_apply_updates": { + "RDEPEND": "dev-libs/M dev-libs/N dev-libs/P", + "EAPI": "4", + "SLOT": "2", + }, + "dev-libs/B-1::test_repo": { + "RDEPEND": "dev-libs/M dev-libs/N dev-libs/P", + "EAPI": "4", + }, + "dev-libs/M-1::test_repo": { + "EAPI": "4", + }, + "dev-libs/N-1::test_repo": { + "EAPI": "4", + }, + "dev-libs/N-2::test_repo": { + "EAPI": "4", + }, + } + + binpkgs = { + "dev-libs/A-1::test_repo": { + "RDEPEND": "dev-libs/M dev-libs/N dev-libs/P", + "EAPI": "4", + }, + "dev-libs/A-2::dont_apply_updates": { + "RDEPEND": "dev-libs/M dev-libs/N dev-libs/P", + "EAPI": "4", + "SLOT": "2", + }, + "dev-libs/B-1::test_repo": { + "RDEPEND": "dev-libs/M dev-libs/N dev-libs/P", + "EAPI": "4", + }, + } + + world = ["dev-libs/M", "dev-libs/N"] + + updates = textwrap.dedent( + """ + move dev-libs/M dev-libs/M-moved + """ + ) + + for binpkg_format in ("gpkg",): + with self.subTest(binpkg_format=binpkg_format): + print(colorize("HILITE", binpkg_format), end=" ... ") + sys.stdout.flush() + playground = ResolverPlayground( + binpkgs=binpkgs, + ebuilds=ebuilds, + installed=installed, + world=world, + user_config={ + "make.conf": (f'BINPKG_FORMAT="{binpkg_format}"',), + }, + ) + + settings = playground.settings + trees = playground.trees + eroot = settings["EROOT"] + test_repo_location = settings.repositories["test_repo"].location + portdb = trees[eroot]["porttree"].dbapi + vardb = trees[eroot]["vartree"].dbapi + bindb = trees[eroot]["bintree"].dbapi + setconfig = trees[eroot]["root_config"].setconfig + selected_set = setconfig.getSets()["selected"] + + updates_dir = os.path.join(test_repo_location, "profiles", "updates") + + try: + ensure_dirs(updates_dir) + with open(os.path.join(updates_dir, "1Q-2010"), "w") as f: + f.write(updates) + + # Create an empty updates directory, so that this + # repo doesn't inherit updates from the main repo. + ensure_dirs( + os.path.join( + portdb.getRepositoryPath("dont_apply_updates"), + "profiles", + "updates", + ) + ) + + global_noiselimit = portage.util.noiselimit + portage.util.noiselimit = -2 + try: + _do_global_updates(trees, {}) + finally: + portage.util.noiselimit = global_noiselimit + + # Workaround for cache validation not working + # correctly when filesystem has timestamp precision + # of 1 second. + vardb._clear_cache() + + # M -> M-moved + old_pattern = re.compile(r"\bdev-libs/M(\s|$)") + rdepend = vardb.aux_get("dev-libs/A-1", ["RDEPEND"])[0] + self.assertTrue(old_pattern.search(rdepend) is None) + self.assertTrue("dev-libs/M-moved" in rdepend) + rdepend = bindb.aux_get("dev-libs/A-1", ["RDEPEND"])[0] + print(old_pattern.search(rdepend) is None) + self.assertFalse(old_pattern.search(rdepend) is None) + self.assertFalse("dev-libs/M-moved" in rdepend) + rdepend = vardb.aux_get("dev-libs/B-1", ["RDEPEND"])[0] + self.assertTrue(old_pattern.search(rdepend) is None) + self.assertTrue("dev-libs/M-moved" in rdepend) + rdepend = vardb.aux_get("dev-libs/B-1", ["RDEPEND"])[0] + self.assertTrue(old_pattern.search(rdepend) is None) + self.assertTrue("dev-libs/M-moved" in rdepend) + + # dont_apply_updates + rdepend = vardb.aux_get("dev-libs/A-2", ["RDEPEND"])[0] + self.assertTrue("dev-libs/M" in rdepend) + self.assertTrue("dev-libs/M-moved" not in rdepend) + rdepend = bindb.aux_get("dev-libs/A-2", ["RDEPEND"])[0] + self.assertTrue("dev-libs/M" in rdepend) + self.assertTrue("dev-libs/M-moved" not in rdepend) + + selected_set.load() + self.assertTrue("dev-libs/M" not in selected_set) + self.assertTrue("dev-libs/M-moved" in selected_set) + + finally: + playground.cleanup() |