Skip to content

Commit

Permalink
Grit: Generate resource_ids as part of the build
Browse files Browse the repository at this point in the history
Eliminates the need to manually run "grit update_resource_ids"

Bug: 979886
Change-Id: Ifa89368bfe6f8ba36750536a42d2a308c2555604
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1980793
Commit-Queue: Andrew Grieve <agrieve@chromium.org>
Reviewed-by: Samuel Huang <huangs@chromium.org>
Cr-Commit-Position: refs/heads/master@{#728095}
  • Loading branch information
Andrew Grieve authored and Commit Bot committed Jan 3, 2020
1 parent 423c6e6 commit 11c825d
Show file tree
Hide file tree
Showing 6 changed files with 349 additions and 294 deletions.
1 change: 1 addition & 0 deletions .gn
Original file line number Diff line number Diff line change
Expand Up @@ -662,4 +662,5 @@ exec_script_whitelist =
"//remoting/host/installer/win/generate_clsids.gni",

"//tools/grit/grit_rule.gni",
"//tools/gritsettings/BUILD.gn",
]
48 changes: 41 additions & 7 deletions tools/grit/grit/tool/update_resource_ids/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,7 @@ def _MultiReplace(data, repl):
return ''.join(res)


def _CreateAndOutputResult(data, repl, output):
new_data = _MultiReplace(data, repl)
def _WriteFile(output, new_data):
if output:
with open(output, 'wt') as fh:
fh.write(new_data)
Expand All @@ -118,18 +117,24 @@ def _CreateAndOutputResult(data, repl, output):
class _Args:
"""Encapsulated arguments for this module."""
def __init__(self):
self.input = None
self.output = None
self.add_header = False
self.analyze_inputs = False
self.count = False
self.depfile = None
self.fake = False
self.input = None
self.naive = False
self.output = None
self.parse = False
self.tokenize = False

@staticmethod
def Parse(raw_args):
own_opts, raw_args = getopt.getopt(raw_args, 'o:cpt', [
'add-header',
'analyze-inputs',
'count',
'depfile=',
'fake',
'naive',
'parse',
Expand All @@ -144,8 +149,14 @@ def Parse(raw_args):
for (key, val) in own_opts:
if key == '-o':
args.output = val
elif key == '--add-header':
args.add_header = True
elif key == '--analyze-inputs':
args.analyze_inputs = True
elif key in ('--count', '-c'):
args.count = True
elif key == '--depfile':
args.depfile = val
elif key == '--fake':
args.fake = True
elif key == '--naive':
Expand All @@ -164,7 +175,8 @@ class UpdateResourceIds(interface.Tool):
Usage: grit update_resource_ids [--parse|-p] [--read-grd|-r] [--tokenize|-t]
[--naive] [--fake] [-o OUTPUT_FILE]
RESOURCE_IDS_FILE
[--analyze-inputs] [--depfile DEPFILE]
[--add-header] RESOURCE_IDS_FILE
RESOURCE_IDS_FILE is the path of the input resource_ids file.
Expand All @@ -188,6 +200,9 @@ class UpdateResourceIds(interface.Tool):
--tokenize|-t Tokenizes RESOURCE_IDS_FILE and reprints it as syntax-
highlighted output.
--depfile=DEPFILE Write out a depfile for ninja to know about dependencies.
--analyze-inputs Writes dependencies to stdout.
--add-header Adds a "THIS FILE IS GENERATED" header to the output.
"""

def __init(self):
Expand Down Expand Up @@ -242,13 +257,32 @@ def Run(self, opts, raw_args):
item_list = common.BuildItemList(root_obj)

src_dir = os.path.abspath(os.sep.join([file_dir, root_obj['SRCDIR'].val]))
usage_gen = reader.GenerateResourceUsages(item_list, src_dir, args.fake)
seen_files = set()
usage_gen = reader.GenerateResourceUsages(item_list, src_dir, args.fake,
seen_files)
if args.count:
return self._DumpResourceCounts(usage_gen)
for item, tag_name_to_usage in usage_gen:
item.SetUsages(tag_name_to_usage)

if args.analyze_inputs:
print('\n'.join(sorted(seen_files)))
return 0

new_ids_gen = assigner.GenerateNewIds(item_list, args.naive)
# Create replacement specs usable by _MultiReplace().
repl = [(tag.lo, tag.hi, str(new_id)) for tag, new_id in new_ids_gen]
_CreateAndOutputResult(data, repl, args.output)
# Update "SRCDIR" entry.
new_srcdir = os.path.relpath(src_dir, os.path.dirname(args.output))
repl.append(
(root_obj['SRCDIR'].lo, root_obj['SRCDIR'].hi, repr(new_srcdir)))
new_data = _MultiReplace(data, repl)
if args.add_header:
new_data = ('# GENERATED FILE.\n' +
'# Edit {} instead.\n'.format(args.input) +
'#################\n') + new_data
_WriteFile(args.output, new_data)

if args.depfile:
deps_data = '{}: {}'.format(args.output, ' '.join(sorted(seen_files)))
_WriteFile(args.depfile, deps_data)
20 changes: 14 additions & 6 deletions tools/grit/grit/tool/update_resource_ids/reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,34 @@
import os

from grit import grd_reader
from grit import util
from grit.tool.update_resource_ids import common

TAGS_OF_INTEREST = set(['include', 'message', 'structure'])


def _CountResourceUsage(grd):
def _CountResourceUsage(grd, seen_files):
tag_name_to_count = {tag: set() for tag in TAGS_OF_INTEREST}
# Pass '_chromium', but '_google_chrome' would produce the same result.
root = grd_reader.Parse(grd, defines={'_chromium': True})
seen_files.add(grd)
# Count all descendant tags, regardless of whether they're active.
for node in root.Preorder():
if node.name in TAGS_OF_INTEREST:
tag_name_to_count[node.name].add(node.attrs['name'])
elif node.name == 'part':
part_path = os.path.join(os.path.dirname(grd), node.GetInputPath())
seen_files.add(util.normpath(part_path))
return {k: len(v) for k, v in tag_name_to_count.iteritems() if v}


def GenerateResourceUsages(item_list, src_dir, fake):
def GenerateResourceUsages(item_list, src_dir, fake, seen_files):
"""Visits a list of ItemInfo to generate maps from tag name to usage.
Args:
root_obj: Root dict of a resource_ids file.
src_dir: Absolute directory of Chrome's src/ directory.
fake: For testing: Sets 10 as usages for all tags, to avoid reading GRD.
seen_files: A set to collect paths of files read.
Yields:
Tuple (item, tag_name_to_usage), where |item| is from |item_list| and
|tag_name_to_usage| is a dict() mapping tag name to (int) usage.
Expand All @@ -64,9 +69,12 @@ def GenerateResourceUsages(item_list, src_dir, fake):
raise ValueError('%s: Generated GRD must use META with "sizes" field '
'to specify size bounds.' % item.grd)
grd_file = os.sep.join([src_dir, item.grd])
if not os.path.isfile(grd_file):
raise ValueError('Nonexistent GRD provided: %s' % item.grd)
tag_name_to_usage = _CountResourceUsage(grd_file)
if not os.path.exists(grd_file):
# Silently skip missing files so that src-internal files do not break
# public checkouts.
yield item, {}
continue
tag_name_to_usage = _CountResourceUsage(grd_file, seen_files)
tag_names = set(tag_name_to_usage.keys())
if not tag_names.issubset(supported_tag_names):
missing = [t + 's' for t in tag_names - supported_tag_names]
Expand Down
Loading

0 comments on commit 11c825d

Please sign in to comment.