Bug 609333 Mozrunner should stop use xml.dom instead of elementtree for parsing addon information r=ctalbert a=NPOTB
authorJeff Hammel <jhammel@mozilla.com>
Thu, 04 Nov 2010 17:01:13 -0700
changeset 56886 126e28ef841d5a00d3a3787b9cb85ceeb057e1ac
parent 56885 6a0621d487241d2e2cc4f6548c47cde9b127acaa
child 56887 fa209325ef51f59ca66b2467d87e11a164587b98
push id16719
push userctalbert@mozilla.com
push dateFri, 05 Nov 2010 00:01:44 +0000
treeherdermozilla-central@126e28ef841d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersctalbert, NPOTB
bugs609333
milestone2.0b8pre
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 609333 Mozrunner should stop use xml.dom instead of elementtree for parsing addon information r=ctalbert a=NPOTB
testing/mozmill/installmozmill.py
testing/mozmill/mozrunner/mozrunner/__init__.py
testing/mozmill/mozrunner/setup.py
--- a/testing/mozmill/installmozmill.py
+++ b/testing/mozmill/installmozmill.py
@@ -45,16 +45,19 @@ import os
 import sys
 from subprocess import call
 
 def main(args=None):
   """command line front-end function"""
 
   args = args or sys.argv[1:]
 
+  # Print the python version
+  print 'Python: %s' % sys.version
+
   # The data is kept in the same directory as the script
   source=os.path.abspath(os.path.dirname(__file__))
 
   # directory to install to
   if not len(args):
     destination = source
   elif len(args) == 1:
     destination = os.path.abspath(args[0])
@@ -73,17 +76,23 @@ def main(args=None):
 
   # packages to install in dependency order
   PACKAGES=file('PACKAGES').read().split()
   assert PACKAGES
   
   # create the virtualenv and install packages
   env = os.environ.copy()
   env.pop('PYTHONHOME', None)
-  call([sys.executable, 'virtualenv/virtualenv.py', destination], env=env)
+  returncode = call([sys.executable, 'virtualenv/virtualenv.py', destination], env=env)
+  if returncode:
+    print 'Failure to install virtualenv'
+    sys.exit(returncode)
   if sys.platform.startswith('win'):
     pip = os.path.join(destination, 'Scripts', 'pip.exe')
   else:
     pip = os.path.join(destination, 'bin', 'pip')
-  call([pip, 'install'] + PACKAGES, env=env)
+  returncode = call([pip, 'install'] + PACKAGES, env=env)
+  if returncode:
+    print 'Failure to install packages'
+    sys.exit(returncode)
 
 if __name__ == '__main__':
   main()
--- a/testing/mozmill/mozrunner/mozrunner/__init__.py
+++ b/testing/mozmill/mozrunner/mozrunner/__init__.py
@@ -46,23 +46,20 @@ import commands
 import zipfile
 import optparse
 import killableprocess
 import subprocess
 import platform
 
 from distutils import dir_util
 from time import sleep
+from xml.dom import minidom
 
 # conditional (version-dependent) imports
 try:
-    from xml.etree import ElementTree
-except ImportError:
-    from elementtree import ElementTree
-try:
     import simplejson
 except ImportError:
     import json as simplejson
 
 import logging
 logger = logging.getLogger(__name__)
 
 # Use dir_util for copy/rm operations because shutil is all kinds of broken
@@ -194,72 +191,98 @@ class Profile(object):
 
         self.set_preferences(self.preferences)
 
     def create_new_profile(self, binary):
         """Create a new clean profile in tmp which is a simple empty folder"""
         profile = tempfile.mkdtemp(suffix='.mozrunner')
         return profile
 
+    ### methods related to addons
+
+    @classmethod
+    def addon_id(self, addon_path):
+        """
+        return the id for a given addon, or None if not found
+        - addon_path : path to the addon directory
+        """
+        
+        def find_id(desc):
+            """finds the addon id give its description"""
+            
+            addon_id = None
+            for elem in desc:
+                apps = elem.getElementsByTagName('em:targetApplication')
+                if apps:
+                    for app in apps:
+                        # remove targetApplication nodes, they contain id's we aren't interested in
+                        elem.removeChild(app)
+                    if elem.getElementsByTagName('em:id'):
+                        addon_id = str(elem.getElementsByTagName('em:id')[0].firstChild.data)
+                    elif elem.hasAttribute('em:id'):
+                        addon_id = str(elem.getAttribute('em:id'))
+            return addon_id
+
+        doc = minidom.parse(os.path.join(addon_path, 'install.rdf')) 
+
+        for tag in 'Description', 'RDF:Description':
+            desc = doc.getElementsByTagName(tag)
+            addon_id = find_id(desc)
+            if addon_id:
+                return addon_id
+
+
     def install_addon(self, path):
         """Installs the given addon or directory of addons in the profile."""
+        
+        # if the addon is a directory, install all addons in it
         addons = [path]
         if not path.endswith('.xpi') and not os.path.exists(os.path.join(path, 'install.rdf')):
             addons = [os.path.join(path, x) for x in os.listdir(path)]
 
+        # install each addon
         for addon in addons:
-            tmpdir = None
+
+            # if the addon is an .xpi, uncompress it to a temporary directory
             if addon.endswith('.xpi'):
                 tmpdir = tempfile.mkdtemp(suffix = "." + os.path.split(addon)[-1])
                 compressed_file = zipfile.ZipFile(addon, "r")
                 for name in compressed_file.namelist():
                     if name.endswith('/'):
                         makedirs(os.path.join(tmpdir, name))
                     else:
                         if not os.path.isdir(os.path.dirname(os.path.join(tmpdir, name))):
                             makedirs(os.path.dirname(os.path.join(tmpdir, name)))
                         data = compressed_file.read(name)
                         f = open(os.path.join(tmpdir, name), 'wb')
                         f.write(data) ; f.close()
                 addon = tmpdir
 
-            tree = ElementTree.ElementTree(file=os.path.join(addon, 'install.rdf'))
-            # description_element =
-            # tree.find('.//{http://www.w3.org/1999/02/22-rdf-syntax-ns#}Description/')
+            # determine the addon id
+            addon_id = Profile.addon_id(addon)
+            assert addon_id is not None, "The addon id could not be found: %s" % addon
 
-            desc = tree.find('.//{http://www.w3.org/1999/02/22-rdf-syntax-ns#}Description')
-            apps = desc.findall('.//{http://www.mozilla.org/2004/em-rdf#}targetApplication')
-            for app in apps:
-              desc.remove(app)
-            if len(desc) and desc.attrib.has_key('{http://www.mozilla.org/2004/em-rdf#}id'):
-                addon_id = desc.attrib['{http://www.mozilla.org/2004/em-rdf#}id']
-            elif len(desc) and desc.find('.//{http://www.mozilla.org/2004/em-rdf#}id') is not None:
-                addon_id = desc.find('.//{http://www.mozilla.org/2004/em-rdf#}id').text
-            else:
-                about = [e for e in tree.findall(
-                            './/{http://www.w3.org/1999/02/22-rdf-syntax-ns#}Description') if
-                             e.get('{http://www.w3.org/1999/02/22-rdf-syntax-ns#}about') ==
-                             'urn:mozilla:install-manifest'
-                        ]
-
-                x = e.find('.//{http://www.w3.org/1999/02/22-rdf-syntax-ns#}Description')
-
-                if len(about) == 0:
-                    addon_element = tree.find('.//{http://www.mozilla.org/2004/em-rdf#}id')
-                    addon_id = addon_element.text
-                else:
-                    addon_id = about[0].get('{http://www.mozilla.org/2004/em-rdf#}id')
-
+            # copy the addon to the profile
             addon_path = os.path.join(self.profile, 'extensions', addon_id)
             copytree(addon, addon_path, preserve_symlinks=1)
             self.addons_installed.append(addon_path)
 
+    def clean_addons(self):
+        """Cleans up addons in the profile."""
+        for addon in self.addons_installed:
+            if os.path.isdir(addon):
+                rmtree(addon)
+
+    ### methods related to preferences
+
     def set_preferences(self, preferences):
         """Adds preferences dict to profile preferences"""
+
         prefs_file = os.path.join(self.profile, 'user.js')
+
         # Ensure that the file exists first otherwise create an empty file
         if os.path.isfile(prefs_file):
             f = open(prefs_file, 'a+')
         else:
             f = open(prefs_file, 'w')
 
         f.write('\n#MozRunner Prefs Start\n')
 
@@ -274,21 +297,17 @@ class Profile(object):
     def clean_preferences(self):
         """Removed preferences added by mozrunner."""
         lines = open(os.path.join(self.profile, 'user.js'), 'r').read().splitlines()
         s = lines.index('#MozRunner Prefs Start') ; e = lines.index('#MozRunner Prefs End')
         cleaned_prefs = '\n'.join(lines[:s] + lines[e+1:])
         f = open(os.path.join(self.profile, 'user.js'), 'w')
         f.write(cleaned_prefs) ; f.flush() ; f.close()
 
-    def clean_addons(self):
-        """Cleans up addons in the profile."""
-        for addon in self.addons_installed:
-            if os.path.isdir(addon):
-                rmtree(addon)
+    ### cleanup 
 
     def cleanup(self):
         """Cleanup operations on the profile."""
         if self.create_new:
             rmtree(self.profile)
         else:
             self.clean_preferences()
             self.clean_addons()
@@ -604,8 +623,15 @@ class CLI(object):
         try:
             runner.wait()
         except KeyboardInterrupt:
             runner.stop()
 
 
 def cli():
     CLI().run()
+
+def print_addon_ids(args=sys.argv[1:]):
+    """print addon ids for testing"""
+    for arg in args:
+        print Profile.addon_id(arg)
+    
+    
--- a/testing/mozmill/mozrunner/setup.py
+++ b/testing/mozmill/mozrunner/setup.py
@@ -34,44 +34,42 @@
 # the terms of any one of the MPL, the GPL or the LGPL.
 #
 # ***** END LICENSE BLOCK *****
 
 from setuptools import setup, find_packages
 import sys
 
 desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
-summ = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
 
 PACKAGE_NAME = "mozrunner"
 PACKAGE_VERSION = "2.5.2rc2"
 
 deps = []
 
 # we only support python 2 right now
 assert sys.version_info[0] == 2
 
 # version-dependent dependencies
-if not sys.version_info[1] < 6:
+if sys.version_info[1] < 6:
     deps.append('simplejson')
-if not sys.version_info[1] < 5:
-    deps.append('elementtree')
 
 setup(name=PACKAGE_NAME,
       version=PACKAGE_VERSION,
       description=desc,
-      long_description=summ,
+      long_description=desc,
       author='Mikeal Rogers, Mozilla',
       author_email='mikeal.rogers@gmail.com',
       url='http://github.com/mozautomation/mozmill',
       license='MPL 1.1/GPL 2.0/LGPL 2.1',
       packages=find_packages(exclude=['legacy']),
       entry_points="""
           [console_scripts]
           mozrunner = mozrunner:cli
+          addon_id = mozrunner:print_addon_ids
         """,
       platforms =['Any'],
       install_requires = deps,
       classifiers=['Development Status :: 4 - Beta',
                    'Environment :: Console',
                    'Intended Audience :: Developers',
                    'License :: OSI Approved :: Mozilla Public License 1.1 (MPL 1.1)',
                    'Operating System :: OS Independent',