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