Skip virtual packages when parsing APKINDEX (#1278)

Since PR #1247 we are using the virtual package `.pmbootstrap` to mark
packages as not explcitly installed. In case `pmbootstrap` doesn't
finish the installation because of a bug, the `.pmbootstrap` virtual
package may not get uninstalled.

As virtual packages don't have the "timestamp" attribute set in the
package database (which indicates when the package was built), the
APKINDEX parser fails to parse them.

Changes:
* pmb.parse.apkindex.parse_next_block(): don't require the "timestamp"
  attribute to be set (but the arch attribute instead, which is always
  present)
* pmb.parse.apkindex.parse(): when a block does not have a `timestamp`
  attribute, skip it, because it must be a virtual package.
* add test cases for both functions with a package database that
  contains a virtual package.
This commit is contained in:
Oliver Smith 2018-03-10 13:15:30 +00:00 committed by GitHub
parent 4cad170844
commit af4b817c21
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 99 additions and 1 deletions

View File

@ -37,9 +37,16 @@ def parse_next_block(args, path, lines, start):
:returns: a dictionary with the following structure:
{ "arch": "noarch",
"depends": ["busybox-extras", "lddtree", ... ],
"origin": "postmarketos-mkinitfs",
"pkgname": "postmarketos-mkinitfs",
"provides": ["mkinitfs=0.0.1"],
"timestamp": "1500000000",
"version": "0.0.4-r10" }
NOTE: "depends" is not set for packages without any dependencies,
e.g. musl.
NOTE: "timestamp" and "origin" are not set for virtual packages
(#1273). We use that information to skip these virtual
packages in parse().
:returns: None, when there are no more blocks
"""
@ -77,7 +84,7 @@ def parse_next_block(args, path, lines, start):
# Format and return the block
if end_of_block_found:
# Check for required keys
for key in ["pkgname", "version", "timestamp"]:
for key in ["arch", "pkgname", "version"]:
if key not in ret:
raise RuntimeError("Missing required key '" + key +
"' in block " + str(ret) + ", file: " + path)
@ -209,6 +216,12 @@ def parse(args, path, multiple_providers=True):
if not block:
break
# Skip virtual packages
if "timestamp" not in block:
logging.verbose("Skipped virtual package " + str(block) + " in"
" file: " + path)
continue
# Add the next package and all aliases
parse_add_block(ret, block, None, multiple_providers)
if "provides" in block:

View File

@ -101,6 +101,42 @@ def test_parse_next_block_no_error(args):
assert start == [45]
def test_parse_next_block_virtual(args):
"""
Test parsing a virtual package from an APKINDEX.
"""
# Read the file
func = pmb.parse.apkindex.parse_next_block
path = pmb.config.pmb_src + "/test/testdata/apkindex/virtual_package"
with open(path, "r", encoding="utf-8") as handle:
lines = handle.readlines()
# First block
start = [0]
block = {'arch': 'x86_64',
'depends': ['so:libc.musl-x86_64.so.1'],
'origin': 'hello-world',
'pkgname': 'hello-world',
'provides': ['cmd:hello-world'],
'timestamp': '1500000000',
'version': '2-r0'}
assert func(args, path, lines, start) == block
assert start == [20]
# Second block: virtual package
block = {'arch': 'noarch',
'depends': ['hello-world'],
'pkgname': '.pmbootstrap',
'provides': [],
'version': '0'}
assert func(args, path, lines, start) == block
assert start == [31]
# No more blocks
assert func(args, path, lines, start) is None
assert start == [31]
def test_parse_add_block(args):
func = pmb.parse.apkindex.parse_add_block
multiple_providers = False
@ -231,6 +267,24 @@ def test_parse(args):
assert args.cache["apkindex"][path]["multiple"] == ret_multiple
def test_parse_virtual(args):
"""
This APKINDEX contains a virtual package .pbmootstrap. It must not be part
of the output.
"""
path = pmb.config.pmb_src + "/test/testdata/apkindex/virtual_package"
block = {'arch': 'x86_64',
'depends': ['so:libc.musl-x86_64.so.1'],
'origin': 'hello-world',
'pkgname': 'hello-world',
'provides': ['cmd:hello-world'],
'timestamp': '1500000000',
'version': '2-r0'}
ret = {"hello-world": block, "cmd:hello-world": block}
assert pmb.parse.apkindex.parse(args, path, False) == ret
assert args.cache["apkindex"][path]["single"] == ret
def test_providers_invalid_package(args, tmpdir):
# Create empty APKINDEX
path = str(tmpdir) + "/APKINDEX"

31
test/testdata/apkindex/virtual_package vendored Normal file
View File

@ -0,0 +1,31 @@
C:Q1XaZzCVZ9mvH8djPyEb5aUYhG3r4=
P:hello-world
V:2-r0
A:x86_64
S:2897
I:20480
T:hello world program to be built in the testsuite
U:https://en.wikipedia.org/wiki/%22Hello,_World!%22_program
L:MIT
o:hello-world
t:1500000000
c:
D:so:libc.musl-x86_64.so.1
p:cmd:hello-world
F:usr
F:usr/bin
R:hello-world
a:0:0:755
Z:Q1ZjTpsnMchSsSwEPB1cTjihYuJvo=
C:Q127l1Ui9vzedbeR3BMelZnSa4pwY=
P:.pmbootstrap
V:0
A:noarch
S:0
I:0
T:virtual meta package
U:
L:
D:hello-world