public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
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 V2 1/3] EdkRepo: Generate command completion scripts
Date: Fri,  3 Apr 2020 16:49:30 -0700	[thread overview]
Message-ID: <20200403234932.2497-2-nathaniel.l.desimone@intel.com> (raw)
In-Reply-To: <20200403234932.2497-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 | 87 +++++++++++++++++++++++++++
 edkrepo/edkrepo_cli.py                | 61 ++++++++++++++++++-
 setup.py                              |  8 +--
 3 files changed, 151 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..1220924
--- /dev/null
+++ b/edkrepo/command_completion_edkrepo.py
@@ -0,0 +1,87 @@
+#!/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.common.common_repo_functions import combinations_in_manifest
+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(combinations_in_manifest(manifest)))
+
+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.26.0.windows.1


  reply	other threads:[~2020-04-03 23:49 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-04-03 23:49 [edk2-staging/EdkRepo] [PATCH V2 0/3] EdkRepo: Command completion in bash/zsh Nate DeSimone
2020-04-03 23:49 ` Nate DeSimone [this message]
2020-04-03 23:49 ` [edk2-staging/EdkRepo] [PATCH V2 2/3] EdkRepo: Add command completion setup to install.py Nate DeSimone
2020-04-03 23:49 ` [edk2-staging/EdkRepo] [PATCH V2 3/3] EdkRepo: Add command completion setup to Windows installer Nate DeSimone
2020-04-06 18:32 ` [edk2-staging/EdkRepo] [PATCH V2 0/3] EdkRepo: Command completion in bash/zsh 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=20200403234932.2497-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