普通文本  |  98行  |  2.91 KB

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