gsi_util: adding subcommand framework

With this CL, new command can be easily added:
  1. Add a new file: gsi/gsi_util/gsi_util/commands/hello.py
     And implements a function to register parsers into gsi_util's main parser.

     def setup_command_args(subparsers)

  2. In gsi/gsi_util/gsi_util.py, add the new command into GsiUtil():
     _COMMANDS = ['hello']

Bug: 70588453
Test: make gsi_util
Test: gsi_util --help
Test: gsi_util hello --foo
Test: gsi_util --debug hello --bar

Change-Id: I54fa6d1dea5afed724d9ac4a99f88bf78da82732
diff --git a/gsi/gsi_util/Android.bp b/gsi/gsi_util/Android.bp
new file mode 100644
index 0000000..be7b569
--- /dev/null
+++ b/gsi/gsi_util/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+python_binary_host {
+  name: "gsi_util",
+  srcs: [
+    "gsi_util.py",
+    "gsi_util/*.py",
+    "gsi_util/commands/*.py",
+  ],
+  version: {
+    py2: {
+      enabled: true,
+    },
+    py3: {
+      enabled: false,
+    },
+  },
+}
diff --git a/gsi/gsi_util/gsi_util.py b/gsi/gsi_util/gsi_util.py
new file mode 100755
index 0000000..d3cab52
--- /dev/null
+++ b/gsi/gsi_util/gsi_util.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python
+#
+# Copyright 2017 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""gsi_util command-line utility."""
+
+import argparse
+import logging
+import sys
+
+
+class GsiUtil(object):
+  """Object for gsi_util command line tool."""
+
+  _GSI_UTIL_VERSION = '1.0'
+
+  # Adds gsi_util COMMAND here.
+  # TODO(bowgotsai): auto collect from gsi_util/commands/*.py
+  _COMMANDS = ['hello']
+
+  _LOGGING_FORMAT = '%(message)s'
+  _LOGGING_LEVEL = logging.WARNING
+
+  @staticmethod
+  def _get_module_name(command):
+    return 'gsi_util.commands.' + command
+
+  def run(self, argv):
+    """Command-line processor."""
+
+    # Sets up default logging.
+    logging.basicConfig(format=self._LOGGING_FORMAT, level=self._LOGGING_LEVEL)
+
+    # Adds top-level --version/--debug argument.
+    parser = argparse.ArgumentParser()
+    parser.add_argument('-v', '--version', action='version',
+                        version='%(prog)s {}'.format(self._GSI_UTIL_VERSION))
+    parser.add_argument(
+        '-d', '--debug', help='debug mode.', action='store_true')
+
+    # Adds subparsers for each COMMAND.
+    subparsers = parser.add_subparsers(title='COMMAND')
+    for command in self._COMMANDS:
+      module_name = self._get_module_name(command)
+      mod = __import__(module_name, globals(), locals(), ['setup_command_args'])
+      mod.setup_command_args(subparsers)
+
+    args = parser.parse_args(argv[1:])
+    if args.debug:
+      logging.getLogger().setLevel(logging.DEBUG)
+
+    try:
+      args.func(args)
+    except Exception as e:
+      logging.error('%s: %s', argv[0], e.message)
+      logging.exception(e)
+      sys.exit(1)
+
+
+if __name__ == '__main__':
+  tool = GsiUtil()
+  tool.run(sys.argv)
diff --git a/gsi/gsi_util/gsi_util/__init__.py b/gsi/gsi_util/gsi_util/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gsi/gsi_util/gsi_util/__init__.py
diff --git a/gsi/gsi_util/gsi_util/commands/__init__.py b/gsi/gsi_util/gsi_util/commands/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gsi/gsi_util/gsi_util/commands/__init__.py
diff --git a/gsi/gsi_util/gsi_util/commands/hello.py b/gsi/gsi_util/gsi_util/commands/hello.py
new file mode 100644
index 0000000..ff3cdc7
--- /dev/null
+++ b/gsi/gsi_util/gsi_util/commands/hello.py
@@ -0,0 +1,32 @@
+# Copyright 2017 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Implementation of gsi_util hello command."""
+
+import logging
+
+
+def do_hello(args):
+  if args.foo:
+    logging.info('hello foo')
+  if args.bar:
+    logging.info('hello bar')
+
+
+def setup_command_args(subparsers):
+  """Sets up command args for 'hello'."""
+  hello_parser = subparsers.add_parser('hello', help='hello help')
+  hello_parser.add_argument('--foo', action='store_true', help='foo help')
+  hello_parser.add_argument('--bar', action='store_true', help='bar help')
+  hello_parser.set_defaults(func=do_hello)