bug 935237 - use libdmg-hfsplus to create DMG files during packaging on Linux. r=gps
authorTed Mielczarek <ted@mielczarek.org>
Fri, 21 Aug 2015 15:33:03 -0400
changeset 294483 4e21632942b8ce945675a31193c117795b3eb052
parent 294482 0a18e5db95a4505d26260e6690a3e6241f0e16de
child 294484 19bd2475605038a80eac3701c1418bb48e713ef1
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgps
bugs935237
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 935237 - use libdmg-hfsplus to create DMG files during packaging on Linux. r=gps
configure.in
python/mozbuild/mozpack/dmg.py
--- a/configure.in
+++ b/configure.in
@@ -845,16 +845,18 @@ fi
 MOZ_PATH_PROG(XARGS, xargs)
 if test -z "$XARGS" -o "$XARGS" = ":"; then
     AC_MSG_ERROR([xargs not found in \$PATH .])
 fi
 
 MOZ_PATH_PROG(RPMBUILD, rpmbuild, :)
 AC_SUBST(RPMBUILD)
 
+MOZ_PATH_PROG(GENISOIMAGE, genisoimage, :)
+
 if test "$COMPILE_ENVIRONMENT"; then
 
 dnl ========================================================
 dnl = Mac OS X toolchain support
 dnl ========================================================
 
 dnl The universal machinery sets UNIVERSAL_BINARY to inform packager.mk
 dnl that a universal binary is being produced and MOZ_CAN_RUN_PROGRAMS
@@ -8980,16 +8982,18 @@ AC_SUBST_LIST(LIBAV_FFT_ASFLAGS)
 AC_SUBST(MOZ_PACKAGE_JSSHELL)
 AC_SUBST(MOZ_FOLD_LIBS)
 AC_SUBST(MOZ_FOLD_LIBS_FLAGS)
 AC_SUBST(SOCORRO_SYMBOL_UPLOAD_TOKEN_FILE)
 
 AC_SUBST(MOZ_ENABLE_SZIP)
 AC_SUBST(MOZ_SZIP_FLAGS)
 
+AC_SUBST(DMG_TOOL)
+
 dnl Host JavaScript runtime, if any, to use during cross compiles.
 AC_SUBST(JS_BINARY)
 
 if test "$MOZ_DEBUG"; then
     MOZ_EM_DEBUG=1
 fi
 AC_SUBST(MOZ_EM_DEBUG)
 
--- a/python/mozbuild/mozpack/dmg.py
+++ b/python/mozbuild/mozpack/dmg.py
@@ -1,18 +1,20 @@
 # 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 errno
 import mozfile
 import os
+import platform
 import shutil
 import subprocess
 
+is_linux = platform.system() == 'Linux'
 
 def mkdir(dir):
     if not os.path.isdir(dir):
         try:
             os.makedirs(dir)
         except OSError as e:
             if e.errno != errno.EEXIST:
                 raise
@@ -29,40 +31,81 @@ def rsync(source, dest):
     if not source.endswith('/'):
         source += '/'
     subprocess.check_call(['rsync', '-a', '--copy-unsafe-links',
                            source, dest])
 
 
 def set_folder_icon(dir):
     'Set HFS attributes of dir to use a custom icon'
-    subprocess.check_call(['SetFile', '-a', 'C', dir])
+    if not is_linux:
+        #TODO: bug 1197325 - figure out how to support this on Linux
+        subprocess.check_call(['SetFile', '-a', 'C', dir])
 
 
 def create_dmg_from_staged(stagedir, output_dmg, tmpdir, volume_name):
     'Given a prepared directory stagedir, produce a DMG at output_dmg.'
-    hybrid = os.path.join(tmpdir, 'hybrid.dmg')
-    subprocess.check_call(['hdiutil', 'makehybrid', '-hfs',
-                           '-hfs-volume-name', volume_name,
-                           '-hfs-openfolder', stagedir,
-                           '-ov', stagedir,
-                           '-o', hybrid])
-    subprocess.check_call(['hdiutil', 'convert', '-format', 'UDBZ',
-                           '-imagekey', 'bzip2-level=9',
-                           '-ov', hybrid, '-o', output_dmg])
+    if not is_linux:
+        # Running on OS X
+        hybrid = os.path.join(tmpdir, 'hybrid.dmg')
+        subprocess.check_call(['hdiutil', 'makehybrid', '-hfs',
+                               '-hfs-volume-name', volume_name,
+                               '-hfs-openfolder', stagedir,
+                               '-ov', stagedir,
+                               '-o', hybrid])
+        subprocess.check_call(['hdiutil', 'convert', '-format', 'UDBZ',
+                               '-imagekey', 'bzip2-level=9',
+                               '-ov', hybrid, '-o', output_dmg])
+    else:
+        import buildconfig
+        uncompressed = os.path.join(tmpdir, 'uncompressed.dmg')
+        subprocess.check_call([
+            buildconfig.substs['GENISOIMAGE'],
+            '-V', volume_name,
+            '-D', '-R', '-apple', '-no-pad',
+            '-o', uncompressed,
+            stagedir
+        ])
+        subprocess.check_call([
+            buildconfig.substs['DMG_TOOL'],
+            'dmg',
+            uncompressed,
+            output_dmg
+        ],
+                              # dmg is seriously chatty
+                              stdout=open(os.devnull, 'wb'))
+
+def check_tools(*tools):
+    '''
+    Check that each tool named in tools exists in SUBSTS and is executable.
+    '''
+    import buildconfig
+    for tool in tools:
+        path = buildconfig.substs[tool]
+        if not path:
+            raise Exception('Required tool "%s" not found' % tool)
+        if not os.path.isfile(path):
+            raise Exception('Required tool "%s" not found at path "%s"' % (tool, path))
+        if not os.access(path, os.X_OK):
+            raise Exception('Required tool "%s" at path "%s" is not executable' % (tool, path))
 
 
 def create_dmg(source_directory, output_dmg, volume_name, extra_files):
     '''
     Create a DMG disk image at the path output_dmg from source_directory.
 
     Use volume_name as the disk image volume name, and
     use extra_files as a list of tuples of (filename, relative path) to copy
     into the disk image.
     '''
+    if platform.system() not in ('Darwin', 'Linux'):
+        raise Exception("Don't know how to build a DMG on '%s'" % platform.system())
+
+    if is_linux:
+        check_tools('DMG_TOOL', 'GENISOIMAGE')
     with mozfile.TemporaryDirectory() as tmpdir:
         stagedir = os.path.join(tmpdir, 'stage')
         os.mkdir(stagedir)
         # Copy the app bundle over using rsync
         rsync(source_directory, stagedir)
         # Copy extra files
         for source, target in extra_files:
             full_target = os.path.join(stagedir, target)