gsi_util: add build.py to build and pack gsi_util

There are some command in build.py:

'setup_env' command can build the dependency files and copy these
files to the script.

'build' command also zip the dependency files to a zip file which
could be released independently.

The patch includes a list REQUIRED_ITEMS, which maintains the
source and destination of the dependency files. INCLUDE_FILES
maintains the files to be included to zip file additionally.

Uses 'list_deps' to list all dependency files.

Bug: 70253683
Test: setup_env and build command and check the files
Change-Id: I0b36da4457fdd04f9995cf30aadb26a2e32c1dd8
diff --git a/gsi/gsi_util/.gitignore b/gsi/gsi_util/.gitignore
new file mode 100644
index 0000000..7febc2e
--- /dev/null
+++ b/gsi/gsi_util/.gitignore
@@ -0,0 +1,5 @@
+bin/
+lib/
+lib64/
+gsi_util.bin
+gsi_util.zip
diff --git a/gsi/gsi_util/README.md b/gsi/gsi_util/README.md
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gsi/gsi_util/README.md
diff --git a/gsi/gsi_util/build.py b/gsi/gsi_util/build.py
new file mode 100755
index 0000000..c8e09c7
--- /dev/null
+++ b/gsi/gsi_util/build.py
@@ -0,0 +1,158 @@
+#!/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.
+"""A utility to build and pack gsi_util."""
+
+import argparse
+from collections import namedtuple
+import errno
+import logging
+import os
+import shutil
+import sys
+import zipfile
+
+from gsi_util.utils.cmd_utils import run_command
+
+_MAKE_MODULE_NAME = 'gsi_util'
+
+RequiredItem = namedtuple('RequiredItem', 'dest src')
+
+# The list of dependency modules
+# Format in (dest, src in host out)
+REQUIRED_ITEMS = [
+    # named as 'gsi_util.bin' to avoid conflict with the folder 'gsi_util'
+    RequiredItem('gsi_util.bin', 'bin/gsi_util'),
+    RequiredItem('bin/checkvintf', 'bin/checkvintf'),
+    RequiredItem('lib64/libbase.so', 'lib64/libbase.so'),
+    RequiredItem('lib64/liblog.so', 'lib64/liblog.so'),
+    RequiredItem('bin/simg2img', 'bin/simg2img'),
+    RequiredItem('lib64/libc++.so', 'lib64/libc++.so'),
+]  # pyformat: disable
+
+# Files to be included to zip file additionally
+INCLUDE_FILES = [
+    'README.md']  # pyformat: disable
+
+
+def _check_android_env():
+  if not os.environ.get('ANDROID_BUILD_TOP'):
+    raise EnvironmentError('Need \'lunch\'.')
+
+
+def _switch_to_prog_dir():
+  prog = sys.argv[0]
+  abspath = os.path.abspath(prog)
+  dirname = os.path.dirname(abspath)
+  os.chdir(dirname)
+
+
+def _make_all():
+  logging.info('Make %s...', _MAKE_MODULE_NAME)
+
+  build_top = os.environ['ANDROID_BUILD_TOP']
+  run_command(['make', '-j', _MAKE_MODULE_NAME], cwd=build_top)
+
+
+def _create_dirs_and_copy_file(dest, src):
+  dir_path = os.path.dirname(dest)
+  try:
+    if dir_path != '':
+      os.makedirs(dir_path)
+  except OSError as exc:
+    if exc.errno != errno.EEXIST:
+      raise
+  logging.debug('copy(): %s %s', src, dest)
+  shutil.copy(src, dest)
+
+
+def _copy_deps():
+  logging.info('Copy depend files...')
+  host_out = os.environ['ANDROID_HOST_OUT']
+  logging.debug('  ANDROID_HOST_OUT=%s', host_out)
+
+  for item in REQUIRED_ITEMS:
+    print 'Copy {}...'.format(item.dest)
+    full_src = os.path.join(host_out, item.src)
+    _create_dirs_and_copy_file(item.dest, full_src)
+
+
+def _build_zipfile(filename):
+  print 'Archive to {}...'.format(filename)
+  with zipfile.ZipFile(filename, mode='w') as zf:
+    for f in INCLUDE_FILES:
+      print 'Add {}'.format(f)
+      zf.write(f)
+    for f in REQUIRED_ITEMS:
+      print 'Add {}'.format(f[0])
+      zf.write(f[0])
+
+
+def do_setup_env(args):
+  _check_android_env()
+  _make_all()
+  _switch_to_prog_dir()
+  _copy_deps()
+
+
+def do_list_deps(args):
+  print 'Depend files (zip <== host out):'
+  for item in REQUIRED_ITEMS:
+    print '  {:20} <== {}'.format(item.dest, item.src)
+  print 'Other include files:'
+  for item in INCLUDE_FILES:
+    print '  {}'.format(item)
+
+
+def do_build(args):
+  _check_android_env()
+  _make_all()
+  _switch_to_prog_dir()
+  _copy_deps()
+  _build_zipfile(args.output)
+
+
+def main(argv):
+
+  parser = argparse.ArgumentParser()
+  subparsers = parser.add_subparsers(title='COMMAND')
+
+  # Command 'setup_env'
+  setup_env_parser = subparsers.add_parser(
+      'setup_env',
+      help='setup environment by building and copying dependency files')
+  setup_env_parser.set_defaults(func=do_setup_env)
+
+  # Command 'list_dep'
+  list_dep_parser = subparsers.add_parser(
+      'list_deps', help='list all dependency files')
+  list_dep_parser.set_defaults(func=do_list_deps)
+
+  # Command 'build'
+  # TODO(szuweilin@): do not add this command if this is runned by package
+  build_parser = subparsers.add_parser(
+      'build', help='build a zip file including all required files')
+  build_parser.add_argument(
+      '-o',
+      '--output',
+      default='gsi_util.zip',
+      help='the name of output zip file (default: gsi_util.zip)')
+  build_parser.set_defaults(func=do_build)
+
+  args = parser.parse_args(argv[1:])
+  args.func(args)
+
+
+if __name__ == '__main__':
+  main(sys.argv)