Bug 1185666 - Move DMG unpack logic to a python script, support linux. r=mshal a=IanN DONTBUILD CLOSED TREE SEAMONKEY_2_49_ESR_RELBRANCH
authorJustin Wood <Callek@gmail.com>
Tue, 28 Mar 2017 21:46:19 -0400
branchSEAMONKEY_2_49_ESR_RELBRANCH
changeset 357566 0e50ef35d3ac32a545c37351176e09b4ed9b041a
parent 357565 09bfc5a069ed8e7dc8e32ac28e77d4bbe7258b90
child 357567 4939882bc713553dc564fae3d5b67a8b896496ca
push id7836
push userfrgrahl@gmx.net
push dateMon, 15 Jul 2019 16:17:02 +0000
treeherdermozilla-esr52@3a4afe7ecac5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmshal, IanN
bugs1185666
milestone52.9.1
Bug 1185666 - Move DMG unpack logic to a python script, support linux. r=mshal a=IanN DONTBUILD CLOSED TREE SeaMonkey ESR52 release branch only. MozReview-Commit-ID: inKT2BWof4
python/mozbuild/mozbuild/action/unpack_dmg.py
python/mozbuild/mozpack/dmg.py
toolkit/mozapps/installer/upload-files.mk
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/action/unpack_dmg.py
@@ -0,0 +1,35 @@
+# 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/.
+
+from __future__ import print_function
+
+from mozpack import dmg
+
+import argparse
+import sys
+
+
+def main(args):
+    parser = argparse.ArgumentParser(
+        description='Explode a DMG into its relevant files')
+
+    parser.add_argument('--dsstore', help='DSStore file from')
+    parser.add_argument('--background', help='Background file from')
+    parser.add_argument('--icon', help='Icon file from')
+
+    parser.add_argument('dmgfile', metavar='DMG_IN',
+                        help='DMG File to Unpack')
+    parser.add_argument('outpath', metavar='PATH_OUT',
+                        help='Location to put unpacked files')
+
+    options = parser.parse_args(args)
+
+    dmg.extract_dmg(dmgfile=options.dmgfile, output=options.outpath,
+                    dsstore=options.dsstore, background=options.background,
+                    icon=options.icon)
+    return 0
+
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv[1:]))
--- a/python/mozbuild/mozpack/dmg.py
+++ b/python/mozbuild/mozpack/dmg.py
@@ -4,16 +4,17 @@
 
 import buildconfig
 import errno
 import mozfile
 import os
 import platform
 import shutil
 import subprocess
+import sys
 
 from mozbuild.util import ensureParentDir
 
 is_linux = platform.system() == 'Linux'
 
 
 def mkdir(dir):
     if not os.path.isdir(dir):
@@ -26,18 +27,18 @@ def mkdir(dir):
 
 def chmod(dir):
     'Set permissions of DMG contents correctly'
     subprocess.check_call(['chmod', '-R', 'a+rX,a-st,u+w,go-w', dir])
 
 
 def rsync(source, dest):
     'rsync the contents of directory source into directory dest'
-    # Ensure a trailing slash so rsync copies the *contents* of source.
-    if not source.endswith('/'):
+    # Ensure a trailing slash on directories so rsync copies the *contents* of source.
+    if not source.endswith('/') and os.path.isdir(source):
         source += '/'
     subprocess.check_call(['rsync', '-a', '--copy-unsafe-links',
                            source, dest])
 
 
 def set_folder_icon(dir, tmpdir):
     'Set HFS attributes of dir to use a custom icon'
     if not is_linux:
@@ -151,8 +152,58 @@ def create_dmg(source_directory, output_
             mkdir(os.path.dirname(full_target))
             shutil.copyfile(source, full_target)
         generate_hfs_file(stagedir, tmpdir, volume_name)
         create_app_symlink(stagedir, tmpdir)
         # Set the folder attributes to use a custom icon
         set_folder_icon(stagedir, tmpdir)
         chmod(stagedir)
         create_dmg_from_staged(stagedir, output_dmg, tmpdir, volume_name)
+
+
+def extract_dmg_contents(dmgfile, destdir):
+    import buildconfig
+    if is_linux:
+        with mozfile.TemporaryDirectory() as tmpdir:
+            hfs_file = os.path.join(tmpdir, 'firefox.hfs')
+            subprocess.check_call([
+                    buildconfig.substs['DMG_TOOL'],
+                    'extract',
+                    dmgfile,
+                    hfs_file
+                ],
+                # dmg is seriously chatty
+                stdout=open(os.devnull, 'wb'))
+            subprocess.check_call([
+                buildconfig.substs['HFS_TOOL'], hfs_file, 'extractall', '/', destdir])
+    else:
+        unpack_diskimage = os.path.join(buildconfig.topsrcdir, 'build', 'package',
+                                        'mac_osx', 'unpack-diskimage')
+        unpack_mountpoint = os.path.join(
+            '/tmp', '{}-unpack'.format(buildconfig.substs['MOZ_APP_NAME']))
+        subprocess.check_call([unpack_diskimage, dmgfile, unpack_mountpoint,
+                               destdir])
+
+
+def extract_dmg(dmgfile, output, dsstore=None, icon=None, background=None):
+    if platform.system() not in ('Darwin', 'Linux'):
+        raise Exception("Don't know how to extract a DMG on '%s'" % platform.system())
+
+    if is_linux:
+        check_tools('DMG_TOOL', 'MKFSHFS', 'HFS_TOOL')
+
+    with mozfile.TemporaryDirectory() as tmpdir:
+        extract_dmg_contents(dmgfile, tmpdir)
+        if os.path.islink(os.path.join(tmpdir, ' ')):
+            # Rsync will fail on the presence of this symlink
+            os.remove(os.path.join(tmpdir, ' '))
+        rsync(tmpdir, output)
+
+        if dsstore:
+            mkdir(os.path.dirname(dsstore))
+            rsync(os.path.join(tmpdir, '.DS_Store'), dsstore)
+        if background:
+            mkdir(os.path.dirname(background))
+            rsync(os.path.join(tmpdir, '.background', os.path.basename(background)),
+                  background)
+        if icon:
+            mkdir(os.path.dirname(icon))
+            rsync(os.path.join(tmpdir, '.VolumeIcon.icns'), icon)
--- a/toolkit/mozapps/installer/upload-files.mk
+++ b/toolkit/mozapps/installer/upload-files.mk
@@ -216,34 +216,22 @@ endif
 
 ifeq ($(MOZ_PKG_FORMAT),DMG)
   PKG_SUFFIX	= .dmg
 
   _ABS_MOZSRCDIR = $(shell cd $(MOZILLA_DIR) && pwd)
   PKG_DMG_SOURCE = $(STAGEPATH)$(MOZ_PKG_DIR)
   INNER_MAKE_PACKAGE	= $(call py_action,make_dmg,'$(PKG_DMG_SOURCE)' '$(PACKAGE)')
   INNER_UNMAKE_PACKAGE	= \
-    set -ex; \
-    rm -rf $(ABS_DIST)/unpack.tmp; \
-    mkdir -p $(ABS_DIST)/unpack.tmp; \
-    $(_ABS_MOZSRCDIR)/build/package/mac_osx/unpack-diskimage $(UNPACKAGE) /tmp/$(MOZ_PKG_APPNAME)-unpack $(ABS_DIST)/unpack.tmp; \
-    rsync -a '$(ABS_DIST)/unpack.tmp/$(_APPNAME)' $(MOZ_PKG_DIR); \
-    test -n '$(MOZ_PKG_MAC_DSSTORE)' && \
-      rsync -a '$(ABS_DIST)/unpack.tmp/.DS_Store' '$(MOZ_PKG_MAC_DSSTORE)'; \
-    test -n '$(MOZ_PKG_MAC_BACKGROUND)' && \
-      rsync -a '$(ABS_DIST)/unpack.tmp/.background/$(notdir $(MOZ_PKG_MAC_BACKGROUND))' '$(MOZ_PKG_MAC_BACKGROUND)'; \
-    test -n '$(MOZ_PKG_MAC_ICON)' && \
-      rsync -a '$(ABS_DIST)/unpack.tmp/.VolumeIcon.icns' '$(MOZ_PKG_MAC_ICON)'; \
-    rm -rf $(ABS_DIST)/unpack.tmp; \
-    if test -n '$(MOZ_PKG_MAC_RSRC)' ; then \
-      cp $(UNPACKAGE) $(MOZ_PKG_APPNAME).tmp.dmg && \
-      hdiutil unflatten $(MOZ_PKG_APPNAME).tmp.dmg && \
-      { /Developer/Tools/DeRez -skip plst -skip blkx $(MOZ_PKG_APPNAME).tmp.dmg > '$(MOZ_PKG_MAC_RSRC)' || { rm -f $(MOZ_PKG_APPNAME).tmp.dmg && false; }; } && \
-      rm -f $(MOZ_PKG_APPNAME).tmp.dmg; \
-    fi
+    $(call py_action,unpack_dmg, \
+        $(if $(MOZ_PKG_MAC_DSSTORE),--dsstore '$(MOZ_PKG_MAC_DSSTORE)') \
+        $(if $(MOZ_PKG_MAC_BACKGROUND),--background '$(MOZ_PKG_MAC_BACKGROUND)') \
+        $(if $(MOZ_PKG_MAC_ICON),--icon '$(MOZ_PKG_MAC_ICON)') \
+        '$(UNPACKAGE)' '$(MOZ_PKG_DIR)' \
+        )
 endif
 
 ifdef MOZ_INTERNAL_SIGNING_FORMAT
   MOZ_SIGN_PREPARED_PACKAGE_CMD=$(MOZ_SIGN_CMD) $(foreach f,$(MOZ_INTERNAL_SIGNING_FORMAT),-f $(f)) $(foreach i,$(SIGN_INCLUDES),-i $(i)) $(foreach x,$(SIGN_EXCLUDES),-x $(x))
   ifeq (WINNT,$(OS_ARCH))
     MOZ_SIGN_PREPARED_PACKAGE_CMD += --nsscmd '$(ABS_DIST)/bin/shlibsign$(BIN_SUFFIX) -v -i'
   endif
 endif