1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved.
2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)# found in the LICENSE file.
4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)import contextlib
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import fnmatch
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import json
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import os
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import pipes
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import shlex
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import shutil
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import subprocess
13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import sys
14f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)import tempfile
15f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)import zipfile
16f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
17f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)CHROMIUM_SRC = os.path.join(os.path.dirname(__file__),
18f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                            os.pardir, os.pardir, os.pardir, os.pardir)
19f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)COLORAMA_ROOT = os.path.join(CHROMIUM_SRC,
20f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                             'third_party', 'colorama', 'src')
21f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
22f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
23f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)@contextlib.contextmanager
24f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)def TempDir():
25f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  dirname = tempfile.mkdtemp()
26f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  try:
27f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    yield dirname
28f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  finally:
29f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    shutil.rmtree(dirname)
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)def MakeDirectory(dir_path):
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  try:
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    os.makedirs(dir_path)
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  except OSError:
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    pass
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)def DeleteDirectory(dir_path):
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if os.path.exists(dir_path):
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    shutil.rmtree(dir_path)
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)def Touch(path):
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  MakeDirectory(os.path.dirname(path))
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  with open(path, 'a'):
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    os.utime(path, None)
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)def FindInDirectory(directory, filename_filter):
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  files = []
5223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  for root, _dirnames, filenames in os.walk(directory):
5323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    matched_files = fnmatch.filter(filenames, filename_filter)
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    files.extend((os.path.join(root, f) for f in matched_files))
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return files
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)def FindInDirectories(directories, filename_filter):
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  all_files = []
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for directory in directories:
6123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    all_files.extend(FindInDirectory(directory, filename_filter))
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return all_files
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)def ParseGypList(gyp_string):
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  # The ninja generator doesn't support $ in strings, so use ## to
67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  # represent $.
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  # TODO(cjhopman): Remove when
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  # https://code.google.com/p/gyp/issues/detail?id=327
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  # is addressed.
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  gyp_string = gyp_string.replace('##', '$')
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return shlex.split(gyp_string)
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)def CheckOptions(options, parser, required=None):
7623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if not required:
7723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for option_name in required:
79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if getattr(options, option_name) is None:
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      parser.error('--%s is required' % option_name.replace('_', '-'))
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)def WriteJson(obj, path, only_if_changed=False):
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  old_dump = None
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if os.path.exists(path):
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    with open(path, 'r') as oldfile:
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      old_dump = oldfile.read()
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
88f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  new_dump = json.dumps(obj, sort_keys=True, indent=2, separators=(',', ': '))
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if not only_if_changed or old_dump != new_dump:
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    with open(path, 'w') as outfile:
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      outfile.write(new_dump)
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)def ReadJson(path):
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  with open(path, 'r') as jsonfile:
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return json.load(jsonfile)
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
99a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class CalledProcessError(Exception):
100a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  """This exception is raised when the process run by CheckOutput
101a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  exits with a non-zero exit code."""
102a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
103a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  def __init__(self, cwd, args, output):
10423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    super(CalledProcessError, self).__init__()
105a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    self.cwd = cwd
106a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    self.args = args
107a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    self.output = output
108a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
109a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  def __str__(self):
110a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    # A user should be able to simply copy and paste the command that failed
111a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    # into their shell.
112a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    copyable_command = '( cd {}; {} )'.format(os.path.abspath(self.cwd),
113a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        ' '.join(map(pipes.quote, self.args)))
114a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return 'Command failed: {}\n{}'.format(copyable_command, self.output)
115a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
116a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
117a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)# This can be used in most cases like subprocess.check_output(). The output,
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)# particularly when the command fails, better highlights the command's failure.
119a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)# If the command fails, raises a build_utils.CalledProcessError.
120f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)def CheckOutput(args, cwd=None,
121f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                print_stdout=False, print_stderr=True,
122f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                stdout_filter=None,
123f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                stderr_filter=None,
1240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                fail_func=lambda returncode, stderr: returncode != 0):
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if not cwd:
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    cwd = os.getcwd()
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  child = subprocess.Popen(args,
129f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd)
130f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  stdout, stderr = child.communicate()
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
132f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if stdout_filter is not None:
133f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    stdout = stdout_filter(stdout)
134f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
135f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if stderr_filter is not None:
136f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    stderr = stderr_filter(stderr)
137f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
1380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if fail_func(child.returncode, stderr):
139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    raise CalledProcessError(cwd, args, stdout + stderr)
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
141a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if print_stdout:
142a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    sys.stdout.write(stdout)
143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if print_stderr:
144a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    sys.stderr.write(stderr)
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
146a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return stdout
147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)def GetModifiedTime(path):
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  # For a symlink, the modified time should be the greater of the link's
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  # modified time and the modified time of the target.
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return max(os.lstat(path).st_mtime, os.stat(path).st_mtime)
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)def IsTimeStale(output, inputs):
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if not os.path.exists(output):
157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return True
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  output_time = GetModifiedTime(output)
16023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  for i in inputs:
16123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    if GetModifiedTime(i) > output_time:
162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return True
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return False
164b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
165b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
166b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)def IsDeviceReady():
167a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  device_state = CheckOutput(['adb', 'get-state'])
168b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return device_state.strip() == 'device'
169b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
170b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
171f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)def CheckZipPath(name):
172f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if os.path.normpath(name) != name:
173f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    raise Exception('Non-canonical zip path: %s' % name)
174f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if os.path.isabs(name):
175f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    raise Exception('Absolute zip path: %s' % name)
176f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
177f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
178f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)def ExtractAll(zip_path, path=None, no_clobber=True):
179f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if path is None:
180f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    path = os.getcwd()
181f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  elif not os.path.exists(path):
182f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    MakeDirectory(path)
183f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
184f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  with zipfile.ZipFile(zip_path) as z:
185f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    for name in z.namelist():
186f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      CheckZipPath(name)
187f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      if no_clobber:
188f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        output_path = os.path.join(path, name)
189f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        if os.path.exists(output_path):
190f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          raise Exception(
191f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)              'Path already exists from zip: %s %s %s'
192f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)              % (zip_path, name, output_path))
193f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
194f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    z.extractall(path=path)
195f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
196f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
197f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)def DoZip(inputs, output, base_dir):
198f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  with zipfile.ZipFile(output, 'w') as outfile:
199f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    for f in inputs:
200f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      CheckZipPath(os.path.relpath(f, base_dir))
201f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      outfile.write(f, os.path.relpath(f, base_dir))
202f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
203f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
204b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)def PrintWarning(message):
205b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  print 'WARNING: ' + message
206b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
207b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
208b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)def PrintBigWarning(message):
209b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  print '*****     ' * 8
210b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  PrintWarning(message)
211b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  print '*****     ' * 8
212