Bug 1048446 - [mozinstall] Add ability to download and extract installer from a url, r=whimboo
authorAndrew Halberstadt <ahalberstadt@mozilla.com>
Thu, 09 Mar 2017 12:20:03 -0500
changeset 411390 42084b6fc3f926badd3af331876c995312103299
parent 411389 03b97e826142d8fc2d4d94ece6b4bfdbf1a5a60c
child 411391 f375a096bff95e10f770a779155012ff8647847d
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswhimboo
bugs1048446
milestone55.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 1048446 - [mozinstall] Add ability to download and extract installer from a url, r=whimboo This is a minor convenience for downloading the installer from a url. It uses requests (which should be available everywhere in-tree). MozReview-Commit-ID: 8IfiVkYNr06
testing/mozbase/mozinstall/mozinstall/mozinstall.py
testing/mozbase/mozinstall/setup.py
testing/mozbase/mozinstall/tests/test.py
--- a/testing/mozbase/mozinstall/mozinstall/mozinstall.py
+++ b/testing/mozbase/mozinstall/mozinstall/mozinstall.py
@@ -3,19 +3,22 @@
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from optparse import OptionParser
 import os
 import shutil
 import subprocess
 import sys
 import tarfile
+import tempfile
 import time
 import zipfile
 
+import requests
+
 import mozfile
 import mozinfo
 
 try:
     import pefile
     has_pefile = True
 except ImportError:
     has_pefile = False
@@ -91,22 +94,31 @@ def get_binary(path, app_name):
 def install(src, dest):
     """Install a zip, exe, tar.gz, tar.bz2 or dmg file, and return the path of
     the installation folder.
 
     :param src: Path to the install file
     :param dest: Path to install to (to ensure we do not overwrite any existent
                  files the folder should not exist yet)
     """
+
+    if not is_installer(src):
+        msg = "{} is not a valid installer file".format(src)
+        if '://' in src:
+            try:
+                return _install_url(src, dest)
+            except:
+                exc, val, tb = sys.exc_info()
+                msg = "{} ({})".format(msg, val)
+                raise InvalidSource, msg, tb
+        raise InvalidSource(msg)
+
     src = os.path.realpath(src)
     dest = os.path.realpath(dest)
 
-    if not is_installer(src):
-        raise InvalidSource(src + ' is not valid installer file.')
-
     did_we_create = False
     if not os.path.exists(dest):
         did_we_create = True
         os.makedirs(dest)
 
     trbk = None
     try:
         install_dir = None
@@ -232,16 +244,36 @@ def uninstall(install_folder):
                 # http://docs.python.org/library/sys.html#sys.exc_info
                 del trbk
 
     # Ensure that we remove any trace of the installation. Even the uninstaller
     # on Windows leaves files behind we have to explicitely remove.
     mozfile.remove(install_folder)
 
 
+def _install_url(url, dest):
+    """Saves a url to a temporary file, and passes that through to the
+    install function.
+
+    :param url: Url to the install file
+    :param dest: Path to install to (to ensure we do not overwrite any existent
+                 files the folder should not exist yet)
+    """
+    r = requests.get(url, stream=True)
+    name = tempfile.mkstemp()[1]
+    try:
+        with open(name, 'w+b') as fh:
+            for chunk in r.iter_content(chunk_size=16*1024):
+                fh.write(chunk)
+        result = install(name, dest)
+    finally:
+        mozfile.remove(name)
+    return result
+
+
 def _install_dmg(src, dest):
     """Extract a dmg file into the destination folder and return the
     application folder.
 
     src -- DMG image which has to be extracted
     dest -- the path to extract to
 
     """
--- a/testing/mozbase/mozinstall/setup.py
+++ b/testing/mozbase/mozinstall/setup.py
@@ -6,20 +6,21 @@ import os
 from setuptools import setup
 
 try:
     here = os.path.dirname(os.path.abspath(__file__))
     description = file(os.path.join(here, 'README.md')).read()
 except IOError:
     description = None
 
-PACKAGE_VERSION = '1.12'
+PACKAGE_VERSION = '1.13'
 
 deps = ['mozinfo >= 0.7',
         'mozfile >= 1.0',
+        'requests',
         ]
 
 setup(name='mozInstall',
       version=PACKAGE_VERSION,
       description="package for installing and uninstalling Mozilla applications",
       long_description="see http://mozbase.readthedocs.org/",
       # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
       classifiers=['Environment :: Console',
--- a/testing/mozbase/mozinstall/tests/test.py
+++ b/testing/mozbase/mozinstall/tests/test.py
@@ -108,16 +108,20 @@ class TestMozInstall(unittest.TestCase):
         elif mozinfo.isWin:
             self.assertRaises(mozinstall.InvalidSource, mozinstall.install,
                               self.bz2, 'firefox')
 
         elif mozinfo.isMac:
             self.assertRaises(mozinstall.InvalidSource, mozinstall.install,
                               self.bz2, 'firefox')
 
+        # Test an invalid url handler
+        self.assertRaises(mozinstall.InvalidSource, mozinstall.install,
+                          'file://foo.bar', 'firefox')
+
     @unittest.skipIf(mozinfo.isWin, "Bug 1157352 - We need a new firefox.exe "
                      "for mozinstall 1.12 and higher.")
     def test_install(self):
         """ Test mozinstall's install capability """
 
         if mozinfo.isLinux:
             installdir = mozinstall.install(self.bz2, self.tempdir)
             self.assertEqual(os.path.join(self.tempdir, 'firefox'), installdir)
@@ -162,10 +166,11 @@ class TestMozInstall(unittest.TestCase):
             mozinstall.uninstall(installdir_zip)
             self.assertFalse(os.path.exists(installdir_zip))
 
         elif mozinfo.isMac:
             installdir = mozinstall.install(self.dmg, self.tempdir)
             mozinstall.uninstall(installdir)
             self.assertFalse(os.path.exists(installdir))
 
+
 if __name__ == '__main__':
     mozunit.main()