# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import json
import logging
import os
import subprocess
import tempfile
import zipfile
from contextlib
import nullcontext
as does_not_raise
from io
import StringIO
from unittest.mock
import Mock
import mozunit
import pytest
from mozbuild.repackaging
import deb, desktop_file
_APPLICATION_INI_CONTENT =
"" "[App]
Vendor=Mozilla
Name=Firefox
RemotingName=firefox-nightly-
try
CodeName=Firefox Nightly
BuildID=
20230222000000
"" "
_APPLICATION_INI_CONTENT_DATA = {
"name" :
"Firefox" ,
"display_name" :
"Firefox Nightly" ,
"vendor" :
"Mozilla" ,
"remoting_name" :
"firefox-nightly-try" ,
"build_id" :
"20230222000000" ,
}
ZH_TW_FTL =
"" "\
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# These messages are used by the Firefox ".desktop" file on Linux.
# https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html
# The entry name is the label on the desktop icon, among other things.
desktop-entry-name = { -brand-shortcut-name }
# The comment usually appears as a tooltip when hovering over application menu entry.
desktop-entry-comment-
1 = 瀏覽全球資訊網
desktop-entry-generic-name = 網頁瀏覽器
# Keywords are search terms used to find this application.
# The string is a list of keywords separated by semicolons:
# - Do NOT replace semicolons with other punctuation signs.
# - The list MUST end with a semicolon.
desktop-entry-keywords = 網際網路;網路;瀏覽器;網頁;上網;Internet;WWW;Browser;Web;Explorer;
## Actions are visible in a context menu after right clicking the
## taskbar icon, possibly other places depending on the environment.
desktop-action-new-window-name = 開新視窗
desktop-action-new-private-window-name = 開新隱私視窗
"" "
NIGHTLY_DESKTOP_ENTRY_FILE_TEXT =
"" "\
[Desktop Entry]
Version=
1 .
0
Type=Application
Exec=firefox-nightly %u
Terminal=
false
X-MultipleArgs=
false
Icon=firefox-nightly
StartupWMClass=firefox-nightly
Categories=GNOME;GTK;Network;WebBrowser;
MimeType=application/json;application/pdf;application/rdf+xml;application/rss+xm
l;application/x-xpinstall;application/xhtml+xml;application/xml;audio/flac;audio/ogg;audio/webm;image/avif;image/gif;image/jpeg;image/png;image/svg+xml;image/webp;text/html;text/xml;video/ogg;video/webm;x-scheme-handler/chrome;x-scheme-handler/http;x-scheme-handler/https;x-scheme-handler/mailto;
StartupNotify=true
Actions=new-window;new-private-window;open-profile-manager;
Name=en-US-desktop-entry-name
Name[zh_TW]=zh-TW-desktop-entry-name
Comment=en-US-desktop-entry-comment-1
Comment[zh_TW]=zh-TW-desktop-entry-comment-1
GenericName=en-US-desktop-entry-generic-name
GenericName[zh_TW]=zh-TW-desktop-entry-generic-name
Keywords=en-US-desktop-entry-keywords
Keywords[zh_TW]=zh-TW-desktop-entry-keywords
X-GNOME-FullName=en-US-desktop-entry-x-gnome-full-name-1
X-GNOME-FullName[zh_TW]=zh-TW-desktop-entry-x-gnome-full-name-1
[Desktop Action new-window]
Exec=firefox-nightly --new-window %u
Name=en-US-desktop-action-new-window-name
Name[zh_TW]=zh-TW-desktop-action-new-window-name
[Desktop Action new-private-window]
Exec=firefox-nightly --private-window %u
Name=en-US-desktop-action-new-private-window-name
Name[zh_TW]=zh-TW-desktop-action-new-private-window-name
[Desktop Action open-profile-manager]
Exec=firefox-nightly --ProfileManager
Name=en-US-desktop-action-open-profile-manager
Name[zh_TW]=zh-TW-desktop-action-open-profile-manager
"" "
DEVEDITION_DESKTOP_ENTRY_FILE_TEXT = "" "\
[Desktop Entry]
Version=1 .0
Type=Application
Exec=firefox-devedition %u
Terminal=false
X-MultipleArgs=false
Icon=firefox-devedition
StartupWMClass=firefox-dev
Categories=GNOME;GTK;Network;WebBrowser;
MimeType=application/json;application/pdf;application/rdf+xml;application/rss+xml;application/x-xpinstall;application/xhtml+xml;application/xml;audio/flac;audio/ogg;audio/webm;image/avif;image/gif;image/jpeg;image/png;image/svg+xml;image/webp;text/html;text/xml;video/ogg;video/webm;x-scheme-handler/chrome;x-scheme-handler/http;x-scheme-handler/https;x-scheme-handler/mailto;
StartupNotify=true
Actions=new-window;new-private-window;open-profile-manager;
Name=en-US-desktop-entry-name
Name[zh_TW]=zh-TW-desktop-entry-name
Comment=en-US-desktop-entry-comment-1
Comment[zh_TW]=zh-TW-desktop-entry-comment-1
GenericName=en-US-desktop-entry-generic-name
GenericName[zh_TW]=zh-TW-desktop-entry-generic-name
Keywords=en-US-desktop-entry-keywords
Keywords[zh_TW]=zh-TW-desktop-entry-keywords
X-GNOME-FullName=en-US-desktop-entry-x-gnome-full-name-1
X-GNOME-FullName[zh_TW]=zh-TW-desktop-entry-x-gnome-full-name-1
[Desktop Action new-window]
Exec=firefox-devedition --new-window %u
Name=en-US-desktop-action-new-window-name
Name[zh_TW]=zh-TW-desktop-action-new-window-name
[Desktop Action new-private-window]
Exec=firefox-devedition --private-window %u
Name=en-US-desktop-action-new-private-window-name
Name[zh_TW]=zh-TW-desktop-action-new-private-window-name
[Desktop Action open-profile-manager]
Exec=firefox-devedition --ProfileManager
Name=en-US-desktop-action-open-profile-manager
Name[zh_TW]=zh-TW-desktop-action-open-profile-manager
"" "
def test_generate_deb_desktop_entry_file_text(monkeypatch):
def check_call(cmd=[], cwd=None ):
assert len(cmd) > 1
assert cmd[0 ] == "git"
assert cmd[1 ] in ["init" , "remote" , "fetch" , "reset" ]
if cmd[1 ] == "init" :
assert cwd is None
test_generate_deb_desktop_entry_file_text.l10n_repo_clone = cmd[2 ]
if cmd[1 ] == "remote" :
assert cwd is not None
assert cmd[2 ] == "add"
assert cmd[3 ] == "origin"
assert cmd[4 ] == "https://github.com/mozilla-l10n/firefox-l10n "
if cmd[1 ] == "fetch" :
assert cwd is not None
assert cmd[2 ] == "--no-progress"
assert cmd[3 ] == "--depth=1"
assert cmd[4 ] == "origin"
assert cmd[5 ] == "default"
if cmd[1 ] == "reset" :
assert cwd is not None
assert cmd[2 ] == "--hard"
assert cmd[3 ] == "FETCH_HEAD"
desktop_zhTW_file = os.path.join(
cwd, "zh-TW" , "browser" , "browser" , "linuxDesktopEntry.ftl"
)
os.makedirs(os.path.dirname(desktop_zhTW_file))
with open(desktop_zhTW_file, "w" , encoding="utf-8" ) as zhTW:
zhTW.write(ZH_TW_FTL)
monkeypatch.setattr(desktop_file.subprocess, "check_call" , check_call)
output_stream = StringIO()
logger = logging.getLogger("mozbuild:test:repackaging" )
logger.setLevel(logging.DEBUG)
stream_handler = logging.StreamHandler(output_stream)
logger.addHandler(stream_handler)
def log(level, action, params, format_str):
logger.log(
level,
format_str.format(**params),
extra={"action" : action, "params" : params},
)
def fluent_localization(locales, resources, loader):
def format_value(resource):
return f"{locales[0]}-{resource}"
return Mock(**{"format_value" : format_value})
fluent_resource_loader = Mock()
monkeypatch.setattr(
desktop_file.json,
"load" ,
lambda f: {"zh-TW" : {"platforms" : ["linux" ], "revision" : "default" }},
)
build_variables = {
"PKG_NAME" : "firefox-nightly" ,
"Icon" : "firefox-nightly" ,
"REMOTING_NAME" : "firefox-nightly" ,
}
release_product = "firefox"
release_type = "nightly"
def mock_copy(source_path, destination_path):
assert source_path in [
os.path.join(
"browser" , "locales" , "en-US" , "browser" , "linuxDesktopEntry.ftl"
),
os.path.join(
"browser" , "branding" , "nightly" , "locales" , "en-US" , "brand.ftl"
),
os.path.join(
"browser" , "branding" , "aurora" , "locales" , "en-US" , "brand.ftl"
),
os.path.join(
test_generate_deb_desktop_entry_file_text.l10n_repo_clone,
"zh-TW" ,
"browser" ,
"browser" ,
"linuxDesktopEntry.ftl" ,
),
]
if source_path == os.path.join(
"browser" , "locales" , "en-US" , "browser" , "linuxDesktopEntry.ftl"
):
assert os.path.join("en-US" , "linuxDesktopEntry.ftl" ) in destination_path
if source_path in [
os.path.join(
"browser" , "branding" , "nightly" , "locales" , "en-US" , "brand.ftl"
),
os.path.join(
"browser" , "branding" , "aurora" , "locales" , "en-US" , "brand.ftl"
),
]:
destination_path_subdir = os.path.sep.join(
destination_path.split(os.path.sep)[-2 :]
)
assert destination_path_subdir in [
os.path.join("en-US" , "brand.ftl" ),
os.path.join("zh-TW" , "brand.ftl" ),
]
with open(source_path, encoding="utf-8" ) as src:
with open(destination_path, "w" , encoding="utf-8" ) as dest:
dest.write(src.read())
monkeypatch.setattr(desktop_file.shutil, "copyfile" , mock_copy)
desktop_entry_file_text = desktop_file.generate_browser_desktop_entry_file_text(
log,
build_variables,
release_product,
release_type,
fluent_localization,
fluent_resource_loader,
)
assert test_generate_deb_desktop_entry_file_text.l10n_repo_clone is not None
assert desktop_entry_file_text == NIGHTLY_DESKTOP_ENTRY_FILE_TEXT
build_variables = {
"PKG_NAME" : "firefox-devedition" ,
"Icon" : "firefox-devedition" ,
"REMOTING_NAME" : "firefox-dev" ,
}
release_product = "devedition"
release_type = "beta"
desktop_entry_file_text = desktop_file.generate_browser_desktop_entry_file_text(
log,
build_variables,
release_product,
release_type,
fluent_localization,
fluent_resource_loader,
)
assert desktop_entry_file_text == DEVEDITION_DESKTOP_ENTRY_FILE_TEXT
def outage(cmd=[], cwd=None ):
raise subprocess.CalledProcessError(cmd=cmd, returncode=42 )
monkeypatch.setattr(desktop_file.subprocess, "check_call" , outage)
with pytest.raises(subprocess.CalledProcessError):
desktop_entry_file_text = desktop_file.generate_browser_desktop_entry_file_text(
log,
build_variables,
release_product,
release_type,
fluent_localization,
fluent_resource_loader,
)
@pytest.mark.parametrize(
"does_path_exits, expectation" ,
(
(True , does_not_raise()),
(False , pytest.raises(deb.NoDebPackageFound)),
),
)
def test_generate_deb_archive(
monkeypatch,
does_path_exits,
expectation,
):
monkeypatch.setattr(deb, "_get_command" , lambda _: ["mock_command" ])
monkeypatch.setattr(deb.subprocess, "check_call" , lambda *_, **__: None )
def mock_exists(path):
assert path == "/target_dir/firefox_111.0_amd64.deb"
return does_path_exits
monkeypatch.setattr(deb.os.path, "exists" , mock_exists)
def mock_move(source_path, destination_path):
assert source_path == "/target_dir/firefox_111.0_amd64.deb"
assert destination_path == "/output/target.deb"
monkeypatch.setattr(deb.shutil, "move" , mock_move)
with expectation:
deb._generate_deb_archive(
source_dir="/source_dir" ,
target_dir="/target_dir" ,
output_file_path="/output/target.deb" ,
build_variables={
"PKG_NAME" : "firefox" ,
"PKG_VERSION" : "111.0" ,
},
arch="x86_64" ,
)
@pytest.mark.parametrize(
"arch, is_chroot_available, expected" ,
(
(
"all" ,
True ,
[
"chroot" ,
"/srv/jessie-amd64" ,
"bash" ,
"-c" ,
"cd /tmp/*/source; dpkg-buildpackage -us -uc -b" ,
],
),
("all" , False , ["dpkg-buildpackage" , "-us" , "-uc" , "-b" ]),
(
"x86" ,
True ,
[
"chroot" ,
"/srv/jessie-i386" ,
"bash" ,
"-c" ,
"cd /tmp/*/source; dpkg-buildpackage -us -uc -b --host-arch=i386" ,
],
),
("x86" , False , ["dpkg-buildpackage" , "-us" , "-uc" , "-b" , "--host-arch=i386" ]),
(
"x86_64" ,
True ,
[
"chroot" ,
"/srv/jessie-amd64" ,
"bash" ,
"-c" ,
"cd /tmp/*/source; dpkg-buildpackage -us -uc -b --host-arch=amd64" ,
],
),
(
"x86_64" ,
False ,
["dpkg-buildpackage" , "-us" , "-uc" , "-b" , "--host-arch=amd64" ],
),
),
)
def test_get_command(monkeypatch, arch, is_chroot_available, expected):
monkeypatch.setattr(deb, "_is_chroot_available" , lambda _: is_chroot_available)
assert deb._get_command(arch) == expected
@pytest.mark.parametrize(
"arch, does_dir_exist, expected_path, expected_result" ,
(
("all" , False , "/srv/jessie-amd64" , False ),
("all" , True , "/srv/jessie-amd64" , True ),
("x86" , False , "/srv/jessie-i386" , False ),
("x86_64" , False , "/srv/jessie-amd64" , False ),
("x86" , True , "/srv/jessie-i386" , True ),
("x86_64" , True , "/srv/jessie-amd64" , True ),
),
)
def test_is_chroot_available(
monkeypatch, arch, does_dir_exist, expected_path, expected_result
):
def _mock_is_dir(path):
assert path == expected_path
return does_dir_exist
monkeypatch.setattr(deb.os.path, "isdir" , _mock_is_dir)
assert deb._is_chroot_available(arch) == expected_result
@pytest.mark.parametrize(
"arch, expected" ,
(
("all" , "/srv/jessie-amd64" ),
("x86" , "/srv/jessie-i386" ),
("x86_64" , "/srv/jessie-amd64" ),
),
)
def test_get_chroot_path(arch, expected):
assert deb._get_chroot_path(arch) == expected
_MANIFEST_JSON_DATA = {
"langpack_id" : "fr" ,
"manifest_version" : 2 ,
"browser_specific_settings" : {
"gecko" : {
"id" : "langpack-fr@devedition.mozilla.org" ,
"strict_min_version" : "112.0a1" ,
"strict_max_version" : "112.0a1" ,
}
},
"name" : "Language: Français (French)" ,
"description" : "Firefox Developer Edition Language Pack for Français (fr) – French" ,
"version" : "112.0.20230227.181253" ,
"languages" : {
"fr" : {
"version" : "20230223164410" ,
"chrome_resources" : {
"app-marketplace-icons" : "browser/chrome/browser/locale/fr/app-marketplace-icons/" ,
"branding" : "browser/chrome/fr/locale/branding/" ,
"browser" : "browser/chrome/fr/locale/browser/" ,
"browser-region" : "browser/chrome/fr/locale/browser-region/" ,
"devtools" : "browser/chrome/fr/locale/fr/devtools/client/" ,
"devtools-shared" : "browser/chrome/fr/locale/fr/devtools/shared/" ,
"alerts" : "chrome/fr/locale/fr/alerts/" ,
"autoconfig" : "chrome/fr/locale/fr/autoconfig/" ,
"global" : "chrome/fr/locale/fr/global/" ,
"global-platform" : {
"macosx" : "chrome/fr/locale/fr/global-platform/mac/" ,
"linux" : "chrome/fr/locale/fr/global-platform/unix/" ,
"android" : "chrome/fr/locale/fr/global-platform/unix/" ,
"win" : "chrome/fr/locale/fr/global-platform/win/" ,
},
"mozapps" : "chrome/fr/locale/fr/mozapps/" ,
"necko" : "chrome/fr/locale/fr/necko/" ,
"passwordmgr" : "chrome/fr/locale/fr/passwordmgr/" ,
"pdf.js" : "chrome/fr/locale/pdfviewer/" ,
"pipnss" : "chrome/fr/locale/fr/pipnss/" ,
"pippki" : "chrome/fr/locale/fr/pippki/" ,
"places" : "chrome/fr/locale/fr/places/" ,
"weave" : "chrome/fr/locale/fr/services/" ,
},
}
},
"sources" : {"browser" : {"base_path" : "browser/" }},
"author" : "mozfr.org (contributors: L’équipe francophone)" ,
}
def test_extract_langpack_metadata():
with tempfile.TemporaryDirectory() as d:
langpack_path = os.path.join(d, "langpack.xpi" )
with zipfile.ZipFile(langpack_path, "w" ) as zip:
zip.writestr("manifest.json" , json.dumps(_MANIFEST_JSON_DATA))
assert deb._extract_langpack_metadata(langpack_path) == _MANIFEST_JSON_DATA
if __name__ == "__main__" :
mozunit.main()
Messung V0.5 in Prozent C=88 H=95 G=91
¤ Dauer der Verarbeitung: 0.17 Sekunden
¤
*© Formatika GbR, Deutschland