Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  0091.patch   Sprache: unbekannt

 
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.py
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

--> --------------------

[ Dauer der Verarbeitung: 0.21 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge