diff --git a/get_current_revision_from_manifest.py b/get_current_revision_from_manifest.py new file mode 100755 index 0000000000000000000000000000000000000000..16d6f90b0f02390f165a81cb93c6c85235ac49c0 --- /dev/null +++ b/get_current_revision_from_manifest.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python3 +import common + +import argparse +import logging +import re +from gitlab import Gitlab +from gitlab.v4.objects import Project + +from lxml import etree + + +def get_current_revision_from_manifest( + manifest_project: Project, + manifest_branch, + project: Project, + recipe_name=None, + srcrev_file=common.srcrev_file, +): + """ + Reads the xml manifest an the SRC_REVC file in the given manifest project + at given branch and returns the current revision of the given project. + Returns a dict containing the file referencing the project as key and the revision + """ + + if manifest_branch is None: + manifest_branch = manifest_project.default_branch + logging.debug("Using default branch %s", manifest_project) + + # Get all manifest xml + repository_tree = manifest_project.repository_tree( + ref=manifest_branch, all=True, retry_transient_errors=True + ) + logging.debug(repository_tree) + manifest_files = [ + f + for f in repository_tree + if (f["name"].endswith(".xml") or f["name"] == srcrev_file) + and f["type"] == "blob" + ] + results = {} + for f in manifest_files: + file_name = f["name"] + logging.debug(file_name) + content = common.get_repository_file_raw( + manifest_project, file_name, ref=manifest_branch + ) + if content is None: + logging.error("Failed to read %s.", file_name) + continue + logging.debug(content) + revision = None + if file_name.endswith(".xml"): + manifest = etree.fromstring(content.encode()) + + for node in manifest.findall("project"): + project_name = node.get("name") + if project_name is not None and project_name.endswith(project.path): + logging.debug(node) + revision = node.get("revision") + + elif recipe_name is not None: + # read from SRCREV + project_line = None + # Match "...RECIPE_NAME =" + pattern = re.compile("{}[ ,\t]{{0,}}?=".format(recipe_name)) + for line in content.splitlines(): + if pattern.search(line): + project_line = line + if project_line is None: + continue + # Get current project revision from SRCREV file + # Assuming notation: <project> = "<hash>" + revision = project_line.split('"')[1] + + if revision is not None: + results[file_name] = revision + return results + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument( + "--gitlab-url", + help="""URL to the GitLab instance""", + dest="gitlab_url", + required=True, + ) + parser.add_argument( + "--token", + help="""GitLab REST API private access token""", + dest="token", + required=True, + ) + parser.add_argument( + "--manifest-project", + help="""name of the manifest project""", + dest="manifest_project", + required=True, + ) + parser.add_argument( + "--manifest-branch", + help="""the branch in the manifest repo to read, use project's default if not set""", + dest="manifest_branch", + default=None, + ) + parser.add_argument( + "--project", + help="""name of the project get the current revision for""", + dest="project", + required=True, + ) + parser.add_argument( + "--srcrev-file", + help="""source revision file name (default: 'SRCREV.conf')""", + dest="srcrev_file", + default=common.srcrev_file, + required=False, + ) + parser.add_argument( + "--recipe-name", + help="""recipe name to resolve the project in 'SRCREV.conf'""", + dest="recipe_name", + default=None, + required=False, + ) + parser.add_argument( + "-v", + "--verbose", + action="store_true", + help="""Increase verbosity.""", + ) + + args, _ = parser.parse_known_args() + if args.verbose: + logging.basicConfig(level=logging.DEBUG) + + gitlab = Gitlab(args.gitlab_url, private_token=args.token) + project = common.get_project(gitlab, args.project) + manifest_project = common.get_project(gitlab, args.manifest_project) + + current_revisions = get_current_revision_from_manifest( + manifest_project=manifest_project, + manifest_branch=args.manifest_branch, + project=project, + recipe_name=args.recipe_name, + srcrev_file=args.srcrev_file, + ) + print( + "The manifest repo {} includes the project {} at revision {}".format( + manifest_project.name, project.name, current_revisions + ) + ) + + +if __name__ == "__main__": + main()