Spracherkennung für: .patch vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]
From: Nico Grunbaum <na-g@nostrum.com>
Date: Fri, 30 Apr 2021 21:51:00 +0000
Subject: Bug 1654112 - Add grit dep for building webrtc on android; r=mjf
Differential Revision:
https://phabricator.services.mozilla.com/D114027
Mercurial Revision:
https://hg.mozilla.org/mozilla-central/rev/3cce5e6938f0df87bd9ab12a5f556aceb93dfa1d
---
tools/grit/.gitignore | 1 +
tools/grit/BUILD.gn | 48 +
tools/grit/MANIFEST.in | 3 +
tools/grit/OWNERS | 8 +
tools/grit/PRESUBMIT.py | 22 +
tools/grit/README.md | 19 +
tools/grit/grit.py | 31 +
tools/grit/grit/__init__.py | 19 +
tools/grit/grit/clique.py | 491 +++
tools/grit/grit/clique_unittest.py | 265 ++
tools/grit/grit/constants.py | 23 +
tools/grit/grit/exception.py | 139 +
tools/grit/grit/extern/BogoFP.py | 22 +
tools/grit/grit/extern/FP.py | 72 +
tools/grit/grit/extern/__init__.py | 0
tools/grit/grit/extern/tclib.py | 503 +++
tools/grit/grit/format/__init__.py | 8 +
tools/grit/grit/format/android_xml.py | 212 ++
.../grit/grit/format/android_xml_unittest.py | 149 +
tools/grit/grit/format/c_format.py | 95 +
tools/grit/grit/format/c_format_unittest.py | 81 +
.../grit/grit/format/chrome_messages_json.py | 59 +
.../format/chrome_messages_json_unittest.py | 190 +
tools/grit/grit/format/data_pack.py | 321 ++
tools/grit/grit/format/data_pack_unittest.py | 102 +
.../grit/grit/format/gen_predetermined_ids.py | 144 +
.../format/gen_predetermined_ids_unittest.py | 46 +
tools/grit/grit/format/gzip_string.py | 46 +
.../grit/grit/format/gzip_string_unittest.py | 65 +
tools/grit/grit/format/html_inline.py | 602 ++++
.../grit/grit/format/html_inline_unittest.py | 927 +++++
tools/grit/grit/format/minifier.py | 45 +
.../grit/grit/format/policy_templates_json.py | 26 +
.../format/policy_templates_json_unittest.py | 207 ++
tools/grit/grit/format/rc.py | 474 +++
tools/grit/grit/format/rc_header.py | 48 +
tools/grit/grit/format/rc_header_unittest.py | 138 +
tools/grit/grit/format/rc_unittest.py | 415 +++
tools/grit/grit/format/resource_map.py | 159 +
.../grit/grit/format/resource_map_unittest.py | 345 ++
tools/grit/grit/gather/__init__.py | 8 +
tools/grit/grit/gather/admin_template.py | 62 +
.../grit/gather/admin_template_unittest.py | 115 +
tools/grit/grit/gather/chrome_html.py | 377 ++
.../grit/grit/gather/chrome_html_unittest.py | 610 ++++
tools/grit/grit/gather/chrome_scaled_image.py | 157 +
.../gather/chrome_scaled_image_unittest.py | 209 ++
tools/grit/grit/gather/interface.py | 172 +
tools/grit/grit/gather/json_loader.py | 27 +
tools/grit/grit/gather/policy_json.py | 325 ++
.../grit/grit/gather/policy_json_unittest.py | 347 ++
tools/grit/grit/gather/rc.py | 343 ++
tools/grit/grit/gather/rc_unittest.py | 372 ++
tools/grit/grit/gather/regexp.py | 82 +
tools/grit/grit/gather/skeleton_gatherer.py | 149 +
tools/grit/grit/gather/tr_html.py | 743 ++++
tools/grit/grit/gather/tr_html_unittest.py | 524 +++
tools/grit/grit/gather/txt.py | 38 +
tools/grit/grit/gather/txt_unittest.py | 35 +
tools/grit/grit/grd_reader.py | 238 ++
tools/grit/grit/grd_reader_unittest.py | 346 ++
tools/grit/grit/grit-todo.xml | 62 +
tools/grit/grit/grit_runner.py | 334 ++
tools/grit/grit/grit_runner_unittest.py | 42 +
tools/grit/grit/lazy_re.py | 46 +
tools/grit/grit/lazy_re_unittest.py | 40 +
tools/grit/grit/node/__init__.py | 8 +
tools/grit/grit/node/base.py | 670 ++++
tools/grit/grit/node/base_unittest.py | 259 ++
tools/grit/grit/node/brotli_util.py | 29 +
tools/grit/grit/node/custom/__init__.py | 8 +
tools/grit/grit/node/custom/filename.py | 29 +
.../grit/node/custom/filename_unittest.py | 34 +
tools/grit/grit/node/empty.py | 64 +
tools/grit/grit/node/include.py | 170 +
tools/grit/grit/node/include_unittest.py | 134 +
tools/grit/grit/node/mapping.py | 60 +
tools/grit/grit/node/message.py | 362 ++
tools/grit/grit/node/message_unittest.py | 380 ++
tools/grit/grit/node/misc.py | 707 ++++
tools/grit/grit/node/misc_unittest.py | 590 ++++
tools/grit/grit/node/mock_brotli.py | 10 +
tools/grit/grit/node/node_io.py | 117 +
tools/grit/grit/node/node_io_unittest.py | 182 +
tools/grit/grit/node/structure.py | 375 ++
tools/grit/grit/node/structure_unittest.py | 178 +
tools/grit/grit/node/variant.py | 41 +
tools/grit/grit/pseudo.py | 129 +
tools/grit/grit/pseudo_rtl.py | 104 +
tools/grit/grit/pseudo_unittest.py | 55 +
tools/grit/grit/shortcuts.py | 93 +
tools/grit/grit/shortcuts_unittest.py | 79 +
tools/grit/grit/tclib.py | 246 ++
tools/grit/grit/tclib_unittest.py | 180 +
tools/grit/grit/test_suite_all.py | 34 +
tools/grit/grit/testdata/GoogleDesktop.adm | 945 +++++
tools/grit/grit/testdata/README.txt | 87 +
tools/grit/grit/testdata/about.html | 45 +
tools/grit/grit/testdata/android.xml | 24 +
tools/grit/grit/testdata/bad_browser.html | 16 +
tools/grit/grit/testdata/browser.html | 42 +
tools/grit/grit/testdata/buildinfo.grd | 46 +
tools/grit/grit/testdata/cache_prefix.html | 24 +
.../grit/grit/testdata/cache_prefix_file.html | 25 +
tools/grit/grit/testdata/chat_result.html | 24 +
.../chrome/app/generated_resources.grd | 199 ++
tools/grit/grit/testdata/chrome_html.html | 6 +
.../grit/testdata/default_100_percent/a.png | Bin 0 -> 159 bytes
.../grit/testdata/default_100_percent/b.png | 1 +
tools/grit/grit/testdata/del_footer.html | 8 +
tools/grit/grit/testdata/del_header.html | 60 +
tools/grit/grit/testdata/deleted.html | 21 +
tools/grit/grit/testdata/depfile.grd | 18 +
tools/grit/grit/testdata/details.html | 10 +
.../grit/testdata/duplicate-name-input.xml | 26 +
tools/grit/grit/testdata/email_result.html | 34 +
tools/grit/grit/testdata/email_thread.html | 10 +
tools/grit/grit/testdata/error.html | 8 +
tools/grit/grit/testdata/explicit_web.html | 11 +
tools/grit/grit/testdata/footer.html | 14 +
.../grit/testdata/generated_resources_fr.xtb | 3079 +++++++++++++++++
.../grit/testdata/generated_resources_iw.xtb | 4 +
.../grit/testdata/generated_resources_no.xtb | 4 +
tools/grit/grit/testdata/grit_part.grdp | 5 +
tools/grit/grit/testdata/header.html | 39 +
tools/grit/grit/testdata/homepage.html | 37 +
tools/grit/grit/testdata/hover.html | 177 +
tools/grit/grit/testdata/include_test.html | 31 +
tools/grit/grit/testdata/included_sample.html | 1 +
tools/grit/grit/testdata/indexing_speed.html | 58 +
tools/grit/grit/testdata/install_prefs.html | 92 +
tools/grit/grit/testdata/install_prefs2.html | 52 +
.../grit/testdata/klonk-alternate-skeleton.rc | Bin 0 -> 1088 bytes
tools/grit/grit/testdata/klonk.ico | Bin 0 -> 766 bytes
tools/grit/grit/testdata/klonk.rc | Bin 0 -> 9824 bytes
.../grit/grit/testdata/ko_oem_enable_bug.html | 1 +
.../grit/testdata/ko_oem_non_admin_bug.html | 1 +
tools/grit/grit/testdata/mini.html | 36 +
tools/grit/grit/testdata/oem_enable.html | 106 +
tools/grit/grit/testdata/oem_non_admin.html | 39 +
tools/grit/grit/testdata/onebox.html | 21 +
tools/grit/grit/testdata/oneclick.html | 34 +
tools/grit/grit/testdata/password.html | 37 +
tools/grit/grit/testdata/preferences.html | 234 ++
tools/grit/grit/testdata/preprocess_test.html | 7 +
tools/grit/grit/testdata/privacy.html | 35 +
tools/grit/grit/testdata/quit_apps.html | 49 +
tools/grit/grit/testdata/recrawl.html | 30 +
tools/grit/grit/testdata/resource_ids | 13 +
tools/grit/grit/testdata/script.html | 38 +
tools/grit/grit/testdata/searchbox.html | 22 +
tools/grit/grit/testdata/sidebar_h.html | 82 +
tools/grit/grit/testdata/sidebar_v.html | 267 ++
tools/grit/grit/testdata/simple-input.xml | 52 +
tools/grit/grit/testdata/simple.html | 3 +
tools/grit/grit/testdata/source.rc | 57 +
.../grit/testdata/special_100_percent/a.png | Bin 0 -> 159 bytes
tools/grit/grit/testdata/status.html | 44 +
.../grit/testdata/structure_variables.html | 4 +
tools/grit/grit/testdata/substitute.grd | 31 +
tools/grit/grit/testdata/substitute.xmb | 10 +
.../grit/grit/testdata/substitute_no_ids.grd | 31 +
tools/grit/grit/testdata/substitute_tmpl.grd | 31 +
tools/grit/grit/testdata/test_css.css | 1 +
tools/grit/grit/testdata/test_html.html | 1 +
tools/grit/grit/testdata/test_js.js | 1 +
tools/grit/grit/testdata/test_svg.svg | 1 +
tools/grit/grit/testdata/test_text.txt | 1 +
tools/grit/grit/testdata/time_related.html | 11 +
tools/grit/grit/testdata/toolbar_about.html | 138 +
.../grit/testdata/tools/grit/resource_ids | 176 +
tools/grit/grit/testdata/transl.rc | 56 +
tools/grit/grit/testdata/versions.html | 7 +
tools/grit/grit/testdata/whitelist.txt | 4 +
.../grit/testdata/whitelist_resources.grd | 54 +
.../grit/grit/testdata/whitelist_strings.grd | 23 +
tools/grit/grit/tool/__init__.py | 8 +
tools/grit/grit/tool/android2grd.py | 484 +++
tools/grit/grit/tool/android2grd_unittest.py | 181 +
tools/grit/grit/tool/build.py | 556 +++
tools/grit/grit/tool/build_unittest.py | 341 ++
tools/grit/grit/tool/buildinfo.py | 78 +
tools/grit/grit/tool/buildinfo_unittest.py | 90 +
tools/grit/grit/tool/count.py | 52 +
tools/grit/grit/tool/diff_structures.py | 119 +
.../grit/tool/diff_structures_unittest.py | 46 +
tools/grit/grit/tool/interface.py | 62 +
tools/grit/grit/tool/menu_from_parts.py | 79 +
tools/grit/grit/tool/newgrd.py | 85 +
tools/grit/grit/tool/newgrd_unittest.py | 51 +
tools/grit/grit/tool/postprocess_interface.py | 29 +
tools/grit/grit/tool/postprocess_unittest.py | 64 +
tools/grit/grit/tool/preprocess_interface.py | 25 +
tools/grit/grit/tool/preprocess_unittest.py | 50 +
tools/grit/grit/tool/rc2grd.py | 418 +++
tools/grit/grit/tool/rc2grd_unittest.py | 163 +
tools/grit/grit/tool/resize.py | 295 ++
tools/grit/grit/tool/test.py | 24 +
tools/grit/grit/tool/transl2tc.py | 251 ++
tools/grit/grit/tool/transl2tc_unittest.py | 133 +
tools/grit/grit/tool/unit.py | 43 +
.../grit/tool/update_resource_ids/__init__.py | 305 ++
.../grit/tool/update_resource_ids/assigner.py | 286 ++
.../update_resource_ids/assigner_unittest.py | 154 +
.../grit/tool/update_resource_ids/common.py | 101 +
.../grit/tool/update_resource_ids/parser.py | 231 ++
.../grit/tool/update_resource_ids/reader.py | 83 +
tools/grit/grit/tool/xmb.py | 295 ++
tools/grit/grit/tool/xmb_unittest.py | 132 +
tools/grit/grit/util.py | 691 ++++
tools/grit/grit/util_unittest.py | 118 +
tools/grit/grit/xtb_reader.py | 140 +
tools/grit/grit/xtb_reader_unittest.py | 110 +
tools/grit/grit_info.py | 173 +
tools/grit/grit_rule.gni | 485 +++
tools/grit/minify_with_uglify.py | 44 +
tools/grit/minimize_css.py | 105 +
tools/grit/minimize_css_unittest.py | 58 +
tools/grit/pak_util.py | 223 ++
tools/grit/repack.gni | 189 +
tools/grit/setup.py | 46 +
tools/grit/stamp_grit_sources.py | 57 +
tools/grit/third_party/six/LICENSE | 18 +
tools/grit/third_party/six/README | 16 +
tools/grit/third_party/six/README.chromium | 13 +
tools/grit/third_party/six/__init__.py | 868 +++++
226 files changed, 33440 insertions(+)
create mode 100644 tools/grit/.gitignore
create mode 100644 tools/grit/BUILD.gn
create mode 100644 tools/grit/MANIFEST.in
create mode 100644 tools/grit/OWNERS
create mode 100644 tools/grit/PRESUBMIT.py
create mode 100644 tools/grit/README.md
create mode 100644 tools/grit/grit.py
create mode 100644 tools/grit/grit/__init__.py
create mode 100644 tools/grit/grit/clique.py
create mode 100644 tools/grit/grit/clique_unittest.py
create mode 100644 tools/grit/grit/constants.py
create mode 100644 tools/grit/grit/exception.py
create mode 100644 tools/grit/grit/extern/BogoFP.py
create mode 100644 tools/grit/grit/extern/FP.py
create mode 100644 tools/grit/grit/extern/__init__.py
create mode 100644 tools/grit/grit/extern/tclib.py
create mode 100644 tools/grit/grit/format/__init__.py
create mode 100644 tools/grit/grit/format/android_xml.py
create mode 100644 tools/grit/grit/format/android_xml_unittest.py
create mode 100644 tools/grit/grit/format/c_format.py
create mode 100644 tools/grit/grit/format/c_format_unittest.py
create mode 100644 tools/grit/grit/format/chrome_messages_json.py
create mode 100644 tools/grit/grit/format/chrome_messages_json_unittest.py
create mode 100644 tools/grit/grit/format/data_pack.py
create mode 100644 tools/grit/grit/format/data_pack_unittest.py
create mode 100644 tools/grit/grit/format/gen_predetermined_ids.py
create mode 100644 tools/grit/grit/format/gen_predetermined_ids_unittest.py
create mode 100644 tools/grit/grit/format/gzip_string.py
create mode 100644 tools/grit/grit/format/gzip_string_unittest.py
create mode 100644 tools/grit/grit/format/html_inline.py
create mode 100644 tools/grit/grit/format/html_inline_unittest.py
create mode 100644 tools/grit/grit/format/minifier.py
create mode 100644 tools/grit/grit/format/policy_templates_json.py
create mode 100644 tools/grit/grit/format/policy_templates_json_unittest.py
create mode 100644 tools/grit/grit/format/rc.py
create mode 100644 tools/grit/grit/format/rc_header.py
create mode 100644 tools/grit/grit/format/rc_header_unittest.py
create mode 100644 tools/grit/grit/format/rc_unittest.py
create mode 100644 tools/grit/grit/format/resource_map.py
create mode 100644 tools/grit/grit/format/resource_map_unittest.py
create mode 100644 tools/grit/grit/gather/__init__.py
create mode 100644 tools/grit/grit/gather/admin_template.py
create mode 100644 tools/grit/grit/gather/admin_template_unittest.py
create mode 100644 tools/grit/grit/gather/chrome_html.py
create mode 100644 tools/grit/grit/gather/chrome_html_unittest.py
create mode 100644 tools/grit/grit/gather/chrome_scaled_image.py
create mode 100644 tools/grit/grit/gather/chrome_scaled_image_unittest.py
create mode 100644 tools/grit/grit/gather/interface.py
create mode 100644 tools/grit/grit/gather/json_loader.py
create mode 100644 tools/grit/grit/gather/policy_json.py
create mode 100644 tools/grit/grit/gather/policy_json_unittest.py
create mode 100644 tools/grit/grit/gather/rc.py
create mode 100644 tools/grit/grit/gather/rc_unittest.py
create mode 100644 tools/grit/grit/gather/regexp.py
create mode 100644 tools/grit/grit/gather/skeleton_gatherer.py
create mode 100644 tools/grit/grit/gather/tr_html.py
create mode 100644 tools/grit/grit/gather/tr_html_unittest.py
create mode 100644 tools/grit/grit/gather/txt.py
create mode 100644 tools/grit/grit/gather/txt_unittest.py
create mode 100644 tools/grit/grit/grd_reader.py
create mode 100644 tools/grit/grit/grd_reader_unittest.py
create mode 100644 tools/grit/grit/grit-todo.xml
create mode 100644 tools/grit/grit/grit_runner.py
create mode 100644 tools/grit/grit/grit_runner_unittest.py
create mode 100644 tools/grit/grit/lazy_re.py
create mode 100644 tools/grit/grit/lazy_re_unittest.py
create mode 100644 tools/grit/grit/node/__init__.py
create mode 100644 tools/grit/grit/node/base.py
create mode 100644 tools/grit/grit/node/base_unittest.py
create mode 100644 tools/grit/grit/node/brotli_util.py
create mode 100644 tools/grit/grit/node/custom/__init__.py
create mode 100644 tools/grit/grit/node/custom/filename.py
create mode 100644 tools/grit/grit/node/custom/filename_unittest.py
create mode 100644 tools/grit/grit/node/empty.py
create mode 100644 tools/grit/grit/node/include.py
create mode 100644 tools/grit/grit/node/include_unittest.py
create mode 100644 tools/grit/grit/node/mapping.py
create mode 100644 tools/grit/grit/node/message.py
create mode 100644 tools/grit/grit/node/message_unittest.py
create mode 100644 tools/grit/grit/node/misc.py
create mode 100644 tools/grit/grit/node/misc_unittest.py
create mode 100644 tools/grit/grit/node/mock_brotli.py
create mode 100644 tools/grit/grit/node/node_io.py
create mode 100644 tools/grit/grit/node/node_io_unittest.py
create mode 100644 tools/grit/grit/node/structure.py
create mode 100644 tools/grit/grit/node/structure_unittest.py
create mode 100644 tools/grit/grit/node/variant.py
create mode 100644 tools/grit/grit/pseudo.py
create mode 100644 tools/grit/grit/pseudo_rtl.py
create mode 100644 tools/grit/grit/pseudo_unittest.py
create mode 100644 tools/grit/grit/shortcuts.py
create mode 100644 tools/grit/grit/shortcuts_unittest.py
create mode 100644 tools/grit/grit/tclib.py
create mode 100644 tools/grit/grit/tclib_unittest.py
create mode 100644 tools/grit/grit/test_suite_all.py
create mode 100644 tools/grit/grit/testdata/GoogleDesktop.adm
create mode 100644 tools/grit/grit/testdata/README.txt
create mode 100644 tools/grit/grit/testdata/about.html
create mode 100644 tools/grit/grit/testdata/android.xml
create mode 100644 tools/grit/grit/testdata/bad_browser.html
create mode 100644 tools/grit/grit/testdata/browser.html
create mode 100644 tools/grit/grit/testdata/buildinfo.grd
create mode 100644 tools/grit/grit/testdata/cache_prefix.html
create mode 100644 tools/grit/grit/testdata/cache_prefix_file.html
create mode 100644 tools/grit/grit/testdata/chat_result.html
create mode 100644 tools/grit/grit/testdata/chrome/app/generated_resources.grd
create mode 100644 tools/grit/grit/testdata/chrome_html.html
create mode 100644 tools/grit/grit/testdata/default_100_percent/a.png
create mode 100644 tools/grit/grit/testdata/default_100_percent/b.png
create mode 100644 tools/grit/grit/testdata/del_footer.html
create mode 100644 tools/grit/grit/testdata/del_header.html
create mode 100644 tools/grit/grit/testdata/deleted.html
create mode 100644 tools/grit/grit/testdata/depfile.grd
create mode 100644 tools/grit/grit/testdata/details.html
create mode 100644 tools/grit/grit/testdata/duplicate-name-input.xml
create mode 100644 tools/grit/grit/testdata/email_result.html
create mode 100644 tools/grit/grit/testdata/email_thread.html
create mode 100644 tools/grit/grit/testdata/error.html
create mode 100644 tools/grit/grit/testdata/explicit_web.html
create mode 100644 tools/grit/grit/testdata/footer.html
create mode 100644 tools/grit/grit/testdata/generated_resources_fr.xtb
create mode 100644 tools/grit/grit/testdata/generated_resources_iw.xtb
create mode 100644 tools/grit/grit/testdata/generated_resources_no.xtb
create mode 100644 tools/grit/grit/testdata/grit_part.grdp
create mode 100644 tools/grit/grit/testdata/header.html
create mode 100644 tools/grit/grit/testdata/homepage.html
create mode 100644 tools/grit/grit/testdata/hover.html
create mode 100644 tools/grit/grit/testdata/include_test.html
create mode 100644 tools/grit/grit/testdata/included_sample.html
create mode 100644 tools/grit/grit/testdata/indexing_speed.html
create mode 100644 tools/grit/grit/testdata/install_prefs.html
create mode 100644 tools/grit/grit/testdata/install_prefs2.html
create mode 100644 tools/grit/grit/testdata/klonk-alternate-skeleton.rc
create mode 100644 tools/grit/grit/testdata/klonk.ico
create mode 100644 tools/grit/grit/testdata/klonk.rc
create mode 100644 tools/grit/grit/testdata/ko_oem_enable_bug.html
create mode 100644 tools/grit/grit/testdata/ko_oem_non_admin_bug.html
create mode 100644 tools/grit/grit/testdata/mini.html
create mode 100644 tools/grit/grit/testdata/oem_enable.html
create mode 100644 tools/grit/grit/testdata/oem_non_admin.html
create mode 100644 tools/grit/grit/testdata/onebox.html
create mode 100644 tools/grit/grit/testdata/oneclick.html
create mode 100644 tools/grit/grit/testdata/password.html
create mode 100644 tools/grit/grit/testdata/preferences.html
create mode 100644 tools/grit/grit/testdata/preprocess_test.html
create mode 100644 tools/grit/grit/testdata/privacy.html
create mode 100644 tools/grit/grit/testdata/quit_apps.html
create mode 100644 tools/grit/grit/testdata/recrawl.html
create mode 100644 tools/grit/grit/testdata/resource_ids
create mode 100644 tools/grit/grit/testdata/script.html
create mode 100644 tools/grit/grit/testdata/searchbox.html
create mode 100644 tools/grit/grit/testdata/sidebar_h.html
create mode 100644 tools/grit/grit/testdata/sidebar_v.html
create mode 100644 tools/grit/grit/testdata/simple-input.xml
create mode 100644 tools/grit/grit/testdata/simple.html
create mode 100644 tools/grit/grit/testdata/source.rc
create mode 100644 tools/grit/grit/testdata/special_100_percent/a.png
create mode 100644 tools/grit/grit/testdata/status.html
create mode 100644 tools/grit/grit/testdata/structure_variables.html
create mode 100644 tools/grit/grit/testdata/substitute.grd
create mode 100644 tools/grit/grit/testdata/substitute.xmb
create mode 100644 tools/grit/grit/testdata/substitute_no_ids.grd
create mode 100644 tools/grit/grit/testdata/substitute_tmpl.grd
create mode 100644 tools/grit/grit/testdata/test_css.css
create mode 100644 tools/grit/grit/testdata/test_html.html
create mode 100644 tools/grit/grit/testdata/test_js.js
create mode 100644 tools/grit/grit/testdata/test_svg.svg
create mode 100644 tools/grit/grit/testdata/test_text.txt
create mode 100644 tools/grit/grit/testdata/time_related.html
create mode 100644 tools/grit/grit/testdata/toolbar_about.html
create mode 100644 tools/grit/grit/testdata/tools/grit/resource_ids
create mode 100644 tools/grit/grit/testdata/transl.rc
create mode 100644 tools/grit/grit/testdata/versions.html
create mode 100644 tools/grit/grit/testdata/whitelist.txt
create mode 100644 tools/grit/grit/testdata/whitelist_resources.grd
create mode 100644 tools/grit/grit/testdata/whitelist_strings.grd
create mode 100644 tools/grit/grit/tool/__init__.py
create mode 100644 tools/grit/grit/tool/android2grd.py
create mode 100644 tools/grit/grit/tool/android2grd_unittest.py
create mode 100644 tools/grit/grit/tool/build.py
create mode 100644 tools/grit/grit/tool/build_unittest.py
create mode 100644 tools/grit/grit/tool/buildinfo.py
create mode 100644 tools/grit/grit/tool/buildinfo_unittest.py
create mode 100644 tools/grit/grit/tool/count.py
create mode 100644 tools/grit/grit/tool/diff_structures.py
create mode 100644 tools/grit/grit/tool/diff_structures_unittest.py
create mode 100644 tools/grit/grit/tool/interface.py
create mode 100644 tools/grit/grit/tool/menu_from_parts.py
create mode 100644 tools/grit/grit/tool/newgrd.py
create mode 100644 tools/grit/grit/tool/newgrd_unittest.py
create mode 100644 tools/grit/grit/tool/postprocess_interface.py
create mode 100644 tools/grit/grit/tool/postprocess_unittest.py
create mode 100644 tools/grit/grit/tool/preprocess_interface.py
create mode 100644 tools/grit/grit/tool/preprocess_unittest.py
create mode 100644 tools/grit/grit/tool/rc2grd.py
create mode 100644 tools/grit/grit/tool/rc2grd_unittest.py
create mode 100644 tools/grit/grit/tool/resize.py
create mode 100644 tools/grit/grit/tool/test.py
create mode 100644 tools/grit/grit/tool/transl2tc.py
create mode 100644 tools/grit/grit/tool/transl2tc_unittest.py
create mode 100644 tools/grit/grit/tool/unit.py
create mode 100644 tools/grit/grit/tool/update_resource_ids/__init__.py
create mode 100644 tools/grit/grit/tool/update_resource_ids/assigner.py
create mode 100644 tools/grit/grit/tool/update_resource_ids/assigner_unittest.py
create mode 100644 tools/grit/grit/tool/update_resource_ids/common.py
create mode 100644 tools/grit/grit/tool/update_resource_ids/parser.py
create mode 100644 tools/grit/grit/tool/update_resource_ids/reader.py
create mode 100644 tools/grit/grit/tool/xmb.py
create mode 100644 tools/grit/grit/tool/xmb_unittest.py
create mode 100644 tools/grit/grit/util.py
create mode 100644 tools/grit/grit/util_unittest.py
create mode 100644 tools/grit/grit/xtb_reader.py
create mode 100644 tools/grit/grit/xtb_reader_unittest.py
create mode 100644 tools/grit/grit_info.py
create mode 100644 tools/grit/grit_rule.gni
create mode 100644 tools/grit/minify_with_uglify.py
create mode 100644 tools/grit/minimize_css.py
create mode 100644 tools/grit/minimize_css_unittest.py
create mode 100644 tools/grit/pak_util.py
create mode 100644 tools/grit/repack.gni
create mode 100644 tools/grit/setup.py
create mode 100644 tools/grit/stamp_grit_sources.py
create mode 100644 tools/grit/third_party/six/LICENSE
create mode 100644 tools/grit/third_party/six/README
create mode 100644 tools/grit/third_party/six/README.chromium
create mode 100644 tools/grit/third_party/six/__init__.py
diff --git a/tools/grit/.gitignore b/tools/grit/.gitignore
new file mode 100644
index 0000000000..0d20b6487c
--- /dev/null
+++ b/tools/grit/.gitignore
@@ -0,0 +1 @@
+*.pyc
diff --git a/tools/grit/BUILD.gn b/tools/grit/BUILD.gn
new file mode 100644
index 0000000000..1cd3c75b55
--- /dev/null
+++ b/tools/grit/BUILD.gn
@@ -0,0 +1,48 @@
+# Copyright 2014 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.
+
+# This target creates a stamp file that depends on all the sources in the grit
+# directory. By depending on this, a target can force itself to be rebuilt if
+# grit itself changes.
+
+import("//build/config/sanitizers/sanitizers.gni")
+
+action("grit_sources") {
+ depfile = "$target_out_dir/grit_sources.d"
+ script = "stamp_grit_sources.py"
+
+ inputs = [ "grit.py" ]
+
+ # Note that we can't call this "grit_sources.stamp" because that file is
+ # implicitly created by GN for script actions.
+ outputs = [ "$target_out_dir/grit_sources.script.stamp" ]
+
+ args = [
+ rebase_path("//tools/grit", root_build_dir),
+ rebase_path(outputs[0], root_build_dir),
+ rebase_path(depfile, root_build_dir),
+ ]
+}
+
+group("grit_python_unittests") {
+ testonly = true
+
+ data = [
+ "//testing/scripts/common.py",
+ "//testing/scripts/run_isolated_script_test.py",
+ "//testing/xvfb.py",
+ "//tools/grit/",
+ "//third_party/catapult/third_party/typ/",
+ ]
+}
+
+# See
https://crbug.com/983200
+if (is_mac && is_asan) {
+ create_bundle("brotli_mac_asan_workaround") {
+ bundle_root_dir = "$target_out_dir/$target_name"
+ bundle_executable_dir = bundle_root_dir
+
+ public_deps = [ "//third_party/brotli:brotli($host_toolchain)" ]
+ }
+}
diff --git a/tools/grit/MANIFEST.in b/tools/grit/MANIFEST.in
new file mode 100644
index 0000000000..1cbff42400
--- /dev/null
+++ b/tools/grit/MANIFEST.in
@@ -0,0 +1,3 @@
+exclude grit/test_suite_all.py
+exclude grit/tool/test.py
+global-exclude *_unittest.py
diff --git a/tools/grit/OWNERS b/tools/grit/OWNERS
new file mode 100644
index 0000000000..6a8f447b82
--- /dev/null
+++ b/tools/grit/OWNERS
@@ -0,0 +1,8 @@
+agrieve@chromium.org
+flackr@chromium.org
+thakis@chromium.org
+thestig@chromium.org
+
+# Admin policy related grit tools.
+per-file *policy*=file://components/policy/tools/OWNERS
+per-file *admin_template*=file://components/policy/tools/OWNERS
diff --git a/tools/grit/PRESUBMIT.py b/tools/grit/PRESUBMIT.py
new file mode 100644
index 0000000000..03b7188551
--- /dev/null
+++ b/tools/grit/PRESUBMIT.py
@@ -0,0 +1,22 @@
+# Copyright (c) 2012 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.
+
+"""grit unittests presubmit script.
+
+See
http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts for
+details on the presubmit API built into gcl.
+"""
+
+
+def RunUnittests(input_api, output_api):
+ return input_api.canned_checks.RunUnitTests(input_api, output_api,
+ [input_api.os_path.join('grit', 'test_suite_all.py')])
+
+
+def CheckChangeOnUpload(input_api, output_api):
+ return RunUnittests(input_api, output_api)
+
+
+def CheckChangeOnCommit(input_api, output_api):
+ return RunUnittests(input_api, output_api)
diff --git a/tools/grit/README.md b/tools/grit/README.md
new file mode 100644
index 0000000000..b5c3f4b51b
--- /dev/null
+++ b/tools/grit/README.md
@@ -0,0 +1,19 @@
+# GRIT (Google Resource and Internationalization Tool)
+
+This is a tool for projects to manage resources and simplify the localization
+workflow.
+
+See the user guide for more details on using this project:
+
https://dev.chromium.org/developers/tools-we-use-in-chromium/grit/grit-users-guide
+
+## History
+
+This code previously used to live at
+
https://code.google.com/p/grit-i18n/source/checkout which still contains the
+project's history.
https://chromium.googlesource.com/external/grit-i18n/ is
+a git mirror of the SVN repository that's identical except for the last two
+commits. The project is now developed in the Chromium project directly.
+
+There is a read-only mirror of just this directory at
+
https://chromium.googlesource.com/chromium/src/tools/grit/ if you don't want to
+check out all of Chromium.
diff --git a/tools/grit/grit.py b/tools/grit/grit.py
new file mode 100644
index 0000000000..abd1ab6449
--- /dev/null
+++ b/tools/grit/grit.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 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.
+
+'''Bootstrapping for GRIT.
+'''
+
+from __future__ import print_function
+
+import os
+import sys
+
+import grit.grit_runner
+
+sys.path.append(
+ os.path.join(
+ os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
+ 'diagnosis'))
+try:
+ import crbug_1001171
+except ImportError:
+ crbug_1001171 = None
+
+
+if __name__ == '__main__':
+ if crbug_1001171:
+ with crbug_1001171.DumpStateOnLookupError():
+ sys.exit(grit.grit_runner.Main(sys.argv[1:]))
+ else:
+ sys.exit(grit.grit_runner.Main(sys.argv[1:]))
diff --git a/tools/grit/grit/__init__.py b/tools/grit/grit/__init__.py
new file mode 100644
index 0000000000..91ac9ee896
--- /dev/null
+++ b/tools/grit/grit/__init__.py
@@ -0,0 +1,19 @@
+# Copyright (c) 2012 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.
+
+'''Package 'grit'
+'''
+
+from __future__ import print_function
+
+import os
+import sys
+
+
+_CUR_DIR = os.path.abspath(os.path.dirname(__file__))
+_GRIT_DIR = os.path.dirname(_CUR_DIR)
+_THIRD_PARTY_DIR = os.path.join(_GRIT_DIR, 'third_party')
+
+if _THIRD_PARTY_DIR not in sys.path:
+ sys.path.insert(0, _THIRD_PARTY_DIR)
diff --git a/tools/grit/grit/clique.py b/tools/grit/grit/clique.py
new file mode 100644
index 0000000000..e7be3ec164
--- /dev/null
+++ b/tools/grit/grit/clique.py
@@ -0,0 +1,491 @@
+# Copyright (c) 2012 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.
+
+'''Collections of messages and their translations, called cliques. Also
+collections of cliques (uber-cliques).
+'''
+
+from __future__ import print_function
+
+import re
+
+import six
+
+from grit import constants
+from grit import exception
+from grit import lazy_re
+from grit import pseudo
+from grit import pseudo_rtl
+from grit import tclib
+
+
+class UberClique(object):
+ '''A factory (NOT a singleton factory) for making cliques. It has several
+ methods for working with the cliques created using the factory.
+ '''
+
+ def __init__(self):
+ # A map from message ID to list of cliques whose source messages have
+ # that ID. This will contain all cliques created using this factory.
+ # Different messages can have the same ID because they have the
+ # same translateable portion and placeholder names, but occur in different
+ # places in the resource tree.
+ #
+ # Each list of cliques is kept sorted by description, to achieve
+ # stable results from the BestClique method, see below.
+ self.cliques_ = {}
+
+ # A map of clique IDs to list of languages to indicate translations where we
+ # fell back to English.
+ self.fallback_translations_ = {}
+
+ # A map of clique IDs to list of languages to indicate missing translations.
+ self.missing_translations_ = {}
+
+ def _AddMissingTranslation(self, lang, clique, is_error):
+ tl = self.fallback_translations_
+ if is_error:
+ tl = self.missing_translations_
+ id = clique.GetId()
+ if id not in tl:
+ tl[id] = {}
+ if lang not in tl[id]:
+ tl[id][lang] = 1
+
+ def HasMissingTranslations(self):
+ return len(self.missing_translations_) > 0
+
+ def MissingTranslationsReport(self):
+ '''Returns a string suitable for printing to report missing
+ and fallback translations to the user.
+ '''
+ def ReportTranslation(clique, langs):
+ text = clique.GetMessage().GetPresentableContent()
+ # The text 'error' (usually 'Error:' but we are conservative)
+ # can trigger some build environments (Visual Studio, we're
+ # looking at you) to consider invocation of grit to have failed,
+ # so we make sure never to output that word.
+ extract = re.sub(r'(?i)error', 'REDACTED', text[0:40])[0:40]
+ ellipsis = ''
+ if len(text) > 40:
+ ellipsis = '...'
+ langs_extract = langs[0:6]
+ describe_langs = ','.join(langs_extract)
+ if len(langs) > 6:
+ describe_langs += " and %d more" % (len(langs) - 6)
+ return " %s \"%s%s\" %s" % (clique.GetId(), extract, ellipsis,
+ describe_langs)
+ lines = []
+ if len(self.fallback_translations_):
+ lines.append(
+ "WARNING: Fell back to English for the following translations:")
+ for (id, langs) in self.fallback_translations_.items():
+ lines.append(
+ ReportTranslation(self.cliques_[id][0], list(langs.keys())))
+ if len(self.missing_translations_):
+ lines.append("ERROR: The following translations are MISSING:")
+ for (id, langs) in self.missing_translations_.items():
+ lines.append(
+ ReportTranslation(self.cliques_[id][0], list(langs.keys())))
+ return '\n'.join(lines)
+
+ def MakeClique(self, message, translateable=True):
+ '''Create a new clique initialized with a message.
+
+ Args:
+ message: tclib.Message()
+ translateable: True | False
+ '''
+ clique = MessageClique(self, message, translateable)
+
+ # Enable others to find this clique by its message ID
+ if message.GetId() in self.cliques_:
+ presentable_text = clique.GetMessage().GetPresentableContent()
+ if not message.HasAssignedId():
+ for c in self.cliques_[message.GetId()]:
+ assert c.GetMessage().GetPresentableContent() == presentable_text
+ self.cliques_[message.GetId()].append(clique)
+ # We need to keep each list of cliques sorted by description, to
+ # achieve stable results from the BestClique method, see below.
+ self.cliques_[message.GetId()].sort(
+ key=lambda c:c.GetMessage().GetDescription())
+ else:
+ self.cliques_[message.GetId()] = [clique]
+
+ return clique
+
+ def FindCliqueAndAddTranslation(self, translation, language):
+ '''Adds the specified translation to the clique with the source message
+ it is a translation of.
+
+ Args:
+ translation: tclib.Translation()
+ language: 'en' | 'fr' ...
+
+ Return:
+ True if the source message was found, otherwise false.
+ '''
+ if translation.GetId() in self.cliques_:
+ for clique in self.cliques_[translation.GetId()]:
+ clique.AddTranslation(translation, language)
+ return True
+ else:
+ return False
+
+ def BestClique(self, id):
+ '''Returns the "best" clique from a list of cliques. All the cliques
+ must have the same ID. The "best" clique is chosen in the following
+ order of preference:
+ - The first clique that has a non-ID-based description.
+ - If no such clique found, the first clique with an ID-based description.
+ - Otherwise the first clique.
+
+ This method is stable in terms of always returning a clique with
+ an identical description (on different runs of GRIT on the same
+ data) because self.cliques_ is sorted by description.
+ '''
+ clique_list = self.cliques_[id]
+ clique_with_id = None
+ clique_default = None
+ for clique in clique_list:
+ if not clique_default:
+ clique_default = clique
+
+ description = clique.GetMessage().GetDescription()
+ if description and len(description) > 0:
+ if not description.startswith('ID:'):
+ # this is the preferred case so we exit right away
+ return clique
+ elif not clique_with_id:
+ clique_with_id = clique
+ if clique_with_id:
+ return clique_with_id
+ else:
+ return clique_default
+
+ def BestCliquePerId(self):
+ '''Iterates over the list of all cliques and returns the best clique for
+ each ID. This will be the first clique with a source message that has a
+ non-empty description, or an arbitrary clique if none of them has a
+ description.
+ '''
+ for id in self.cliques_:
+ yield self.BestClique(id)
+
+ def BestCliqueByOriginalText(self, text, meaning):
+ '''Finds the "best" (as in BestClique()) clique that has original text
+ 'text' and meaning 'meaning'. Returns None if there is no such clique.
+ '''
+ # If needed, this can be optimized by maintaining a map of
+ # fingerprints of original text+meaning to cliques.
+ for c in self.BestCliquePerId():
+ msg = c.GetMessage()
+ if msg.GetRealContent() == text and msg.GetMeaning() == meaning:
+ return msg
+ return None
+
+ def AllMessageIds(self):
+ '''Returns a list of all defined message IDs.
+ '''
+ return list(self.cliques_.keys())
+
+ def AllCliques(self):
+ '''Iterates over all cliques. Note that this can return multiple cliques
+ with the same ID.
+ '''
+ for cliques in self.cliques_.values():
+ for c in cliques:
+ yield c
+
+ def GenerateXtbParserCallback(self, lang, debug=False):
+ '''Creates a callback function as required by grit.xtb_reader.Parse().
+ This callback will create Translation objects for each message from
+ the XTB that exists in this uberclique, and add them as translations for
+ the relevant cliques. The callback will add translations to the language
+ specified by 'lang'
+
+ Args:
+ lang: 'fr'
+ debug: True | False
+ '''
+ def Callback(id, structure):
+ if id not in self.cliques_:
+ if debug:
+ print("Ignoring translation #%s" % id)
+ return
+
+ if debug:
+ print("Adding translation #%s" % id)
+
+ # We fetch placeholder information from the original message (the XTB file
+ # only contains placeholder names).
+ original_msg = self.BestClique(id).GetMessage()
+
+ translation = tclib.Translation(id=id)
+ for is_ph,text in structure:
+ if not is_ph:
+ translation.AppendText(text)
+ else:
+ found_placeholder = False
+ for ph in original_msg.GetPlaceholders():
+ if ph.GetPresentation() == text:
+ translation.AppendPlaceholder(tclib.Placeholder(
+ ph.GetPresentation(), ph.GetOriginal(), ph.GetExample()))
+ found_placeholder = True
+ break
+ if not found_placeholder:
+ raise exception.MismatchingPlaceholders(
+ 'Translation for message ID %s had <ph name="%s"/>, no match\n'
+ 'in original message' % (id, text))
+ self.FindCliqueAndAddTranslation(translation, lang)
+ return Callback
+
+
+class CustomType(object):
+ '''A base class you should implement if you wish to specify a custom type
+ for a message clique (i.e. custom validation and optional modification of
+ translations).'''
+
+ def Validate(self, message):
+ '''Returns true if the message (a tclib.Message object) is valid,
+ otherwise false.
+ '''
+ raise NotImplementedError()
+
+ def ValidateAndModify(self, lang, translation):
+ '''Returns true if the translation (a tclib.Translation object) is valid,
+ otherwise false. The language is also passed in. This method may modify
+ the translation that is passed in, if it so wishes.
+ '''
+ raise NotImplementedError()
+
+ def ModifyTextPart(self, lang, text):
+ '''If you call ModifyEachTextPart, it will turn around and call this method
+ for each text part of the translation. You should return the modified
+ version of the text, or just the original text to not change anything.
+ '''
+ raise NotImplementedError()
+
+ def ModifyEachTextPart(self, lang, translation):
+ '''Call this to easily modify one or more of the textual parts of a
+ translation. It will call ModifyTextPart for each part of the
+ translation.
+ '''
+ contents = translation.GetContent()
+ for ix in range(len(contents)):
+ if (isinstance(contents[ix], six.string_types)):
+ contents[ix] = self.ModifyTextPart(lang, contents[ix])
+
+
+class OneOffCustomType(CustomType):
+ '''A very simple custom type that performs the validation expressed by
+ the input expression on all languages including the source language.
+ The expression can access the variables 'lang', 'msg' and 'text()' where
+ 'lang' is the language of 'msg', 'msg' is the message or translation being
+ validated and 'text()' returns the real contents of 'msg' (for shorthand).
+ '''
+ def __init__(self, expression):
+ self.expr = expression
+ def Validate(self, message):
+ return self.ValidateAndModify(MessageClique.source_language, message)
+ def ValidateAndModify(self, lang, msg):
+ def text():
+ return msg.GetRealContent()
+ return eval(self.expr, {},
+ {'lang' : lang,
+ 'text' : text,
+ 'msg' : msg,
+ })
+
+
+class MessageClique(object):
+ '''A message along with all of its translations. Also code to bring
+ translations together with their original message.'''
+
+ # change this to the language code of Messages you add to cliques_.
+ # TODO(joi) Actually change this based on the <grit> node's source language
+ source_language = 'en'
+
+ # A constant translation we use when asked for a translation into the
+ # special language constants.CONSTANT_LANGUAGE.
+ CONSTANT_TRANSLATION = tclib.Translation(text='TTTTTT')
+
+ # A pattern to match messages that are empty or whitespace only.
+ WHITESPACE_MESSAGE = lazy_re.compile(r'^\s*$')
+
+ def __init__(self, uber_clique, message, translateable=True,
+ custom_type=None):
+ '''Create a new clique initialized with just a message.
+
+ Note that messages with a body comprised only of whitespace will implicitly
+ be marked non-translatable.
+
+ Args:
+ uber_clique: Our uber-clique (collection of cliques)
+ message: tclib.Message()
+ translateable: True | False
+ custom_type: instance of clique.CustomType interface
+ '''
+ # Our parent
+ self.uber_clique = uber_clique
+ # If not translateable, we only store the original message.
+ self.translateable = translateable
+
+ # We implicitly mark messages that have a whitespace-only body as
+ # non-translateable.
+ if MessageClique.WHITESPACE_MESSAGE.match(message.GetRealContent()):
+ self.translateable = False
+
+ # A mapping of language identifiers to tclib.BaseMessage and its
+ # subclasses (i.e. tclib.Message and tclib.Translation).
+ self.clique = { MessageClique.source_language : message }
+ # A list of the "shortcut groups" this clique is
+ # part of. Within any given shortcut group, no shortcut key (e.g. &J)
+ # must appear more than once in each language for all cliques that
+ # belong to the group.
+ self.shortcut_groups = []
+ # An instance of the CustomType interface, or None. If this is set, it will
+ # be used to validate the original message and translations thereof, and
+ # will also get a chance to modify translations of the message.
+ self.SetCustomType(custom_type)
+
+ def GetMessage(self):
+ '''Retrieves the tclib.Message that is the source for this clique.'''
+ return self.clique[MessageClique.source_language]
+
+ def GetId(self):
+ '''Retrieves the message ID of the messages in this clique.'''
+ return self.GetMessage().GetId()
+
+ def IsTranslateable(self):
+ return self.translateable
+
+ def AddToShortcutGroup(self, group):
+ self.shortcut_groups.append(group)
+
+ def SetCustomType(self, custom_type):
+ '''Makes this clique use custom_type for validating messages and
+ translations, and optionally modifying translations.
+ '''
+ self.custom_type = custom_type
+ if custom_type and not custom_type.Validate(self.GetMessage()):
+ raise exception.InvalidMessage(self.GetMessage().GetRealContent())
+
+ def MessageForLanguage(self, lang, pseudo_if_no_match=True,
+ fallback_to_english=False):
+ '''Returns the message/translation for the specified language, providing
+ a pseudotranslation if there is no available translation and a pseudo-
+ translation is requested.
+
+ The translation of any message whatsoever in the special language
+ 'x_constant' is the message "TTTTTT".
+
+ Args:
+ lang: 'en'
+ pseudo_if_no_match: True
+ fallback_to_english: False
+
+ Return:
+ tclib.BaseMessage
+ '''
+ if not self.translateable:
+ return self.GetMessage()
+
+ if lang == constants.CONSTANT_LANGUAGE:
+ return self.CONSTANT_TRANSLATION
+
+ for msglang in self.clique:
+ if lang == msglang:
+ return self.clique[msglang]
+
+ if lang == constants.FAKE_BIDI:
+ return pseudo_rtl.PseudoRTLMessage(self.GetMessage())
+
+ if fallback_to_english:
+ self.uber_clique._AddMissingTranslation(lang, self, is_error=False)
+ return self.GetMessage()
+
+ # If we're not supposed to generate pseudotranslations, we add an error
+ # report to a list of errors, then fail at a higher level, so that we
+ # get a list of all messages that are missing translations.
+ if not pseudo_if_no_match:
+ self.uber_clique._AddMissingTranslation(lang, self, is_error=True)
+
+ return pseudo.PseudoMessage(self.GetMessage())
+
+ def AllMessagesThatMatch(self, lang_re, include_pseudo = True):
+ '''Returns a map of all messages that match 'lang', including the pseudo
+ translation if requested.
+
+ Args:
+ lang_re: re.compile(r'fr|en')
+ include_pseudo: True
+
+ Return:
+ { 'en' : tclib.Message,
+ 'fr' : tclib.Translation,
+ pseudo.PSEUDO_LANG : tclib.Translation }
+ '''
+ if not self.translateable:
+ return [self.GetMessage()]
+
+ matches = {}
+ for msglang in self.clique:
+ if lang_re.match(msglang):
+ matches[msglang] = self.clique[msglang]
+
+ if include_pseudo:
+ matches[pseudo.PSEUDO_LANG] = pseudo.PseudoMessage(self.GetMessage())
+
+ return matches
+
+ def AddTranslation(self, translation, language):
+ '''Add a translation to this clique. The translation must have the same
+ ID as the message that is the source for this clique.
+
+ If this clique is not translateable, the function just returns.
+
+ Args:
+ translation: tclib.Translation()
+ language: 'en'
+
+ Throws:
+ grit.exception.InvalidTranslation if the translation you're trying to add
+ doesn't have the same message ID as the source message of this clique.
+ '''
+ if not self.translateable:
+ return
+ if translation.GetId() != self.GetId():
+ raise exception.InvalidTranslation(
+ 'Msg ID %s, transl ID %s' % (self.GetId(), translation.GetId()))
+
+ assert not language in self.clique
+
+ # Because two messages can differ in the original content of their
+ # placeholders yet share the same ID (because they are otherwise the
+ # same), the translation we are getting may have different original
+ # content for placeholders than our message, yet it is still the right
+ # translation for our message (because it is for the same ID). We must
+ # therefore fetch the original content of placeholders from our original
+ # English message.
+ #
+ # See grit.clique_unittest.MessageCliqueUnittest.testSemiIdenticalCliques
+ # for a concrete explanation of why this is necessary.
+
+ original = self.MessageForLanguage(self.source_language, False)
+ if len(original.GetPlaceholders()) != len(translation.GetPlaceholders()):
+ print("ERROR: '%s' translation of message id %s does not match" %
+ (language, translation.GetId()))
+ assert False
+
+ transl_msg = tclib.Translation(id=self.GetId(),
+ text=translation.GetPresentableContent(),
+ placeholders=original.GetPlaceholders())
+
+ if (self.custom_type and
+ not self.custom_type.ValidateAndModify(language, transl_msg)):
+ print("WARNING: %s translation failed validation: %s" %
+ (language, transl_msg.GetId()))
+
+ self.clique[language] = transl_msg
diff --git a/tools/grit/grit/clique_unittest.py b/tools/grit/grit/clique_unittest.p
y
new file mode 100644
index 0000000000..7d2d7318ba
--- /dev/null
+++ b/tools/grit/grit/clique_unittest.py
@@ -0,0 +1,265 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 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.
+
+'''Unit tests for grit.clique'''
+
+from __future__ import print_function
+
+import os
+import sys
+if __name__ == '__main__':
+ sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
+
+import re
+import unittest
+
+from six import StringIO
+
+from grit import clique
+from grit import exception
+from grit import pseudo
+from grit import tclib
+from grit import grd_reader
+from grit import util
+
+class MessageCliqueUnittest(unittest.TestCase):
+ def testClique(self):
+ factory = clique.UberClique()
+ msg = tclib.Message(text='Hello USERNAME, how are you?',
+ placeholders=[
+ tclib.Placeholder('USERNAME', '%s', 'Joi')])
+ c = factory.MakeClique(msg)
+
+ self.failUnless(c.GetMessage() == msg)
+ self.failUnless(c.GetId() == msg.GetId())
+
+ msg_fr = tclib.Translation(text='Bonjour USERNAME, comment ca va?',
+ id=msg.GetId(), placeholders=[
+ tclib.Placeholder('USERNAME', '%s', 'Joi')])
+ msg_de = tclib.Translation(text='Guten tag USERNAME, wie geht es dir?',
+ id=msg.GetId(), placeholders=[
+ tclib.Placeholder('USERNAME', '%s', 'Joi')])
+
+ c.AddTranslation(msg_fr, 'fr')
+ factory.FindCliqueAndAddTranslation(msg_de, 'de')
+
+ # sort() sorts lists in-place and does not return them
+ for lang in ('en', 'fr', 'de'):
+ self.failUnless(lang in c.clique)
+
+ self.failUnless(c.MessageForLanguage('fr').GetRealContent() ==
+ msg_fr.GetRealContent())
+
+ try:
+ c.MessageForLanguage('zh-CN', False)
+ self.fail('Should have gotten exception')
+ except:
+ pass
+
+ self.failUnless(c.MessageForLanguage('zh-CN', True) != None)
+
+ rex = re.compile('fr|de|bingo')
+ self.failUnless(len(c.AllMessagesThatMatch(rex, False)) == 2)
+ self.failUnless(
+ c.AllMessagesThatMatch(rex, True)[pseudo.PSEUDO_LANG] is not None)
+
+ def testBestClique(self):
+ factory = clique.UberClique()
+ factory.MakeClique(tclib.Message(text='Alfur', description='alfaholl'))
+ factory.MakeClique(tclib.Message(text='Alfur', description=''))
+ factory.MakeClique(tclib.Message(text='Vaettur', description=''))
+ factory.MakeClique(tclib.Message(text='Vaettur', description=''))
+ factory.MakeClique(tclib.Message(text='Troll', description=''))
+ factory.MakeClique(tclib.Message(text='Gryla', description='ID: IDS_GRYLA'))
+ factory.MakeClique(tclib.Message(text='Gryla', description='vondakerling'))
+ factory.MakeClique(tclib.Message(text='Leppaludi', description='ID: IDS_LL'))
+ factory.MakeClique(tclib.Message(text='Leppaludi', description=''))
+
+ count_best_cliques = 0
+ for c in factory.BestCliquePerId():
+ count_best_cliques += 1
+ msg = c.GetMessage()
+ text = msg.GetRealContent()
+ description = msg.GetDescription()
+ if text == 'Alfur':
+ self.failUnless(description == 'alfaholl')
+ elif text == 'Gryla':
+ self.failUnless(description == 'vondakerling')
+ elif text == 'Leppaludi':
+ self.failUnless(description == 'ID: IDS_LL')
+ self.failUnless(count_best_cliques == 5)
+
+ def testAllInUberClique(self):
+ resources = grd_reader.Parse(
+ StringIO(u'''<?xml version="1.0" encoding="UTF-8"?>
+<grit latest_public_release="2" source_lang_id="en-US" current_release="3" base_dir=".">
+ <release seq="3">
+ <messages>
+ <message name="IDS_GREETING" desc="Printed to greet the currently logged in user">
+ Hello <ph name="USERNAME">%s<ex>Joi</ex></ph>, how are you doing today?
+ </message>
+ </messages>
+ <structures>
+ <structure type="dialog" name="IDD_ABOUTBOX" encoding="utf-16" file="grit/testdata/klonk.rc" />
+ <structure type="tr_html" name="ID_HTML" file="grit/testdata/simple.html" />
+ </structures>
+ </release>
+</grit>'''), util.PathFromRoot('.'))
+ resources.SetOutputLanguage('en')
+ resources.RunGatherers()
+ content_list = []
+ for clique_list in resources.UberClique().cliques_.values():
+ for clique in clique_list:
+ content_list.append(clique.GetMessage().GetRealContent())
+ self.failUnless('Hello %s, how are you doing today?' in content_list)
+ self.failUnless('Jack "Black" Daniels' in content_list)
+ self.failUnless('Hello!' in content_list)
+
+ def testCorrectExceptionIfWrongEncodingOnResourceFile(self):
+ '''This doesn't really belong in this unittest file, but what the heck.'''
+ resources = grd_reader.Parse(
+ StringIO(u'''<?xml version="1.0" encoding="UTF-8"?>
+<grit latest_public_release="2" source_lang_id="en-US" current_release="3" base_dir=".">
+ <release seq="3">
+ <structures>
+ <structure type="dialog" name="IDD_ABOUTBOX" file="grit/testdata/klonk.rc" />
+ </structures>
+ </release>
+</grit>'''), util.PathFromRoot('.'))
+ self.assertRaises(exception.SectionNotFound, resources.RunGatherers)
+
+ def testSemiIdenticalCliques(self):
+ messages = [
+ tclib.Message(text='Hello USERNAME',
+ placeholders=[tclib.Placeholder('USERNAME', '$1', 'Joi')]),
+ tclib.Message(text='Hello USERNAME',
+ placeholders=[tclib.Placeholder('USERNAME', '%s', 'Joi')]),
+ ]
+ self.failUnless(messages[0].GetId() == messages[1].GetId())
+
+ # Both of the above would share a translation.
+ translation = tclib.Translation(id=messages[0].GetId(),
+ text='Bonjour USERNAME',
+ placeholders=[tclib.Placeholder(
+ 'USERNAME', '$1', 'Joi')])
+
+ factory = clique.UberClique()
+ cliques = [factory.MakeClique(msg) for msg in messages]
+
+ for clq in cliques:
+ clq.AddTranslation(translation, 'fr')
+
+ self.failUnless(cliques[0].MessageForLanguage('fr').GetRealContent() ==
+ 'Bonjour $1')
+ self.failUnless(cliques[1].MessageForLanguage('fr').GetRealContent() ==
+ 'Bonjour %s')
+
+ def testMissingTranslations(self):
+ messages = [ tclib.Message(text='Hello'), tclib.Message(text='Goodbye') ]
+ factory = clique.UberClique()
+ cliques = [factory.MakeClique(msg) for msg in messages]
+
+ cliques[1].MessageForLanguage('fr', False, True)
+
+ self.failUnless(not factory.HasMissingTranslations())
+
+ cliques[0].MessageForLanguage('de', False, False)
+
+ self.failUnless(factory.HasMissingTranslations())
+
+ report = factory.MissingTranslationsReport()
+ self.failUnless(report.count('WARNING') == 1)
+ self.failUnless(report.count('8053599568341804890 "Goodbye" fr') == 1)
+ self.failUnless(report.count('ERROR') == 1)
+ self.failUnless(report.count('800120468867715734 "Hello" de') == 1)
+
+ def testCustomTypes(self):
+ factory = clique.UberClique()
+ message = tclib.Message(text='Bingo bongo')
+ c = factory.MakeClique(message)
+ try:
+ c.SetCustomType(DummyCustomType())
+ self.fail()
+ except:
+ pass # expected case - 'Bingo bongo' does not start with 'jjj'
+
+ message = tclib.Message(text='jjjBingo bongo')
+ c = factory.MakeClique(message)
+ c.SetCustomType(util.NewClassInstance(
+ 'grit.clique_unittest.DummyCustomType', clique.CustomType))
+ translation = tclib.Translation(id=message.GetId(), text='Bilingo bolongo')
+ c.AddTranslation(translation, 'fr')
+ self.failUnless(c.MessageForLanguage('fr').GetRealContent().startswith('jjj'))
+
+ def testWhitespaceMessagesAreNontranslateable(self):
+ factory = clique.UberClique()
+
+ message = tclib.Message(text=' \t')
+ c = factory.MakeClique(message, translateable=True)
+ self.failIf(c.IsTranslateable())
+
+ message = tclib.Message(text='\n \n ')
+ c = factory.MakeClique(message, translateable=True)
+ self.failIf(c.IsTranslateable())
+
+ message = tclib.Message(text='\n hello')
+ c = factory.MakeClique(message, translateable=True)
+ self.failUnless(c.IsTranslateable())
+
+ def testEachCliqueKeptSorted(self):
+ factory = clique.UberClique()
+ msg_a = tclib.Message(text='hello', description='a')
+ msg_b = tclib.Message(text='hello', description='b')
+ msg_c = tclib.Message(text='hello', description='c')
+ # Insert out of order
+ clique_b = factory.MakeClique(msg_b, translateable=True)
+ clique_a = factory.MakeClique(msg_a, translateable=True)
+ clique_c = factory.MakeClique(msg_c, translateable=True)
+ clique_list = factory.cliques_[clique_a.GetId()]
+ self.failUnless(len(clique_list) == 3)
+ self.failUnless(clique_list[0] == clique_a)
+ self.failUnless(clique_list[1] == clique_b)
+ self.failUnless(clique_list[2] == clique_c)
+
+ def testBestCliqueSortIsStable(self):
+ factory = clique.UberClique()
+ text = 'hello'
+ msg_no_description = tclib.Message(text=text)
+ msg_id_description_a = tclib.Message(text=text, description='ID: a')
+ msg_id_description_b = tclib.Message(text=text, description='ID: b')
+ msg_description_x = tclib.Message(text=text, description='x')
+ msg_description_y = tclib.Message(text=text, description='y')
+ clique_id = msg_no_description.GetId()
+
+ # Insert in an order that tests all outcomes.
+ clique_no_description = factory.MakeClique(msg_no_description,
+ translateable=True)
+ self.failUnless(factory.BestClique(clique_id) == clique_no_description)
+ clique_id_description_b = factory.MakeClique(msg_id_description_b,
+ translateable=True)
+ self.failUnless(factory.BestClique(clique_id) == clique_id_description_b)
+ clique_id_description_a = factory.MakeClique(msg_id_description_a,
+ translateable=True)
+ self.failUnless(factory.BestClique(clique_id) == clique_id_description_a)
+ clique_description_y = factory.MakeClique(msg_description_y,
+ translateable=True)
+ self.failUnless(factory.BestClique(clique_id) == clique_description_y)
+ clique_description_x = factory.MakeClique(msg_description_x,
+ translateable=True)
+ self.failUnless(factory.BestClique(clique_id) == clique_description_x)
+
+
+class DummyCustomType(clique.CustomType):
+ def Validate(self, message):
+ return message.GetRealContent().startswith('jjj')
+ def ValidateAndModify(self, lang, translation):
+ is_ok = self.Validate(translation)
+ self.ModifyEachTextPart(lang, translation)
+ def ModifyTextPart(self, lang, text):
+ return 'jjj%s' % text
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tools/grit/grit/constants.py b/tools/grit/grit/constants.py
new file mode 100644
index 0000000000..8229c94b09
--- /dev/null
+++ b/tools/grit/grit/constants.py
@@ -0,0 +1,23 @@
+# Copyright (c) 2012 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.
+
+'''Constant definitions for GRIT.
+'''
+
+from __future__ import print_function
+
+# This is the Icelandic noun meaning "grit" and is used to check that our
+# input files are in the correct encoding. The middle character gets encoded
+# as two bytes in UTF-8, so this is sufficient to detect incorrect encoding.
+ENCODING_CHECK = u'm\u00f6l'
+
+# A special language, translations into which are always "TTTTTT".
+CONSTANT_LANGUAGE = 'x_constant'
+
+FAKE_BIDI = 'fake-bidi'
+
+# Magic number added to the header of resources brotli compressed by grit. Used
+# to easily identify resources as being brotli compressed. See
+# ui/base/resource/resource_bundle.h for decompression usage.
+BROTLI_CONST = b'\x1e\x9b'
diff --git a/tools/grit/grit/exception.py b/tools/grit/grit/exception.py
new file mode 100644
index 0000000000..2a363fb077
--- /dev/null
+++ b/tools/grit/grit/exception.py
@@ -0,0 +1,139 @@
+# Copyright (c) 2012 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.
+
+'''Exception types for GRIT.
+'''
+
+from __future__ import print_function
+
+class Base(Exception):
+ '''A base exception that uses the class's docstring in addition to any
+ user-provided message as the body of the Base.
+ '''
+ def __init__(self, msg=''):
+ if len(msg):
+ if self.__doc__:
+ msg = self.__doc__ + ': ' + msg
+ else:
+ msg = self.__doc__
+ super(Base, self).__init__(msg)
+
+
+class Parsing(Base):
+ '''An error occurred parsing a GRD or XTB file.'''
+ pass
+
+
+class UnknownElement(Parsing):
+ '''An unknown node type was encountered.'''
+ pass
+
+
+class MissingElement(Parsing):
+ '''An expected element was missing.'''
+ pass
+
+
+class UnexpectedChild(Parsing):
+ '''An unexpected child element was encountered (on a leaf node).'''
+ pass
+
+
+class UnexpectedAttribute(Parsing):
+ '''The attribute was not expected'''
+ pass
+
+
+class UnexpectedContent(Parsing):
+ '''This element should not have content'''
+ pass
+
+class MissingMandatoryAttribute(Parsing):
+ '''This element is missing a mandatory attribute'''
+ pass
+
+
+class MutuallyExclusiveMandatoryAttribute(Parsing):
+ '''This element has 2 mutually exclusive mandatory attributes'''
+ pass
+
+
+class DuplicateKey(Parsing):
+ '''A duplicate key attribute was found.'''
+ pass
+
+
+class TooManyExamples(Parsing):
+ '''Only one <ex> element is allowed for each <ph> element.'''
+ pass
+
+
+class FileNotFound(Parsing):
+ '''The resource file was not found.'''
+ pass
+
+
+class InvalidMessage(Base):
+ '''The specified message failed validation.'''
+ pass
+
+
+class InvalidTranslation(Base):
+ '''Attempt to add an invalid translation to a clique.'''
+ pass
+
+
+class NoSuchTranslation(Base):
+ '''Requested translation not available'''
+ pass
+
+
--> --------------------
--> maximum size reached
--> --------------------