#!/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)