From: "Desimone, Ashley E" <ashley.e.desimone@intel.com>
To: "Desimone, Nathaniel L" <nathaniel.l.desimone@intel.com>,
"devel@edk2.groups.io" <devel@edk2.groups.io>
Subject: Re: [edk2-staging/EdkRepo] [PATCH V3] EdkRepo: Add list-repos command
Date: Wed, 4 Dec 2019 20:27:14 +0000 [thread overview]
Message-ID: <4CF3A9EB60ABDA47BE7821A4DA3A0A3353CB17B8@ORSMSX116.amr.corp.intel.com> (raw)
In-Reply-To: <20191204014255.2582-1-nathaniel.l.desimone@intel.com>
Reviewed-by: Ashley E Desimone <ashley.e.desimone@intel.com>
-----Original Message-----
From: Desimone, Nathaniel L
Sent: Tuesday, December 3, 2019 5:43 PM
To: devel@edk2.groups.io
Cc: Desimone, Ashley E <ashley.e.desimone@intel.com>
Subject: [edk2-staging/EdkRepo] [PATCH V3] 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.desimone@intel.com>
Signed-off-by: Nate DeSimone <nathaniel.l.desimone@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 | 248 ++++++++++++++++++
setup.py | 5 +-
5 files changed, 300 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..7133201
--- /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. The name of a repo is determined by the
+name given by the most manifest files.'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..9083d8e
--- /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(s) {} 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..caf0373
--- /dev/null
+++ b/edkrepo/commands/list_repos_command.py
@@ -0,0 +1,248 @@
+#!/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)++ #If the user provided a list of repositories to view, check to make sure+ #at least one repository will be shown, if not provide an error+ if args.repos and len([x for x in self.repo_names if x in args.repos]) <= 0:+ raise EdkrepoInvalidParametersException(humble.REPO_NOT_FOUND_IN_MANIFEST.format(','.join(args.repos)))++ #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
prev parent reply other threads:[~2019-12-04 20:27 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-12-04 1:42 [edk2-staging/EdkRepo] [PATCH V3] EdkRepo: Add list-repos command Nate DeSimone
2019-12-04 20:27 ` Desimone, Ashley E [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4CF3A9EB60ABDA47BE7821A4DA3A0A3353CB17B8@ORSMSX116.amr.corp.intel.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox