|  | #!/usr/bin/env python | 
|  | # | 
|  | # Copyright 2015 Google Inc. | 
|  | # | 
|  | # Use of this source code is governed by a BSD-style license that can be | 
|  | # found in the LICENSE file. | 
|  |  | 
|  | # This script does a very rough simulation of BUILD file expansion, | 
|  | # mostly to see the effects of glob(). | 
|  |  | 
|  | # We start by adding some symbols to our namespace that BUILD.public calls. | 
|  |  | 
|  | import glob | 
|  | import os | 
|  | import pprint | 
|  | import re | 
|  |  | 
|  | def noop(*args, **kwargs): | 
|  | pass | 
|  |  | 
|  | def select_simulator(d): | 
|  | result = [] | 
|  | for k in d: | 
|  | result.append("*** BEGIN %s ***" % k) | 
|  | result.extend(d[k]) | 
|  | result.append("*** END %s ***" % k) | 
|  | return result | 
|  |  | 
|  | DOUBLE_STAR_RE = re.compile(r'/\*\*/') | 
|  | STAR_RE = re.compile(r'\*') | 
|  | DOUBLE_STAR_PLACEHOLDER = "xxxdoublestarxxx" | 
|  | STAR_PLACEHOLDER = "xxxstarxxx" | 
|  |  | 
|  | # Returns a set of files that match pattern. | 
|  | def BUILD_glob_single(pattern): | 
|  | if pattern.find('**') < 0: | 
|  | # If pattern doesn't include **, glob.glob more-or-less does the right | 
|  | # thing. | 
|  | return glob.glob(pattern) | 
|  | # First transform pattern into a regexp. | 
|  | # Temporarily remove ** and *. | 
|  | pattern2 = DOUBLE_STAR_RE.sub(DOUBLE_STAR_PLACEHOLDER, pattern) | 
|  | pattern3 = STAR_RE.sub(STAR_PLACEHOLDER, pattern2) | 
|  | # Replace any regexp special characters. | 
|  | pattern4 = re.escape(pattern3) | 
|  | # Replace * with [^/]* and ** with .*. | 
|  | pattern5 = pattern4.replace(STAR_PLACEHOLDER, '[^/]*') | 
|  | pattern6 = pattern5.replace(DOUBLE_STAR_PLACEHOLDER, '.*/') | 
|  | # Anchor the match at the beginning and end. | 
|  | pattern7 = "^" + pattern6 + "$" | 
|  | pattern_re = re.compile(pattern7) | 
|  | matches = set() | 
|  | for root, _, files in os.walk('.'): | 
|  | for fname in files: | 
|  | # Remove initial "./". | 
|  | path = os.path.join(root, fname)[2:] | 
|  | if pattern_re.match(path): | 
|  | matches.add(path) | 
|  | return matches | 
|  |  | 
|  | # Simulates BUILD file glob(). | 
|  | def BUILD_glob(include, exclude=()): | 
|  | files = set() | 
|  | for pattern in include: | 
|  | files.update(BUILD_glob_single(pattern)) | 
|  | for pattern in exclude: | 
|  | files.difference_update(BUILD_glob_single(pattern)) | 
|  | return list(sorted(files)) | 
|  |  | 
|  | # With these namespaces, we can treat BUILD.public as if it were | 
|  | # Python code.  This pulls its variable definitions (SRCS, HDRS, | 
|  | # DEFINES, etc.) into local_names. | 
|  | global_names = { | 
|  | 'cc_library': noop, | 
|  | 'cc_test': noop, | 
|  | 'exports_files': noop, | 
|  | 'glob': BUILD_glob, | 
|  | 'select': select_simulator, | 
|  | 'BASE_DIR': '', | 
|  | 'BASE_EXTERNAL_DEPS_ANDROID': [], | 
|  | 'BASE_EXTERNAL_DEPS_IOS': [], | 
|  | 'BASE_EXTERNAL_DEPS_UNIX': [], | 
|  | 'CONDITION_ANDROID': 'CONDITION_ANDROID', | 
|  | 'CONDITION_IOS': 'CONDITION_IOS', | 
|  | 'DM_EXTERNAL_DEPS': [], | 
|  | 'EXTERNAL_DEPS_ALL': [], | 
|  | 'EXTERNAL_INCLUDES': [], | 
|  | } | 
|  | local_names = {} | 
|  | execfile('BUILD.public', global_names, local_names) | 
|  |  | 
|  | with open('tools/BUILD.public.expected', 'w') as out: | 
|  | print >>out, "This file is auto-generated by tools/BUILD_simulator.py." | 
|  | print >>out, "It expands BUILD.public to make it easy to see changes." | 
|  | for name, value in sorted(local_names.items()): | 
|  | print >>out, name, '= ', | 
|  | pprint.pprint(value, out) |