Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(42)

Unified Diff: build/android/gyp/util/build_utils.py

Issue 2101243005: Add a snapshot of flutter/engine/src/build to our sdk (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: add README.dart Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « build/android/gyp/util/build_device.py ('k') | build/android/gyp/util/md5_check.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
new file mode 100644
index 0000000000000000000000000000000000000000..65b1a643c26a2ca920ff176af40bfcad85057f3d
--- /dev/null
+++ b/build/android/gyp/util/build_utils.py
@@ -0,0 +1,376 @@
+# 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
+
« no previous file with comments | « build/android/gyp/util/build_device.py ('k') | build/android/gyp/util/md5_check.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698