# Copyright (c) 2015 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 collections
import os
import re
import tracing_project
from tracing_build import check_common
class _Token(object):
def __init__(self, data, token_id=None):
self.data = data
if token_id:
self.token_id = token_id
else:
self.token_id = 'plain'
class BuildFile(object):
def __init__(self, text, file_groups):
self._file_groups = file_groups
self._tokens = [token for token in self._Tokenize(text)]
def _Tokenize(self, text):
rest = text
token_regex = self._TokenRegex()
while len(rest):
m = token_regex.search(rest)
if not m:
# In `rest', we couldn't find a match.
# So, lump the entire `rest' into a token
# and stop producing any more tokens.
yield _Token(rest)
return
min_index, end_index, matched_token = self._ProcessMatch(m)
if min_index > 0:
yield _Token(rest[:min_index])
yield matched_token
rest = rest[end_index:]
def Update(self, files_by_group):
for token in self._tokens:
if token.token_id in files_by_group:
token.data = self._GetReplacementListAsString(
token.data,
files_by_group[token.token_id])
def Write(self, f):
for token in self._tokens:
f.write(token.data)
def _ProcessMatch(self, match):
raise NotImplementedError
def _TokenRegex(self):
raise NotImplementedError
def _GetReplacementListAsString(self, existing_list_as_string, filelist):
raise NotImplementedError
class GypiFile(BuildFile):
def _ProcessMatch(self, match):
min_index = match.start(2)
end_index = match.end(2)
token = _Token(match.string[min_index:end_index],
token_id=match.groups()[0])
return min_index, end_index, token
def _TokenRegex(self):
# regexp to match the following:
# 'file_group_name': [
# 'path/to/one/file.extension',
# 'another/file.ex',
# ]
# In the match,
# group 1 is : 'file_group_name'
# group 2 is : """ 'path/to/one/file.extension',\n 'another/file.ex',\n"""
regexp_str = r"'(%s)': \[\n(.+?) +\],?\n" % "|".join(self._file_groups)
return re.compile(regexp_str, re.MULTILINE | re.DOTALL)
def _GetReplacementListAsString(self, existing_list_as_string, filelist):
list_entry = existing_list_as_string.splitlines()[0]
prefix, _, suffix = list_entry.split("'")
return "".join(["'".join([prefix, filename, suffix + '\n'])
for filename in filelist])
def _GroupFiles(file_name_to_group_name_func, filenames):
file_groups = collections.defaultdict(lambda: [])
for filename in filenames:
file_groups[file_name_to_group_name_func(filename)].append(filename)
for group in file_groups:
file_groups[group].sort()
return file_groups
def _UpdateBuildFile(filename, build_file_class):
with open(filename, 'r') as f:
build_file = build_file_class(f.read(), check_common.FILE_GROUPS)
files_by_group = _GroupFiles(check_common.GetFileGroupFromFileName,
check_common.GetKnownFiles())
build_file.Update(files_by_group)
with open(filename, 'w') as f:
build_file.Write(f)
def UpdateGypi():
tvp = tracing_project.TracingProject()
_UpdateBuildFile(
os.path.join(tvp.tracing_root_path, 'trace_viewer.gypi'), GypiFile)
def Update():
UpdateGypi()