1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#!/usr/bin/pyton
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot# Copyright 2017 Google Inc.
4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#
5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot# Use of this source code is governed by a BSD-style license that can be
6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot# found in the LICENSE file.
7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotimport os
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotimport sys
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotimport subprocess
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotimport multiprocessing
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotfrom argparse import ArgumentParser
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotREADME = """
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSimply run
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot\033[36m
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    python {0} TEST_GIT_BRANCH
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot\033[0m
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotto see if TEST_GIT_BRANCH has performance regressions against master in 8888.
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotTo compare a specific config with svg and skp resources included, add --config
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotand --extraarg option. For exampe,
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot\033[36m
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    python {0} TEST_GIT_BRANCH --config gl \\
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        --extraarg "--svgs ~/Desktop/bots/svgs --skps ~/Desktop/bots/skps"
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot\033[0m
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotFor more options, please see
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    python {0} --help
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot""".format(__file__)
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotCURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotAB_SCRIPT = "ab.py"
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotdef parse_args():
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  if len(sys.argv) <= 1 or sys.argv[1] == '-h' or sys.argv[1] == '--help':
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    print README
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  parser = ArgumentParser(
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    description='Noiselessly (hence calm) becnhmark a git branch against ' +
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                'another baseline branch (e.g., master) using multiple ' +
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                ' nanobench runs.'
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  )
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  default_threads = max(1, multiprocessing.cpu_count() / 2);
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  default_skiadir = os.path.normpath(CURRENT_DIR + "/../../")
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  config_help = (
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      'nanobench config; we currently support only one config '
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      'at a time (default: %(default)s)')
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  reps_help = (
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      'initial repititions of the nanobench run; this may be '
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      'overridden when we have many threads (default: %(default)s)')
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  extraarg_help = (
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      'nanobench args (example: --svgs ~/Desktop/bots/svgs --skps '
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      '~/Desktop/bots/skps)')
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  baseline_help = (
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      'baseline branch to compare against (default: %(default)s)')
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  basearg_help = (
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      'nanobench arg for the baseline branch; if not given, we use '
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      ' the same arg for both the test branch and the baseline branch')
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  threads_help = (
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      'number of threads to be used (default: %(default)s); '
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      'for GPU config, this will always be 1')
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  no_compile_help = (
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      'whether NOT to compile nanobench and copy it to WRITEDIR '
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      '(i.e., reuse previous nanobench compiled)')
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  skip_base_help = (
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      'whether NOT to run nanobench on baseline branch '
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      '(i.e., reuse previous baseline measurements)')
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  noinit_help = (
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      'whether to skip initial nanobench runs (default: %(default)s)')
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  branch_help = (
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      "the test branch to benchmark; if it's 'modified', we'll benchmark the "
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      "current modified code against 'git stash'.")
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  definitions = [
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    # argname, type, default value, help
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    ['--config',    str, '8888', config_help],
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    ['--skiadir',   str, default_skiadir, 'default: %(default)s'],
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    ['--ninjadir',  str, 'out/Release', 'default: %(default)s'],
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    ['--writedir',  str, '/var/tmp', 'default: %(default)s'],
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    ['--extraarg',  str, '', extraarg_help],
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    ['--baseline',  str, 'master', baseline_help],
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    ['--basearg',   str, '', basearg_help],
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    ['--reps',      int, 2, reps_help],
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    ['--threads',   int, default_threads, threads_help],
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  ]
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  for d in definitions:
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    parser.add_argument(d[0], type=d[1], default=d[2], help=d[3])
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  parser.add_argument('branch', type=str, help=branch_help)
98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  parser.add_argument('--no-compile', dest='no_compile', action="store_true",
99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      help=no_compile_help)
100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  parser.add_argument('--skip-base', dest='skipbase', action="store_true",
101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      help=skip_base_help)
102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  parser.add_argument('--noinit', dest='noinit', action="store_true",
103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      help=noinit_help)
104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  parser.add_argument('--concise', dest='concise', action="store_true",
105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      help="If set, no verbose thread info will be printed.")
106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  parser.set_defaults(no_compile=False);
107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  parser.set_defaults(skipbase=False);
108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  parser.set_defaults(noinit=False);
109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  parser.set_defaults(concise=False);
110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  # Additional args for bots
112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  BHELP = "bot specific options"
113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  parser.add_argument('--githash', type=str, help=BHELP)
114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  parser.add_argument('--keys', type=str, default=[], nargs='+', help=BHELP)
115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  args = parser.parse_args()
117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  if not args.basearg:
118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    args.basearg = args.extraarg
119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  return args
121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotdef nano_path(args, branch):
124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  return args.writedir + '/nanobench_' + branch
125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotdef compile_branch(args, branch):
128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  print "Compiling branch %s" % args.branch
129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  commands = [
131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    ['git', 'checkout', branch],
132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    ['gclient', 'sync'],
133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    ['ninja', '-C', args.ninjadir, 'nanobench'],
134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    ['cp', args.ninjadir + '/nanobench', nano_path(args, branch)]
135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  ]
136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  for command in commands:
137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    subprocess.check_call(command, cwd=args.skiadir)
138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotdef compile_modified(args):
141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  print "Compiling modified code"
142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  subprocess.check_call(
143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      ['ninja', '-C', args.ninjadir, 'nanobench'], cwd=args.skiadir)
144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  subprocess.check_call(
145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      ['cp', args.ninjadir + '/nanobench', nano_path(args, args.branch)],
146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      cwd=args.skiadir)
147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  print "Compiling stashed code"
149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  stash_output = subprocess.check_output(['git', 'stash'], cwd=args.skiadir)
150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  if 'No local changes to save' in stash_output:
151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    subprocess.check_call(['git', 'reset', 'HEAD^', '--soft'])
152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    subprocess.check_call(['git', 'stash'])
153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  subprocess.check_call(['gclient', 'sync'], cwd=args.skiadir)
155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  subprocess.check_call(
156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      ['ninja', '-C', args.ninjadir, 'nanobench'], cwd=args.skiadir)
157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  subprocess.check_call(
158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      ['cp', args.ninjadir + '/nanobench', nano_path(args, args.baseline)],
159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      cwd=args.skiadir)
160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  subprocess.check_call(['git', 'stash', 'pop'], cwd=args.skiadir)
161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotdef compile_nanobench(args):
163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  if args.branch == 'modified':
164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    compile_modified(args)
165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  else:
166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    compile_branch(args, args.branch)
167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    compile_branch(args, args.baseline)
168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotdef main():
171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  args = parse_args()
172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  # copy in case that it will be gone after git branch switching
174fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  orig_ab_name = CURRENT_DIR + "/" + AB_SCRIPT
175fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  temp_ab_name = args.writedir + "/" + AB_SCRIPT
176fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  subprocess.check_call(['cp', orig_ab_name, temp_ab_name])
177fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
178fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  if not args.no_compile:
179fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    compile_nanobench(args)
180fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
181fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  command = [
182fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    'python',
183fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    temp_ab_name,
184fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    args.writedir,
185fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    args.branch + ("_A" if args.branch == args.baseline else ""),
186fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    args.baseline + ("_B" if args.branch == args.baseline else ""),
187fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    nano_path(args, args.branch),
188fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    nano_path(args, args.baseline),
189fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    args.extraarg,
190fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    args.basearg,
191fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    str(args.reps),
192fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    "true" if args.skipbase else "false",
193fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    args.config,
194fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    str(args.threads if args.config in ["8888", "565"] else 1),
195fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    "true" if args.noinit else "false"
196fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  ]
197fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
198fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  if args.githash:
199fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    command += ['--githash', args.githash]
200fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  if args.keys:
201fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    command += (['--keys'] + args.keys)
202fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
203fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  if args.concise:
204fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    command.append("--concise")
205fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
206fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  p = subprocess.Popen(command, cwd=args.skiadir)
207fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  try:
208fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    p.wait()
209fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  except KeyboardInterrupt:
210fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    try:
211fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      p.terminate()
212fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    except OSError as e:
213fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot      print e
214fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
215fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
216fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotif __name__ == "__main__":
217fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot  main()
218