Bug 1966468 - Make mozinstall handle archives when cross-compiling. r=firefox-build-system-reviewers,ahal,glandium

Differential Revision: https://phabricator.services.mozilla.com/D249445
This commit is contained in:
Nick Alexander
2025-05-17 01:27:59 +00:00
committed by nalexander@mozilla.com
parent 4ebe801530
commit c46d4a5469
4 changed files with 79 additions and 64 deletions

View File

@@ -692,7 +692,6 @@ class MacArtifactJob(ArtifactJob):
def process_package_artifact(self, filename, processed_filename):
tempdir = tempfile.mkdtemp()
oldcwd = os.getcwd()
try:
self.log(
logging.DEBUG,
@@ -700,25 +699,7 @@ class MacArtifactJob(ArtifactJob):
{"tempdir": tempdir},
"Unpacking DMG into {tempdir}",
)
if self._substs["HOST_OS_ARCH"] == "Linux":
# This is a cross build, use hfsplus and dmg tools to extract the dmg.
os.chdir(tempdir)
with open(os.devnull, "wb") as devnull:
subprocess.check_call(
[
self._substs["DMG_TOOL"],
"extract",
filename,
"extracted_img",
],
stdout=devnull,
)
subprocess.check_call(
[self._substs["HFS_TOOL"], "extracted_img", "extractall"],
stdout=devnull,
)
else:
mozinstall.install(filename, tempdir)
mozinstall.install(filename, tempdir)
bundle_dirs = glob.glob(mozpath.join(tempdir, "*.app"))
if len(bundle_dirs) != 1:
@@ -768,7 +749,6 @@ class MacArtifactJob(ArtifactJob):
writer.add(destpath.encode("utf-8"), f.open(), mode=f.mode)
finally:
os.chdir(oldcwd)
try:
shutil.rmtree(tempdir)
except OSError:

View File

@@ -38,14 +38,7 @@ class InvalidBinary(Exception):
class InvalidSource(Exception):
"""Thrown when the specified source is not a recognized file type.
Supported types:
Linux: tar.gz, tar.bz2, tar.xz
Mac: dmg
Windows: zip, exe
"""
"""Thrown when the specified source is not a recognized file type."""
class UninstallError(Exception):
@@ -128,14 +121,16 @@ def install(src, dest):
trbk = None
try:
install_dir = None
if src.lower().endswith(".dmg"):
if zipfile.is_zipfile(src) or tarfile.is_tarfile(src):
install_dir = mozfile.extract(src, dest)[0]
elif src.lower().endswith(".dmg"):
install_dir = _install_dmg(src, dest)
elif src.lower().endswith(".exe"):
install_dir = _install_exe(src, dest)
elif src.lower().endswith(".msix"):
install_dir = _install_msix(src)
elif zipfile.is_zipfile(src) or tarfile.is_tarfile(src):
install_dir = mozfile.extract(src, dest)[0]
else:
raise InvalidSource(f"{src} is not a valid installer file")
return install_dir
@@ -168,9 +163,9 @@ def is_installer(src):
"""Tests if the given file is a valid installer package.
Supported types:
Linux: tar.gz, tar.bz2, tar.xz
Mac: dmg
Windows: zip, exe
All: zip, tar.gz, tar.bz2, tar.xz
Linux, Mac: dmg
Windows: exe, msix
On Windows pefile will be used to determine if the executable is the
right type, if it is installed on the system.
@@ -182,14 +177,13 @@ def is_installer(src):
if not os.path.isfile(src):
return False
if mozinfo.isLinux:
return tarfile.is_tarfile(src)
elif mozinfo.isMac:
if zipfile.is_zipfile(src):
return True
if tarfile.is_tarfile(src):
return True
if mozinfo.isMac or mozinfo.isLinux:
return src.lower().endswith(".dmg")
elif mozinfo.isWin:
if zipfile.is_zipfile(src):
return True
if mozinfo.isWin:
if os.access(src, os.X_OK) and src.lower().endswith(".exe"):
if has_pefile:
# try to determine if binary is actually a gecko installer
@@ -204,7 +198,7 @@ def is_installer(src):
# pefile not available, just assume a proper binary was passed in
return True
return False
return False
def uninstall(install_folder):
@@ -298,6 +292,9 @@ def _install_dmg(src, dest):
dest -- the path to extract to
"""
if mozinfo.isLinux:
return _install_dmg_cross(src, dest)
appDir = None
try:
# According to the Apple doc, the hdiutil output is stable and is based on the tab
@@ -336,6 +333,49 @@ def _install_dmg(src, dest):
return dest
def _install_dmg_cross(src, dest):
# This is a cross build, use hfsplus and dmg tools to extract the dmg.
try:
import buildconfig
dmg_tool = buildconfig.substs.get("DMG_TOOL")
hfs_tool = buildconfig.substs.get("HFS_TOOL")
except ImportError:
pass
if not dmg_tool:
dmg_tool = os.environ.get("DMG_TOOL")
if not dmg_tool:
raise InstallError("No DMG_TOOL in environment")
if not hfs_tool:
hfs_tool = os.environ.get("HFS_TOOL")
if not hfs_tool:
raise InstallError("No HFS_TOOL in environment")
oldcwd = os.getcwd()
try:
os.chdir(dest)
with open(os.devnull, "wb") as devnull:
subprocess.check_call(
[
dmg_tool,
"extract",
src,
"extracted_img",
],
stdout=devnull,
)
subprocess.check_call(
[hfs_tool, "extracted_img", "extractall"],
stdout=devnull,
)
finally:
os.chdir(oldcwd)
return dest
def _install_exe(src, dest):
"""Run the MSI installer to silently install the application into the
destination folder. Return the folder path.

View File

@@ -12,13 +12,10 @@ import pytest
)
def test_is_installer(request, get_installer):
"""Test that we can identify a correct installer."""
if mozinfo.isLinux:
assert mozinstall.is_installer(get_installer("tar.xz"))
assert mozinstall.is_installer(get_installer("tar.xz"))
assert mozinstall.is_installer(get_installer("zip"))
if mozinfo.isWin:
# test zip installer
assert mozinstall.is_installer(get_installer("zip"))
# test exe installer
assert mozinstall.is_installer(get_installer("exe"))
@@ -34,23 +31,23 @@ def test_is_installer(request, get_installer):
except ImportError:
pass
if mozinfo.isMac:
if mozinfo.isMac or mozinfo.isLinux:
assert mozinstall.is_installer(get_installer("dmg"))
def test_invalid_source_error(get_installer):
"""Test that InvalidSource error is raised with an incorrect installer."""
if mozinfo.isLinux:
if mozinfo.isWin:
with pytest.raises(mozinstall.InvalidSource):
mozinstall.install(get_installer("dmg"), "firefox")
elif mozinfo.isWin:
elif mozinfo.isLinux:
with pytest.raises(mozinstall.InvalidSource):
mozinstall.install(get_installer("tar.xz"), "firefox")
mozinstall.install(get_installer("msix"), "firefox")
elif mozinfo.isMac:
with pytest.raises(mozinstall.InvalidSource):
mozinstall.install(get_installer("tar.xz"), "firefox")
mozinstall.install(get_installer("exe"), "firefox")
# Test an invalid url handler
with pytest.raises(mozinstall.InvalidSource):
@@ -63,6 +60,11 @@ def test_invalid_source_error(get_installer):
)
def test_install(tmpdir, get_installer):
"""Test to install an installer."""
installdir_zip = mozinstall.install(
get_installer("zip"), tmpdir.join("zip").strpath
)
assert installdir_zip == tmpdir.join("zip", "firefox").strpath
if mozinfo.isLinux:
installdir = mozinstall.install(get_installer("tar.xz"), tmpdir.strpath)
assert installdir == tmpdir.join("firefox").strpath
@@ -73,11 +75,6 @@ def test_install(tmpdir, get_installer):
)
assert installdir_exe == tmpdir.join("exe", "firefox").strpath
installdir_zip = mozinstall.install(
get_installer("zip"), tmpdir.join("zip").strpath
)
assert installdir_zip == tmpdir.join("zip", "firefox").strpath
elif mozinfo.isMac:
installdir = mozinstall.install(get_installer("dmg"), tmpdir.strpath)
assert installdir == tmpdir.realpath().join("Firefox Stub.app").strpath

View File

@@ -10,13 +10,11 @@ import pytest
)
def test_is_installer(request, get_installer):
"""Test that we can identify a correct installer."""
if mozinfo.isLinux:
assert mozinstall.is_installer(get_installer("tar.xz"))
assert mozinstall.is_installer(get_installer("tar.xz"))
assert mozinstall.is_installer(get_installer("zip"))
if mozinfo.isWin:
# test zip installer
assert mozinstall.is_installer(get_installer("zip"))
# test exe installer
assert mozinstall.is_installer(get_installer("exe"))
@@ -32,7 +30,7 @@ def test_is_installer(request, get_installer):
except ImportError:
pass
if mozinfo.isMac:
if mozinfo.isMac or mozinfo.isLinux:
assert mozinstall.is_installer(get_installer("dmg"))