It looks good for now but in the future I would like to see an error message when the repo name passed with the --repos flag is not found.
Reviewed-by: Ashley E DeSimone <ashley.e.desim...@intel.com> -----Original Message----- From: Desimone, Nathaniel L Sent: Tuesday, December 3, 2019 3:06 PM To: devel@edk2.groups.io Cc: Desimone, Ashley E <ashley.e.desim...@intel.com> Subject: [edk2-staging/EdkRepo] [PATCH V2] EdkRepo: Add list-repos command list-repos lists the git repos used by all projects and which branches those projects use. Cc: Ashley E Desimone <ashley.e.desim...@intel.com> Signed-off-by: Nate DeSimone <nathaniel.l.desim...@intel.com> --- edkrepo/commands/arguments/list_repos_args.py | 16 ++ edkrepo/commands/humble/__init__.py | 8 + edkrepo/commands/humble/list_repos_humble.py | 26 ++ edkrepo/commands/list_repos_command.py | 243 ++++++++++++++++++ setup.py | 5 +- 5 files changed, 295 insertions(+), 3 deletions(-) create mode 100644 edkrepo/commands/arguments/list_repos_args.py create mode 100644 edkrepo/commands/humble/__init__.py create mode 100644 edkrepo/commands/humble/list_repos_humble.py create mode 100644 edkrepo/commands/list_repos_command.py diff --git a/edkrepo/commands/arguments/list_repos_args.py b/edkrepo/commands/arguments/list_repos_args.py new file mode 100644 index 0000000..6ff9b9c --- /dev/null +++ b/edkrepo/commands/arguments/list_repos_args.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3+#+## @file+# list_repos_args.py+#+# Copyright +(c) 2019, Intel Corporation. All rights reserved.<BR>+# +SPDX-License-Identifier: BSD-2-Clause-Patent+#++''' Contains the help +and description strings for arguments in the+list-repos command meta +data.+'''++COMMAND_DESCRIPTION = 'Lists the git repos used by available +projects and the branches that are used.'+ARCHIVED_HELP = 'Include a +listing of archived projects.'+REPOS_HELP = 'Only show the given subset +of repos instead of all repos.'diff --git +a/edkrepo/commands/humble/__init__.py +b/edkrepo/commands/humble/__init__.py new file mode 100644 index 0000000..dea6eb4 --- /dev/null +++ b/edkrepo/commands/humble/__init__.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python3+#+## @file+# __init__.py+#+# Copyright (c) 2019, +Intel Corporation. All rights reserved.<BR>+# SPDX-License-Identifier: +BSD-2-Clause-Patent+#diff --git +a/edkrepo/commands/humble/list_repos_humble.py +b/edkrepo/commands/humble/list_repos_humble.py new file mode 100644 index 0000000..bbb05a7 --- /dev/null +++ b/edkrepo/commands/humble/list_repos_humble.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3+#+## @file+# list_repos_humble.py+#+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>+# SPDX-License-Identifier: BSD-2-Clause-Patent+#++'''+Contains user visible strings printed by the list-repos command.+'''++from colorama import Fore+from colorama import Style++BRANCHES = 'Branches:'+BRANCH_FORMAT_STRING = ' {}{}{{}}{}'.format(Fore.BLUE, Style.BRIGHT, Style.RESET_ALL)+COMBO_FORMAT_STRING = ' {{}} {}{}({{}}){}'.format(Fore.CYAN, Style.BRIGHT, Style.RESET_ALL)+DEFAULT_COMBO_FORMAT_STRING = ' {{}} {}{}*({{}})*{}'.format(Fore.GREEN, Style.BRIGHT, Style.RESET_ALL)+MANIFEST_DIRECTORY = 'Manifest directory:'+PROJECT_NAME_FORMAT_STRING = '{}{}{{}}{}:'.format(Fore.YELLOW, Style.BRIGHT, Style.RESET_ALL)+REPOSITORIES = 'Repositories:'+REPO_NAME_AND_URL = '{}{}{{}}{} - [{}{}{{}}{}]'.format(Fore.MAGENTA, Style.BRIGHT, Style.RESET_ALL, Fore.RED, Style.BRIGHT, Style.RESET_ALL)+REPO_NAME_NOT_FOUND = 'repo_name not found'+REPO_NOT_FOUND_IN_MANIFEST = 'Repo {} not found in any manifest file'diff --git a/edkrepo/commands/list_repos_command.py b/edkrepo/commands/list_repos_command.py new file mode 100644 index 0000000..9035993 --- /dev/null +++ b/edkrepo/commands/list_repos_command.py @@ -0,0 +1,243 @@ +#!/usr/bin/env python3+#+## @file+# list_repos_command.py+#+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>+# SPDX-License-Identifier: BSD-2-Clause-Patent+#++import collections+import os++#from git import Repo+from colorama import Fore, Style++# Our modules+from edkrepo.commands.edkrepo_command import EdkrepoCommand+from edkrepo.commands.edkrepo_command import ColorArgument+import edkrepo.commands.arguments.list_repos_args as arguments+import edkrepo.commands.humble.list_repos_humble as humble+from edkrepo.common.common_repo_functions import pull_latest_manifest_repo+from edkrepo.common.edkrepo_exception import EdkrepoInvalidParametersException, EdkrepoManifestInvalidException+from edkrepo.common.ui_functions import init_color_console+from edkrepo_manifest_parser.edk_manifest import CiIndexXml, ManifestXml++class ListReposCommand(EdkrepoCommand):+ def __init__(self):+ super().__init__()+ self.repo_names = None++ def get_metadata(self):+ metadata = {}+ metadata['name'] = 'list-repos'+ metadata['help-text'] = arguments.COMMAND_DESCRIPTION+ args = []+ metadata['arguments'] = args+ args.append({'name': 'repos',+ 'positional': False,+ 'required': False,+ 'action': 'store',+ 'nargs': '+',+ 'help-text': arguments.REPOS_HELP})+ args.append({'name': 'archived',+ 'short-name': 'a',+ 'positional': False,+ 'required': False,+ 'help-text': arguments.ARCHIVED_HELP})+ args.append(ColorArgument)+ return metadata++ def run_command(self, args, config):+ print()+ init_color_console(args.color)++ # Get path to global manifest file+ global_manifest_directory = config['cfg_file'].manifest_repo_abs_local_path+ if args.verbose:+ print(humble.MANIFEST_DIRECTORY)+ print(global_manifest_directory)+ print()+ index_path = os.path.join(global_manifest_directory, 'CiIndex.xml')++ pull_latest_manifest_repo(args, config)+ print()++ #Create a dictionary containing all the manifests listed in the CiIndex.xml file+ ci_index_xml = CiIndexXml(index_path)+ manifests = {}+ repo_urls = set()+ project_list = list(ci_index_xml.project_list)+ if args.archived:+ project_list.extend(ci_index_xml.archived_project_list)+ for project in project_list:+ xml_file = ci_index_xml.get_project_xml(project)+ manifest = ManifestXml(os.path.normpath(os.path.join(global_manifest_directory, xml_file)))+ manifests[project] = manifest+ for combo in [c.name for c in manifest.combinations]:+ sources = manifest.get_repo_sources(combo)+ for source in sources:+ repo_urls.add(self.get_repo_url(source.remote_url))++ #Sort the manifests so projects will be displayed alphabetically+ manifests = collections.OrderedDict(sorted(manifests.items()))+ project_justify = len(max(manifests.keys(), key=len))++ #Determine the names of the repositories+ self.generate_repo_names(repo_urls, manifests)+ print(humble.REPOSITORIES)++ #For each each git repository...+ for repo_name in self.repo_names:+ if args.repos and repo_name not in args.repos:+ continue+ repo = self.repo_names[repo_name][0]+ print(humble.REPO_NAME_AND_URL.format(repo_name, repo))+ print(humble.BRANCHES)++ #Determine the list of branches that used by any branch combination in any manifest+ branches = set()+ for project_name in manifests:+ for combo in [c.name for c in manifests[project_name].combinations]:+ sources = manifests[project_name].get_repo_sources(combo)+ for source in sources:+ if self.get_repo_url(source.remote_url) == repo:+ branches.add(source.branch)++ #Sort the branch names so they will be displayed alphabetically+ #with the exception that if a branch named "master" exists, then it+ #will be displayed first+ branches = sorted(branches, key=str.casefold)+ if 'master' in branches:+ branches.remove('master')+ branches.insert(0, 'master')++ #For each interesting branch in the current git repository...+ for branch in branches:+ print(humble.BRANCH_FORMAT_STRING.format(branch))++ #Determine the branch combinations that use that branch+ for project_name in manifests:+ combos = []+ for combo in [c.name for c in manifests[project_name].combinations]:+ sources = manifests[project_name].get_repo_sources(combo)+ for source in sources:+ if self.get_repo_url(source.remote_url) == repo and source.branch == branch:+ combos.append(combo)+ break+ if len(combos) > 0:+ #Sort the branch combinations so they will be displayed alphabetically+ #with the exception that the default branch combination for the manifest+ #file will be displayed first+ combos = sorted(combos, key=str.casefold)+ default_combo = manifests[project_name].general_config.default_combo+ if default_combo in combos:+ combos.remove(default_combo)+ combos.insert(0, default_combo)+ first_combo = True+ for combo in combos:+ #Print the project name+ if first_combo:+ project_name_print = humble.PROJECT_NAME_FORMAT_STRING.format(project_name.ljust(project_justify))+ first_combo = False+ else:+ project_name_print = '{} '.format((' ' * len(project_name)).ljust(project_justify))+ #Print the branch combination name, if this is the default branch combination,+ #then print it in green color with *'s around it+ if default_combo == combo:+ print(humble.DEFAULT_COMBO_FORMAT_STRING.format(project_name_print, combo))+ else:+ print(humble.COMBO_FORMAT_STRING.format(project_name_print, combo))++ def get_repo_url(self, repo_url):+ if repo_url[-4:].lower() == '.git':+ return repo_url[:-4]+ return repo_url++ def get_repo_name(self, repo_url, manifests):+ for name in self.repo_names:+ if self.repo_names[name][0] == repo_url:+ return name+ raise EdkrepoInvalidParametersException(humble.REPO_NAME_NOT_FOUND)++ def generate_repo_names(self, repo_urls, manifests):+ #Determine the names of the repositories+ self.repo_names = collections.OrderedDict()+ for repo_url in repo_urls:+ self.__repo_name_worker(repo_url, manifests)++ #Sort the git repositories so they will be displayed alphabetically+ self.repo_names = collections.OrderedDict(sorted(self.repo_names.items()))+ names_to_move = []+ for repo_name in self.repo_names:+ if repo_name.lower().find('edk2') == 0:+ names_to_move.append(repo_name)+ names_to_move = sorted(names_to_move, reverse=True)+ for name_to_move in names_to_move:+ self.repo_names.move_to_end(name_to_move, False)+ names_to_move = []+ for repo_name in self.repo_names:+ if repo_name.lower().find('intel') == 0:+ names_to_move.append(repo_name)+ names_to_move = sorted(names_to_move, reverse=True)+ for name_to_move in names_to_move:+ self.repo_names.move_to_end(name_to_move, False)++ def __repo_name_worker(self, repo_url, manifests):+ #This is a heuristic that guesses the "name" of a repository by looking+ #at the name given to it by the most manifest files.+ names = collections.defaultdict(int)+ for project_name in manifests:+ for combo in [c.name for c in manifests[project_name].combinations]:+ sources = manifests[project_name].get_repo_sources(combo)+ for source in sources:+ if self.get_repo_url(source.remote_url) == repo_url:+ names[source.root] += 1+ found_unique_name = False+ original_best_name = None+ original_best_name_frequency = 0+ while not found_unique_name:+ best_name = None+ best_name_frequency = 0+ if len(names) <= 0:+ if original_best_name_frequency == 1:+ #If only 1 project uses this name, then append the project+ #name to the directory name to create the repo name+ for project_name in manifests:+ for combo in [c.name for c in manifests[project_name].combinations]:+ sources = manifests[project_name].get_repo_sources(combo)+ for source in sources:+ if self.get_repo_url(source.remote_url) == repo_url and source.root == original_best_name:+ best_name = "{}-{}".format(original_best_name, project_name)+ best_name_frequency = original_best_name_frequency+ else:+ best_name = repo_url+ best_name_frequency = 0+ break+ for name in names:+ if names[name] > best_name_frequency:+ best_name = name+ best_name_frequency = names[name]+ if best_name is None:+ raise EdkrepoManifestInvalidException(humble.REPO_NOT_FOUND_IN_MANIFEST.format(repo_url))+ if original_best_name is None:+ original_best_name = best_name+ original_best_name_frequency = best_name_frequency+ if best_name in self.repo_names:+ if self.repo_names[best_name][0] == repo_url:+ found_unique_name = True+ else:+ #If there is a name collision, then which repo has the most+ #Usage of the name owns the name+ if best_name_frequency > self.repo_names[best_name][1]:+ old_repo_url = self.repo_names[name][0]+ del self.repo_names[best_name]+ found_unique_name = True+ self.repo_names[best_name] = (repo_url, best_name_frequency)+ self.__repo_name_worker(old_repo_url, manifests)+ else:+ #Use the name given by the second most manifest files+ del names[best_name]+ else:+ found_unique_name = True+ self.repo_names[best_name] = (repo_url, best_name_frequency)diff --git a/setup.py b/setup.py index 73ce9a9..1b9edad 100755 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ ## @file # setup.py # -# Copyright (c) 2017- 2019, Intel Corporation. All rights reserved.<BR> +# Copyright (c) 2017 - 2019, Intel Corporation. All rights +reserved.<BR> # SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -12,7 +12,7 @@ from setuptools import setup setup(name='edkrepo', version='2.0.0', description='The edkrepo tools', - packages=['edkrepo', 'edkrepo.commands', 'edkrepo.commands.arguments', 'edkrepo.common', 'edkrepo.config', 'edkrepo_manifest_parser', 'project_utils'], + packages=['edkrepo', 'edkrepo.commands', + 'edkrepo.commands.arguments', 'edkrepo.commands.humble', + 'edkrepo.common', 'edkrepo.config', 'edkrepo_manifest_parser', + 'project_utils'], package_data={ }, include_package_data=True, @@ -22,4 +22,3 @@ setup(name='edkrepo', ] } ) - -- 2.24.0.windows.2 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#51698): https://edk2.groups.io/g/devel/message/51698 Mute This Topic: https://groups.io/mt/66074555/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-