• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2013 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import fnmatch
6import json
7import os
8import pipes
9import shlex
10import shutil
11import subprocess
12import sys
13import traceback
14
15
16def MakeDirectory(dir_path):
17  try:
18    os.makedirs(dir_path)
19  except OSError:
20    pass
21
22
23def DeleteDirectory(dir_path):
24  if os.path.exists(dir_path):
25    shutil.rmtree(dir_path)
26
27
28def Touch(path):
29  MakeDirectory(os.path.dirname(path))
30  with open(path, 'a'):
31    os.utime(path, None)
32
33
34def FindInDirectory(directory, filter):
35  files = []
36  for root, dirnames, filenames in os.walk(directory):
37    matched_files = fnmatch.filter(filenames, filter)
38    files.extend((os.path.join(root, f) for f in matched_files))
39  return files
40
41
42def FindInDirectories(directories, filter):
43  all_files = []
44  for directory in directories:
45    all_files.extend(FindInDirectory(directory, filter))
46  return all_files
47
48
49def ParseGypList(gyp_string):
50  # The ninja generator doesn't support $ in strings, so use ## to
51  # represent $.
52  # TODO(cjhopman): Remove when
53  # https://code.google.com/p/gyp/issues/detail?id=327
54  # is addressed.
55  gyp_string = gyp_string.replace('##', '$')
56  return shlex.split(gyp_string)
57
58
59def CheckOptions(options, parser, required=[]):
60  for option_name in required:
61    if not getattr(options, option_name):
62      parser.error('--%s is required' % option_name.replace('_', '-'))
63
64def WriteJson(obj, path, only_if_changed=False):
65  old_dump = None
66  if os.path.exists(path):
67    with open(path, 'r') as oldfile:
68      old_dump = oldfile.read()
69
70  new_dump = json.dumps(obj)
71
72  if not only_if_changed or old_dump != new_dump:
73    with open(path, 'w') as outfile:
74      outfile.write(new_dump)
75
76def ReadJson(path):
77  with open(path, 'r') as jsonfile:
78    return json.load(jsonfile)
79
80
81class CalledProcessError(Exception):
82  """This exception is raised when the process run by CheckOutput
83  exits with a non-zero exit code."""
84
85  def __init__(self, cwd, args, output):
86    self.cwd = cwd
87    self.args = args
88    self.output = output
89
90  def __str__(self):
91    # A user should be able to simply copy and paste the command that failed
92    # into their shell.
93    copyable_command = '( cd {}; {} )'.format(os.path.abspath(self.cwd),
94        ' '.join(map(pipes.quote, self.args)))
95    return 'Command failed: {}\n{}'.format(copyable_command, self.output)
96
97
98# This can be used in most cases like subprocess.check_output(). The output,
99# particularly when the command fails, better highlights the command's failure.
100# If the command fails, raises a build_utils.CalledProcessError.
101def CheckOutput(args, cwd=None, print_stdout=False, print_stderr=True,
102                fail_if_stderr=False):
103  if not cwd:
104    cwd = os.getcwd()
105
106  child = subprocess.Popen(args,
107      stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd)
108  stdout, stderr = child.communicate()
109
110  if child.returncode or (stderr and fail_if_stderr):
111    raise CalledProcessError(cwd, args, stdout + stderr)
112
113  if print_stdout:
114    sys.stdout.write(stdout)
115  if print_stderr:
116    sys.stderr.write(stderr)
117
118  return stdout
119
120
121def GetModifiedTime(path):
122  # For a symlink, the modified time should be the greater of the link's
123  # modified time and the modified time of the target.
124  return max(os.lstat(path).st_mtime, os.stat(path).st_mtime)
125
126
127def IsTimeStale(output, inputs):
128  if not os.path.exists(output):
129    return True
130
131  output_time = GetModifiedTime(output)
132  for input in inputs:
133    if GetModifiedTime(input) > output_time:
134      return True
135  return False
136
137
138def IsDeviceReady():
139  device_state = CheckOutput(['adb', 'get-state'])
140  return device_state.strip() == 'device'
141
142
143def PrintWarning(message):
144  print 'WARNING: ' + message
145
146
147def PrintBigWarning(message):
148  print '*****     ' * 8
149  PrintWarning(message)
150  print '*****     ' * 8
151