| Index: build/android/gyp/util/build_utils.py
|
| diff --git a/build/android/gyp/util/build_utils.py b/build/android/gyp/util/build_utils.py
|
| deleted file mode 100644
|
| index 65b1a643c26a2ca920ff176af40bfcad85057f3d..0000000000000000000000000000000000000000
|
| --- a/build/android/gyp/util/build_utils.py
|
| +++ /dev/null
|
| @@ -1,376 +0,0 @@
|
| -# Copyright 2013 The Chromium Authors. All rights reserved.
|
| -# Use of this source code is governed by a BSD-style license that can be
|
| -# found in the LICENSE file.
|
| -
|
| -import ast
|
| -import contextlib
|
| -import fnmatch
|
| -import json
|
| -import os
|
| -import pipes
|
| -import re
|
| -import shlex
|
| -import shutil
|
| -import subprocess
|
| -import sys
|
| -import tempfile
|
| -import zipfile
|
| -
|
| -
|
| -CHROMIUM_SRC = os.path.normpath(
|
| - os.path.join(os.path.dirname(__file__),
|
| - os.pardir, os.pardir, os.pardir, os.pardir))
|
| -COLORAMA_ROOT = os.path.join(CHROMIUM_SRC,
|
| - 'third_party', 'colorama', 'src')
|
| -# aapt should ignore OWNERS files in addition the default ignore pattern.
|
| -AAPT_IGNORE_PATTERN = ('!OWNERS:!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:' +
|
| - '!CVS:!thumbs.db:!picasa.ini:!*~:!*.d.stamp')
|
| -
|
| -
|
| -@contextlib.contextmanager
|
| -def TempDir():
|
| - dirname = tempfile.mkdtemp()
|
| - try:
|
| - yield dirname
|
| - finally:
|
| - shutil.rmtree(dirname)
|
| -
|
| -
|
| -def MakeDirectory(dir_path):
|
| - try:
|
| - os.makedirs(dir_path)
|
| - except OSError:
|
| - pass
|
| -
|
| -
|
| -def DeleteDirectory(dir_path):
|
| - if os.path.exists(dir_path):
|
| - shutil.rmtree(dir_path)
|
| -
|
| -
|
| -def Touch(path, fail_if_missing=False):
|
| - if fail_if_missing and not os.path.exists(path):
|
| - raise Exception(path + ' doesn\'t exist.')
|
| -
|
| - MakeDirectory(os.path.dirname(path))
|
| - with open(path, 'a'):
|
| - os.utime(path, None)
|
| -
|
| -
|
| -def FindInDirectory(directory, filename_filter):
|
| - files = []
|
| - for root, _dirnames, filenames in os.walk(directory):
|
| - matched_files = fnmatch.filter(filenames, filename_filter)
|
| - files.extend((os.path.join(root, f) for f in matched_files))
|
| - return files
|
| -
|
| -
|
| -def FindInDirectories(directories, filename_filter):
|
| - all_files = []
|
| - for directory in directories:
|
| - all_files.extend(FindInDirectory(directory, filename_filter))
|
| - return all_files
|
| -
|
| -
|
| -def ParseGnList(gn_string):
|
| - return ast.literal_eval(gn_string)
|
| -
|
| -
|
| -def ParseGypList(gyp_string):
|
| - # The ninja generator doesn't support $ in strings, so use ## to
|
| - # represent $.
|
| - # TODO(cjhopman): Remove when
|
| - # https://code.google.com/p/gyp/issues/detail?id=327
|
| - # is addressed.
|
| - gyp_string = gyp_string.replace('##', '$')
|
| -
|
| - if gyp_string.startswith('['):
|
| - return ParseGnList(gyp_string)
|
| - return shlex.split(gyp_string)
|
| -
|
| -
|
| -def CheckOptions(options, parser, required=None):
|
| - if not required:
|
| - return
|
| - for option_name in required:
|
| - if getattr(options, option_name) is None:
|
| - parser.error('--%s is required' % option_name.replace('_', '-'))
|
| -
|
| -
|
| -def WriteJson(obj, path, only_if_changed=False):
|
| - old_dump = None
|
| - if os.path.exists(path):
|
| - with open(path, 'r') as oldfile:
|
| - old_dump = oldfile.read()
|
| -
|
| - new_dump = json.dumps(obj, sort_keys=True, indent=2, separators=(',', ': '))
|
| -
|
| - if not only_if_changed or old_dump != new_dump:
|
| - with open(path, 'w') as outfile:
|
| - outfile.write(new_dump)
|
| -
|
| -
|
| -def ReadJson(path):
|
| - with open(path, 'r') as jsonfile:
|
| - return json.load(jsonfile)
|
| -
|
| -
|
| -class CalledProcessError(Exception):
|
| - """This exception is raised when the process run by CheckOutput
|
| - exits with a non-zero exit code."""
|
| -
|
| - def __init__(self, cwd, args, output):
|
| - super(CalledProcessError, self).__init__()
|
| - self.cwd = cwd
|
| - self.args = args
|
| - self.output = output
|
| -
|
| - def __str__(self):
|
| - # A user should be able to simply copy and paste the command that failed
|
| - # into their shell.
|
| - copyable_command = '( cd {}; {} )'.format(os.path.abspath(self.cwd),
|
| - ' '.join(map(pipes.quote, self.args)))
|
| - return 'Command failed: {}\n{}'.format(copyable_command, self.output)
|
| -
|
| -
|
| -# This can be used in most cases like subprocess.check_output(). The output,
|
| -# particularly when the command fails, better highlights the command's failure.
|
| -# If the command fails, raises a build_utils.CalledProcessError.
|
| -def CheckOutput(args, cwd=None,
|
| - print_stdout=False, print_stderr=True,
|
| - stdout_filter=None,
|
| - stderr_filter=None,
|
| - fail_func=lambda returncode, stderr: returncode != 0):
|
| - if not cwd:
|
| - cwd = os.getcwd()
|
| -
|
| - child = subprocess.Popen(args,
|
| - stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd)
|
| - stdout, stderr = child.communicate()
|
| -
|
| - if stdout_filter is not None:
|
| - stdout = stdout_filter(stdout)
|
| -
|
| - if stderr_filter is not None:
|
| - stderr = stderr_filter(stderr)
|
| -
|
| - if fail_func(child.returncode, stderr):
|
| - raise CalledProcessError(cwd, args, stdout + stderr)
|
| -
|
| - if print_stdout:
|
| - sys.stdout.write(stdout)
|
| - if print_stderr:
|
| - sys.stderr.write(stderr)
|
| -
|
| - return stdout
|
| -
|
| -
|
| -def GetModifiedTime(path):
|
| - # For a symlink, the modified time should be the greater of the link's
|
| - # modified time and the modified time of the target.
|
| - return max(os.lstat(path).st_mtime, os.stat(path).st_mtime)
|
| -
|
| -
|
| -def IsTimeStale(output, inputs):
|
| - if not os.path.exists(output):
|
| - return True
|
| -
|
| - output_time = GetModifiedTime(output)
|
| - for i in inputs:
|
| - if GetModifiedTime(i) > output_time:
|
| - return True
|
| - return False
|
| -
|
| -
|
| -def IsDeviceReady():
|
| - device_state = CheckOutput(['adb', 'get-state'])
|
| - return device_state.strip() == 'device'
|
| -
|
| -
|
| -def CheckZipPath(name):
|
| - if os.path.normpath(name) != name:
|
| - raise Exception('Non-canonical zip path: %s' % name)
|
| - if os.path.isabs(name):
|
| - raise Exception('Absolute zip path: %s' % name)
|
| -
|
| -
|
| -def ExtractAll(zip_path, path=None, no_clobber=True, pattern=None):
|
| - if path is None:
|
| - path = os.getcwd()
|
| - elif not os.path.exists(path):
|
| - MakeDirectory(path)
|
| -
|
| - with zipfile.ZipFile(zip_path) as z:
|
| - for name in z.namelist():
|
| - if name.endswith('/'):
|
| - continue
|
| - if pattern is not None:
|
| - if not fnmatch.fnmatch(name, pattern):
|
| - continue
|
| - CheckZipPath(name)
|
| - if no_clobber:
|
| - output_path = os.path.join(path, name)
|
| - if os.path.exists(output_path):
|
| - raise Exception(
|
| - 'Path already exists from zip: %s %s %s'
|
| - % (zip_path, name, output_path))
|
| -
|
| - z.extractall(path=path)
|
| -
|
| -
|
| -def DoZip(inputs, output, base_dir):
|
| - with zipfile.ZipFile(output, 'w') as outfile:
|
| - for f in inputs:
|
| - CheckZipPath(os.path.relpath(f, base_dir))
|
| - outfile.write(f, os.path.relpath(f, base_dir))
|
| -
|
| -
|
| -def ZipDir(output, base_dir):
|
| - with zipfile.ZipFile(output, 'w') as outfile:
|
| - for root, _, files in os.walk(base_dir):
|
| - for f in files:
|
| - path = os.path.join(root, f)
|
| - archive_path = os.path.relpath(path, base_dir)
|
| - CheckZipPath(archive_path)
|
| - outfile.write(path, archive_path)
|
| -
|
| -
|
| -def MergeZips(output, inputs, exclude_patterns=None):
|
| - added_names = set()
|
| - def Allow(name):
|
| - if exclude_patterns is not None:
|
| - for p in exclude_patterns:
|
| - if fnmatch.fnmatch(name, p):
|
| - return False
|
| - return True
|
| -
|
| - with zipfile.ZipFile(output, 'w') as out_zip:
|
| - for in_file in inputs:
|
| - with zipfile.ZipFile(in_file, 'r') as in_zip:
|
| - for name in in_zip.namelist():
|
| - if name not in added_names and Allow(name):
|
| - out_zip.writestr(name, in_zip.read(name))
|
| - added_names.add(name)
|
| -
|
| -
|
| -def PrintWarning(message):
|
| - print 'WARNING: ' + message
|
| -
|
| -
|
| -def PrintBigWarning(message):
|
| - print '***** ' * 8
|
| - PrintWarning(message)
|
| - print '***** ' * 8
|
| -
|
| -
|
| -def GetSortedTransitiveDependencies(top, deps_func):
|
| - """Gets the list of all transitive dependencies in sorted order.
|
| -
|
| - There should be no cycles in the dependency graph.
|
| -
|
| - Args:
|
| - top: a list of the top level nodes
|
| - deps_func: A function that takes a node and returns its direct dependencies.
|
| - Returns:
|
| - A list of all transitive dependencies of nodes in top, in order (a node will
|
| - appear in the list at a higher index than all of its dependencies).
|
| - """
|
| - def Node(dep):
|
| - return (dep, deps_func(dep))
|
| -
|
| - # First: find all deps
|
| - unchecked_deps = list(top)
|
| - all_deps = set(top)
|
| - while unchecked_deps:
|
| - dep = unchecked_deps.pop()
|
| - new_deps = deps_func(dep).difference(all_deps)
|
| - unchecked_deps.extend(new_deps)
|
| - all_deps = all_deps.union(new_deps)
|
| -
|
| - # Then: simple, slow topological sort.
|
| - sorted_deps = []
|
| - unsorted_deps = dict(map(Node, all_deps))
|
| - while unsorted_deps:
|
| - for library, dependencies in unsorted_deps.items():
|
| - if not dependencies.intersection(unsorted_deps.keys()):
|
| - sorted_deps.append(library)
|
| - del unsorted_deps[library]
|
| -
|
| - return sorted_deps
|
| -
|
| -
|
| -def GetPythonDependencies():
|
| - """Gets the paths of imported non-system python modules.
|
| -
|
| - A path is assumed to be a "system" import if it is outside of chromium's
|
| - src/. The paths will be relative to the current directory.
|
| - """
|
| - module_paths = (m.__file__ for m in sys.modules.itervalues()
|
| - if m is not None and hasattr(m, '__file__'))
|
| -
|
| - abs_module_paths = map(os.path.abspath, module_paths)
|
| -
|
| - non_system_module_paths = [
|
| - p for p in abs_module_paths if p.startswith(CHROMIUM_SRC)]
|
| - def ConvertPycToPy(s):
|
| - if s.endswith('.pyc'):
|
| - return s[:-1]
|
| - return s
|
| -
|
| - non_system_module_paths = map(ConvertPycToPy, non_system_module_paths)
|
| - non_system_module_paths = map(os.path.relpath, non_system_module_paths)
|
| - return sorted(set(non_system_module_paths))
|
| -
|
| -
|
| -def AddDepfileOption(parser):
|
| - parser.add_option('--depfile',
|
| - help='Path to depfile. This must be specified as the '
|
| - 'action\'s first output.')
|
| -
|
| -
|
| -def WriteDepfile(path, dependencies):
|
| - with open(path, 'w') as depfile:
|
| - depfile.write(path)
|
| - depfile.write(': ')
|
| - depfile.write(' '.join(dependencies))
|
| - depfile.write('\n')
|
| -
|
| -
|
| -def ExpandFileArgs(args):
|
| - """Replaces file-arg placeholders in args.
|
| -
|
| - These placeholders have the form:
|
| - @FileArg(filename:key1:key2:...:keyn)
|
| -
|
| - The value of such a placeholder is calculated by reading 'filename' as json.
|
| - And then extracting the value at [key1][key2]...[keyn].
|
| -
|
| - Note: This intentionally does not return the list of files that appear in such
|
| - placeholders. An action that uses file-args *must* know the paths of those
|
| - files prior to the parsing of the arguments (typically by explicitly listing
|
| - them in the action's inputs in build files).
|
| - """
|
| - new_args = list(args)
|
| - file_jsons = dict()
|
| - r = re.compile('@FileArg\((.*?)\)')
|
| - for i, arg in enumerate(args):
|
| - match = r.search(arg)
|
| - if not match:
|
| - continue
|
| -
|
| - if match.end() != len(arg):
|
| - raise Exception('Unexpected characters after FileArg: ' + arg)
|
| -
|
| - lookup_path = match.group(1).split(':')
|
| - file_path = lookup_path[0]
|
| - if not file_path in file_jsons:
|
| - file_jsons[file_path] = ReadJson(file_path)
|
| -
|
| - expansion = file_jsons[file_path]
|
| - for k in lookup_path[1:]:
|
| - expansion = expansion[k]
|
| -
|
| - new_args[i] = arg[:match.start()] + str(expansion)
|
| -
|
| - return new_args
|
| -
|
|
|