Bug 1360525 - 'mach repackage' for installer & stub installer; r?chmanchester draft
authorMike Shal <mshal@mozilla.com>
Thu, 04 May 2017 14:48:12 -0400
changeset 593489 eb8f1bc347aca08e2820fa8c64f66e063b68bc2b
parent 593488 b6e8ff1947926492c5160f66aee7cdc5d8dcfdeb
child 593490 5a70d34b310bfe986b0b56ca79583cf1802098a0
push id63715
push userbmo:mshal@mozilla.com
push dateTue, 13 Jun 2017 18:44:17 +0000
reviewerschmanchester
bugs1360525
milestone55.0a1
Bug 1360525 - 'mach repackage' for installer & stub installer; r?chmanchester These commands are similar to 'mach repackage dmg', except the installer and stub installer require multiple inputs. The regular installer needs a package, tag file, and setup.exe file; the stub installer needs just a tag file and setup.exe file. The output is a self-extracting .exe file. The archive_exe() function originally just supported the regular installer, but by supporting an optional package, the function can support the stub installer as well.
python/mozbuild/mozbuild/action/exe_7z_archive.py
python/mozbuild/mozbuild/mach_commands.py
python/mozbuild/mozbuild/repackaging/installer.py
--- a/python/mozbuild/mozbuild/action/exe_7z_archive.py
+++ b/python/mozbuild/mozbuild/action/exe_7z_archive.py
@@ -8,24 +8,31 @@ import os
 import shutil
 import sys
 import subprocess
 import tempfile
 import mozpack.path as mozpath
 
 def archive_exe(pkg_dir, tagfile, sfx_package, package):
     tmpdir = tempfile.mkdtemp(prefix='tmp')
-    subprocess.check_call(['upx', '--best', '-o', mozpath.join(tmpdir, '7zSD.sfx'), sfx_package])
-    shutil.move(pkg_dir, 'core')
-    subprocess.check_call(['7z', 'a', '-r', '-t7z', mozpath.join(tmpdir, 'app.7z'), '-mx', '-m0=BCJ2', '-m1=LZMA:d25', '-m2=LZMA:d19', '-m3=LZMA:d19', '-mb0:1', '-mb0s1:2', '-mb0s2:3'])
-    shutil.move('core', pkg_dir)
-    with open(package, 'wb') as o:
-        for i in [mozpath.join(tmpdir, '7zSD.sfx'), tagfile, mozpath.join(tmpdir, 'app.7z')]:
-            shutil.copyfileobj(open(i, 'rb'), o)
-    os.chmod(package, 0755)
+    try:
+        if pkg_dir:
+            shutil.move(pkg_dir, 'core')
+        subprocess.check_call(['upx', '--best', '-o', mozpath.join(tmpdir, '7zSD.sfx'), sfx_package])
+
+        subprocess.check_call(['7z', 'a', '-r', '-t7z', mozpath.join(tmpdir, 'app.7z'), '-mx', '-m0=BCJ2', '-m1=LZMA:d25', '-m2=LZMA:d19', '-m3=LZMA:d19', '-mb0:1', '-mb0s1:2', '-mb0s2:3'])
+
+        with open(package, 'wb') as o:
+            for i in [mozpath.join(tmpdir, '7zSD.sfx'), tagfile, mozpath.join(tmpdir, 'app.7z')]:
+                shutil.copyfileobj(open(i, 'rb'), o)
+        os.chmod(package, 0755)
+    finally:
+        if pkg_dir:
+            shutil.move('core', pkg_dir)
+        shutil.rmtree(tmpdir)
 
 def main(args):
     if len(args) != 4:
         print('Usage: exe_7z_archive.py <pkg_dir> <tagfile> <sfx_package> <package>',
               file=sys.stderr)
         return 1
     else:
         archive_exe(args[0], args[1], args[2], args[3])
--- a/python/mozbuild/mozbuild/mach_commands.py
+++ b/python/mozbuild/mozbuild/mach_commands.py
@@ -1958,8 +1958,22 @@ class Repackage(MachCommandBase):
 
         if not os.path.exists(os.path.join(self.topobjdir, 'config.status')):
             print('config.status not found.  Please run |mach configure| '
                   'prior to |mach repackage|.')
             return 1
 
         from mozbuild.repackaging.dmg import repackage_dmg
         repackage_dmg(input, output)
+
+    @SubCommand('repackage', 'installer',
+                description='Repackage into a Windows installer exe')
+    @CommandArgument('--tag', type=str, required=True,
+        help='The .tag file used to build the installer')
+    @CommandArgument('--setupexe', type=str, required=True,
+        help='setup.exe file inside the installer')
+    @CommandArgument('--package', type=str, required=False,
+        help='Optional package .zip for building a full installer')
+    @CommandArgument('--output', '-o', type=str, required=True,
+        help='Output filename')
+    def repackage_installer(self, tag, setupexe, package, output):
+        from mozbuild.repackaging.installer import repackage_installer
+        repackage_installer(self.topsrcdir, tag, setupexe, package, output)
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/repackaging/installer.py
@@ -0,0 +1,45 @@
+# 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 os
+import tempfile
+import shutil
+import zipfile
+import mozpack.path as mozpath
+from mozbuild.action.exe_7z_archive import archive_exe
+from mozbuild.util import ensureParentDir
+
+def repackage_installer(topsrcdir, tag, setupexe, package, output):
+    if package and not zipfile.is_zipfile(package):
+        raise Exception("Package file %s is not a valid .zip file." % package)
+
+    # We need the full path for the tag and output, since we chdir later.
+    tag = mozpath.realpath(tag)
+    output = mozpath.realpath(output)
+    ensureParentDir(output)
+
+    tmpdir = tempfile.mkdtemp()
+    old_cwd = os.getcwd()
+    try:
+        if package:
+            z = zipfile.ZipFile(package)
+            z.extractall(tmpdir)
+            z.close()
+
+        # Copy setup.exe into the root of the install dir, alongside the
+        # package.
+        shutil.copyfile(setupexe, mozpath.join(tmpdir, mozpath.basename(setupexe)))
+
+        # archive_exe requires us to be in the directory where the package is
+        # unpacked (the tmpdir)
+        os.chdir(tmpdir)
+
+        sfx_package = mozpath.join(topsrcdir, 'other-licenses/7zstub/firefox/7zSD.sfx')
+
+        package_name = 'firefox' if package else None
+        archive_exe(package_name, tag, sfx_package, output)
+
+    finally:
+        os.chdir(old_cwd)
+        shutil.rmtree(tmpdir)