From 51052dafe034ce72ef1178c937455df36b50e154 Mon Sep 17 00:00:00 2001 From: Daniel Mach Date: Fri, 7 Jul 2023 13:14:27 +0200 Subject: [PATCH] The repo list command now resolves and displays flags (build, publish, ...) --- behave/features/repo.feature | 15 +++++---- osc/_private/project.py | 63 ++++++++++++++++++++++++++++++++++-- osc/commands/repo_list.py | 20 ++++++++++++ 3 files changed, 90 insertions(+), 8 deletions(-) diff --git a/behave/features/repo.feature b/behave/features/repo.feature index 900ebc3e..3ad7d46a 100644 --- a/behave/features/repo.feature +++ b/behave/features/repo.feature @@ -13,9 +13,10 @@ Scenario: Run `osc repo list` on a project Then stdout is """ Repository : standard - Architectures : x86_64 - i586 + Architectures : x86_64, i586 Paths : openSUSE.org:openSUSE:Tumbleweed/standard + Flags + build : disable: x86_64, i586 """ @@ -26,15 +27,17 @@ Scenario: Run `osc repo add` on a project Then stdout is """ Repository : standard - Architectures : x86_64 - i586 + Architectures : x86_64, i586 Paths : openSUSE.org:openSUSE:Tumbleweed/standard + Flags + build : disable: x86_64, i586 Repository : new-repo - Architectures : x86_64 - aarch64 + Architectures : x86_64, aarch64 Paths : test:factory/standard test:devel/standard + Flags + build : disable: x86_64, aarch64 """ diff --git a/osc/_private/project.py b/osc/_private/project.py index b6edbec2..856bd3a3 100644 --- a/osc/_private/project.py +++ b/osc/_private/project.py @@ -1,11 +1,13 @@ from . import api from .api import ET +from .. import core as osc_core from .. import oscerr class APIXMLBase: - def __init__(self, xml_root): + def __init__(self, xml_root, apiurl=None): self.root = xml_root + self.apiurl = apiurl def to_bytes(self): ET.indent(self.root, space=" ", level=0) @@ -20,7 +22,7 @@ class ProjectMeta(APIXMLBase): def from_api(cls, apiurl, project): url_path = ["source", project, "_meta"] root = api.get(apiurl, url_path) - obj = cls(root) + obj = cls(root, apiurl=apiurl) return obj def to_api(self, apiurl, project): @@ -93,3 +95,60 @@ class ProjectMeta(APIXMLBase): if len(publish_node) == 0: self.root.remove(publish_node) + + REPOSITORY_FLAGS_TEMPLATE = { + "build": None, + "debuginfo": None, + "publish": None, + "useforbuild": None, + } + + def _update_repository_flags(self, repository_flags, xml_root): + """ + Update `repository_flags` with data from the `xml_root`. + """ + for flag in self.REPOSITORY_FLAGS_TEMPLATE: + flag_node = xml_root.find(flag) + if flag_node is None: + continue + for node in flag_node: + action = node.tag + repo = node.get("repository") + arch = node.get("arch") + for (entry_repo, entry_arch), entry_data in repository_flags.items(): + match = False + if (repo, arch) == (entry_repo, entry_arch): + # apply to matching repository and architecture + match = True + elif repo == entry_repo and not arch: + # apply to all matching repositories + match = True + elif not repo and arch == entry_arch: + # apply to all matching architectures + match = True + elif not repo and not arch: + # apply to everything + match = True + if match: + entry_data[flag] = True if action == "enable" else False + + def resolve_repository_flags(self, package=None): + """ + Resolve the `build`, `debuginfo`, `publish` and `useforbuild` flags + and return their values for each repository and build arch. + + :returns: {(repo_name, repo_buildarch): {flag_name: bool} for all available repos + """ + result = {} + # TODO: avoid calling get_repos_of_project(), use self.root instead + for repo in osc_core.get_repos_of_project(self.apiurl, self.root.attrib["name"]): + result[(repo.name, repo.arch)] = self.REPOSITORY_FLAGS_TEMPLATE.copy() + + self._update_repository_flags(result, self.root) + + if package: + m = osc_core.show_package_meta(self.apiurl, self.root.attrib["name"], package) + root = ET.fromstring(b''.join(m)) + self._update_repository_flags(result, root) + + return result diff --git a/osc/commands/repo_list.py b/osc/commands/repo_list.py index cbc2b847..a23ea0f2 100644 --- a/osc/commands/repo_list.py +++ b/osc/commands/repo_list.py @@ -20,6 +20,16 @@ class RepoListCommand(osc.commandline.OscCommand): def run(self, args): meta = ProjectMeta.from_api(args.apiurl, args.project) + + repo_flags = meta.resolve_repository_flags() + flag_map = {} + for (repo_name, arch), data in repo_flags.items(): + for flag_name, flag_value in data.items(): + if flag_value is None: + continue + action = "enable" if flag_value else "disable" + flag_map.setdefault(repo_name, {}).setdefault(flag_name, {}).setdefault(action, []).append(arch) + table = KeyValueTable() for repo in meta.repository_list(): table.add("Repository", repo["name"], color="bold") @@ -27,5 +37,15 @@ class RepoListCommand(osc.commandline.OscCommand): if repo["paths"]: paths = [f"{path['project']}/{path['repository']}" for path in repo["paths"]] table.add("Paths", paths) + + if repo["name"] in flag_map: + table.add("Flags", None) + for flag_name in flag_map[repo["name"]]: + lines = [] + for action, archs in flag_map[repo["name"]][flag_name].items(): + lines.append(f"{action + ':':<8s} {', '.join(archs)}") + lines.sort() + table.add(flag_name, lines, indent=4) + table.newline() print(str(table))