From: "Nate DeSimone" <nathaniel.l.desimone@intel.com>
To: devel@edk2.groups.io
Cc: Ashley DeSimone <ashley.e.desimone@intel.com>,
Puja Pandya <puja.pandya@intel.com>,
Erik Bjorge <erik.c.bjorge@intel.com>,
Prince Agyeman <prince.agyeman@intel.com>,
Bret Barkelew <Bret.Barkelew@microsoft.com>,
Philippe Mathieu-Daude <philmd@redhat.com>
Subject: [edk2-staging/EdkRepo] [PATCH V1 1/3] EdkRepo: Generate command completion scripts
Date: Wed, 1 Apr 2020 15:34:50 -0700 [thread overview]
Message-ID: <20200401223452.4805-2-nathaniel.l.desimone@intel.com> (raw)
In-Reply-To: <20200401223452.4805-1-nathaniel.l.desimone@intel.com>
Adds code to edkrepo_cli.py to generate a bash/zsh
compatible command completion script.
Add a new command_completion_edkrepo.py script which
is callable by the shell when needed for dynamic
completion data. For example, providing completion for
"edkrepo checkout" requires the shell to know the list
of possible branch combinations, this requires parsing
the manifest XML. command_completion_edkrepo.py provides
a means for the shell to get that type of data.
Cc: Ashley DeSimone <ashley.e.desimone@intel.com>
Cc: Puja Pandya <puja.pandya@intel.com>
Cc: Erik Bjorge <erik.c.bjorge@intel.com>
Cc: Prince Agyeman <prince.agyeman@intel.com>
Cc: Bret Barkelew <Bret.Barkelew@microsoft.com>
Cc: Philippe Mathieu-Daude <philmd@redhat.com>
Signed-off-by: Nate DeSimone <nathaniel.l.desimone@intel.com>
---
edkrepo/command_completion_edkrepo.py | 86 +++++++++++++++++++++++++++
edkrepo/edkrepo_cli.py | 61 ++++++++++++++++++-
setup.py | 8 +--
3 files changed, 150 insertions(+), 5 deletions(-)
create mode 100644 edkrepo/command_completion_edkrepo.py
diff --git a/edkrepo/command_completion_edkrepo.py b/edkrepo/command_completion_edkrepo.py
new file mode 100644
index 0000000..05de9ca
--- /dev/null
+++ b/edkrepo/command_completion_edkrepo.py
@@ -0,0 +1,86 @@
+#!/usr/bin/env python3
+#
+## @file
+# command_completion_edkrepo.py
+#
+# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+import argparse
+import io
+import os
+import sys
+import traceback
+
+from edkrepo_manifest_parser.edk_manifest import ManifestXml
+from edkrepo.config import config_factory
+from edkrepo.config.config_factory import get_workspace_manifest
+
+def checkout(parsed_args, config):
+ manifest = get_workspace_manifest()
+ print(' '.join([c.name for c in manifest.combinations]))
+
+def current_combo(parsed_args, config):
+ manifest = get_workspace_manifest()
+ print(" [{}]".format(manifest.general_config.current_combo))
+
+def checkout_pin(parsed_args, config):
+ pins = []
+ manifest_directory = config['cfg_file'].manifest_repo_abs_local_path
+ manifest = get_workspace_manifest()
+ pin_folder = os.path.normpath(os.path.join(manifest_directory, manifest.general_config.pin_path))
+ for dirpath, _, filenames in os.walk(pin_folder):
+ for file in filenames:
+ pin_file = os.path.join(dirpath, file)
+ # Capture error output from manifest parser stdout so it is hidden unless verbose is enabled
+ stdout = sys.stdout
+ sys.stdout = io.StringIO()
+ pin = ManifestXml(pin_file)
+ parse_output = sys.stdout.getvalue()
+ sys.stdout = stdout
+ if parsed_args.verbose and parse_output.strip() != '':
+ print('Pin {} Parsing Errors: {}\n'.format(file, parse_output.strip()))
+ if pin.project_info.codename == manifest.project_info.codename:
+ pins.append(file)
+ print(' '.join(pins))
+
+# To add command completions for a new command, add an entry to this dictionary.
+command_completions = {
+ 'current-combo': current_combo,
+ 'checkout': checkout,
+ 'checkout-pin': checkout_pin,
+ 'chp': checkout_pin
+}
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("-v", "--verbose", action="store_true", help='Increases command verbosity')
+ subparsers = parser.add_subparsers(dest='subparser_name')
+ for command_completion in command_completions:
+ subparsers.add_parser(command_completion, formatter_class=argparse.RawTextHelpFormatter)
+ if len(sys.argv) <= 1:
+ return 0
+ parsed_args = parser.parse_args()
+ try:
+ command_name = parsed_args.subparser_name
+ config = {}
+ config["cfg_file"] = config_factory.GlobalConfig()
+ config["user_cfg_file"] = config_factory.GlobalUserConfig()
+ if command_name not in command_completions:
+ return 1
+ command_completions[command_name](parsed_args, config)
+ return 0
+ except Exception as e:
+ if parsed_args.verbose:
+ traceback.print_exc()
+ print("Error: {}".format(str(e)))
+ return 1
+ return 0
+
+if __name__ == "__main__":
+ try:
+ sys.exit(main())
+ except Exception as e:
+ traceback.print_exc()
+ sys.exit(1)
diff --git a/edkrepo/edkrepo_cli.py b/edkrepo/edkrepo_cli.py
index 0b69860..03061c9 100644
--- a/edkrepo/edkrepo_cli.py
+++ b/edkrepo/edkrepo_cli.py
@@ -3,7 +3,7 @@
## @file
# edkrepo_cli.py
#
-# Copyright (c) 2017- 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2017 - 2020, Intel Corporation. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
@@ -29,6 +29,7 @@ from edkrepo.common.edkrepo_exception import EdkrepoException, EdkrepoGlobalConf
from edkrepo.common.edkrepo_exception import EdkrepoWarningException
from edkrepo.common.edkrepo_exception import EdkrepoConfigFileInvalidException
from edkrepo.common.humble import KEYBOARD_INTERRUPT, GIT_CMD_ERROR
+from edkrepo.common.pathfix import get_actual_path
def generate_command_line(command):
parser = argparse.ArgumentParser()
@@ -100,6 +101,61 @@ def generate_command_line(command):
subparser_name.add_argument(('--' + arg.get('name')), action=arg_action, help=arg.get('help-text'))
return parser
+command_completion_script_header='''#!/usr/bin/env bash
+#
+## @file edkrepo_completions.sh
+#
+# Automatically generated please DO NOT modify !!!
+#
+
+'''
+def generate_command_completion_script(script_filename, parser):
+ import edkrepo.command_completion_edkrepo as completion
+ commands = []
+ for action in parser._positionals._group_actions:
+ if action.choices is not None:
+ commands = [c for c in action.choices]
+ break
+ commands = sorted(commands)
+ commands_with_3rd_param_completion = [c for c in completion.command_completions if c in commands]
+ commands_with_3rd_param_completion = sorted(commands_with_3rd_param_completion)
+ with open(script_filename, 'w') as f:
+ f.write(command_completion_script_header)
+ if sys.platform == "win32":
+ command_completion_path = os.path.dirname(sys.executable)
+ command_completion_path = os.path.join(command_completion_path, 'Scripts', "command_completion_edkrepo.exe")
+ if not os.path.isfile(command_completion_path):
+ print('command_completion_edkrepo.exe not found')
+ return
+ command_completion_path = get_actual_path(command_completion_path)
+ (drive, path) = os.path.splitdrive(command_completion_path)
+ command_completion_path = '/{}{}'.format(drive.replace(':','').lower(), path.replace('\\','/'))
+ f.write("export command_completion_edkrepo_file='{}'\n".format(command_completion_path))
+ f.write('alias command_completion_edkrepo="$command_completion_edkrepo_file"\n')
+ f.write('_edkrepo_completions() {\n if [ "${#COMP_WORDS[@]}" -eq "2" ]; then\n')
+ f.write(' COMPREPLY=($(compgen -W "{}" -- "${{COMP_WORDS[1]}}"))\n'.format(' '.join(commands)))
+ if len(commands_with_3rd_param_completion) > 0:
+ f.write(' elif [ "${#COMP_WORDS[@]}" -eq "3" ]; then\n')
+ first_loop = True
+ for command in commands_with_3rd_param_completion:
+ if first_loop:
+ f.write(' if [ "${{COMP_WORDS[1]}}" == "{}" ]; then\n'.format(command))
+ first_loop = False
+ else:
+ f.write(' elif [ "${{COMP_WORDS[1]}}" == "{}" ]; then\n'.format(command))
+ f.write(' COMPREPLY=($(compgen -W "$(command_completion_edkrepo ${COMP_WORDS[1]})" -- "${COMP_WORDS[2]}"))\n')
+ if len(commands_with_3rd_param_completion) > 0:
+ f.write(' fi\n')
+ f.write(' fi\n}\n\n')
+ if len(commands_with_3rd_param_completion) > 0:
+ if sys.platform == "win32":
+ f.write('if [ -x "$(command -v edkrepo)" ] && [ -x "$(command -v $command_completion_edkrepo_file)" ]; then\n')
+ else:
+ f.write('if [ -x "$(command -v edkrepo)" ] && [ -x "$(command -v command_completion_edkrepo)" ]; then\n')
+ else:
+ f.write('if [ -x "$(command -v edkrepo)" ]; then\n')
+ f.write(' complete -F _edkrepo_completions edkrepo\nfi\n')
+
def main():
command = command_factory.create_composite_command()
config = {}
@@ -117,6 +173,9 @@ def main():
if len(sys.argv) <= 1:
parser.print_help()
return 1
+ if sys.argv[1] == 'generate-command-completion-script' and len(sys.argv) >= 3:
+ generate_command_completion_script(sys.argv[2], parser)
+ return 0
parsed_args = parser.parse_args()
command_name = parsed_args.subparser_name
try:
diff --git a/setup.py b/setup.py
index e14aed1..e7e6ce8 100755
--- a/setup.py
+++ b/setup.py
@@ -1,9 +1,8 @@
#!/usr/bin/env python3
#
-## @file
-# setup.py
+## @file setup.py
#
-# Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2017 - 2020, Intel Corporation. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
@@ -20,7 +19,8 @@ setup(name='edkrepo',
include_package_data=True,
entry_points={
'console_scripts': [
- 'edkrepo = edkrepo.edkrepo_entry_point:main'
+ 'edkrepo = edkrepo.edkrepo_entry_point:main',
+ 'command_completion_edkrepo = edkrepo.command_completion_edkrepo:main'
]
}
)
--
2.24.0.windows.2
next prev parent reply other threads:[~2020-04-01 22:35 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-04-01 22:34 [edk2-staging/EdkRepo] [PATCH V1 0/3] EdkRepo: Command completion in bash/zsh Nate DeSimone
2020-04-01 22:34 ` Nate DeSimone [this message]
2020-04-03 21:33 ` [edk2-staging/EdkRepo] [PATCH V1 1/3] EdkRepo: Generate command completion scripts Ashley E Desimone
2020-04-01 22:34 ` [edk2-staging/EdkRepo] [PATCH V1 2/3] EdkRepo: Add command completion setup to install.py Nate DeSimone
2020-04-03 21:51 ` Ashley E Desimone
2020-04-01 22:34 ` [edk2-staging/EdkRepo] [PATCH V1 3/3] EdkRepo: Add command completion setup to Windows installer Nate DeSimone
2020-04-03 21:55 ` Ashley E Desimone
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=20200401223452.4805-2-nathaniel.l.desimone@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