#!/usr/bin/env python3
# Copyright 2017 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""
A tool to generate a predetermined resource ids file that can be used as an
input to grit via the -p option. This is meant to be run manually every once in
a while and its output checked in. See tools/gritsettings/README.md for details.
"""
import os
import re
import sys
# Regular expression for parsing the #define macro format. Matches both the
# version of the macro with allowlist support and the one without. For example,
# Without generate allowlist flag:
# #define IDS_FOO_MESSAGE 1234
# With generate allowlist flag:
# #define IDS_FOO_MESSAGE (::ui::AllowlistedResource<1234>(), 1234)
RESOURCE_EXTRACT_REGEX = re.compile(r'^#define (\S*).* (\d+)\)?$', re.MULTILINE)
ORDERED_RESOURCE_IDS_REGEX = re.compile(r'^Resource=(\d*)$', re.MULTILINE)
def _GetResourceNameIdPairsIter(string_to_scan):
"""Gets an iterator of the resource name and id pairs of the given string.
Scans the input string for lines of the form "#define NAME ID" and returns
an iterator over all matching (NAME, ID) pairs.
Args:
string_to_scan: The input string to scan.
Yields:
A tuple of name and id.
"""
for match in RESOURCE_EXTRACT_REGEX.finditer(string_to_scan):
yield match.group(1, 2)
def _ReadOrderedResourceIds(path):
"""Reads ordered resource ids from the given file.
The resources are expected to be of the format produced by running Chrome
with --print-resource-ids command line.
Args:
path: File path to read resource ids from.
Returns:
An array of ordered resource ids.
"""
ordered_resource_ids = []
with open(path) as f:
for match in ORDERED_RESOURCE_IDS_REGEX.finditer(f.read()):
ordered_resource_ids.append(int(match.group(1)))
return ordered_resource_ids
def GenerateResourceMapping(original_resources, ordered_resource_ids):
"""Generates a resource mapping from the ordered ids and the original mapping.
The returned dict will assign new ids to ordered_resource_ids numerically
increasing from 101.
Args:
original_resources: A dict of original resource ids to resource names.
ordered_resource_ids: An array of ordered resource ids.
Returns:
A dict of resource ids to resource names.
"""
output_resource_map = {}
# 101 is used as the starting value since other parts of GRIT require it to be
# the minimum (e.g. rc_header.py) based on Windows resource numbering.
next_id = 101
for original_id in ordered_resource_ids:
resource_name = original_resources[original_id]
output_resource_map[next_id] = resource_name
next_id += 1
return output_resource_map
def ReadResourceIdsFromFile(file, original_resources):
"""Reads resource ids from a GRIT-produced header file.
Args:
file: File to a GRIT-produced header file to read from.
original_resources: Dict of resource ids to resource names to add to.
"""
for resource_name, resource_id in _GetResourceNameIdPairsIter(file.read()):
original_resources[int(resource_id)] = resource_name
def _ReadOriginalResourceIds(out_dir):
"""Reads resource ids from GRIT header files in the specified directory.
Args:
out_dir: A Chrome build output directory (e.g. out/gn) to scan.
Returns:
A dict of resource ids to resource names.
"""
original_resources = {}
for root, dirnames, filenames in os.walk(out_dir + '/gen'):
for filename in filenames:
if filename.endswith(
('_resources.h', '_settings.h', '_strings.h', '_synonyms.h')):
with open(os.path.join(root, filename)) as f:
ReadResourceIdsFromFile(f, original_resources)
return original_resources
def _GeneratePredeterminedIdsFile(ordered_resources_file, out_dir):
"""Generates a predetermined ids file.
Args:
ordered_resources_file: File path to read ordered resource ids from.
out_dir: A Chrome build output directory (e.g. out/gn) to scan.
Returns:
A dict of resource ids to resource names.
"""
original_resources = _ReadOriginalResourceIds(out_dir)
ordered_resource_ids = _ReadOrderedResourceIds(ordered_resources_file)
output_resource_map = GenerateResourceMapping(original_resources,
ordered_resource_ids)
for res_id in sorted(output_resource_map.keys()):
print(output_resource_map[res_id], res_id)
def main(argv):
if len(argv) != 2:
print("usage: gen_predetermined_ids.py <ordered_resources_file> <out_dir>")
sys.exit(1)
ordered_resources_file, out_dir = argv[0], argv[1]
_GeneratePredeterminedIdsFile(ordered_resources_file, out_dir)
if '__main__' == __name__:
main(sys.argv[1:])