build: add support for conflicting dependencies (MR 2146)
This adds support for the depends="!conflict ..." syntax for explicitly marking another package as conflicting with the current one. Fixes: #2085
This commit is contained in:
parent
8a14d366ef
commit
a9d1049a3c
|
@ -130,6 +130,9 @@ def build_depends(args, apkbuild, arch, strict):
|
|||
if "no_depends" in args and args.no_depends:
|
||||
pmb.helpers.repo.update(args, arch)
|
||||
for depend in depends:
|
||||
# Ignore conflicting dependencies
|
||||
if depend.startswith("!"):
|
||||
continue
|
||||
# Check if binary package is missing
|
||||
if not pmb.parse.apkindex.package(args, depend, arch, False):
|
||||
raise RuntimeError("Missing binary package for dependency '" +
|
||||
|
@ -147,6 +150,8 @@ def build_depends(args, apkbuild, arch, strict):
|
|||
else:
|
||||
# Build the dependencies
|
||||
for depend in depends:
|
||||
if depend.startswith("!"):
|
||||
continue
|
||||
if package(args, depend, arch, strict=strict):
|
||||
depends_built += [depend]
|
||||
logging.verbose(pkgname + ": build dependencies: done, built: " +
|
||||
|
|
|
@ -97,6 +97,10 @@ def install_is_necessary(args, build, arch, package, packages_installed):
|
|||
:returns: True if the package needs to be installed/updated,
|
||||
False otherwise.
|
||||
"""
|
||||
# For packages to be removed we can do the test immediately
|
||||
if package.startswith("!"):
|
||||
return package[1:] in packages_installed
|
||||
|
||||
# User may have disabled buiding packages during "pmbootstrap install"
|
||||
build_disabled = False
|
||||
if args.action == "install" and not args.build_pkgs_on_install:
|
||||
|
|
|
@ -81,8 +81,6 @@ def parse_next_block(path, lines, start):
|
|||
values = ret[key].split(" ")
|
||||
ret[key] = []
|
||||
for value in values:
|
||||
if value.startswith("!"):
|
||||
continue
|
||||
for operator in [">", "=", "<", "~"]:
|
||||
if operator in value:
|
||||
value = value.split(operator)[0]
|
||||
|
|
|
@ -116,7 +116,8 @@ def recurse(args, pkgnames, suffix="native"):
|
|||
has multiple providers, we look at the installed packages in
|
||||
the chroot to make a decision (see package_provider()).
|
||||
:returns: list of pkgnames: consists of the initial pkgnames plus all
|
||||
depends
|
||||
depends. Dependencies explicitly marked as conflicting are
|
||||
prefixed with !.
|
||||
"""
|
||||
logging.debug(f"({suffix}) calculate depends of {', '.join(pkgnames)} "
|
||||
"(pmbootstrap -v for details)")
|
||||
|
@ -131,6 +132,10 @@ def recurse(args, pkgnames, suffix="native"):
|
|||
if pkgname_depend in ret:
|
||||
continue
|
||||
|
||||
# Check if the dependency is explicitly marked as conflicting
|
||||
is_conflict = pkgname_depend.startswith("!")
|
||||
pkgname_depend = pkgname_depend.lstrip("!")
|
||||
|
||||
# Get depends and pkgname from aports
|
||||
pkgnames_install = list(ret) + todo
|
||||
package = package_from_aports(args, pkgname_depend)
|
||||
|
@ -147,18 +152,23 @@ def recurse(args, pkgnames, suffix="native"):
|
|||
f"Required by '{source}'. See: "
|
||||
"https://postmarketos.org/depends")
|
||||
|
||||
# Append to todo/ret (unless it is a duplicate)
|
||||
# Determine pkgname
|
||||
pkgname = package["pkgname"]
|
||||
if is_conflict:
|
||||
pkgname = f"!{pkgname}"
|
||||
|
||||
# Append to todo/ret (unless it is a duplicate)
|
||||
if pkgname in ret:
|
||||
logging.verbose(f"{pkgname}: already found")
|
||||
else:
|
||||
depends = package["depends"]
|
||||
logging.verbose(f"{pkgname}: depends on: {','.join(depends)}")
|
||||
if depends:
|
||||
todo += depends
|
||||
for dep in depends:
|
||||
if dep not in required_by:
|
||||
required_by[dep] = set()
|
||||
required_by[dep].add(pkgname_depend)
|
||||
if not is_conflict:
|
||||
depends = package["depends"]
|
||||
logging.verbose(f"{pkgname}: depends on: {','.join(depends)}")
|
||||
if depends:
|
||||
todo += depends
|
||||
for dep in depends:
|
||||
if dep not in required_by:
|
||||
required_by[dep] = set()
|
||||
required_by[dep].add(pkgname_depend)
|
||||
ret.append(pkgname)
|
||||
return ret
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
# Copyright 2021 Oliver Smith
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
import pytest
|
||||
import sys
|
||||
|
||||
import pmb_test # noqa
|
||||
import pmb.chroot.apk
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def args(tmpdir, request):
|
||||
import pmb.parse
|
||||
sys.argv = ["pmbootstrap.py", "init"]
|
||||
args = pmb.parse.arguments()
|
||||
args.log = args.work + "/log_testsuite.txt"
|
||||
pmb.helpers.logging.init(args)
|
||||
request.addfinalizer(pmb.helpers.logging.logfd.close)
|
||||
return args
|
||||
|
||||
|
||||
def test_install_is_necessary(args):
|
||||
# osk-sdl not installed, nothing to do
|
||||
ret = pmb.chroot.apk.install_is_necessary(args, False, "aarch64",
|
||||
"!osk-sdl",
|
||||
{"unl0kr": {"unl0kr": {}}})
|
||||
assert not ret
|
||||
|
||||
# osk-sdl installed, (un)install necessary
|
||||
ret = pmb.chroot.apk.install_is_necessary(args, False, "aarch64",
|
||||
"!osk-sdl",
|
||||
{"osk-sdl": {"osk-sdl": {}}})
|
||||
assert ret
|
|
@ -140,16 +140,18 @@ def test_get_depends(monkeypatch):
|
|||
def test_build_depends(args, monkeypatch):
|
||||
# Shortcut and fake apkbuild
|
||||
func = pmb.build._package.build_depends
|
||||
apkbuild = {"pkgname": "test", "depends": ["a"], "makedepends": ["b"],
|
||||
"checkdepends": [], "subpackages": {"d": None}, "options": []}
|
||||
apkbuild = {"pkgname": "test", "depends": ["a", "!c"],
|
||||
"makedepends": ["b"], "checkdepends": [],
|
||||
"subpackages": {"d": None}, "options": []}
|
||||
|
||||
# No depends built (first makedepends + depends, then only makedepends)
|
||||
monkeypatch.setattr(pmb.build._package, "package", return_none)
|
||||
assert func(args, apkbuild, "armhf", True) == (["a", "b"], [])
|
||||
assert func(args, apkbuild, "armhf", True) == (["!c", "a", "b"], [])
|
||||
|
||||
# All depends built (makedepends only)
|
||||
monkeypatch.setattr(pmb.build._package, "package", return_string)
|
||||
assert func(args, apkbuild, "armhf", False) == (["a", "b"], ["a", "b"])
|
||||
assert func(args, apkbuild, "armhf", False) == (["!c", "a", "b"],
|
||||
["a", "b"])
|
||||
|
||||
|
||||
def test_build_depends_no_binary_error(args, monkeypatch):
|
||||
|
|
|
@ -115,6 +115,34 @@ def test_parse_next_block_virtual():
|
|||
assert start == [31]
|
||||
|
||||
|
||||
def test_parse_next_block_conflict():
|
||||
"""
|
||||
Test parsing a package that specifies a conflicting dependency from an
|
||||
APKINDEX.
|
||||
"""
|
||||
# Read the file
|
||||
func = pmb.parse.apkindex.parse_next_block
|
||||
path = pmb.config.pmb_src + "/test/testdata/apkindex/conflict"
|
||||
with open(path, "r", encoding="utf-8") as handle:
|
||||
lines = handle.readlines()
|
||||
|
||||
# First block
|
||||
start = [0]
|
||||
block = {'arch': 'x86_64',
|
||||
'depends': ['!conflict', 'so:libc.musl-x86_64.so.1'],
|
||||
'origin': 'hello-world',
|
||||
'pkgname': 'hello-world',
|
||||
'provides': ['cmd:hello-world'],
|
||||
'timestamp': '1500000000',
|
||||
'version': '2-r0'}
|
||||
assert func(path, lines, start) == block
|
||||
assert start == [20]
|
||||
|
||||
# No more blocks
|
||||
assert func(path, lines, start) is None
|
||||
assert start == [20]
|
||||
|
||||
|
||||
def test_parse_add_block(args):
|
||||
func = pmb.parse.apkindex.parse_add_block
|
||||
multiple_providers = False
|
||||
|
|
|
@ -146,7 +146,8 @@ def test_recurse(args, monkeypatch):
|
|||
depends = {
|
||||
"test": ["libtest", "so:libtest.so.1"],
|
||||
"libtest": ["libtest_depend"],
|
||||
"libtest_depend": [],
|
||||
"libtest_depend": ["!libtest_conflict"],
|
||||
"libtest_conflict": [],
|
||||
"so:libtest.so.1": ["libtest_depend"],
|
||||
}
|
||||
|
||||
|
@ -158,5 +159,6 @@ def test_recurse(args, monkeypatch):
|
|||
# Run
|
||||
func = pmb.parse.depends.recurse
|
||||
pkgnames = ["test", "so:libtest.so.1"]
|
||||
result = ["test", "so:libtest.so.1", "libtest", "libtest_depend"]
|
||||
result = ["test", "so:libtest.so.1", "libtest", "libtest_depend",
|
||||
"!libtest_conflict"]
|
||||
assert func(args, pkgnames) == result
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
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:!conflict 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=
|
||||
|
Loading…
Reference in New Issue