Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # Copyright 2014 The Chromium Authors. All rights reserved. | 2 # Copyright 2014 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 import argparse | |
| 6 import collections | 7 import collections |
| 7 import hashlib | 8 import hashlib |
| 8 import operator | 9 import operator |
| 9 import os | 10 import os |
| 10 import re | 11 import re |
| 11 import sys | 12 import sys |
| 12 | 13 |
| 13 | 14 SCRIPT_NAME = "generate_ui_string_overrider.py" |
| 14 RESOURCE_EXTRACT_REGEX = re.compile('^#define (\S*) (\d*)$', re.MULTILINE) | 15 RESOURCE_EXTRACT_REGEX = re.compile('^#define (\S*) (\d*)$', re.MULTILINE) |
| 15 | 16 |
| 16 class Error(Exception): | 17 class Error(Exception): |
| 17 """Base error class for all exceptions in generated_resources_map.""" | 18 """Base error class for all exceptions in generated_resources_map.""" |
| 18 | 19 |
| 19 | 20 |
| 20 class HashCollisionError(Error): | 21 class HashCollisionError(Error): |
| 21 """Multiple resource names hash to the same value.""" | 22 """Multiple resource names hash to the same value.""" |
| 22 | 23 |
| 23 | 24 |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 116 lines = [entry_pattern % (data_getter(r), r.name) for r in resources] | 117 lines = [entry_pattern % (data_getter(r), r.name) for r in resources] |
| 117 pattern = """const %(type)s %(name)s[] = { | 118 pattern = """const %(type)s %(name)s[] = { |
| 118 %(content)s | 119 %(content)s |
| 119 }; | 120 }; |
| 120 """ | 121 """ |
| 121 return pattern % {'type': array_type, | 122 return pattern % {'type': array_type, |
| 122 'name': array_name, | 123 'name': array_name, |
| 123 'content': '\n'.join(lines)} | 124 'content': '\n'.join(lines)} |
| 124 | 125 |
| 125 | 126 |
| 126 def _GenerateFileContent(resources_content): | 127 def _GenerateSourceFileContent(resources_content, namespace, header_filename): |
| 127 """Generates the .cc content from the given generated_resources.h content. | 128 """Generates the .cc content from the given generated grit headers content. |
| 128 | 129 |
| 129 Args: | 130 Args: |
| 130 resources_content: The input string to process, contains lines of the form | 131 resources_content: The input string to process, contains lines of the form |
| 131 "#define NAME INDEX". | 132 "#define NAME INDEX". |
| 132 | 133 |
| 134 namespace: The namespace in which the generated code should be scoped. If | |
| 135 not defined, then the code will be in the global namespace. | |
| 136 | |
| 137 header_filename: Path to the corresponding .h. | |
| 138 | |
| 133 Returns: | 139 Returns: |
| 134 .cc file content defining the kResourceHashes and kResourceIndices arrays. | 140 .cc file content implementing the CreateUIStringOverrider() factory. |
| 135 """ | 141 """ |
| 136 hashed_tuples = _GetResourceListFromString(resources_content) | 142 hashed_tuples = _GetResourceListFromString(resources_content) |
| 137 | 143 |
| 138 collisions = _CheckForHashCollisions(hashed_tuples) | 144 collisions = _CheckForHashCollisions(hashed_tuples) |
| 139 if collisions: | 145 if collisions: |
| 140 error_message = "\n".join( | 146 error_message = "\n".join( |
| 141 ["hash: %i, name: %s" % (i[0], i[1]) for i in sorted(collisions)]) | 147 ["hash: %i, name: %s" % (i[0], i[1]) for i in sorted(collisions)]) |
| 142 error_message = ("\nThe following names had hash collisions " | 148 error_message = ("\nThe following names had hash collisions " |
| 143 "(sorted by the hash value):\n%s\n" %(error_message)) | 149 "(sorted by the hash value):\n%s\n" %(error_message)) |
| 144 raise HashCollisionError(error_message) | 150 raise HashCollisionError(error_message) |
| 145 | 151 |
| 146 hashes_array = _GenDataArray( | 152 hashes_array = _GenDataArray( |
| 147 hashed_tuples, " %iU, // %s", 'kResourceHashes', 'uint32_t', | 153 hashed_tuples, " %iU, // %s", 'kResourceHashes', 'uint32_t', |
| 148 operator.attrgetter('hash')) | 154 operator.attrgetter('hash')) |
| 149 indices_array = _GenDataArray( | 155 indices_array = _GenDataArray( |
| 150 hashed_tuples, " %s, // %s", 'kResourceIndices', 'int', | 156 hashed_tuples, " %s, // %s", 'kResourceIndices', 'int', |
| 151 operator.attrgetter('index')) | 157 operator.attrgetter('index')) |
| 152 | 158 |
| 159 namespace_prefix = "" | |
| 160 namespace_suffix = "" | |
| 161 if namespace: | |
| 162 namespace_prefix = "namespace %s {\n\n" % namespace | |
| 163 namespace_suffix = "\n} // namespace %s\n" % namespace | |
| 164 | |
| 153 return ( | 165 return ( |
| 154 "// This file was generated by generate_resources_map.py. Do not edit.\n" | 166 "// This file was generated by %s. Do not edit.\n" |
| 155 "\n\n" | 167 "\n" |
| 156 "#include " | 168 "#include \"%s\"\n\n" |
| 157 "\"chrome/browser/metrics/variations/generated_resources_map.h\"\n\n" | 169 "%s" |
| 158 "namespace chrome_variations {\n\n" | 170 "namespace {\n\n" |
| 159 "const size_t kNumResources = %i;\n\n" | 171 "const size_t kNumResources = %i;\n\n" |
| 160 "%s" | 172 "%s" |
| 161 "\n" | 173 "\n" |
| 162 "%s" | 174 "%s" |
| 163 "\n" | 175 "\n" |
| 164 "} // namespace chrome_variations\n") % ( | 176 "} // namespace\n" |
| 165 len(hashed_tuples), hashes_array, indices_array) | 177 "\n" |
| 178 "variations::UIStringOverrider CreateUIStringOverrider() {\n" | |
| 179 " return variations::UIStringOverrider(\n" | |
| 180 " kResourceHashes, kResourceIndices, kNumResources);\n" | |
| 181 "}\n" | |
| 182 "%s") % ( | |
|
jwd
2015/09/29 15:02:54
Can you use dictionary based string interpolation
sdefresne
2015/09/30 09:38:43
Done.
| |
| 183 SCRIPT_NAME, header_filename, namespace_prefix, len(hashed_tuples), | |
| 184 hashes_array, indices_array, namespace_suffix) | |
| 166 | 185 |
| 167 | 186 |
| 168 def main(resources_file, map_file): | 187 def _GenerateHeaderFileContent(namespace, header_filename): |
| 188 """Generates the .h for to the .cc generated by _GenerateSourceFileContent. | |
| 189 | |
| 190 Args: | |
| 191 namespace: The namespace in which the generated code should be scoped. If | |
| 192 not defined, then the code will be in the global namespace. | |
| 193 | |
| 194 header_filename: Path to the corresponding .h. Used to generate the include | |
| 195 guards. | |
| 196 | |
| 197 Returns: | |
| 198 .cc file content implementing the CreateUIStringOverrider() factory. | |
| 199 """ | |
| 200 | |
| 201 include_guard = re.sub('[^A-Z]', '_', header_filename.upper()) + '_' | |
| 202 | |
| 203 namespace_prefix = "" | |
| 204 namespace_suffix = "" | |
| 205 if namespace: | |
| 206 namespace_prefix = "namespace %s {\n\n" % namespace | |
| 207 namespace_suffix = "\n} // namespace %s\n" % namespace | |
| 208 | |
| 209 return ( | |
| 210 "// This file was generated by %s. Do not edit.\n" | |
| 211 "\n" | |
| 212 "#ifndef %s\n" | |
| 213 "#define %s\n" | |
| 214 "\n" | |
| 215 "#include \"components/variations/service/ui_string_overrider.h\"\n\n" | |
| 216 "%s" | |
| 217 "// Returns an initialized UIStringOverrider.\n" | |
| 218 "variations::UIStringOverrider CreateUIStringOverrider();\n" | |
| 219 "%s" | |
| 220 "\n" | |
| 221 "#endif // %s\n" | |
|
jwd
2015/09/29 15:02:54
optional nit: use dictionary string interpolation
sdefresne
2015/09/30 09:38:43
Done.
| |
| 222 ) % ( | |
| 223 SCRIPT_NAME, include_guard, include_guard, namespace_prefix, | |
| 224 namespace_suffix, include_guard) | |
| 225 | |
| 226 | |
| 227 def main(): | |
| 228 arg_parser = argparse.ArgumentParser( | |
| 229 description="Generate UIStringOverrider factory from resources headers " | |
| 230 "generated by grit.") | |
| 231 arg_parser.add_argument( | |
| 232 "--output_dir", "-o", required=True, | |
| 233 help="Base directory to for generated files.") | |
| 234 arg_parser.add_argument( | |
| 235 "--source_filename", "-S", required=True, | |
| 236 help="File name of the generated source file.") | |
| 237 arg_parser.add_argument( | |
| 238 "--header_filename", "-H", required=True, | |
| 239 help="File name of the generated header file.") | |
| 240 arg_parser.add_argument( | |
| 241 "--namespace", "-N", default="", | |
| 242 help="Namespace of the generated factory function (code will be in " | |
| 243 "the global namespace if this is omitted).") | |
| 244 arg_parser.add_argument( | |
| 245 "--test_support", "-t", action="store_true", default=False, | |
| 246 help="Make internal variables accessible for testing.") | |
| 247 arg_parser.add_argument( | |
| 248 "inputs", metavar="FILENAME", nargs="+", | |
| 249 help="Path to resources header file generated by grit.") | |
| 250 arguments = arg_parser.parse_args() | |
| 251 | |
| 169 generated_resources_h = "" | 252 generated_resources_h = "" |
| 170 with open(resources_file, "r") as resources: | 253 for resources_file in arguments.inputs: |
| 171 generated_resources_h = resources.read() | 254 with open(resources_file, "r") as resources: |
| 255 generated_resources_h += resources.read() | |
| 172 | 256 |
| 173 if len(generated_resources_h) == 0: | 257 if len(generated_resources_h) == 0: |
| 174 raise Error("No content loaded for %s." % (resources_file)) | 258 raise Error("No content loaded for %s." % (resources_file)) |
| 175 | 259 |
| 176 file_content = _GenerateFileContent(generated_resources_h) | 260 source_file_content = _GenerateSourceFileContent( |
| 261 generated_resources_h, arguments.namespace, arguments.header_filename) | |
| 262 header_file_content = _GenerateHeaderFileContent( | |
| 263 arguments.namespace, arguments.header_filename) | |
| 177 | 264 |
| 178 with open(map_file, "w") as generated_file: | 265 with open(os.path.join( |
| 179 generated_file.write(file_content) | 266 arguments.output_dir, arguments.source_filename), "w") as generated_file: |
| 267 generated_file.write(source_file_content) | |
| 268 with open(os.path.join( | |
| 269 arguments.output_dir, arguments.header_filename), "w") as generated_file: | |
| 270 generated_file.write(header_file_content) | |
| 180 | 271 |
| 181 | 272 |
| 182 if __name__ == '__main__': | 273 if __name__ == '__main__': |
| 183 sys.exit(main(sys.argv[1], sys.argv[2])) | 274 sys.exit(main()) |
| OLD | NEW |