tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 4533a2607969f2633ee05e2e9dee201df85431c1
parent 4fd1490bd1be8ecdf2afda6a53717f0716d6bc3c
Author: Bastien Orivel <borivel@mozilla.com>
Date:   Tue,  4 Nov 2025 09:24:50 +0000

Bug 1997143 - Properly name XPI files in the langpack RPM packages. r=releng-reviewers,jcristau

Firefox expects XPI files in `distribution/extensions` to be named with
their ID or it throws exceptions on startup like
`/usr/lib/firefox-nightly/distribution/extensions/langpack-it@firefox-nightly.mozilla.org.xpi
contains an add-on with an incorrect ID`.

The previous code would use the package name but the langpack XPI ID is
actually using the remoting name (firefox/devedition) and does not
contain the track for which it was built. So we ended up with
`langpack-fr@firefox-nightly.mozilla.org.xpi` instead of
`langpack-fr@firefox.mozilla.org.xpi` for nightly builds (same issue
with beta), which prevents the langpack from loading.

Differential Revision: https://phabricator.services.mozilla.com/D270551

Diffstat:
Mbrowser/installer/linux/app/rpm/firefox.spec.j2 | 16++++++++--------
Mpython/mozbuild/mozbuild/repackaging/utils.py | 8++++++--
Mpython/mozbuild/mozbuild/test/repackaging/test_utils.py | 46+++++++++++++++++++++++++++++++++++++---------
3 files changed, 51 insertions(+), 19 deletions(-)

diff --git a/browser/installer/linux/app/rpm/firefox.spec.j2 b/browser/installer/linux/app/rpm/firefox.spec.j2 @@ -9,8 +9,8 @@ Vendor: Mozilla Source0: %{name}.tar.xz Source1: %{name}.desktop Source2: %{name}.1 -{%- for codename in LANGUAGES %} -Source{{ loop.index + 2 }}: {{ codename }}.langpack.xpi +{%- for codename, metadata in LANGUAGES.items() %} +Source{{ loop.index + 2 }}: {{ metadata.extension_id }}.xpi {%- endfor %} %global mozappdir /{{ PKG_INSTALL_PATH }} @@ -27,8 +27,8 @@ Source{{ loop.index + 2 }}: {{ codename }}.langpack.xpi %{__install} -m 0644 %{SOURCE2} %{buildroot}%{_mandir}/man1/%{name}.1 %{__ln_s} %{mozappdir}/firefox %{buildroot}%{_bindir}/%{name} %{__mkdir_p} %{buildroot}/%{mozappdir}/distribution/extensions -{%- for codename in LANGUAGES %} -%{__install} -m 0644 %{SOURCE{{ loop.index + 2 }}} %{buildroot}%{mozappdir}/distribution/extensions/langpack-{{ codename }}@{{ PKG_NAME }}.mozilla.org.xpi +{%- for codename, metadata in LANGUAGES.items() %} +%{__install} -m 0644 %{SOURCE{{ loop.index + 2 }}} %{buildroot}%{mozappdir}/distribution/extensions/{{ metadata.extension_id }}.xpi {%- endfor %} %{__install} -D -m 0644 %{buildroot}%{mozappdir}/browser/chrome/icons/default/default16.png %{buildroot}%{_datadir}/icons/hicolor/16x16/apps/%{name}.png %{__install} -D -m 0644 %{buildroot}%{mozappdir}/browser/chrome/icons/default/default32.png %{buildroot}%{_datadir}/icons/hicolor/32x32/apps/%{name}.png @@ -36,18 +36,18 @@ Source{{ loop.index + 2 }}: {{ codename }}.langpack.xpi %{__install} -D -m 0644 %{buildroot}%{mozappdir}/browser/chrome/icons/default/default64.png %{buildroot}%{_datadir}/icons/hicolor/64x64/apps/%{name}.png %{__install} -D -m 0644 %{buildroot}%{mozappdir}/browser/chrome/icons/default/default128.png %{buildroot}%{_datadir}/icons/hicolor/128x128/apps/%{name}.png -{% for codename, description in LANGUAGES.items() %} +{% for codename, metadata in LANGUAGES.items() %} %package l10n-{{ codename }} -Summary: {{ description }} +Summary: {{ metadata.description }} BuildArch: noarch Requires: %{name} = %{version}-%{release} Supplements: (%{name} = %{version}-%{release} and langpacks-{{ codename }}) %description l10n-{{ codename }} -{{ description }} +{{ metadata.description }} %files l10n-{{ codename }} -%{mozappdir}/distribution/extensions/langpack-{{ codename }}@{{ PKG_NAME }}.mozilla.org.xpi +%{mozappdir}/distribution/extensions/{{ metadata.extension_id }}.xpi {% endfor %} %files diff --git a/python/mozbuild/mozbuild/repackaging/utils.py b/python/mozbuild/mozbuild/repackaging/utils.py @@ -218,8 +218,12 @@ def prepare_langpack_files(output_dir, xpi_directory): manifest = get_manifest_from_langpack(xpi_file, output_dir) if manifest is not None: language = manifest["langpack_id"] - metadata[language] = manifest["description"] - output_file = mozpath.join(output_dir, f"{language}.langpack.xpi") + extension_id = manifest["browser_specific_settings"]["gecko"]["id"] + metadata[language] = { + "description": manifest["description"], + "extension_id": extension_id, + } + output_file = mozpath.join(output_dir, f"{extension_id}.xpi") shutil.copy(xpi_file, output_file) return metadata diff --git a/python/mozbuild/mozbuild/test/repackaging/test_utils.py b/python/mozbuild/mozbuild/test/repackaging/test_utils.py @@ -541,7 +541,11 @@ def test_inject_desktop_entry_file(monkeypatch): _MINIMAL_MANIFEST_JSON = """{ "langpack_id": "%(lang)s", "manifest_version": 2, - "browser_specific_settings": {}, + "browser_specific_settings": { + "gecko": { + "id": "langpack-%(lang)s@%(remoting_name)s.mozilla.org" + } + }, "name": "Language: %(lang)s", "description": "Firefox Language Pack for %(lang)s", "version": "136.0.20250326.231000", @@ -561,27 +565,49 @@ def test_get_manifest_from_langpack(): with zipfile.ZipFile(path, "w") as zip_file: zip_file.writestr( - "manifest.json", _MINIMAL_MANIFEST_JSON % {"lang": "dummy"} + "manifest.json", + _MINIMAL_MANIFEST_JSON % {"lang": "dummy", "remoting_name": "firefox"}, ) assert utils.get_manifest_from_langpack(path, d) == json.loads( - _MINIMAL_MANIFEST_JSON % {"lang": "dummy"} + _MINIMAL_MANIFEST_JSON % {"lang": "dummy", "remoting_name": "firefox"} ) @pytest.mark.parametrize( - "languages, expected", + "languages, remoting_name, expected", ( - ([], {}), + ([], "firefox", {}), ( ["ach", "fr"], + "firefox", + { + "ach": { + "description": "Firefox Language Pack for ach", + "extension_id": "langpack-ach@firefox.mozilla.org", + }, + "fr": { + "description": "Firefox Language Pack for fr", + "extension_id": "langpack-fr@firefox.mozilla.org", + }, + }, + ), + ( + ["de", "es"], + "devedition", { - "ach": "Firefox Language Pack for ach", - "fr": "Firefox Language Pack for fr", + "de": { + "description": "Firefox Language Pack for de", + "extension_id": "langpack-de@devedition.mozilla.org", + }, + "es": { + "description": "Firefox Language Pack for es", + "extension_id": "langpack-es@devedition.mozilla.org", + }, }, ), ), ) -def test_prepare_langpack_files(monkeypatch, languages, expected): +def test_prepare_langpack_files(monkeypatch, languages, remoting_name, expected): def _mock_copy(source, destination): pass @@ -592,7 +618,9 @@ def test_prepare_langpack_files(monkeypatch, languages, expected): path = os.path.join(xpi_dir, f"{language}.langpack.xpi") with zipfile.ZipFile(path, "w") as zip_file: zip_file.writestr( - "manifest.json", _MINIMAL_MANIFEST_JSON % {"lang": language} + "manifest.json", + _MINIMAL_MANIFEST_JSON + % {"lang": language, "remoting_name": remoting_name}, ) assert utils.prepare_langpack_files(output_dir, xpi_dir) == expected