xref: /aosp_15_r20/external/skia/tools/git-sync-deps (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker#!/usr/bin/python3
2*c8dee2aaSAndroid Build Coastguard Worker# Copyright 2014 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker#
4*c8dee2aaSAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker# found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker"""Parse a DEPS file and git checkout all of the dependencies.
9*c8dee2aaSAndroid Build Coastguard Worker
10*c8dee2aaSAndroid Build Coastguard WorkerArgs:
11*c8dee2aaSAndroid Build Coastguard Worker  An optional list of deps_os values.
12*c8dee2aaSAndroid Build Coastguard Worker
13*c8dee2aaSAndroid Build Coastguard WorkerEnvironment Variables:
14*c8dee2aaSAndroid Build Coastguard Worker  GIT_EXECUTABLE: path to "git" binary; if unset, will look for git in
15*c8dee2aaSAndroid Build Coastguard Worker  your default path.
16*c8dee2aaSAndroid Build Coastguard Worker
17*c8dee2aaSAndroid Build Coastguard Worker  GIT_SYNC_DEPS_PATH: file to get the dependency list from; if unset,
18*c8dee2aaSAndroid Build Coastguard Worker  will use the file ../DEPS relative to this script's directory.
19*c8dee2aaSAndroid Build Coastguard Worker
20*c8dee2aaSAndroid Build Coastguard Worker  GIT_SYNC_DEPS_QUIET: if set to non-empty string, suppress messages.
21*c8dee2aaSAndroid Build Coastguard Worker
22*c8dee2aaSAndroid Build Coastguard WorkerGit Config:
23*c8dee2aaSAndroid Build Coastguard Worker  To disable syncing of a single repository:
24*c8dee2aaSAndroid Build Coastguard Worker      cd path/to/repository
25*c8dee2aaSAndroid Build Coastguard Worker      git config sync-deps.disable true
26*c8dee2aaSAndroid Build Coastguard Worker
27*c8dee2aaSAndroid Build Coastguard Worker  To re-enable sync:
28*c8dee2aaSAndroid Build Coastguard Worker      cd path/to/repository
29*c8dee2aaSAndroid Build Coastguard Worker      git config --unset sync-deps.disable
30*c8dee2aaSAndroid Build Coastguard Worker"""
31*c8dee2aaSAndroid Build Coastguard Worker
32*c8dee2aaSAndroid Build Coastguard Worker
33*c8dee2aaSAndroid Build Coastguard Workerimport os
34*c8dee2aaSAndroid Build Coastguard Workerimport subprocess
35*c8dee2aaSAndroid Build Coastguard Workerimport sys
36*c8dee2aaSAndroid Build Coastguard Workerimport threading
37*c8dee2aaSAndroid Build Coastguard Worker
38*c8dee2aaSAndroid Build Coastguard Worker
39*c8dee2aaSAndroid Build Coastguard Workerdef git_executable():
40*c8dee2aaSAndroid Build Coastguard Worker  """Find the git executable.
41*c8dee2aaSAndroid Build Coastguard Worker
42*c8dee2aaSAndroid Build Coastguard Worker  Returns:
43*c8dee2aaSAndroid Build Coastguard Worker      A string suitable for passing to subprocess functions, or None.
44*c8dee2aaSAndroid Build Coastguard Worker  """
45*c8dee2aaSAndroid Build Coastguard Worker  envgit = os.environ.get('GIT_EXECUTABLE')
46*c8dee2aaSAndroid Build Coastguard Worker  searchlist = ['git', 'git.bat']
47*c8dee2aaSAndroid Build Coastguard Worker  if envgit:
48*c8dee2aaSAndroid Build Coastguard Worker    searchlist.insert(0, envgit)
49*c8dee2aaSAndroid Build Coastguard Worker  with open(os.devnull, 'w') as devnull:
50*c8dee2aaSAndroid Build Coastguard Worker    for git in searchlist:
51*c8dee2aaSAndroid Build Coastguard Worker      try:
52*c8dee2aaSAndroid Build Coastguard Worker        subprocess.call([git, '--version'], stdout=devnull)
53*c8dee2aaSAndroid Build Coastguard Worker      except (OSError,):
54*c8dee2aaSAndroid Build Coastguard Worker        continue
55*c8dee2aaSAndroid Build Coastguard Worker      return git
56*c8dee2aaSAndroid Build Coastguard Worker  return None
57*c8dee2aaSAndroid Build Coastguard Worker
58*c8dee2aaSAndroid Build Coastguard Worker
59*c8dee2aaSAndroid Build Coastguard WorkerDEFAULT_DEPS_PATH = os.path.normpath(
60*c8dee2aaSAndroid Build Coastguard Worker  os.path.join(os.path.dirname(__file__), os.pardir, 'DEPS'))
61*c8dee2aaSAndroid Build Coastguard Worker
62*c8dee2aaSAndroid Build Coastguard Worker
63*c8dee2aaSAndroid Build Coastguard Workerdef usage(deps_file_path = None):
64*c8dee2aaSAndroid Build Coastguard Worker  sys.stderr.write(
65*c8dee2aaSAndroid Build Coastguard Worker    'Usage: run to grab dependencies, with optional platform support:\n')
66*c8dee2aaSAndroid Build Coastguard Worker  sys.stderr.write('  %s %s' % (sys.executable, __file__))
67*c8dee2aaSAndroid Build Coastguard Worker  if deps_file_path:
68*c8dee2aaSAndroid Build Coastguard Worker    parsed_deps = parse_file_to_dict(deps_file_path)
69*c8dee2aaSAndroid Build Coastguard Worker    if 'deps_os' in parsed_deps:
70*c8dee2aaSAndroid Build Coastguard Worker      for deps_os in parsed_deps['deps_os']:
71*c8dee2aaSAndroid Build Coastguard Worker        sys.stderr.write(' [%s]' % deps_os)
72*c8dee2aaSAndroid Build Coastguard Worker  sys.stderr.write('\n\n')
73*c8dee2aaSAndroid Build Coastguard Worker  sys.stderr.write(__doc__)
74*c8dee2aaSAndroid Build Coastguard Worker
75*c8dee2aaSAndroid Build Coastguard Worker
76*c8dee2aaSAndroid Build Coastguard Workerdef git_repository_sync_is_disabled(git, directory):
77*c8dee2aaSAndroid Build Coastguard Worker  try:
78*c8dee2aaSAndroid Build Coastguard Worker    disable = subprocess.check_output(
79*c8dee2aaSAndroid Build Coastguard Worker      [git, 'config', 'sync-deps.disable'], cwd=directory)
80*c8dee2aaSAndroid Build Coastguard Worker    return disable.lower().strip() in ['true', '1', 'yes', 'on']
81*c8dee2aaSAndroid Build Coastguard Worker  except subprocess.CalledProcessError:
82*c8dee2aaSAndroid Build Coastguard Worker    return False
83*c8dee2aaSAndroid Build Coastguard Worker
84*c8dee2aaSAndroid Build Coastguard Worker
85*c8dee2aaSAndroid Build Coastguard Workerdef is_git_toplevel(git, directory):
86*c8dee2aaSAndroid Build Coastguard Worker  """Return true iff the directory is the top level of a Git repository.
87*c8dee2aaSAndroid Build Coastguard Worker
88*c8dee2aaSAndroid Build Coastguard Worker  Args:
89*c8dee2aaSAndroid Build Coastguard Worker    git (string) the git executable
90*c8dee2aaSAndroid Build Coastguard Worker
91*c8dee2aaSAndroid Build Coastguard Worker    directory (string) the path into which the repository
92*c8dee2aaSAndroid Build Coastguard Worker              is expected to be checked out.
93*c8dee2aaSAndroid Build Coastguard Worker  """
94*c8dee2aaSAndroid Build Coastguard Worker  try:
95*c8dee2aaSAndroid Build Coastguard Worker    toplevel = subprocess.check_output(
96*c8dee2aaSAndroid Build Coastguard Worker      [git, 'rev-parse', '--show-toplevel'], cwd=directory).strip()
97*c8dee2aaSAndroid Build Coastguard Worker    return (os.path.normcase(os.path.realpath(directory)) ==
98*c8dee2aaSAndroid Build Coastguard Worker            os.path.normcase(os.path.realpath(toplevel.decode())))
99*c8dee2aaSAndroid Build Coastguard Worker  except subprocess.CalledProcessError:
100*c8dee2aaSAndroid Build Coastguard Worker    return False
101*c8dee2aaSAndroid Build Coastguard Worker
102*c8dee2aaSAndroid Build Coastguard Worker
103*c8dee2aaSAndroid Build Coastguard Workerdef status(directory, commithash, change):
104*c8dee2aaSAndroid Build Coastguard Worker  def truncate_beginning(s, length):
105*c8dee2aaSAndroid Build Coastguard Worker    return s if len(s) <= length else '...' + s[-(length-3):]
106*c8dee2aaSAndroid Build Coastguard Worker  def truncate_end(s, length):
107*c8dee2aaSAndroid Build Coastguard Worker    return s if len(s) <= length else s[:(length - 3)] + '...'
108*c8dee2aaSAndroid Build Coastguard Worker
109*c8dee2aaSAndroid Build Coastguard Worker  dlen = 36
110*c8dee2aaSAndroid Build Coastguard Worker  directory = truncate_beginning(directory, dlen)
111*c8dee2aaSAndroid Build Coastguard Worker  commithash = truncate_end(commithash, 40)
112*c8dee2aaSAndroid Build Coastguard Worker  symbol = '>' if change else '@'
113*c8dee2aaSAndroid Build Coastguard Worker  sys.stdout.write('%-*s %s %s\n' % (dlen, directory, symbol, commithash))
114*c8dee2aaSAndroid Build Coastguard Worker
115*c8dee2aaSAndroid Build Coastguard Worker
116*c8dee2aaSAndroid Build Coastguard Workerdef git_checkout_to_directory(git, repo, commithash, directory, shallow, verbose):
117*c8dee2aaSAndroid Build Coastguard Worker  """Checkout (and clone if needed) a Git repository.
118*c8dee2aaSAndroid Build Coastguard Worker
119*c8dee2aaSAndroid Build Coastguard Worker  Args:
120*c8dee2aaSAndroid Build Coastguard Worker    git (string) the git executable
121*c8dee2aaSAndroid Build Coastguard Worker
122*c8dee2aaSAndroid Build Coastguard Worker    repo (string) the location of the repository, suitable
123*c8dee2aaSAndroid Build Coastguard Worker         for passing to `git clone`.
124*c8dee2aaSAndroid Build Coastguard Worker
125*c8dee2aaSAndroid Build Coastguard Worker    commithash (string) a commit, suitable for passing to `git checkout`
126*c8dee2aaSAndroid Build Coastguard Worker
127*c8dee2aaSAndroid Build Coastguard Worker    directory (string) the path into which the repository
128*c8dee2aaSAndroid Build Coastguard Worker              should be checked out.
129*c8dee2aaSAndroid Build Coastguard Worker
130*c8dee2aaSAndroid Build Coastguard Worker    verbose (boolean)
131*c8dee2aaSAndroid Build Coastguard Worker
132*c8dee2aaSAndroid Build Coastguard Worker  Raises an exception if any calls to git fail.
133*c8dee2aaSAndroid Build Coastguard Worker  """
134*c8dee2aaSAndroid Build Coastguard Worker  if not os.path.isdir(directory):
135*c8dee2aaSAndroid Build Coastguard Worker    subprocess.check_call(
136*c8dee2aaSAndroid Build Coastguard Worker      [git, 'clone', '--quiet', *(['--depth=1'] if shallow else []),
137*c8dee2aaSAndroid Build Coastguard Worker       '--no-checkout', repo, directory])
138*c8dee2aaSAndroid Build Coastguard Worker
139*c8dee2aaSAndroid Build Coastguard Worker  if not is_git_toplevel(git, directory):
140*c8dee2aaSAndroid Build Coastguard Worker    # if the directory exists, but isn't a git repo, you will modify
141*c8dee2aaSAndroid Build Coastguard Worker    # the parent repository, which isn't what you want.
142*c8dee2aaSAndroid Build Coastguard Worker    sys.stdout.write('%s\n  IS NOT TOP-LEVEL GIT DIRECTORY.\n' % directory)
143*c8dee2aaSAndroid Build Coastguard Worker    return
144*c8dee2aaSAndroid Build Coastguard Worker
145*c8dee2aaSAndroid Build Coastguard Worker  # Check to see if this repo is disabled.  Quick return.
146*c8dee2aaSAndroid Build Coastguard Worker  if git_repository_sync_is_disabled(git, directory):
147*c8dee2aaSAndroid Build Coastguard Worker    sys.stdout.write('%s\n  SYNC IS DISABLED.\n' % directory)
148*c8dee2aaSAndroid Build Coastguard Worker    return
149*c8dee2aaSAndroid Build Coastguard Worker
150*c8dee2aaSAndroid Build Coastguard Worker  with open(os.devnull, 'w') as devnull:
151*c8dee2aaSAndroid Build Coastguard Worker    # If this fails, we will fetch before trying again.  Don't spam user
152*c8dee2aaSAndroid Build Coastguard Worker    # with error infomation.
153*c8dee2aaSAndroid Build Coastguard Worker    if 0 == subprocess.call([git, 'checkout', '--quiet', commithash],
154*c8dee2aaSAndroid Build Coastguard Worker                            cwd=directory, stderr=devnull):
155*c8dee2aaSAndroid Build Coastguard Worker      # if this succeeds, skip slow `git fetch`.
156*c8dee2aaSAndroid Build Coastguard Worker      if verbose:
157*c8dee2aaSAndroid Build Coastguard Worker        status(directory, commithash, False)  # Success.
158*c8dee2aaSAndroid Build Coastguard Worker      return
159*c8dee2aaSAndroid Build Coastguard Worker
160*c8dee2aaSAndroid Build Coastguard Worker  # If the repo has changed, always force use of the correct repo.
161*c8dee2aaSAndroid Build Coastguard Worker  # If origin already points to repo, this is a quick no-op.
162*c8dee2aaSAndroid Build Coastguard Worker  subprocess.check_call(
163*c8dee2aaSAndroid Build Coastguard Worker      [git, 'remote', 'set-url', 'origin', repo], cwd=directory)
164*c8dee2aaSAndroid Build Coastguard Worker
165*c8dee2aaSAndroid Build Coastguard Worker  subprocess.check_call(
166*c8dee2aaSAndroid Build Coastguard Worker    [git, 'fetch', '--quiet',
167*c8dee2aaSAndroid Build Coastguard Worker     *(['--depth=1', repo, commithash] if shallow else [])],
168*c8dee2aaSAndroid Build Coastguard Worker    cwd=directory)
169*c8dee2aaSAndroid Build Coastguard Worker
170*c8dee2aaSAndroid Build Coastguard Worker  subprocess.check_call([git, 'checkout', '--quiet', commithash], cwd=directory)
171*c8dee2aaSAndroid Build Coastguard Worker
172*c8dee2aaSAndroid Build Coastguard Worker  if verbose:
173*c8dee2aaSAndroid Build Coastguard Worker    status(directory, commithash, True)  # Success.
174*c8dee2aaSAndroid Build Coastguard Worker
175*c8dee2aaSAndroid Build Coastguard Worker
176*c8dee2aaSAndroid Build Coastguard Workerdef parse_file_to_dict(path):
177*c8dee2aaSAndroid Build Coastguard Worker  dictionary = {}
178*c8dee2aaSAndroid Build Coastguard Worker  with open(path) as f:
179*c8dee2aaSAndroid Build Coastguard Worker    exec('def Var(x): return vars[x]\n' + f.read(), dictionary)
180*c8dee2aaSAndroid Build Coastguard Worker  return dictionary
181*c8dee2aaSAndroid Build Coastguard Worker
182*c8dee2aaSAndroid Build Coastguard Worker
183*c8dee2aaSAndroid Build Coastguard Workerdef is_sha1_sum(s):
184*c8dee2aaSAndroid Build Coastguard Worker  """SHA1 sums are 160 bits, encoded as lowercase hexadecimal."""
185*c8dee2aaSAndroid Build Coastguard Worker  return len(s) == 40 and all(c in '0123456789abcdef' for c in s)
186*c8dee2aaSAndroid Build Coastguard Worker
187*c8dee2aaSAndroid Build Coastguard Worker
188*c8dee2aaSAndroid Build Coastguard Workerdef git_sync_deps(deps_file_path, command_line_os_requests, shallow, verbose):
189*c8dee2aaSAndroid Build Coastguard Worker  """Grab dependencies, with optional platform support.
190*c8dee2aaSAndroid Build Coastguard Worker
191*c8dee2aaSAndroid Build Coastguard Worker  Args:
192*c8dee2aaSAndroid Build Coastguard Worker    deps_file_path (string) Path to the DEPS file.
193*c8dee2aaSAndroid Build Coastguard Worker
194*c8dee2aaSAndroid Build Coastguard Worker    command_line_os_requests (list of strings) Can be empty list.
195*c8dee2aaSAndroid Build Coastguard Worker        List of strings that should each be a key in the deps_os
196*c8dee2aaSAndroid Build Coastguard Worker        dictionary in the DEPS file.
197*c8dee2aaSAndroid Build Coastguard Worker
198*c8dee2aaSAndroid Build Coastguard Worker  Raises git Exceptions.
199*c8dee2aaSAndroid Build Coastguard Worker  """
200*c8dee2aaSAndroid Build Coastguard Worker  git = git_executable()
201*c8dee2aaSAndroid Build Coastguard Worker  assert git
202*c8dee2aaSAndroid Build Coastguard Worker
203*c8dee2aaSAndroid Build Coastguard Worker  deps_file_directory = os.path.dirname(deps_file_path)
204*c8dee2aaSAndroid Build Coastguard Worker  deps_file = parse_file_to_dict(deps_file_path)
205*c8dee2aaSAndroid Build Coastguard Worker  dependencies = deps_file['deps'].copy()
206*c8dee2aaSAndroid Build Coastguard Worker  os_specific_dependencies = deps_file.get('deps_os', dict())
207*c8dee2aaSAndroid Build Coastguard Worker  if 'all' in command_line_os_requests:
208*c8dee2aaSAndroid Build Coastguard Worker    for value in os_specific_dependencies.itervalues():
209*c8dee2aaSAndroid Build Coastguard Worker      dependencies.update(value)
210*c8dee2aaSAndroid Build Coastguard Worker  else:
211*c8dee2aaSAndroid Build Coastguard Worker    for os_name in command_line_os_requests:
212*c8dee2aaSAndroid Build Coastguard Worker      # Add OS-specific dependencies
213*c8dee2aaSAndroid Build Coastguard Worker      if os_name in os_specific_dependencies:
214*c8dee2aaSAndroid Build Coastguard Worker        dependencies.update(os_specific_dependencies[os_name])
215*c8dee2aaSAndroid Build Coastguard Worker  for directory in dependencies:
216*c8dee2aaSAndroid Build Coastguard Worker    for other_dir in dependencies:
217*c8dee2aaSAndroid Build Coastguard Worker      if directory.startswith(other_dir + '/'):
218*c8dee2aaSAndroid Build Coastguard Worker        raise Exception('%r is parent of %r' % (other_dir, directory))
219*c8dee2aaSAndroid Build Coastguard Worker  list_of_arg_lists = []
220*c8dee2aaSAndroid Build Coastguard Worker  for directory in sorted(dependencies):
221*c8dee2aaSAndroid Build Coastguard Worker    if not isinstance(dependencies[directory], str):
222*c8dee2aaSAndroid Build Coastguard Worker      if verbose:
223*c8dee2aaSAndroid Build Coastguard Worker        sys.stdout.write( 'Skipping "%s".\n' % directory)
224*c8dee2aaSAndroid Build Coastguard Worker      continue
225*c8dee2aaSAndroid Build Coastguard Worker    if '@' in dependencies[directory]:
226*c8dee2aaSAndroid Build Coastguard Worker      repo, commithash = dependencies[directory].split('@', 1)
227*c8dee2aaSAndroid Build Coastguard Worker    else:
228*c8dee2aaSAndroid Build Coastguard Worker      raise Exception("please specify commit")
229*c8dee2aaSAndroid Build Coastguard Worker    if not is_sha1_sum(commithash):
230*c8dee2aaSAndroid Build Coastguard Worker      raise Exception("poorly formed commit hash: %r" % commithash)
231*c8dee2aaSAndroid Build Coastguard Worker
232*c8dee2aaSAndroid Build Coastguard Worker    relative_directory = os.path.join(deps_file_directory, directory)
233*c8dee2aaSAndroid Build Coastguard Worker
234*c8dee2aaSAndroid Build Coastguard Worker    list_of_arg_lists.append(
235*c8dee2aaSAndroid Build Coastguard Worker      (git, repo, commithash, relative_directory, shallow, verbose))
236*c8dee2aaSAndroid Build Coastguard Worker
237*c8dee2aaSAndroid Build Coastguard Worker  multithread(git_checkout_to_directory, list_of_arg_lists)
238*c8dee2aaSAndroid Build Coastguard Worker
239*c8dee2aaSAndroid Build Coastguard Worker
240*c8dee2aaSAndroid Build Coastguard Workerdef multithread(function, list_of_arg_lists):
241*c8dee2aaSAndroid Build Coastguard Worker  anything_failed = False
242*c8dee2aaSAndroid Build Coastguard Worker  threads = []
243*c8dee2aaSAndroid Build Coastguard Worker  def hook(args):
244*c8dee2aaSAndroid Build Coastguard Worker    nonlocal anything_failed
245*c8dee2aaSAndroid Build Coastguard Worker    anything_failed = True
246*c8dee2aaSAndroid Build Coastguard Worker  threading.excepthook = hook
247*c8dee2aaSAndroid Build Coastguard Worker  for args in list_of_arg_lists:
248*c8dee2aaSAndroid Build Coastguard Worker    thread = threading.Thread(None, function, None, args)
249*c8dee2aaSAndroid Build Coastguard Worker    thread.start()
250*c8dee2aaSAndroid Build Coastguard Worker    threads.append(thread)
251*c8dee2aaSAndroid Build Coastguard Worker  for thread in threads:
252*c8dee2aaSAndroid Build Coastguard Worker    thread.join()
253*c8dee2aaSAndroid Build Coastguard Worker  if anything_failed:
254*c8dee2aaSAndroid Build Coastguard Worker    raise Exception("Thread failure detected")
255*c8dee2aaSAndroid Build Coastguard Worker
256*c8dee2aaSAndroid Build Coastguard Worker
257*c8dee2aaSAndroid Build Coastguard Workerdef main(argv):
258*c8dee2aaSAndroid Build Coastguard Worker  deps_file_path = os.environ.get('GIT_SYNC_DEPS_PATH', DEFAULT_DEPS_PATH)
259*c8dee2aaSAndroid Build Coastguard Worker  verbose = not bool(os.environ.get('GIT_SYNC_DEPS_QUIET', False))
260*c8dee2aaSAndroid Build Coastguard Worker  skip_emsdk = bool(os.environ.get('GIT_SYNC_DEPS_SKIP_EMSDK', False))
261*c8dee2aaSAndroid Build Coastguard Worker  shallow = not ('--deep' in argv)
262*c8dee2aaSAndroid Build Coastguard Worker
263*c8dee2aaSAndroid Build Coastguard Worker  if '--help' in argv or '-h' in argv:
264*c8dee2aaSAndroid Build Coastguard Worker    usage(deps_file_path)
265*c8dee2aaSAndroid Build Coastguard Worker    return 1
266*c8dee2aaSAndroid Build Coastguard Worker
267*c8dee2aaSAndroid Build Coastguard Worker  git_sync_deps(deps_file_path, argv, shallow, verbose)
268*c8dee2aaSAndroid Build Coastguard Worker  subprocess.check_call(
269*c8dee2aaSAndroid Build Coastguard Worker      [sys.executable,
270*c8dee2aaSAndroid Build Coastguard Worker       os.path.join(os.path.dirname(deps_file_path), 'bin', 'fetch-gn')])
271*c8dee2aaSAndroid Build Coastguard Worker  if not skip_emsdk:
272*c8dee2aaSAndroid Build Coastguard Worker    subprocess.check_call(
273*c8dee2aaSAndroid Build Coastguard Worker        [sys.executable,
274*c8dee2aaSAndroid Build Coastguard Worker         os.path.join(os.path.dirname(deps_file_path), 'bin', 'activate-emsdk')])
275*c8dee2aaSAndroid Build Coastguard Worker  return 0
276*c8dee2aaSAndroid Build Coastguard Worker
277*c8dee2aaSAndroid Build Coastguard Worker
278*c8dee2aaSAndroid Build Coastguard Workerif __name__ == '__main__':
279*c8dee2aaSAndroid Build Coastguard Worker  exit(main(sys.argv[1:]))
280