ci: fix remaining ruff issues and run ruff format

We only disable LOG015 rule, as in the simple situation of pmaports,
it doesn't matter too much if in pytest we are using the root logger
or a custom one.

Signed-off-by: Pablo Correa Gómez <pabloyoyoista@postmarketos.org>
Part-of: <https://gitlab.postmarketos.org/postmarketOS/pmaports/-/merge_requests/9363>
This commit is contained in:
Pablo Correa Gómez
2026-08-12 05:39:47 +00:00
parent 6c7b46ef97
commit d035338047
19 changed files with 374 additions and 234 deletions
+12 -6
View File
@@ -21,7 +21,7 @@ custom_valid_options = [
] ]
def get_kconfigcheck_categories() -> list [str]: def get_kconfigcheck_categories() -> list[str]:
with open("kconfigcheck.toml", "rb") as kconfigcheck_config: with open("kconfigcheck.toml", "rb") as kconfigcheck_config:
kconfigcheck_data = tomllib.load(kconfigcheck_config) kconfigcheck_data = tomllib.load(kconfigcheck_config)
@@ -34,27 +34,33 @@ def get_kconfigcheck_categories() -> list [str]:
else: else:
kconfigcheck_categories.append(category_name) kconfigcheck_categories.append(category_name)
return [item.replace("category:", "pmb:kconfigcheck-") for item in kconfigcheck_categories] return [
item.replace("category:", "pmb:kconfigcheck-")
for item in kconfigcheck_categories
]
if __name__ == "__main__": if __name__ == "__main__":
if common.commit_message_has_string("[ci:skip-apkbuild-lint]"): if common.commit_message_has_string("[ci:skip-apkbuild-lint]"):
print("WARNING: not linting deviceinfo files ([ci:skip-apkbuild-lint])") print("WARNING: not linting deviceinfo files ([ci:skip-apkbuild-lint])")
exit(0) sys.exit(0)
kconfigcheck_categories = get_kconfigcheck_categories() kconfigcheck_categories = get_kconfigcheck_categories()
custom_valid_options += kconfigcheck_categories custom_valid_options += kconfigcheck_categories
os.environ["CUSTOM_VALID_OPTIONS"] = " ".join(custom_valid_options) os.environ["CUSTOM_VALID_OPTIONS"] = " ".join(custom_valid_options)
apkbuilds = {file for file in common.get_changed_files() apkbuilds = {
if os.path.basename(file) == "APKBUILD"} file
for file in common.get_changed_files()
if os.path.basename(file) == "APKBUILD"
}
if len(apkbuilds) < 1: if len(apkbuilds) < 1:
print("No APKBUILDs to lint") print("No APKBUILDs to lint")
sys.exit(0) sys.exit(0)
apkbuilds_filtered = [] apkbuilds_filtered = []
for apkbuild in apkbuilds: for apkbuild in apkbuilds:
if apkbuild.startswith("temp/") or apkbuild.startswith("cross/"): if apkbuild.startswith(("temp/", "cross/")):
print(f"NOTE: Skipping linting of {apkbuild}") print(f"NOTE: Skipping linting of {apkbuild}")
continue continue
apkbuilds_filtered.append(apkbuild) apkbuilds_filtered.append(apkbuild)
+24 -9
View File
@@ -21,11 +21,20 @@ def build_strict(packages, arch: Arch):
common.run_pmbootstrap(["build_init"]) common.run_pmbootstrap(["build_init"])
# We set the timeout to 1 hour because linking the Linux kernel with # We set the timeout to 1 hour because linking the Linux kernel with
# ThinLTO on our aarch64 runners takes slightly over 30 minutes # ThinLTO on our aarch64 runners takes slightly over 30 minutes
common.run_pmbootstrap(["--details-to-stdout", "--no-ccache", common.run_pmbootstrap(
"--timeout", "3600", [
"build", "--details-to-stdout",
"--strict", "--force", "--no-ccache",
"--arch", str(arch), ] + list(packages)) "--timeout",
"3600",
"build",
"--strict",
"--force",
"--arch",
str(arch),
]
+ list(packages)
)
if __name__ == "__main__": if __name__ == "__main__":
@@ -51,7 +60,7 @@ if __name__ == "__main__":
buildable_pkgs.add(os.path.basename(path)) buildable_pkgs.add(os.path.basename(path))
# To store a list of packages from extra-repos/systemd for special handling later: # To store a list of packages from extra-repos/systemd for special handling later:
systemd_pkgs = list() systemd_pkgs = []
# Filter out packages that either: # Filter out packages that either:
# 1. can't be built for given arch # 1. can't be built for given arch
@@ -92,10 +101,16 @@ if __name__ == "__main__":
# filter out packages that can't be built for arch # filter out packages that can't be built for arch
# (Iterate over copy of `systemd_pkgs`, because we modify it in this loop) # (Iterate over copy of `systemd_pkgs`, because we modify it in this loop)
for package in systemd_pkgs.copy(): for package in systemd_pkgs.copy():
apkbuild_path = pmb.helpers.pmaports.find(package, True, True, with_extra_repos="enabled") apkbuild_path = pmb.helpers.pmaports.find(
apkbuild = pmb.parse._apkbuild.apkbuild(pathlib.Path(apkbuild_path, "APKBUILD")) package, True, True, with_extra_repos="enabled"
)
apkbuild = pmb.parse._apkbuild.apkbuild(
pathlib.Path(apkbuild_path, "APKBUILD")
)
if arch not in Arch.from_arch_field(apkbuild["arch"]): if arch not in Arch.from_arch_field(apkbuild["arch"]):
print(f"(extra-repos/systemd) {package}: not enabled for {arch}, skipping") print(
f"(extra-repos/systemd) {package}: not enabled for {arch}, skipping"
)
systemd_pkgs.remove(package) systemd_pkgs.remove(package)
# No packages: skip build # No packages: skip build
+39 -27
View File
@@ -26,8 +26,7 @@ def get_package_contents(package, revision, check=True):
stderr = subprocess.DEVNULL stderr = subprocess.DEVNULL
# Run something like "git show upstream/main:main/hello-world/APKBUILD" # Run something like "git show upstream/main:main/hello-world/APKBUILD"
apkbuild_content = common.run_git(["show", revision + ":" + package], check, apkbuild_content = common.run_git(["show", revision + ":" + package], check, stderr)
stderr)
if not apkbuild_content: if not apkbuild_content:
return None return None
@@ -36,15 +35,14 @@ def get_package_contents(package, revision, check=True):
with tempfile.TemporaryDirectory() as tempdir: with tempfile.TemporaryDirectory() as tempdir:
with open(tempdir + "/APKBUILD", "w", encoding="utf-8") as handle: with open(tempdir + "/APKBUILD", "w", encoding="utf-8") as handle:
handle.write(apkbuild_content) handle.write(apkbuild_content)
parsed = pmb.parse.apkbuild(pathlib.Path(tempdir, "APKBUILD"), parsed = pmb.parse.apkbuild(pathlib.Path(tempdir, "APKBUILD"), False, False)
False, False)
return parsed return parsed
def get_package_version(package, revision, check=True): def get_package_version(package, revision, check=True):
""" returns version in the format "{pkgver}-r{pkgrel}", or None if no """returns version in the format "{pkgver}-r{pkgrel}", or None if no
matching package is found """ matching package is found"""
parsed = get_package_contents(package, revision, check) parsed = get_package_contents(package, revision, check)
if parsed is None: if parsed is None:
return None return None
@@ -52,7 +50,7 @@ def get_package_version(package, revision, check=True):
def version_compare_operator(result): def version_compare_operator(result):
""" :param result: return value from pmb.parse.version.compare() """ """:param result: return value from pmb.parse.version.compare()"""
if result == -1: if result == -1:
return "<" return "<"
elif result == 0: elif result == 0:
@@ -88,7 +86,7 @@ def exit_with_error_message():
print(" latest commit message, then force push.") print(" latest commit message, then force push.")
print() print()
print("Thank you and sorry for the inconvenience.") print("Thank you and sorry for the inconvenience.")
exit(1) sys.exit(1)
def check_versions(packages): def check_versions(packages):
@@ -101,14 +99,21 @@ def check_versions(packages):
# desired here, since we already know what packages changed, and really # desired here, since we already know what packages changed, and really
# want to check if the version was increased towards *current* upstream # want to check if the version was increased towards *current* upstream
# branch HEAD. # branch HEAD.
common.run_git(["remote", "add", "upstream", common.run_git(
"https://gitlab.postmarketos.org/postmarketOS/pmaports.git"], False) [
"remote",
"add",
"upstream",
"https://gitlab.postmarketos.org/postmarketOS/pmaports.git",
],
False,
)
common.run_git(["fetch", "-q", "upstream"]) common.run_git(["fetch", "-q", "upstream"])
commit = f"upstream/{common.get_upstream_branch()}" commit = f"upstream/{common.get_upstream_branch()}"
if common.run_git(["rev-parse", "HEAD"]) == common.run_git(["rev-parse", if common.run_git(["rev-parse", "HEAD"]) == common.run_git(["rev-parse", commit]):
commit]): print(
print(f"NOTE: {commit} is on same commit as HEAD, comparing" f"NOTE: {commit} is on same commit as HEAD, comparing HEAD against HEAD~1."
" HEAD against HEAD~1.") )
commit = "HEAD~1" commit = "HEAD~1"
# Exclude linux-next from pkgrel checks, as it is updated automatically. # Exclude linux-next from pkgrel checks, as it is updated automatically.
@@ -124,28 +129,35 @@ def check_versions(packages):
head = get_package_version(package, "HEAD") head = get_package_version(package, "HEAD")
upstream = get_package_version(package, commit, False) upstream = get_package_version(package, commit, False)
if not upstream: if not upstream:
if head.rpartition('r')[2] != "0": if head.rpartition("r")[2] != "0":
print(f"- {package}: {head} (HEAD) (new package) [ERROR]") print(f"- {package}: {head} (HEAD) (new package) [ERROR]")
error = True error = True
else: else:
print(f"- {package}: {head} (HEAD) (new package)") print(f"- {package}: {head} (HEAD) (new package)")
continue continue
is_device_pkg = os.path.basename(package).startswith('device-') is_device_pkg = os.path.basename(package).startswith("device-")
if is_device_pkg: if is_device_pkg:
# Check pkgver follows expected format for device packages # Check pkgver follows expected format for device packages
pkgver = head.rpartition('-r')[0] pkgver = head.rpartition("-r")[0]
if not pkgver.isdigit(): if not pkgver.isdigit():
print(f" - {package}: invalid pkgver \"{pkgver}\"" print(
"See: https://docs.postmarketos.org/pmaports/main/packaging-guidelines.html#package-versioning-pkgver-pkgrel") f' - {package}: invalid pkgver "{pkgver}"'
"See: https://docs.postmarketos.org/pmaports/main/packaging-guidelines.html#package-versioning-pkgver-pkgrel"
)
error = True error = True
# Check that pkgrel was reset to 0 when pkgver was changed # Check that pkgrel was reset to 0 when pkgver was changed
head_parsed = get_package_contents(package, "HEAD", False) head_parsed = get_package_contents(package, "HEAD", False)
upstream_parsed = get_package_contents(package, commit, False) upstream_parsed = get_package_contents(package, commit, False)
if head_parsed["pkgver"] != upstream_parsed["pkgver"] and head_parsed["pkgrel"] != "0": if (
print(f" - {package}: pkgrel should be 0 when pkgver changes." head_parsed["pkgver"] != upstream_parsed["pkgver"]
"See: https://docs.postmarketos.org/pmaports/main/packaging-guidelines.html#package-versioning-pkgver-pkgrel") and head_parsed["pkgrel"] != "0"
):
print(
f" - {package}: pkgrel should be 0 when pkgver changes."
"See: https://docs.postmarketos.org/pmaports/main/packaging-guidelines.html#package-versioning-pkgver-pkgrel"
)
error = True error = True
# Compare head and upstream versions # Compare head and upstream versions
@@ -169,15 +181,16 @@ if __name__ == "__main__":
packages = common.get_changed_packages() packages = common.get_changed_packages()
if len(packages) == 0: if len(packages) == 0:
print("no aports changed in this branch") print("no aports changed in this branch")
exit(0) sys.exit(0)
print(f"Changed packages: {packages}") print(f"Changed packages: {packages}")
# Potentially skip this check # Potentially skip this check
if common.commit_message_has_string("[ci:skip-vercheck]"): if common.commit_message_has_string("[ci:skip-vercheck]"):
print("WARNING: not checking for changed package versions" print(
" ([ci:skip-vercheck])!") "WARNING: not checking for changed package versions ([ci:skip-vercheck])!"
exit(0) )
sys.exit(0)
# Initialize args (so we can use pmbootstrap's APKBUILD parsing) # Initialize args (so we can use pmbootstrap's APKBUILD parsing)
sys.argv = ["pmbootstrap.py", "chroot"] sys.argv = ["pmbootstrap.py", "chroot"]
@@ -187,7 +200,6 @@ if __name__ == "__main__":
# pmb.helpers.logging.init(args) # pmb.helpers.logging.init(args)
pmb.helpers.logging.init(context.log, args.verbose, context.details_to_stdout) pmb.helpers.logging.init(context.log, args.verbose, context.details_to_stdout)
# Verify package versions # Verify package versions
print("checking changed package versions...") print("checking changed package versions...")
check_versions(packages) check_versions(packages)
+35 -23
View File
@@ -22,7 +22,7 @@ def get_devices() -> list[str]:
# devices that have a working mainline kernel. Those are usually # devices that have a working mainline kernel. Those are usually
# unmaintained and therefore might not appear in the wiki. However, # unmaintained and therefore might not appear in the wiki. However,
# the main device should be documented (remove the -downstream suffix). # the main device should be documented (remove the -downstream suffix).
device = device.removesuffix('-downstream') device = device.removesuffix("-downstream")
ret.append(device) ret.append(device)
return sorted(ret) return sorted(ret)
@@ -30,10 +30,10 @@ def get_devices() -> list[str]:
def get_wiki_devices_html(path: Path | None) -> dict[str, str]: def get_wiki_devices_html(path: Path | None) -> dict[str, str]:
""":param path: to a local file with the saved content of the devices wiki """:param path: to a local file with the saved content of the devices wiki
page or None to download a fresh copy page or None to download a fresh copy
:returns: HTML of the page, split into booting and not booting: :returns: HTML of the page, split into booting and not booting:
{"booting": "<!DOCTYPE HTML>\n<html..." {"booting": "<!DOCTYPE HTML>\n<html..."
"not_booting": "Not booting</span></h2>\n<p>These..."}""" "not_booting": "Not booting</span></h2>\n<p>These..."}"""
content = "" content = ""
if path: if path:
# Read file # Read file
@@ -46,7 +46,7 @@ def get_wiki_devices_html(path: Path | None) -> dict[str, str]:
content = f.read().decode("utf-8") content = f.read().decode("utf-8")
# Split into booting and not booting # Split into booting and not booting
split = content.split("<span class=\"mw-headline\" id=\"Non-booting_devices\">") split = content.split('<span class="mw-headline" id="Non-booting_devices">')
if len(split) != 2: if len(split) != 2:
print("*** Failed to parse wiki page") print("*** Failed to parse wiki page")
@@ -65,16 +65,18 @@ def get_wiki_renamed_devices_html() -> str:
def check_device(device: str, html: dict[str, str], is_booting: bool) -> bool: def check_device(device: str, html: dict[str, str], is_booting: bool) -> bool:
""":param is_booting: require the device to be in the booting section, not """:param is_booting: require the device to be in the booting section, not
just anywhere in the page (i.e. in the not booting just anywhere in the page (i.e. in the not booting
table). table).
:returns: True when the device is in the appropriate section.""" :returns: True when the device is in the appropriate section."""
if device in html["booting"]: if device in html["booting"]:
return True return True
if device in html["not_booting"]: if device in html["not_booting"]:
if is_booting: if is_booting:
print(device + ": still in 'not booting' section (if this is a" print(
" merge request, your device should be in the booting" device + ": still in 'not booting' section (if this is a"
" section already)") " merge request, your device should be in the booting"
" section already)"
)
return False return False
return True return True
if device in html["renamed"]: if device in html["renamed"]:
@@ -88,17 +90,27 @@ def check_device(device: str, html: dict[str, str], is_booting: bool) -> bool:
def main() -> int: def main() -> int:
# Parse arguments # Parse arguments
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument("--booting", help="devices must be in the upper table," parser.add_argument(
" being in the 'not booting' table below is not" "--booting",
" enough (all devices in pmaports main and stable" help="devices must be in the upper table,"
" branches and should be in the upper table)", " being in the 'not booting' table below is not"
action="store_true") " enough (all devices in pmaports main and stable"
parser.add_argument("--path", help="instead of downloading the devices" " branches and should be in the upper table)",
" page from the wiki, use a local HTML file", action="store_true",
type=Path, default=None) )
parser.add_argument("--all", help="check all devices (default: check only" parser.add_argument(
" devices changed from branch point)", "--path",
action="store_true") help="instead of downloading the devices"
" page from the wiki, use a local HTML file",
type=Path,
default=None,
)
parser.add_argument(
"--all",
help="check all devices (default: check only"
" devices changed from branch point)",
action="store_true",
)
args = parser.parse_args() args = parser.parse_args()
html = get_wiki_devices_html(args.path) html = get_wiki_devices_html(args.path)
+35 -21
View File
@@ -16,7 +16,7 @@ def get_pmaports_dir():
def run_git(parameters, check=True, stderr=None): def run_git(parameters, check=True, stderr=None):
""" Run git in the pmaports dir and return the output """ """Run git in the pmaports dir and return the output"""
cmd = ["git", "-C", get_pmaports_dir()] + parameters cmd = ["git", "-C", get_pmaports_dir()] + parameters
try: try:
return subprocess.check_output(cmd, stderr=stderr).decode() return subprocess.check_output(cmd, stderr=stderr).decode()
@@ -34,23 +34,25 @@ def commit_message_has_string(needle):
def all_committed_by_merge_bot(): def all_committed_by_merge_bot():
base_commit = get_base_commit() base_commit = get_base_commit()
commit_emails = run_git(["log", "--pretty=format:%ce", f"{base_commit}..HEAD"]).splitlines() commit_emails = run_git(
["log", "--pretty=format:%ce", f"{base_commit}..HEAD"]
).splitlines()
bot_email = os.getenv("PMOS_MERGE_BOT_EMAIL", "merge-bot@postmarketos.org") bot_email = os.getenv("PMOS_MERGE_BOT_EMAIL", "merge-bot@postmarketos.org")
return all(bot_email == ce for ce in commit_emails) return all(bot_email == ce for ce in commit_emails)
def run_pmbootstrap(parameters): def run_pmbootstrap(parameters):
""" Run pmbootstrap with the pmaports dir as --aports """ """Run pmbootstrap with the pmaports dir as --aports"""
cmd = ["pmbootstrap", "--aports", get_pmaports_dir()] + parameters cmd = ["pmbootstrap", "--aports", get_pmaports_dir()] + parameters
subprocess.run(cmd, text=True, check=True) subprocess.run(cmd, text=True, check=True)
@cache @cache
def get_upstream_branch(): def get_upstream_branch():
""" Use pmaports.cfg from current branch (e.g. "v20.05_fix-ci") and """Use pmaports.cfg from current branch (e.g. "v20.05_fix-ci") and
channels.cfg from main to retrieve the upstream branch. channels.cfg from main to retrieve the upstream branch.
:returns: branch name, e.g. "v20.05" """ :returns: branch name, e.g. "v20.05" """
# Prefer gitlab CI target branch name if it's set (i.e. running in gitlab CI) # Prefer gitlab CI target branch name if it's set (i.e. running in gitlab CI)
if target_branch := os.environ.get("CI_MERGE_REQUEST_TARGET_BRANCH_NAME"): if target_branch := os.environ.get("CI_MERGE_REQUEST_TARGET_BRANCH_NAME"):
@@ -68,10 +70,11 @@ def get_upstream_branch():
channels_cfg_str = run_git(["show", "upstream/main:channels.cfg"]) channels_cfg_str = run_git(["show", "upstream/main:channels.cfg"])
channels_cfg = configparser.ConfigParser() channels_cfg = configparser.ConfigParser()
channels_cfg.read_string(channels_cfg_str) channels_cfg.read_string(channels_cfg_str)
assert channel in channels_cfg, \ assert channel in channels_cfg, (
f"Channel '{channel}' from pmaports.cfg in your branch is unknown." \ f"Channel '{channel}' from pmaports.cfg in your branch is unknown."
" This appears to be an old branch, consider recreating your change" \ " This appears to be an old branch, consider recreating your change"
" on top of master." " on top of master."
)
return channels_cfg[channel]["branch_pmaports"] return channels_cfg[channel]["branch_pmaports"]
@@ -86,8 +89,15 @@ def get_base_commit() -> str:
return commit return commit
# Add a remote pointing to postmarketOS/pmaports # Add a remote pointing to postmarketOS/pmaports
run_git(["remote", "add", "upstream", run_git(
"https://gitlab.postmarketos.org/postmarketOS/pmaports.git"], False) [
"remote",
"add",
"upstream",
"https://gitlab.postmarketos.org/postmarketOS/pmaports.git",
],
False,
)
run_git(["fetch", "-q", "upstream"]) run_git(["fetch", "-q", "upstream"])
branch_upstream = f"upstream/{get_upstream_branch()}" branch_upstream = f"upstream/{get_upstream_branch()}"
@@ -109,10 +119,10 @@ def get_base_commit() -> str:
def get_changed_files(removed=False): def get_changed_files(removed=False):
""" Get all changed files and print them, as well as the branch and the """Get all changed files and print them, as well as the branch and the
commit that was used for the diff. commit that was used for the diff.
:param removed: also return removed files (default: True) :param removed: also return removed files (default: True)
:returns: set of changed files :returns: set of changed files
""" """
commit = get_base_commit() commit = get_base_commit()
@@ -131,7 +141,9 @@ def get_changed_files(removed=False):
return ret return ret
def get_changed_packages(skip_archived: bool = False, keep_dir: bool = False) -> set[str]: def get_changed_packages(
skip_archived: bool = False, keep_dir: bool = False
) -> set[str]:
ret = set() ret = set()
for file in get_changed_files(removed=True): for file in get_changed_files(removed=True):
dirname, filename = os.path.split(file) dirname, filename = os.path.split(file)
@@ -141,11 +153,12 @@ def get_changed_packages(skip_archived: bool = False, keep_dir: bool = False) ->
# * path with a dot (e.g. .ci/, device/.shared-patches/) # * path with a dot (e.g. .ci/, device/.shared-patches/)
# * documentation # * documentation
if ( if (
not dirname not dirname
or file.startswith(".") or file.startswith(".")
or "/." in file or "/." in file
or skip_archived and dirname.startswith("device/archived") or skip_archived
or dirname == "docs" and dirname.startswith("device/archived")
or dirname == "docs"
): ):
continue continue
@@ -185,6 +198,7 @@ def get_changed_kernels(skip_archived: bool = False):
ret += [pkgname] ret += [pkgname]
return ret return ret
def get_changed_devices(skip_archived: bool = False): def get_changed_devices(skip_archived: bool = False):
ret = [] ret = []
for pkgname in get_changed_packages(skip_archived): for pkgname in get_changed_packages(skip_archived):
+6 -3
View File
@@ -12,7 +12,7 @@ import common
if __name__ == "__main__": if __name__ == "__main__":
if common.commit_message_has_string("[ci:skip-dint]"): if common.commit_message_has_string("[ci:skip-dint]"):
print("WARNING: not linting deviceinfo files ([ci:skip-dint])") print("WARNING: not linting deviceinfo files ([ci:skip-dint])")
exit(0) sys.exit(0)
if "deviceinfo_schema.toml" in common.get_changed_files(): if "deviceinfo_schema.toml" in common.get_changed_files():
print("deviceinfo_schema.toml changed -> checking all deviceinfo files") print("deviceinfo_schema.toml changed -> checking all deviceinfo files")
@@ -20,8 +20,11 @@ if __name__ == "__main__":
deviceinfo_files = set(glob.glob(pmaports_dir + "/device/*/*/deviceinfo")) deviceinfo_files = set(glob.glob(pmaports_dir + "/device/*/*/deviceinfo"))
else: else:
# only lint deviceinfo files in the devices repo # only lint deviceinfo files in the devices repo
deviceinfo_files = {file for file in common.get_changed_files() deviceinfo_files = {
if os.path.basename(file) == "deviceinfo" and file.startswith("device/")} file
for file in common.get_changed_files()
if os.path.basename(file) == "deviceinfo" and file.startswith("device/")
}
try: try:
subprocess.run(["dint", "check", *deviceinfo_files], text=True, check=True) subprocess.run(["dint", "check", *deviceinfo_files], text=True, check=True)
+21 -13
View File
@@ -38,7 +38,7 @@ class Device:
fragment_path = self.full_path / "gitlab-ci.yml.j2" fragment_path = self.full_path / "gitlab-ci.yml.j2"
try: try:
fragment_tmpl = fragment_path.read_text() fragment_tmpl = fragment_path.read_text()
except Exception: except FileNotFoundError:
return None return None
return Template(fragment_tmpl).render(device=self) return Template(fragment_tmpl).render(device=self)
@@ -47,8 +47,10 @@ class Device:
def pmaports_path(self) -> Path: def pmaports_path(self) -> Path:
# Find the root of pmaports # Find the root of pmaports
pmaports_root = self.full_path.parent pmaports_root = self.full_path.parent
while (not (pmaports_root / "pmaports.cfg").exists() and while (
pmaports_root != pmaports_root.root): not (pmaports_root / "pmaports.cfg").exists()
and pmaports_root != pmaports_root.root
):
pmaports_root = pmaports_root.parent pmaports_root = pmaports_root.parent
assert pmaports_root != pmaports_root.root assert pmaports_root != pmaports_root.root
@@ -60,11 +62,11 @@ class Device:
@property @property
def pkgname(self) -> str: def pkgname(self) -> str:
return self.apkbuild['pkgname'] return self.apkbuild["pkgname"]
@property @property
def arch(self) -> Arch: def arch(self) -> Arch:
return Arch(self.apkbuild['arch'][0]) return Arch(self.apkbuild["arch"][0])
@property @property
def testing_dependencies(self) -> set[str]: def testing_dependencies(self) -> set[str]:
@@ -88,7 +90,7 @@ class Device:
kernels = [] kernels = []
subpackage_prefix = f"device-{self.codename}-kernel-" subpackage_prefix = f"device-{self.codename}-kernel-"
for subpkgname in self.apkbuild.get('subpackages', []): for subpkgname in self.apkbuild.get("subpackages", []):
if not subpkgname.startswith(subpackage_prefix): if not subpkgname.startswith(subpackage_prefix):
continue continue
kernel_name = subpkgname.removeprefix(subpackage_prefix) kernel_name = subpkgname.removeprefix(subpackage_prefix)
@@ -129,7 +131,7 @@ class Device:
continue continue
supported_devices[dev.pmaports_path] = dev supported_devices[dev.pmaports_path] = dev
except Exception: except FileNotFoundError:
traceback.print_exc() traceback.print_exc()
return supported_devices return supported_devices
@@ -138,17 +140,23 @@ class ArchTagSet(set):
def update(self, iterable): def update(self, iterable):
supported_arches = Arch.supported_binary() supported_arches = Arch.supported_binary()
# This ignores things like !armv7, that could be a follow-up optimization # This ignores things like !armv7, that could be a follow-up optimization
if 'noarch' in iterable or 'all' in iterable: if "noarch" in iterable or "all" in iterable:
iterable = [arch for arch in supported_arches] iterable = [arch for arch in supported_arches]
super().update([Arch(arch) for arch in iterable if Arch(arch) in supported_arches]) super().update(
[Arch(arch) for arch in iterable if Arch(arch) in supported_arches]
)
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter, formatter_class=argparse.ArgumentDefaultsHelpFormatter,
) )
parser.add_argument("--template", default=".ci/build-jobs.yaml.j2", help="Jinja2 input template") parser.add_argument(
parser.add_argument("--output", default=".ci/build-jobs.yaml", help="output pipeline") "--template", default=".ci/build-jobs.yaml.j2", help="Jinja2 input template"
)
parser.add_argument(
"--output", default=".ci/build-jobs.yaml", help="output pipeline"
)
args = parser.parse_args() args = parser.parse_args()
# pmb logging has to be initialized for later pmb commands to work, setting # pmb logging has to be initialized for later pmb commands to work, setting
@@ -179,13 +187,13 @@ if __name__ == "__main__":
if path.name != "APKBUILD": if path.name != "APKBUILD":
continue continue
apkbuild = pmb.parse.apkbuild(path) apkbuild = pmb.parse.apkbuild(path)
packages_modified.add(apkbuild['pkgname']) packages_modified.add(apkbuild["pkgname"])
archs.update(apkbuild["arch"]) archs.update(apkbuild["arch"])
# Add all the devices found in CI that depend on the package that got # Add all the devices found in CI that depend on the package that got
# modified # modified
for device in supported_devices.values(): for device in supported_devices.values():
if apkbuild['pkgname'] in device.dependencies: if apkbuild["pkgname"] in device.dependencies:
devices_under_test.add(device) devices_under_test.add(device)
if common.commit_message_has_string("[ci:skip-build]"): if common.commit_message_has_string("[ci:skip-build]"):
+14 -10
View File
@@ -3,6 +3,7 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
import subprocess import subprocess
import sys
# Same dir # Same dir
import common import common
@@ -12,10 +13,11 @@ def check_kconfig(pkgnames):
last_failed = None last_failed = None
for i in range(len(pkgnames)): for i in range(len(pkgnames)):
pkgname = pkgnames[i] pkgname = pkgnames[i]
print(f" ({i+1}/{len(pkgnames)}) {pkgname}") print(f" ({i + 1}/{len(pkgnames)}) {pkgname}")
p = subprocess.run(["pmbootstrap", "kconfig", "check", "--keep-going", pkgname], p = subprocess.run(
check=False) ["pmbootstrap", "kconfig", "check", "--keep-going", pkgname], check=False
)
if p.returncode: if p.returncode:
last_failed = pkgname last_failed = pkgname
@@ -32,8 +34,10 @@ def show_error(last_failed):
print() print()
print("---") print("---")
print() print()
print("Please adjust your kernel config. This is required for getting your" print(
" patch merged.") "Please adjust your kernel config. This is required for getting your"
" patch merged."
)
print() print()
print("Edit your kernel config:") print("Edit your kernel config:")
print(f" pmbootstrap kconfig edit {last_failed}") print(f" pmbootstrap kconfig edit {last_failed}")
@@ -76,21 +80,21 @@ if __name__ == "__main__":
print("kconfigcheck.toml changed -> checking all kernels") print("kconfigcheck.toml changed -> checking all kernels")
if not check_kconfig_all(): if not check_kconfig_all():
show_error_all() show_error_all()
exit(1) sys.exit(1)
exit(0) sys.exit(0)
pkgnames = common.get_changed_kernels(skip_archived=True) pkgnames = common.get_changed_kernels(skip_archived=True)
print(f"Changed kernels: {pkgnames}") print(f"Changed kernels: {pkgnames}")
if len(pkgnames) == 0: if len(pkgnames) == 0:
print("No kernels changed in this branch") print("No kernels changed in this branch")
exit(0) sys.exit(0)
elif common.commit_message_has_string("[ci:skip-kconfigcheck]"): elif common.commit_message_has_string("[ci:skip-kconfigcheck]"):
print("WARNING: not checking kernel configs ([ci:skip-kconfigcheck])") print("WARNING: not checking kernel configs ([ci:skip-kconfigcheck])")
exit(0) sys.exit(0)
last_failed = check_kconfig(pkgnames) last_failed = check_kconfig(pkgnames)
if last_failed: if last_failed:
show_error(last_failed) show_error(last_failed)
exit(1) sys.exit(1)
+6 -5
View File
@@ -19,8 +19,9 @@ def verify_checksums(packages):
print("verifying checksums: " + ", ".join(packages)) print("verifying checksums: " + ", ".join(packages))
common.run_pmbootstrap(["build_init"]) common.run_pmbootstrap(["build_init"])
common.run_pmbootstrap(["--details-to-stdout", "checksum", "--verify"] + common.run_pmbootstrap(
list(packages)) ["--details-to-stdout", "checksum", "--verify"] + list(packages)
)
if __name__ == "__main__": if __name__ == "__main__":
@@ -39,14 +40,14 @@ if __name__ == "__main__":
archived = set() archived = set()
for path in pmb.core.pkgrepo.pkgrepo_iter_package_dirs(): for path in pmb.core.pkgrepo.pkgrepo_iter_package_dirs():
# Store archived packages for matching later # Store archived packages for matching later
if os.path.split(os.path.split(path)[0])[1] == 'archived': if os.path.split(os.path.split(path)[0])[1] == "archived":
archived.add(os.path.basename(path)) archived.add(os.path.basename(path))
continue continue
buildable_pkgs.add(os.path.basename(path)) buildable_pkgs.add(os.path.basename(path))
# To store a list of packages from extra-repos/systemd for special handling # To store a list of packages from extra-repos/systemd for special handling
# later: # later:
systemd_pkgs = list() systemd_pkgs = []
# Filter out packages are not found in enabled repos or are in archived # Filter out packages are not found in enabled repos or are in archived
# (Iterate over copy of packages, because we modify it in this loop) # (Iterate over copy of packages, because we modify it in this loop)
@@ -73,7 +74,7 @@ if __name__ == "__main__":
if len(packages) == 0: if len(packages) == 0:
print("no packages to check for the current repo") print("no packages to check for the current repo")
else: else:
verify_checksums(packages) verify_checksums(packages)
# FIXME: this should probably be more generic, if other repos are added later? # FIXME: this should probably be more generic, if other repos are added later?
if systemd_pkgs: if systemd_pkgs:
+1 -1
View File
@@ -11,4 +11,4 @@ fi
set -x set -x
# shellcheck disable=SC2046 # shellcheck disable=SC2046
ruff check $(find .ci -name '*.py') ruff check --ignore LOG015 $(find .ci -name '*.py')
+31 -21
View File
@@ -15,13 +15,15 @@ gitlab_groups = [
def device_dependency_check(apkbuild, path): def device_dependency_check(apkbuild, path):
""" Raise an error if a device package has a dependency that is not allowed """Raise an error if a device package has a dependency that is not allowed
(e.g. because it should be in a subpackage instead). """ (e.g. because it should be in a subpackage instead)."""
for depend in apkbuild["depends"]: for depend in apkbuild["depends"]:
if depend == "mesa-dri-gallium": if depend == "mesa-dri-gallium":
raise RuntimeError(f"{path}: mesa-dri-gallium shouldn't be in" raise RuntimeError(
" depends anymore (see pmaports!3478)") f"{path}: mesa-dri-gallium shouldn't be in"
" depends anymore (see pmaports!3478)"
)
def test_aports_device(): def test_aports_device():
@@ -44,11 +46,12 @@ def test_aports_device():
device_dependency_check(apkbuild, path) device_dependency_check(apkbuild, path)
# Architecture # Architecture
device = apkbuild["pkgname"][len("device-"):] device = apkbuild["pkgname"][len("device-") :]
deviceinfo = pmb.parse.deviceinfo(device) deviceinfo = pmb.parse.deviceinfo(device)
if Arch.from_str("".join(apkbuild["arch"])) != deviceinfo.arch: if Arch.from_str("".join(apkbuild["arch"])) != deviceinfo.arch:
raise RuntimeError("wrong architecture, please change to arch=\"" raise RuntimeError(
f"{deviceinfo.arch}\": {path}") f'wrong architecture, please change to arch="{deviceinfo.arch}": {path}'
)
if "!archcheck" not in apkbuild["options"]: if "!archcheck" not in apkbuild["options"]:
raise RuntimeError(f"!archcheck missing in options= line: {path}") raise RuntimeError(f"!archcheck missing in options= line: {path}")
@@ -64,7 +67,7 @@ def test_aports_device_kernel():
for path in aports.glob("device/*/device-*/APKBUILD"): for path in aports.glob("device/*/device-*/APKBUILD"):
# Parse apkbuild and kernels from subpackages # Parse apkbuild and kernels from subpackages
apkbuild = pmb.parse.apkbuild(path) apkbuild = pmb.parse.apkbuild(path)
device = apkbuild["pkgname"][len("device-"):] device = apkbuild["pkgname"][len("device-") :]
kernels_subpackages = pmb.parse._apkbuild.kernels(device) kernels_subpackages = pmb.parse._apkbuild.kernels(device)
# Parse kernels from depends # Parse kernels from depends
@@ -76,20 +79,24 @@ def test_aports_device_kernel():
# Kernel in subpackages *and* depends # Kernel in subpackages *and* depends
if kernels_subpackages: if kernels_subpackages:
raise RuntimeError(f"Kernel package '{depend}' needs to" raise RuntimeError(
" be removed when using kernel" + f"Kernel package '{depend}' needs to"
f" subpackages: {path}") " be removed when using kernel" + f" subpackages: {path}"
)
# No kernel # No kernel
if not kernels_depends and not kernels_subpackages: if not kernels_depends and not kernels_subpackages:
raise RuntimeError("Device doesn't have a kernel in depends or" raise RuntimeError(
f" subpackages: {path}") f"Device doesn't have a kernel in depends or subpackages: {path}"
)
# Multiple kernels in depends # Multiple kernels in depends
if len(kernels_depends) > 1: if len(kernels_depends) > 1:
raise RuntimeError("Please use kernel subpackages instead of" raise RuntimeError(
" multiple kernels in depends (see" "Please use kernel subpackages instead of"
f" <https://postmarketos.org/devicepkg>): {path}") " multiple kernels in depends (see"
f" <https://postmarketos.org/devicepkg>): {path}"
)
# @pytest.mark.xfail # Not all aports have been updated yet # @pytest.mark.xfail # Not all aports have been updated yet
@@ -100,14 +107,15 @@ def test_aports_maintained():
""" """
for path in pkgrepo_iglob("device/main/*/APKBUILD"): for path in pkgrepo_iglob("device/main/*/APKBUILD"):
if 'firmware-' in path.parent.name: if "firmware-" in path.parent.name:
continue continue
maintainers = pmb.parse._apkbuild.maintainers(path) maintainers = pmb.parse._apkbuild.maintainers(path)
assert maintainers and len(maintainers) >= 2, \ assert maintainers and len(maintainers) >= 2, (
f"{path} in main needs at least 1 Maintainer and 1 Co-Maintainer" f"{path} in main needs at least 1 Maintainer and 1 Co-Maintainer"
)
for path in pkgrepo_iglob("device/community/*/APKBUILD"): for path in pkgrepo_iglob("device/community/*/APKBUILD"):
if 'firmware-' in path.parent.name: if "firmware-" in path.parent.name:
continue continue
maintainers = pmb.parse._apkbuild.maintainers(path) maintainers = pmb.parse._apkbuild.maintainers(path)
assert maintainers, f"{path} in community needs at least 1 Maintainer" assert maintainers, f"{path} in community needs at least 1 Maintainer"
@@ -121,5 +129,7 @@ def test_aports_archived():
for path in pkgrepo_iglob("device/archived/*/APKBUILD"): for path in pkgrepo_iglob("device/archived/*/APKBUILD"):
archived = pmb.parse._apkbuild.archived(path) archived = pmb.parse._apkbuild.archived(path)
assert archived, f"{path} should have an Archived: " +\ assert archived, (
"comment that describes why the package is archived" f"{path} should have an Archived: "
+ "comment that describes why the package is archived"
)
+19 -15
View File
@@ -14,14 +14,13 @@ def test_deviceinfo():
# Iterate over all devices # Iterate over all devices
last_exception = None last_exception = None
count = 0 count = 0
pattern = re.compile("^deviceinfo_[a-zA-Z0-9_]*=\".*\"(\\s*# .*)?$") pattern = re.compile('^deviceinfo_[a-zA-Z0-9_]*=".*"(\\s*# .*)?$')
for folder in pkgrepo_iglob("device/*/device-*"): for folder in pkgrepo_iglob("device/*/device-*"):
device = folder.name.split("-", 1)[1] device = folder.name.split("-", 1)[1]
f = open(folder / "deviceinfo") with open(folder / "deviceinfo") as f:
lines = f.read().split("\n") lines = f.read().split("\n")
f.close()
try: try:
for line in lines: for line in lines:
@@ -30,10 +29,12 @@ def test_deviceinfo():
continue continue
# Check line against regex (can't use multiple lines etc.) # Check line against regex (can't use multiple lines etc.)
if not pattern.match(line) or line.endswith("\\\""): if not pattern.match(line) or line.endswith('\\"'):
raise RuntimeError("Line looks invalid, maybe missing" raise RuntimeError(
" quotes/multi-line string/malformed" "Line looks invalid, maybe missing"
f" inline comment? {line}") " quotes/multi-line string/malformed"
f" inline comment? {line}"
)
# Successful deviceinfo parsing / obsolete options # Successful deviceinfo parsing / obsolete options
info = pmb.parse.deviceinfo(device) info = pmb.parse.deviceinfo(device)
@@ -41,15 +42,18 @@ def test_deviceinfo():
# deviceinfo_name must start with manufacturer # deviceinfo_name must start with manufacturer
name = info.name name = info.name
manufacturer = info.manufacturer manufacturer = info.manufacturer
if not name.startswith(manufacturer) and \ if (
not name.startswith("Google") and \ not name.startswith(manufacturer)
not name.startswith("Jolla"): and not name.startswith("Google")
raise RuntimeError("Please add the manufacturer in front of" and not name.startswith("Jolla")
" the deviceinfo_name, e.g.: '" + ):
manufacturer + " " + name + "'") raise RuntimeError(
"Please add the manufacturer in front of"
" the deviceinfo_name, e.g.: '" + manufacturer + " " + name + "'"
)
# Don't abort on first error # Don't abort on first error
except Exception as e: except (RuntimeError, SyntaxError, ValueError) as e:
last_exception = e last_exception = e
count += 1 count += 1
print(device + ": " + str(e)) print(device + ": " + str(e))
+20 -14
View File
@@ -23,9 +23,11 @@ expected_directories = [
# This test makes sure all of them are in one of the expected locations. # This test makes sure all of them are in one of the expected locations.
def test_directories(): def test_directories():
apkbuilds = set(glob.iglob("**/APKBUILD", recursive=True)) apkbuilds = set(glob.iglob("**/APKBUILD", recursive=True))
expected = set(f for d in expected_directories for f in glob.iglob(d + "/*/APKBUILD")) expected = {f for d in expected_directories for f in glob.iglob(d + "/*/APKBUILD")}
assert apkbuilds == expected, "Found APKBUILD in unexpected directory. " \ assert apkbuilds == expected, (
"Found APKBUILD in unexpected directory. "
"Note that we moved firmware/* to device/{main,community,testing}/*." "Note that we moved firmware/* to device/{main,community,testing}/*."
)
# Ensure no file in pmaports are executable. # Ensure no file in pmaports are executable.
@@ -38,11 +40,13 @@ def test_executable_files():
permissions = os.stat(file).st_mode permissions = os.stat(file).st_mode
executable_bits = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH executable_bits = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
if permissions & executable_bits != 0: if permissions & executable_bits != 0:
raise RuntimeError(f"\"{file}\" is executable. Files in pmaports" + raise RuntimeError(
" should not be executables. post-* files" + f'"{file}" is executable. Files in pmaports'
" don't need to be executable and executables" + + " should not be executables. post-* files"
" should be installed using `install -D" + + " don't need to be executable and executables"
"m0755` or a variation thereof.") + " should be installed using `install -D"
+ "m0755` or a variation thereof."
)
# Make sure files belong to a package (below a directory with APKBUILD) # Make sure files belong to a package (below a directory with APKBUILD)
@@ -54,24 +58,26 @@ def test_files_belong_to_package():
# Skip "hidden" directories (.ci/, device/.shared-patches/) # Skip "hidden" directories (.ci/, device/.shared-patches/)
dirs[:] = [d for d in dirs if not d.startswith(".")] dirs[:] = [d for d in dirs if not d.startswith(".")]
# Ignore files in root directory (README.md) # Ignore files in root directory (README.md)
if dirpath == '.': if dirpath == ".":
continue continue
# Ignore files under docs/ # Ignore files under docs/
if dirpath.startswith('./docs'): if dirpath.startswith("./docs"):
continue continue
# Switched to another directory? # Switched to another directory?
if package_dir and not dirpath.startswith(package_dir + os.sep): if package_dir and not dirpath.startswith(package_dir + os.sep):
package_dir = None package_dir = None
if 'APKBUILD' in files: if "APKBUILD" in files:
assert not package_dir, f"Nested packages: {package_dir} and {dirpath} " \ assert not package_dir, (
"both contain an APKBUILD" f"Nested packages: {package_dir} and {dirpath} both contain an APKBUILD"
)
package_dir = dirpath package_dir = dirpath
# Skip specific ".gitlab-ci.yml" files outside of usual structure # Skip specific ".gitlab-ci.yml" files outside of usual structure
if dirpath in ["./cross"]: if dirpath in ["./cross"]:
files[:] = [f for f in files if f != ".gitlab-ci.yml"] files[:] = [f for f in files if f != ".gitlab-ci.yml"]
assert not files or package_dir, "Found files that do not belong to any package: " \ assert not files or package_dir, (
f"{dirpath}/{files}" f"Found files that do not belong to any package: {dirpath}/{files}"
)
+20 -15
View File
@@ -22,28 +22,33 @@ def test_aports_firmware():
"firmware-samsung-maguro", # Depends on firmware-aosp-broadcom-wlan "firmware-samsung-maguro", # Depends on firmware-aosp-broadcom-wlan
"firmware-xiaomi-ferrari", # Depends on soc-qcom-msm8916 "firmware-xiaomi-ferrari", # Depends on soc-qcom-msm8916
"firmware-xiaomi-willow", # Doesn't build, source link is dead (pma#1212) "firmware-xiaomi-willow", # Doesn't build, source link is dead (pma#1212)
"firmware-samsung-i9105p", # Depends on firmware-aosp-broadcom-wlan "firmware-samsung-i9105p", # Depends on firmware-aosp-broadcom-wlan
] ]
for path in pkgrepo_iglob("**/firmware-*/APKBUILD", recursive=True): for path in pkgrepo_iglob("**/firmware-*/APKBUILD", recursive=True):
apkbuild = pmb.parse.apkbuild(path) apkbuild = pmb.parse.apkbuild(path)
aport_name = os.path.basename(path.parent) aport_name = os.path.basename(path.parent)
if aport_name not in excluded: if aport_name not in excluded and "pmb:cross-native" not in apkbuild["options"]:
if "pmb:cross-native" not in apkbuild["options"]: raise RuntimeError(
raise RuntimeError(f"{aport_name}: \"pmb:cross-native\" missing in" f'{aport_name}: "pmb:cross-native" missing in'
" options= line. The pmb:cross-native option is" " options= line. The pmb:cross-native option is"
" preferred because it results in significantly" " preferred because it results in significantly"
" lower build times. If the package doesn't build" " lower build times. If the package doesn't build"
" with the option, you can add an exemption in" " with the option, you can add an exemption in"
" .gitlab-ci/testcases/test_firmware.py.") " .gitlab-ci/testcases/test_firmware.py."
)
if "!tracedeps" not in apkbuild["options"]: if "!tracedeps" not in apkbuild["options"]:
raise RuntimeError(f"{aport_name}: \"!tracedeps\" missing in" raise RuntimeError(
" options= line. The tracedeps option is superfluous" f'{aport_name}: "!tracedeps" missing in'
" for firmware packages.") " options= line. The tracedeps option is superfluous"
" for firmware packages."
)
if "noarch" in apkbuild["arch"]: if "noarch" in apkbuild["arch"]:
raise RuntimeError(f"{aport_name}: \"arch\" must not be \"noarch\"!" raise RuntimeError(
" Please limit this firmware package to the" f'{aport_name}: "arch" must not be "noarch"!'
" required architectures only!") " Please limit this firmware package to the"
" required architectures only!"
)
+8 -10
View File
@@ -1,9 +1,9 @@
# Copyright 2021 Oliver Smith # Copyright 2021 Oliver Smith
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
""" Make sure that components of frameworks (Qt, KDE, ...) have the same """Make sure that components of frameworks (Qt, KDE, ...) have the same
version in all packages. We scan all packages, categorize them by URL version in all packages. We scan all packages, categorize them by URL
and then compare the versions of all packages in each category. """ and then compare the versions of all packages in each category."""
import logging import logging
@@ -41,8 +41,7 @@ def get_categorized_packages():
category = "plasma" category = "plasma"
elif "https://community.kde.org/Frameworks" in url: elif "https://community.kde.org/Frameworks" in url:
category = "kde" category = "kde"
elif url in ["http://qt-project.org/", elif url in ["http://qt-project.org/", "https://www.qt.io/developers/"]:
"https://www.qt.io/developers/"]:
category = "qt" category = "qt"
# Remove hotfix number (i.e. 5.16.90.1 becomes 5.16.90) # Remove hotfix number (i.e. 5.16.90.1 becomes 5.16.90)
@@ -69,7 +68,6 @@ def check_categories(categories):
for category, packages in categories.items(): for category, packages in categories.items():
reference = None reference = None
for pkgname, pkgver in packages.items(): for pkgname, pkgver in packages.items():
# Use the first package as reference and print a summary # Use the first package as reference and print a summary
if not reference: if not reference:
logging.info("---") logging.info("---")
@@ -87,8 +85,9 @@ def check_categories(categories):
# Print the reference and skip checking it against itself # Print the reference and skip checking it against itself
reference = {"pkgname": pkgname, "pkgver": pkgver} reference = {"pkgname": pkgname, "pkgver": pkgver}
logging.info("Reference pkgver: " + pkgver + " (from '" + logging.info(
pkgname + "')") "Reference pkgver: " + pkgver + " (from '" + pkgname + "')"
)
continue continue
# Check version against reference # Check version against reference
@@ -98,8 +97,7 @@ def check_categories(categories):
# Each category must at least have one package # Each category must at least have one package
if not reference: if not reference:
logging.info("ERROR: could not find any packages in category: " + logging.info("ERROR: could not find any packages in category: " + category)
category)
ret = False ret = False
return ret return ret
+36 -17
View File
@@ -21,29 +21,48 @@ def test_aports_kernel():
continue # This package isn't a linux kernel! continue # This package isn't a linux kernel!
if "pmb:cross-native" not in apkbuild["options"]: if "pmb:cross-native" not in apkbuild["options"]:
raise RuntimeError(f"{aport_name}: \"pmb:cross-native\" missing in" raise RuntimeError(
" options= line") f'{aport_name}: "pmb:cross-native" missing in options= line'
)
# cross-compilers should not be in makedepends # cross-compilers should not be in makedepends
for ccc in ["gcc-armv7", "gcc-armhf", "gcc-aarch64", for ccc in [
"gcc4-armv7", "gcc4-armhf", "gcc4-aarch64", "gcc-armv7",
"gcc6-armv7", "gcc6-armhf", "gcc6-aarch64"]: "gcc-armhf",
"gcc-aarch64",
"gcc4-armv7",
"gcc4-armhf",
"gcc4-aarch64",
"gcc6-armv7",
"gcc6-armhf",
"gcc6-aarch64",
]:
if ccc in apkbuild["makedepends"]: if ccc in apkbuild["makedepends"]:
raise RuntimeError(f"{aport_name}: Cross-compiler ({ccc}) should" raise RuntimeError(
" not be explicitly specified in makedepends!" f"{aport_name}: Cross-compiler ({ccc}) should"
" pmbootstrap installs cross-compiler" " not be explicitly specified in makedepends!"
" automatically.") " pmbootstrap installs cross-compiler"
" automatically."
)
# check some options only for main and community devices # check some options only for main and community devices
_, relpath = pkgrepo_relative_path(path) _, relpath = pkgrepo_relative_path(path)
for part in ["main", "community"]: for part in ["main", "community"]:
if part in relpath.parts: if (
if "pmb:kconfigcheck-community" not in apkbuild["options"]: part in relpath.parts
raise RuntimeError(f"{aport_name}: \"pmb:kconfigcheck-community\" missing in" and "pmb:kconfigcheck-community" not in apkbuild["options"]
" options= line, required for all community/main devices.") ):
raise RuntimeError(
f'{aport_name}: "pmb:kconfigcheck-community" missing in'
" options= line, required for all community/main devices."
)
# check for postmarketos-installkernel in makedepends when installing kernel with make # check for postmarketos-installkernel in makedepends when installing kernel with make
if bool(re.search("make z?install", path.read_text(encoding="utf-8"))): if (
if "postmarketos-installkernel" not in apkbuild["makedepends"]: bool(re.search("make z?install", path.read_text(encoding="utf-8")))
raise RuntimeError(f"{aport_name}: \"postmarketos-installkernel\" missing in" and "postmarketos-installkernel" not in apkbuild["makedepends"]
" makedepends, required when using make install/zinstall.") ):
raise RuntimeError(
f'{aport_name}: "postmarketos-installkernel" missing in'
" makedepends, required when using make install/zinstall."
)
+9 -4
View File
@@ -44,7 +44,9 @@ def apkbuild_check_provides(path, apkbuild, version, pkgname, subpkgname=None):
if not provide.endswith(f"={version}"): if not provide.endswith(f"={version}"):
# Valid version strings, per the APKBUILD reference, are fine. This regex # Valid version strings, per the APKBUILD reference, are fine. This regex
# attempts to detect those. # attempts to detect those.
pattern = r'^\d+(\.\d+)*[a-z]?(_(?:alpha|beta|pre|rc|cvs|svn|git|hg|p)\d*)*-r\d+$' pattern = (
r"^\d+(\.\d+)*[a-z]?(_(?:alpha|beta|pre|rc|cvs|svn|git|hg|p)\d*)*-r\d+$"
)
[provide_no_ver, provide_ver] = provide.split("=", 1) [provide_no_ver, provide_ver] = provide.split("=", 1)
if not re.match(pattern, provide_ver): if not re.match(pattern, provide_ver):
error = f"error in , provide_ver{path}:\n" error = f"error in , provide_ver{path}:\n"
@@ -62,7 +64,9 @@ def apkbuild_check_provides(path, apkbuild, version, pkgname, subpkgname=None):
error += " version on purpose, you also need to set a" error += " version on purpose, you also need to set a"
error += " provider_priority (pma#1766).\n" error += " provider_priority (pma#1766).\n"
error += "Reference:" error += "Reference:"
error += " https://wiki.alpinelinux.org/wiki/APKBUILD_Reference#provides" error += (
" https://wiki.alpinelinux.org/wiki/APKBUILD_Reference#provides"
)
error += f"\nVERSION: {provide_no_ver}" error += f"\nVERSION: {provide_no_ver}"
ret += [error] ret += [error]
return ret return ret
@@ -82,8 +86,9 @@ def test_provides():
if not subpkg_data: if not subpkg_data:
# default packaging function like -doc # default packaging function like -doc
continue continue
errors += apkbuild_check_provides(path_rel, subpkg_data, version, errors += apkbuild_check_provides(
pkgname, subpkg) path_rel, subpkg_data, version, pkgname, subpkg
)
if errors: if errors:
for error in errors: for error in errors:
+30 -16
View File
@@ -45,9 +45,11 @@ def parse_source_from_checksums(apkbuild_path):
try: try:
checksum, filename = line.rstrip().split(" ", 2) checksum, filename = line.rstrip().split(" ", 2)
except ValueError: except ValueError:
raise ValueError("Failed to parse checksums. Try to delete the" raise ValueError(
" checksums and generate them again with" "Failed to parse checksums. Try to delete the"
f" 'pmbootstrap checksum': {apkbuild_path}") " checksums and generate them again with"
f" 'pmbootstrap checksum': {apkbuild_path}"
)
# Cut off 'sha512sums="' if the first checksum is in that line # Cut off 'sha512sums="' if the first checksum is in that line
checksum = checksum.removeprefix(start) checksum = checksum.removeprefix(start)
@@ -96,15 +98,21 @@ def test_aports_unreferenced_files():
if rel_file_path in ["APKBUILD", "gitlab-ci.yml.j2"] or os.path.isdir(file): if rel_file_path in ["APKBUILD", "gitlab-ci.yml.j2"] or os.path.isdir(file):
continue continue
# Skip kernel fragments in linux-* packages # Skip kernel fragments in linux-* packages
if os.path.basename(rel_file_path).endswith(".config") and apkbuild["pkgname"].startswith("linux-"): if os.path.basename(rel_file_path).endswith(".config") and apkbuild[
"pkgname"
].startswith("linux-"):
continue continue
if os.path.basename(rel_file_path) not in sources_chk \ if (
and rel_file_path not in apkbuild["install"] \ os.path.basename(rel_file_path) not in sources_chk
and rel_file_path not in subpackage_installs \ and rel_file_path not in apkbuild["install"]
and rel_file_path not in trigger_sources \ and rel_file_path not in subpackage_installs
and not rel_file_path.startswith("tests/"): and rel_file_path not in trigger_sources
raise RuntimeError(f"{apkbuild_path}: found unreferenced file: {rel_file_path}") and not rel_file_path.startswith("tests/")
):
raise RuntimeError(
f"{apkbuild_path}: found unreferenced file: {rel_file_path}"
)
def test_distfiles_conflict(): def test_distfiles_conflict():
@@ -131,8 +139,10 @@ def test_distfiles_conflict():
# First time seeing this file # First time seeing this file
if filename not in source_all: if filename not in source_all:
source_all[filename] = {"checksum": checksum, source_all[filename] = {
"apkbuild_rel": apkbuild_rel} "checksum": checksum,
"apkbuild_rel": apkbuild_rel,
}
continue continue
# Saw this file already with same checksum # Saw this file already with same checksum
@@ -141,15 +151,19 @@ def test_distfiles_conflict():
# Saw this file already with different checksum # Saw this file already with different checksum
logging.error("") logging.error("")
logging.error(f"ERROR: the source file '{filename}' has different" logging.error(
" checksums in the following files:") f"ERROR: the source file '{filename}' has different"
" checksums in the following files:"
)
logging.error(f"- {source_all[filename]['apkbuild_rel']}:") logging.error(f"- {source_all[filename]['apkbuild_rel']}:")
logging.error(f" {source_all[filename]['checksum']}") logging.error(f" {source_all[filename]['checksum']}")
logging.error(f"- {apkbuild_rel}:") logging.error(f"- {apkbuild_rel}:")
logging.error(f" {checksum}") logging.error(f" {checksum}")
logging.error("") logging.error("")
logging.error("Fix this by setting a different target filename in" logging.error(
" the package you modified:") "Fix this by setting a different target filename in"
" the package you modified:"
)
logging.error("https://wiki.alpinelinux.org/wiki/APKBUILD_Reference#source") logging.error("https://wiki.alpinelinux.org/wiki/APKBUILD_Reference#source")
logging.error("") logging.error("")
raise RuntimeError(f"Conflict with source file '{filename}'") raise RuntimeError(f"Conflict with source file '{filename}'")
+8 -4
View File
@@ -31,8 +31,10 @@ def test_aports_ui():
for package in apkbuild["_pmb_recommends"]: for package in apkbuild["_pmb_recommends"]:
depend = pmb.helpers.package.get(package, arch, must_exist=False) depend = pmb.helpers.package.get(package, arch, must_exist=False)
if depend is None: if depend is None:
raise RuntimeError(f"{path}: package '{package}' from" raise RuntimeError(
f" _pmb_recommends not found for arch '{arch}'") f"{path}: package '{package}' from"
f" _pmb_recommends not found for arch '{arch}'"
)
# Check packages from "_pmb_recommends" of -extras subpackage if one exists # Check packages from "_pmb_recommends" of -extras subpackage if one exists
if f"{apkbuild['pkgname']}-extras" in apkbuild["subpackages"]: if f"{apkbuild['pkgname']}-extras" in apkbuild["subpackages"]:
@@ -40,5 +42,7 @@ def test_aports_ui():
for package in apkbuild["_pmb_recommends"]: for package in apkbuild["_pmb_recommends"]:
depend = pmb.helpers.package.get(package, arch, must_exist=False) depend = pmb.helpers.package.get(package, arch, must_exist=False)
if depend is None: if depend is None:
raise RuntimeError(f"{path}: package '{package}' from _pmb_recommends " raise RuntimeError(
f"of -extras subpackage is not found for arch '{arch}'") f"{path}: package '{package}' from _pmb_recommends "
f"of -extras subpackage is not found for arch '{arch}'"
)