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