|
| 1 | +#!/usr/bin/env python3 |
| 2 | + |
| 3 | +import argparse |
| 4 | +import sys |
| 5 | +import re |
| 6 | + |
| 7 | + |
| 8 | +def get_manifest(manifest_path) -> str: |
| 9 | + """ |
| 10 | + This function reads in the manifest file give the path and checks to |
| 11 | + see if it has the manifest keyword at the beginning of the line |
| 12 | + somewhere in the file. |
| 13 | +
|
| 14 | + It then reads in the file as a single string. |
| 15 | +
|
| 16 | + :param manifest_path: The path to a west manifest yml file. |
| 17 | + :type manifest_path: str |
| 18 | + :return: String containing the raw file contents. |
| 19 | + :rtype: str |
| 20 | + """ |
| 21 | + try: |
| 22 | + manifest_file = open(manifest_path, "r") |
| 23 | + except FileNotFoundError: |
| 24 | + print("Manifest file not found at: " + manifest_path) |
| 25 | + sys.exit(255) |
| 26 | + except Exception as e: |
| 27 | + print("Error opening manifest file.") |
| 28 | + print(e) |
| 29 | + sys.exit(255) |
| 30 | + |
| 31 | + try: |
| 32 | + file_contents = manifest_file.read() |
| 33 | + except Exception as e: |
| 34 | + print("Error reading manifest File Contents.") |
| 35 | + print(e) |
| 36 | + sys.exit(255) |
| 37 | + |
| 38 | + file_match = re.search("\nmanifest:", file_contents) |
| 39 | + if file_match is None: |
| 40 | + print("File does not appear to be a manifest file.") |
| 41 | + print("Missing \"manifest\" key in file.") |
| 42 | + sys.exit(255) |
| 43 | + |
| 44 | + return file_contents |
| 45 | + |
| 46 | + |
| 47 | +def parse_revisions(manifest_contents) -> dict: |
| 48 | + """ |
| 49 | + Parses the contents of the manifest file using a regex and then stores the |
| 50 | + output of the matches in a dictionary using the project name as the key and |
| 51 | + the returned revision as the value. |
| 52 | +
|
| 53 | + :param manifest_contents: Raw contents of the manifest file. |
| 54 | + :type manifest_contents: str |
| 55 | + :return: Dictionary containing project name and revision as key, values. |
| 56 | + :rtype: dict |
| 57 | + """ |
| 58 | + regex_pattern = r"- name:[ ]*([^ \n]*)[\s\S]*?revision:[ ]*([a-z,0-9,\.]*)" |
| 59 | + matches = re.findall(regex_pattern, manifest_contents, re.M) |
| 60 | + |
| 61 | + revisions = {} |
| 62 | + for revision_pair in matches: |
| 63 | + if revision_pair is not None and len(revision_pair) == 2: |
| 64 | + revisions[revision_pair[0]] = revision_pair[1] |
| 65 | + |
| 66 | + return revisions |
| 67 | + |
| 68 | + |
| 69 | +def print_all_revisions(revisions): |
| 70 | + """ |
| 71 | + If no project name is supplied on the command line this function will be |
| 72 | + used to print out all project revisions. It will print a single project and |
| 73 | + it's revision per line. |
| 74 | +
|
| 75 | + :param revisions: A dictionary containing project name and revisions. |
| 76 | + :type revisions: dict |
| 77 | + """ |
| 78 | + if len(revisions) == 0: |
| 79 | + print("No projects and revisions could be parsed from manifest.") |
| 80 | + sys.exit(255) |
| 81 | + |
| 82 | + for project, revision in revisions.items(): |
| 83 | + print(project + " " + revision) |
| 84 | + |
| 85 | + |
| 86 | +def print_revision(project, revisions): |
| 87 | + """ |
| 88 | + Attempts to print the revision for the given project if it exists. |
| 89 | +
|
| 90 | + :param project: The project name to print. |
| 91 | + :type project: str |
| 92 | + :param revisions: A dictionary contain project names and revisions. |
| 93 | + :type revisions: dict |
| 94 | + """ |
| 95 | + if len(revisions) == 0: |
| 96 | + print("No projects and revisions could be parsed from manifest.") |
| 97 | + return |
| 98 | + |
| 99 | + if project not in revisions: |
| 100 | + print("Could not find project " + project + " in manifest.") |
| 101 | + print("Possible projects in manifest with revisions:") |
| 102 | + for project, revision in revisions.items(): |
| 103 | + print("- " + project) |
| 104 | + sys.exit(255) |
| 105 | + |
| 106 | + else: |
| 107 | + print(revisions[project]) |
| 108 | + |
| 109 | + |
| 110 | +def get_revision(project, manifest_path): |
| 111 | + """ |
| 112 | + Main work function that takes the CLI input and loads the file, parses |
| 113 | + the revisions, and prints the requested revision(s) if possible. |
| 114 | +
|
| 115 | + :param project: The project name to print, or None if none supplied. |
| 116 | + :type project: str |
| 117 | + :param manifest_path: The path to the manifest file to parse. |
| 118 | + :type manifest_path: str |
| 119 | + """ |
| 120 | + manifest_contents = get_manifest(manifest_path) |
| 121 | + project_revisions = parse_revisions(manifest_contents) |
| 122 | + |
| 123 | + if project is None: |
| 124 | + print_all_revisions(project_revisions) |
| 125 | + else: |
| 126 | + print_revision(project, project_revisions) |
| 127 | + |
| 128 | + |
| 129 | +if __name__ == '__main__': |
| 130 | + parser = argparse.ArgumentParser( |
| 131 | + description='Get revision from the specified project') |
| 132 | + |
| 133 | + parser.add_argument( |
| 134 | + '-p', |
| 135 | + '--project', |
| 136 | + help="The name of the project to retrieve the revision for. " |
| 137 | + "If this option is not used then all revisions " |
| 138 | + "will be printed") |
| 139 | + parser.add_argument( |
| 140 | + '-m', '--manifest', required=True, |
| 141 | + help="The path to the west manifest file to parse for the requested " |
| 142 | + "revision") |
| 143 | + |
| 144 | + args = parser.parse_args() |
| 145 | + get_revision(args.project, args.manifest) |
0 commit comments