import glob
import subprocess
import re
-import xml.sax.handler
import shutil
+import xml.etree.cElementTree as ET
from common import runner
path = os.path.join(root, fname)
os.chmod(path, os.stat(path).st_mode | modes[fname in dirs])
-def make_latest_link(snapshot_path):
- """ make the latest repo link to the new repo
- snapshot_path (str): the local path to snapshot
+def xml_to_obj(xml_f):
"""
- latest = os.path.join(snapshot_path, "../latest")
- rel_path = os.path.basename(snapshot_path)
- if os.path.lexists(latest):
- os.unlink(latest)
- os.symlink(rel_path, latest)
-
-# The function xml2obj is from http://code.activestate.com/recipes/534109/
-# and is distributed under the PSF License.
-#
-# Author: Wai Yip Tung
-# Last Updated: 2007/10/19
-# Version no: 1.3
-# License: PSF License
-# Source: http://code.activestate.com/recipes/534109/
-
-def xml2obj(src):
+ A simple function to converts XML data
+ Xml data:
+ <?xml version="1.0" ?>
+ <build id="1.0">
+ <id>test</id>
+ <archs name='atom'>
+ <arch name='lz'>ia32</arch>
+ <arch>ai32</arch>
+ <arch>ai32</arch>
+ </archs>
+ <repo>repos/atom/packages</repo>
+ <repo type="source"></repo>
+ <repo type="debug">repos/atom/debug</repo>
+ </build>
+ Change result:
+ {archs:{arch:[{name:u'lz', data:u'ia32'}, u'ai32', u'ai32'], name:u'atom'},
+ id:[u'1.0', u'test'],
+ repo:[u'repos/atom/packages', {type:u'source'},
+ {type:u'debug', data:u'repos/atom/debug'}]}
+ stack = [(node, node.children, [node.children.data]),(node, node.children, [])....]
"""
- A simple function to converts XML data into native Python object.
- """
-
- non_id_char = re.compile('[^_0-9a-zA-Z]')
- def _name_mangle(name):
- """Split name though regular expressions"""
- return non_id_char.sub('_', name)
+ node_char = re.compile('[^_0-9a-zA-Z]')
+ def _name_regular(name):
+ """Split name though regular"""
+ return node_char.sub('_', name)
- class DataNode(object):
- """A custom class used to wrap XML attributes and child elements"""
+ class XMLNode(object):
+ """Wrap XML attributes and child elements"""
def __init__(self):
self._attrs = {} # XML attributes and child elements
- self.data = None # child text data
- def __len__(self):
- # treat single element as a list of 1
- return 1
- def __setitem__(self, key, value):
- self._attrs[key] = value
+ self.data = None # text data
+ def add_attr(self, name, value):
+ """Add XML attribute"""
+ if name in self._attrs:
+ # multiple attribute of the same name are represented by a list
+ children = self._attrs[name]
+ if not isinstance(children, list):
+ self._attrs[name] = [children, value]
+ else:
+ children.append(value)
+ else:
+ self._attrs[name] = value
def __getitem__(self, key):
if isinstance(key, basestring):
return self._attrs.get(key, None)
else:
return [self][key]
- def __delitem__(self, key):
- self._attrs.pop(key)
- def __contains__(self, name):
- return name in self._attrs
def __nonzero__(self):
return bool(self._attrs or self.data)
def __getattr__(self, name):
# need to do this for Python special methods???
raise AttributeError(name)
return self._attrs.get(name, None)
- def _add_xml_attr(self, name, value):
- """Add XML attribute"""
- if name in self._attrs:
- # multiple attribute of the same name are represented by a list
- children = self._attrs[name]
- if not isinstance(children, list):
- children = [children]
- self._attrs[name] = children
- children.append(value)
- else:
- self._attrs[name] = value
- def __str__(self):
- return self.data or ''
- def __repr__(self):
- items = sorted(self._attrs.items())
- if self.data:
- items.append(('data', self.data))
- return u'{%s}' % ', '.join([u'%s:%s' % (k, repr(v))
- for k, v in items])
-
- class TreeBuilder(xml.sax.handler.ContentHandler):
- """A wrapper class of ContentHandler"""
- def __init__(self):
- xml.sax.handler.ContentHandler.__init__(self)
- self.stack = []
- self.root = DataNode()
- self.current = self.root
- self.text_parts = []
- # pylint: disable-msg=C0103
- def startElement(self, name, attrs):
- self.stack.append((self.current, self.text_parts))
- self.current = DataNode()
- self.text_parts = []
- # xml attributes --> python attributes
- for k, v in attrs.items():
- self.current._add_xml_attr(_name_mangle(k), v)
- def endElement(self, name):
- text = ''.join(self.text_parts).strip()
- if text:
- self.current.data = text
- if self.current._attrs:
- obj = self.current
+ #Get tree root element
+ if isinstance(xml_f, basestring):
+ root = ET.fromstring(xml_f)
+ else:
+ root = ET.parse(xml_f).getroot()
+ stack = []
+ stack.append((root, root.getchildren(), []))
+
+ tag = None
+ xml_node = None
+ # convert xml data from sub nodes start
+ while stack:
+ cur_node, child_nodes, data_list = stack[-1]
+
+ if tag and xml_node:
+ data_list.append((tag, xml_node))
+ tag = None
+ xml_node = None
+
+ if child_nodes:
+ child_node = child_nodes[0]
+ child_nodes.remove(child_node)
+ stack.append((child_node, child_node.getchildren(), []))
+ continue
+
+ xml_node = XMLNode()
+
+ # add current node attrib into XMLNode
+ for key in cur_node.attrib:
+ xml_node.add_attr(_name_regular(key), cur_node.attrib[key])
+
+ # Add previous node attrib into XMLNode
+ for (previous_tag, node) in data_list:
+ xml_node.add_attr(_name_regular(previous_tag), node)
+
+ # Add current node text info XMLNode's data
+ if cur_node.text and ''.join(cur_node.text.strip()):
+ if xml_node:
+ xml_node.data = cur_node.text
else:
- # a text only node is simply represented by the string
- obj = text or ''
- self.current, self.text_parts = self.stack.pop()
- self.current._add_xml_attr(_name_mangle(name), obj)
- # pylint: enable-msg=C0103
-
- def characters(self, content):
- self.text_parts.append(content)
-
- builder = TreeBuilder()
+ xml_node = cur_node.text
+ tag = cur_node.tag
+ # remove namespaces of node.tag
+ if tag[0] == '{':
+ url, tag = tag[1:].split('}')
+ stack.pop()
+ if not stack:
+ return xml_node
- if isinstance(src, basestring):
- xml.sax.parseString(src, builder)
- else:
- xml.sax.parse(src, builder)
- return builder.root._attrs.values()[0]
+def make_latest_link(snapshot_path):
+ """ make the latest repo link to the new repo
+ snapshot_path (str): the local path to snapshot
+ """
+ latest = os.path.join(snapshot_path, "../latest")
+ rel_path = os.path.basename(snapshot_path)
+ if os.path.lexists(latest):
+ os.unlink(latest)
+ os.symlink(rel_path, latest)