Browse Source

Revert r80770 "Switch from xml.dom.minidom to xml.etree"

Throws exceptions on mac.

R=dpranke@chromium.org
BUG=
TEST=

Review URL: http://codereview.chromium.org/6811020

git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@80771 0039d316-1c4b-4281-b951-d872f2087c98
maruel@chromium.org 14 years ago
parent
commit
d25fb8f68b
7 changed files with 119 additions and 113 deletions
  1. 0 8
      fix_encoding.py
  2. 25 0
      gclient_utils.py
  3. 8 24
      presubmit_canned_checks.py
  4. 1 2
      rietveld.py
  5. 79 73
      scm.py
  6. 4 3
      tests/gclient_utils_test.py
  7. 2 3
      tests/scm_unittest.py

+ 0 - 8
fix_encoding.py

@@ -81,8 +81,6 @@ def fix_win_sys_argv(encoding):
   if _SYS_ARGV_PROCESSED:
   if _SYS_ARGV_PROCESSED:
     return False
     return False
 
 
-  # These types are available on linux but not Mac.
-  # pylint: disable=E0611,F0401
   from ctypes import byref, c_int, POINTER, windll, WINFUNCTYPE
   from ctypes import byref, c_int, POINTER, windll, WINFUNCTYPE
   from ctypes.wintypes import LPCWSTR, LPWSTR
   from ctypes.wintypes import LPCWSTR, LPWSTR
 
 
@@ -188,8 +186,6 @@ class WinUnicodeConsoleOutput(WinUnicodeOutputBase):
     self._console_handle = console_handle
     self._console_handle = console_handle
 
 
     # Loads the necessary function.
     # Loads the necessary function.
-    # These types are available on linux but not Mac.
-    # pylint: disable=E0611,F0401
     from ctypes import byref, GetLastError, POINTER, windll, WINFUNCTYPE
     from ctypes import byref, GetLastError, POINTER, windll, WINFUNCTYPE
     from ctypes.wintypes import BOOL, DWORD, HANDLE, LPWSTR
     from ctypes.wintypes import BOOL, DWORD, HANDLE, LPWSTR
     from ctypes.wintypes import LPVOID  # pylint: disable=E0611
     from ctypes.wintypes import LPVOID  # pylint: disable=E0611
@@ -270,8 +266,6 @@ class WinUnicodeOutput(WinUnicodeOutputBase):
 
 
 def win_handle_is_a_console(handle):
 def win_handle_is_a_console(handle):
   """Returns True if a Windows file handle is a handle to a console."""
   """Returns True if a Windows file handle is a handle to a console."""
-  # These types are available on linux but not Mac.
-  # pylint: disable=E0611,F0401
   from ctypes import byref, POINTER, windll, WINFUNCTYPE
   from ctypes import byref, POINTER, windll, WINFUNCTYPE
   from ctypes.wintypes import BOOL, DWORD, HANDLE
   from ctypes.wintypes import BOOL, DWORD, HANDLE
 
 
@@ -303,8 +297,6 @@ def win_get_unicode_stream(stream, excepted_fileno, output_handle, encoding):
   """
   """
   old_fileno = getattr(stream, 'fileno', lambda: None)()
   old_fileno = getattr(stream, 'fileno', lambda: None)()
   if old_fileno == excepted_fileno:
   if old_fileno == excepted_fileno:
-    # These types are available on linux but not Mac.
-    # pylint: disable=E0611,F0401
     from ctypes import windll, WINFUNCTYPE
     from ctypes import windll, WINFUNCTYPE
     from ctypes.wintypes import DWORD, HANDLE
     from ctypes.wintypes import DWORD, HANDLE
 
 

+ 25 - 0
gclient_utils.py

@@ -14,6 +14,8 @@ import subprocess
 import sys
 import sys
 import threading
 import threading
 import time
 import time
+import xml.dom.minidom
+import xml.parsers.expat
 
 
 
 
 def hack_subprocess():
 def hack_subprocess():
@@ -112,6 +114,29 @@ def SplitUrlRevision(url):
   return tuple(components)
   return tuple(components)
 
 
 
 
+def ParseXML(output):
+  try:
+    return xml.dom.minidom.parseString(output)
+  except xml.parsers.expat.ExpatError:
+    return None
+
+
+def GetNamedNodeText(node, node_name):
+  child_nodes = node.getElementsByTagName(node_name)
+  if not child_nodes:
+    return None
+  assert len(child_nodes) == 1 and child_nodes[0].childNodes.length == 1
+  return child_nodes[0].firstChild.nodeValue
+
+
+def GetNodeNamedAttributeText(node, node_name, attribute_name):
+  child_nodes = node.getElementsByTagName(node_name)
+  if not child_nodes:
+    return None
+  assert len(child_nodes) == 1
+  return child_nodes[0].getAttribute(attribute_name)
+
+
 def SyntaxErrorToError(filename, e):
 def SyntaxErrorToError(filename, e):
   """Raises a gclient_utils.Error exception with the human readable message"""
   """Raises a gclient_utils.Error exception with the human readable message"""
   try:
   try:

+ 8 - 24
presubmit_canned_checks.py

@@ -544,13 +544,8 @@ def RunPylint(input_api, output_api, white_list=None, black_list=None):
 
 
   The default white_list enforces looking only a *.py files.
   The default white_list enforces looking only a *.py files.
   """
   """
-  verbose = False
   white_list = white_list or ['.*\.py$']
   white_list = white_list or ['.*\.py$']
   black_list = black_list or input_api.DEFAULT_BLACK_LIST
   black_list = black_list or input_api.DEFAULT_BLACK_LIST
-  if input_api.is_committing:
-    error_type = output_api.PresubmitError
-  else:
-    error_type = output_api.PresubmitPromptWarning
 
 
   # Only trigger if there is at least one python file affected.
   # Only trigger if there is at least one python file affected.
   src_filter = lambda x: input_api.FilterSourceFile(x, white_list, black_list)
   src_filter = lambda x: input_api.FilterSourceFile(x, white_list, black_list)
@@ -569,6 +564,10 @@ def RunPylint(input_api, output_api, white_list=None, black_list=None):
     # were listed, try to run pylint.
     # were listed, try to run pylint.
     try:
     try:
       from pylint import lint
       from pylint import lint
+      result = lint.Run(sorted(files))
+    except SystemExit, e:
+      # pylint has the bad habit of calling sys.exit(), trap it here.
+      result = e.code
     except ImportError:
     except ImportError:
       if input_api.platform == 'win32':
       if input_api.platform == 'win32':
         return [output_api.PresubmitNotifyResult(
         return [output_api.PresubmitNotifyResult(
@@ -580,31 +579,16 @@ def RunPylint(input_api, output_api, white_list=None, black_list=None):
           'sudo easy_install pylint"\n'
           'sudo easy_install pylint"\n'
           'or visit http://pypi.python.org/pypi/setuptools.\n'
           'or visit http://pypi.python.org/pypi/setuptools.\n'
           'Cannot do static analysis of python files.')]
           'Cannot do static analysis of python files.')]
-
-    def run_lint(files):
-      try:
-        lint.Run(files)
-        assert False
-      except SystemExit, e:
-        # pylint has the bad habit of calling sys.exit(), trap it here.
-        return e.code
-
-    result = None
-    if not verbose:
-      result = run_lint(sorted(files))
-    else:
-      for filename in sorted(files):
-        print('Running pylint on %s' % filename)
-        out = run_lint([filename])
-        if out:
-          result = out
     if result:
     if result:
+      if input_api.is_committing:
+        error_type = output_api.PresubmitError
+      else:
+        error_type = output_api.PresubmitPromptWarning
       return [error_type('Fix pylint errors first.')]
       return [error_type('Fix pylint errors first.')]
     return []
     return []
   finally:
   finally:
     warnings.filterwarnings('default', category=DeprecationWarning)
     warnings.filterwarnings('default', category=DeprecationWarning)
 
 
-
 # TODO(dpranke): Get the host_url from the input_api instead
 # TODO(dpranke): Get the host_url from the input_api instead
 def CheckRietveldTryJobExecution(input_api, output_api, host_url, platforms,
 def CheckRietveldTryJobExecution(input_api, output_api, host_url, platforms,
                                  owner):
                                  owner):

+ 1 - 2
rietveld.py

@@ -34,8 +34,7 @@ import patch
 
 
 # Hack out upload logging.info()
 # Hack out upload logging.info()
 upload.logging = logging.getLogger('upload')
 upload.logging = logging.getLogger('upload')
-# Mac pylint choke on this line.
-upload.logging.setLevel(logging.WARNING)  # pylint: disable=E1103
+upload.logging.setLevel(logging.WARNING)
 
 
 
 
 class Rietveld(object):
 class Rietveld(object):

+ 79 - 73
scm.py

@@ -14,7 +14,7 @@ import subprocess
 import sys
 import sys
 import tempfile
 import tempfile
 import time
 import time
-from xml.etree import ElementTree
+import xml.dom.minidom
 
 
 import gclient_utils
 import gclient_utils
 import subprocess2
 import subprocess2
@@ -512,35 +512,38 @@ class SVN(object):
     """Returns a dictionary from the svn info output for the given file.
     """Returns a dictionary from the svn info output for the given file.
 
 
     Throws an exception if svn info fails."""
     Throws an exception if svn info fails."""
-    result = {}
     output = SVN.Capture(['info', '--xml', cwd])
     output = SVN.Capture(['info', '--xml', cwd])
-    info = ElementTree.XML(output)
-    if info is None:
-      return result
-    entry = info.find('entry')
-
-    # Use .text when the item is not optional.
-    result['Path'] = entry.attrib['path']
-    result['Revision'] = int(entry.attrib['revision'])
-    result['Node Kind'] = entry.attrib['kind']
-    # Differs across versions.
-    if result['Node Kind'] == 'dir':
-      result['Node Kind'] = 'directory'
-    result['URL'] = entry.find('url').text
-    repository = entry.find('repository')
-    result['Repository Root'] = repository.find('root').text
-    result['UUID'] = repository.find('uuid')
-    wc_info = entry.find('wc-info')
-    result['Schedule'] = wc_info.find('schedule').text
-    result['Copied From URL'] = wc_info.find('copy-from-url')
-    result['Copied From Rev'] = wc_info.find('copy-from-rev')
-    for key in result.keys():
-      if isinstance(result[key], unicode):
-        # Unicode results interferes with the higher layers matching up things
-        # in the deps dictionary.
-        result[key] = result[key].encode()
-      # Automatic conversion of optional parameters.
-      result[key] = getattr(result[key], 'text', result[key])
+    dom = gclient_utils.ParseXML(output)
+    result = {}
+    if dom:
+      GetNamedNodeText = gclient_utils.GetNamedNodeText
+      GetNodeNamedAttributeText = gclient_utils.GetNodeNamedAttributeText
+      def C(item, f):
+        if item is not None:
+          return f(item)
+      # /info/entry/
+      #   url
+      #   reposityory/(root|uuid)
+      #   wc-info/(schedule|depth)
+      #   commit/(author|date)
+      # str() the results because they may be returned as Unicode, which
+      # interferes with the higher layers matching up things in the deps
+      # dictionary.
+      result['Repository Root'] = C(GetNamedNodeText(dom, 'root'), str)
+      result['URL'] = C(GetNamedNodeText(dom, 'url'), str)
+      result['UUID'] = C(GetNamedNodeText(dom, 'uuid'), str)
+      result['Revision'] = C(GetNodeNamedAttributeText(dom, 'entry',
+                                                       'revision'),
+                             int)
+      result['Node Kind'] = C(GetNodeNamedAttributeText(dom, 'entry', 'kind'),
+                              str)
+      # Differs across versions.
+      if result['Node Kind'] == 'dir':
+        result['Node Kind'] = 'directory'
+      result['Schedule'] = C(GetNamedNodeText(dom, 'schedule'), str)
+      result['Path'] = C(GetNodeNamedAttributeText(dom, 'entry', 'path'), str)
+      result['Copied From URL'] = C(GetNamedNodeText(dom, 'copy-from-url'), str)
+      result['Copied From Rev'] = C(GetNamedNodeText(dom, 'copy-from-rev'), str)
     return result
     return result
 
 
   @staticmethod
   @staticmethod
@@ -550,7 +553,9 @@ class SVN(object):
     Returns:
     Returns:
       Int base revision
       Int base revision
     """
     """
-    return SVN.CaptureInfo(cwd).get('Revision')
+    info = SVN.Capture(['info', '--xml'], cwd=cwd)
+    dom = xml.dom.minidom.parseString(info)
+    return dom.getElementsByTagName('entry')[0].getAttribute('revision')
 
 
   @staticmethod
   @staticmethod
   def CaptureStatus(files):
   def CaptureStatus(files):
@@ -585,50 +590,51 @@ class SVN(object):
       'replaced': 'R',
       'replaced': 'R',
       'unversioned': '?',
       'unversioned': '?',
     }
     }
-    dom = ElementTree.XML(SVN.Capture(command))
+    dom = gclient_utils.ParseXML(SVN.Capture(command))
     results = []
     results = []
-    if dom is None:
-      return results
-    # /status/target/entry/(wc-status|commit|author|date)
-    for target in dom.findall('target'):
-      for entry in target.findall('entry'):
-        file_path = entry.attrib['path']
-        wc_status = entry.find('wc-status')
-        # Emulate svn 1.5 status ouput...
-        statuses = [' '] * 7
-        # Col 0
-        xml_item_status = wc_status.attrib['item']
-        if xml_item_status in status_letter:
-          statuses[0] = status_letter[xml_item_status]
-        else:
-          raise gclient_utils.Error(
-              'Unknown item status "%s"; please implement me!' %
-                  xml_item_status)
-        # Col 1
-        xml_props_status = wc_status.attrib['props']
-        if xml_props_status == 'modified':
-          statuses[1] = 'M'
-        elif xml_props_status == 'conflicted':
-          statuses[1] = 'C'
-        elif (not xml_props_status or xml_props_status == 'none' or
-              xml_props_status == 'normal'):
-          pass
-        else:
-          raise gclient_utils.Error(
-              'Unknown props status "%s"; please implement me!' %
-                  xml_props_status)
-        # Col 2
-        if wc_status.attrib.get('wc-locked') == 'true':
-          statuses[2] = 'L'
-        # Col 3
-        if wc_status.attrib.get('copied') == 'true':
-          statuses[3] = '+'
-        # Col 4
-        if wc_status.attrib.get('switched') == 'true':
-          statuses[4] = 'S'
-        # TODO(maruel): Col 5 and 6
-        item = (''.join(statuses), file_path)
-        results.append(item)
+    if dom:
+      # /status/target/entry/(wc-status|commit|author|date)
+      for target in dom.getElementsByTagName('target'):
+        #base_path = target.getAttribute('path')
+        for entry in target.getElementsByTagName('entry'):
+          file_path = entry.getAttribute('path')
+          wc_status = entry.getElementsByTagName('wc-status')
+          assert len(wc_status) == 1
+          # Emulate svn 1.5 status ouput...
+          statuses = [' '] * 7
+          # Col 0
+          xml_item_status = wc_status[0].getAttribute('item')
+          if xml_item_status in status_letter:
+            statuses[0] = status_letter[xml_item_status]
+          else:
+            raise gclient_utils.Error(
+                'Unknown item status "%s"; please implement me!' %
+                    xml_item_status)
+          # Col 1
+          xml_props_status = wc_status[0].getAttribute('props')
+          if xml_props_status == 'modified':
+            statuses[1] = 'M'
+          elif xml_props_status == 'conflicted':
+            statuses[1] = 'C'
+          elif (not xml_props_status or xml_props_status == 'none' or
+                xml_props_status == 'normal'):
+            pass
+          else:
+            raise gclient_utils.Error(
+                'Unknown props status "%s"; please implement me!' %
+                    xml_props_status)
+          # Col 2
+          if wc_status[0].getAttribute('wc-locked') == 'true':
+            statuses[2] = 'L'
+          # Col 3
+          if wc_status[0].getAttribute('copied') == 'true':
+            statuses[3] = '+'
+          # Col 4
+          if wc_status[0].getAttribute('switched') == 'true':
+            statuses[4] = 'S'
+          # TODO(maruel): Col 5 and 6
+          item = (''.join(statuses), file_path)
+          results.append(item)
     return results
     return results
 
 
   @staticmethod
   @staticmethod

+ 4 - 3
tests/gclient_utils_test.py

@@ -28,12 +28,13 @@ class GclientUtilsUnittest(GclientUtilBase):
         'CheckCall', 'CheckCallError', 'CheckCallAndFilter',
         'CheckCall', 'CheckCallError', 'CheckCallAndFilter',
         'CheckCallAndFilterAndHeader', 'Error', 'ExecutionQueue', 'FileRead',
         'CheckCallAndFilterAndHeader', 'Error', 'ExecutionQueue', 'FileRead',
         'FileWrite', 'FindFileUpwards', 'FindGclientRoot',
         'FileWrite', 'FindFileUpwards', 'FindGclientRoot',
-        'GetGClientRootAndEntries', 'MakeFileAutoFlush',
-        'MakeFileAnnotated', 'PathDifference', 'Popen',
+        'GetGClientRootAndEntries', 'GetNamedNodeText', 'MakeFileAutoFlush',
+        'GetNodeNamedAttributeText', 'MakeFileAnnotated', 'PathDifference',
+        'ParseXML', 'Popen',
         'PrintableObject', 'RemoveDirectory', 'SoftClone', 'SplitUrlRevision',
         'PrintableObject', 'RemoveDirectory', 'SoftClone', 'SplitUrlRevision',
         'SyntaxErrorToError', 'WorkItem',
         'SyntaxErrorToError', 'WorkItem',
         'errno', 'hack_subprocess', 'logging', 'os', 'Queue', 're', 'rmtree',
         'errno', 'hack_subprocess', 'logging', 'os', 'Queue', 're', 'rmtree',
-        'stat', 'subprocess', 'sys','threading', 'time',
+        'stat', 'subprocess', 'sys','threading', 'time', 'xml',
     ]
     ]
     # If this test fails, you should add the relevant test.
     # If this test fails, you should add the relevant test.
     self.compareMembers(gclient_utils, members)
     self.compareMembers(gclient_utils, members)

+ 2 - 3
tests/scm_unittest.py

@@ -42,10 +42,10 @@ class RootTestCase(BaseSCMTestCase):
   def testMembersChanged(self):
   def testMembersChanged(self):
     self.mox.ReplayAll()
     self.mox.ReplayAll()
     members = [
     members = [
-        'ElementTree', 'GetCasedPath', 'GenFakeDiff', 'GIT', 'SVN',
-        'ValidateEmail',
+        'GetCasedPath', 'GenFakeDiff', 'GIT', 'SVN', 'ValidateEmail',
         'cStringIO', 'determine_scm', 'gclient_utils', 'glob', 'logging', 'os',
         'cStringIO', 'determine_scm', 'gclient_utils', 'glob', 'logging', 'os',
         're', 'shutil', 'subprocess', 'subprocess2', 'sys', 'tempfile', 'time',
         're', 'shutil', 'subprocess', 'subprocess2', 'sys', 'tempfile', 'time',
+        'xml',
     ]
     ]
     # If this test fails, you should add the relevant test.
     # If this test fails, you should add the relevant test.
     self.compareMembers(scm, members)
     self.compareMembers(scm, members)
@@ -104,7 +104,6 @@ class SVNTestCase(BaseSCMTestCase):
     self.mox.StubOutWithMock(scm, 'GetCasedPath')
     self.mox.StubOutWithMock(scm, 'GetCasedPath')
     scm.os.path.abspath = lambda x: x
     scm.os.path.abspath = lambda x: x
     scm.GetCasedPath = lambda x: x
     scm.GetCasedPath = lambda x: x
-    # pylint: disable=E1103
     scm.SVN.CaptureInfo(self.root_dir + '/foo/bar').AndReturn({
     scm.SVN.CaptureInfo(self.root_dir + '/foo/bar').AndReturn({
         'Repository Root': 'svn://svn.chromium.org/chrome',
         'Repository Root': 'svn://svn.chromium.org/chrome',
         'URL': 'svn://svn.chromium.org/chrome/trunk/src',
         'URL': 'svn://svn.chromium.org/chrome/trunk/src',