1#!/usr/bin/env python
2# Copyright 2017 - The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#     http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15"""A utility to build and pack gsi_util."""
16
17import argparse
18from collections import namedtuple
19import errno
20import logging
21import os
22import shutil
23import sys
24import zipfile
25
26from gsi_util.utils.cmd_utils import run_command
27
28_MAKE_MODULE_NAME = 'gsi_util'
29
30RequiredItem = namedtuple('RequiredItem', 'dest src')
31
32# The list of dependency modules
33# Format in (dest, src in host out)
34REQUIRED_ITEMS = [
35    # named as 'gsi_util.bin' to avoid conflict with the folder 'gsi_util'
36    RequiredItem('gsi_util.bin', 'bin/gsi_util'),
37    RequiredItem('bin/checkvintf', 'bin/checkvintf'),
38    RequiredItem('lib64/libbase.so', 'lib64/libbase.so'),
39    RequiredItem('lib64/liblog.so', 'lib64/liblog.so'),
40    RequiredItem('bin/secilc', 'bin/secilc'),
41    RequiredItem('lib64/libsepol.so', 'lib64/libsepol.so'),
42    RequiredItem('bin/simg2img', 'bin/simg2img'),
43    RequiredItem('lib64/libc++.so', 'lib64/libc++.so'),
44]  # pyformat: disable
45
46# Files to be included to zip file additionally
47INCLUDE_FILES = [
48    'README.md']  # pyformat: disable
49
50
51def _check_android_env():
52  if not os.environ.get('ANDROID_BUILD_TOP'):
53    raise EnvironmentError('Need \'lunch\'.')
54
55
56def _switch_to_prog_dir():
57  prog = sys.argv[0]
58  abspath = os.path.abspath(prog)
59  dirname = os.path.dirname(abspath)
60  os.chdir(dirname)
61
62
63def _make_all():
64  logging.info('Make %s...', _MAKE_MODULE_NAME)
65
66  build_top = os.environ['ANDROID_BUILD_TOP']
67  run_command(['make', '-j', _MAKE_MODULE_NAME], cwd=build_top)
68
69
70def _create_dirs_and_copy_file(dest, src):
71  dir_path = os.path.dirname(dest)
72  try:
73    if dir_path != '':
74      os.makedirs(dir_path)
75  except OSError as exc:
76    if exc.errno != errno.EEXIST:
77      raise
78  logging.debug('copy(): %s %s', src, dest)
79  shutil.copy(src, dest)
80
81
82def _copy_deps():
83  logging.info('Copy depend files...')
84  host_out = os.environ['ANDROID_HOST_OUT']
85  logging.debug('  ANDROID_HOST_OUT=%s', host_out)
86
87  for item in REQUIRED_ITEMS:
88    print 'Copy {}...'.format(item.dest)
89    full_src = os.path.join(host_out, item.src)
90    _create_dirs_and_copy_file(item.dest, full_src)
91
92
93def _build_zipfile(filename):
94  print 'Archive to {}...'.format(filename)
95  with zipfile.ZipFile(filename, mode='w') as zf:
96    for f in INCLUDE_FILES:
97      print 'Add {}'.format(f)
98      zf.write(f)
99    for f in REQUIRED_ITEMS:
100      print 'Add {}'.format(f[0])
101      zf.write(f[0])
102
103
104def do_setup_env(args):
105  _check_android_env()
106  _make_all()
107  _switch_to_prog_dir()
108  _copy_deps()
109
110
111def do_list_deps(args):
112  print 'Depend files (zip <== host out):'
113  for item in REQUIRED_ITEMS:
114    print '  {:20} <== {}'.format(item.dest, item.src)
115  print 'Other include files:'
116  for item in INCLUDE_FILES:
117    print '  {}'.format(item)
118
119
120def do_build(args):
121  _check_android_env()
122  _make_all()
123  _switch_to_prog_dir()
124  _copy_deps()
125  _build_zipfile(args.output)
126
127
128def main(argv):
129
130  parser = argparse.ArgumentParser()
131  subparsers = parser.add_subparsers(title='COMMAND')
132
133  # Command 'setup_env'
134  setup_env_parser = subparsers.add_parser(
135      'setup_env',
136      help='setup environment by building and copying dependency files')
137  setup_env_parser.set_defaults(func=do_setup_env)
138
139  # Command 'list_dep'
140  list_dep_parser = subparsers.add_parser(
141      'list_deps', help='list all dependency files')
142  list_dep_parser.set_defaults(func=do_list_deps)
143
144  # Command 'build'
145  # TODO(szuweilin@): do not add this command if this is runned by package
146  build_parser = subparsers.add_parser(
147      'build', help='build a zip file including all required files')
148  build_parser.add_argument(
149      '-o',
150      '--output',
151      default='gsi_util.zip',
152      help='the name of output zip file (default: gsi_util.zip)')
153  build_parser.set_defaults(func=do_build)
154
155  args = parser.parse_args(argv[1:])
156  args.func(args)
157
158
159if __name__ == '__main__':
160  main(sys.argv)
161