[Buildbot-commits] buildbot/buildbot/changes bonsaipoller.py, 1.2, 1.3
Brian Warner
warner at users.sourceforge.net
Sun Nov 5 05:13:16 UTC 2006
Update of /cvsroot/buildbot/buildbot/buildbot/changes
In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv3175/buildbot/changes
Modified Files:
bonsaipoller.py
Log Message:
[project @ bonsaipoller: apply updates+test from Ben Hearsum. Closes SF#1590310.]
Original author: warner at lothar.com
Date: 2006-11-05 05:11:54
Index: bonsaipoller.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/changes/bonsaipoller.py,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- bonsaipoller.py 30 Sep 2006 20:20:35 -0000 1.2
+++ bonsaipoller.py 5 Nov 2006 05:13:14 -0000 1.3
@@ -1,4 +1,3 @@
-
import time
from urllib import urlopen
from xml.dom import minidom, Node
@@ -9,129 +8,170 @@
from buildbot.changes import base, changes
+class InvalidResultError(Exception):
+ def __init__(self, value="InvalidResultError"):
+ self.value = value
+ def __str__(self):
+ return repr(self.value)
+
+class EmptyResult(Exception):
+ pass
+
+class NoMoreCiNodes(Exception):
+ pass
+
+class NoMoreFileNodes(Exception):
+ pass
class BonsaiResult:
"""I hold a list of CiNodes"""
- def __init__(self):
- self.nodes = []
+ def __init__(self, nodes=[]):
+ self.nodes = nodes
+
+ def __cmp__(self, other):
+ if len(self.nodes) != len(other.nodes):
+ return False
+ for i in range(len(self.nodes)):
+ if self.nodes[i].log != other.nodes[i].log \
+ or self.nodes[i].who != other.nodes[i].who \
+ or self.nodes[i].date != other.nodes[i].date \
+ or len(self.nodes[i].files) != len(other.nodes[i].files):
+ return -1
+
+ for j in range(len(self.nodes[i].files)):
+ if self.nodes[i].files[j].revision \
+ != other.nodes[i].files[j].revision \
+ or self.nodes[i].files[j].filename \
+ != other.nodes[i].files[j].filename:
+ return -1
+
+ return 0
class CiNode:
- """I hold information about one Ci node, including a list of files"""
- def __init__(self):
- self.log = ""
- self.who = ""
- self.date = ""
- self.files = []
+ """I hold information baout one <ci> node, including a list of files"""
+ def __init__(self, log="", who="", date=0, files=[]):
+ self.log = log
+ self.who = who
+ self.date = date
+ self.files = files
class FileNode:
- """I hold information about one file node"""
- def __init__(self):
- self.revision = ""
- self.filename = ""
+ """I hold information about one <f> node"""
+ def __init__(self, revision="", filename=""):
+ self.revision = revision
+ self.filename = filename
class BonsaiParser:
- """I parse the XML result from a Bonsai cvsquery.
- Typical usage is as follows::
-
- bp = BonsaiParser(urlopen(bonsaiURL))
- data = bp.getData()
- for cinode in data.nodes:
- print cinode.who, cinode.log, cinode.date
- for file in cinode.files:
- print file.filename, file.revision
- """
+ """I parse the XML result from a bonsai cvsquery."""
def __init__(self, bonsaiQuery):
try:
self.dom = minidom.parse(bonsaiQuery)
except:
- self.dom = None
- return
- self.currentCiNode = None
- self.currentFileNode = None
+ raise InvalidResultError("Malformed XML in result")
+
+ self.ciNodes = self.dom.getElementsByTagName("ci")
+ self.currentCiNode = None # filled in by _nextCiNode()
+ self.fileNodes = None # filled in by _nextCiNode()
+ self.currentFileNode = None # filled in by _nextFileNode()
+ self.bonsaiResult = self._parseData()
def getData(self):
- """I return data from a Bonsai cvsquery"""
- data = BonsaiResult()
- while self._nextCiNode():
- ci = CiNode()
- ci.log = self._getLog()
- ci.who = self._getWho()
- ci.date = self._getDate()
- while self._nextFileNode():
- fn = FileNode()
- fn.revision = self._getRevision()
- fn.filename = self._getFilename()
- ci.files.append(fn)
+ return self.bonsaiResult
- data.nodes.append(ci)
+ def _parseData(self):
+ """Returns data from a Bonsai cvsquery in a BonsaiResult object"""
+ nodes = []
+ try:
+ while self._nextCiNode():
+ files = []
+ try:
+ while self._nextFileNode():
+ files.append(FileNode(self._getRevision(),
+ self._getFilename()))
+ except NoMoreFileNodes:
+ pass
+ except InvalidResultError:
+ raise
+ nodes.append(CiNode(self._getLog(), self._getWho(),
+ self._getDate(), files))
- return data
+ except NoMoreCiNodes:
+ pass
+ except InvalidResultError, EmptyResult:
+ raise
+
+ return BonsaiResult(nodes)
def _nextCiNode(self):
+ """Iterates to the next <ci> node and fills self.fileNodes with
+ child <f> nodes"""
try:
- # first <ci> node?
+ self.currentCiNode = self.ciNodes.pop(0)
+ if len(self.currentCiNode.getElementsByTagName("files")) > 1:
+ raise InvalidResultError("Multiple <files> for one <ci>")
+
+ self.fileNodes = self.currentCiNode.getElementsByTagName("f")
+ except IndexError:
+ # if there was zero <ci> nodes in the result
if not self.currentCiNode:
- # every other sibling is a <ci>, so jump 2 ahead
- self.currentCiNode = self.dom.getElementsByTagName("ci")[0]
+ raise EmptyResult
else:
- self.currentCiNode = self.currentCiNode.nextSibling.nextSibling
- except (AttributeError,IndexError):
- self.currentCiNode = None
+ raise NoMoreCiNodes
- if self.currentCiNode:
- return True
- else:
- return False
+ return True
+
+ def _nextFileNode(self):
+ """Iterates to the next <f> node"""
+ try:
+ self.currentFileNode = self.fileNodes.pop(0)
+ except IndexError:
+ raise NoMoreFileNodes
+
+ return True
def _getLog(self):
- log = ""
- for child in self.currentCiNode.childNodes:
- if child.nodeType == Node.ELEMENT_NODE and child.tagName == "log":
- log = child.firstChild.data
- return str(log)
+ """Returns the log of the current <ci> node"""
+ logs = self.currentCiNode.getElementsByTagName("log")
+ if len(logs) < 1:
+ raise InvalidResultError("No log present")
+ elif len(logs) > 1:
+ raise InvalidResultError("Multiple logs present")
+ return logs[0].firstChild.data
def _getWho(self):
- """Returns the e-mail address of the commit'er"""
- return str(self.currentCiNode.getAttribute("who").replace("%", "@"))
+ """Returns the e-mail address of the commiter"""
+ # convert unicode string to regular string
+ return str(self.currentCiNode.getAttribute("who"))
def _getDate(self):
"""Returns the date (unix time) of the commit"""
- return int(self.currentCiNode.getAttribute("date"))
-
+ # convert unicode number to regular one
+ try:
+ commitDate = int(self.currentCiNode.getAttribute("date"))
+ except ValueError:
+ raise InvalidResultError
- def _firstFileNode(self):
- for child in self.currentCiNode.childNodes:
- if child.nodeType == Node.ELEMENT_NODE and child.tagName == "files":
- # child is now the <files> element
- for c in child.childNodes:
- if c.nodeType == Node.ELEMENT_NODE and c.tagName == "f":
- return c
+ return commitDate
- def _nextFileNode(self):
- # every other sibling is a <f>, so go two past the current one
+ def _getFilename(self):
+ """Returns the filename of the current <f> node"""
try:
- # first <f> node?
- if not self.currentFileNode:
- self.currentFileNode = self._firstFileNode()
- else:
- self.currentFileNode = self.currentFileNode.nextSibling.nextSibling
+ filename = self.currentFileNode.firstChild.data
except AttributeError:
- self.currentFileNode = None
-
- if self.currentFileNode:
- return True
- else:
- return False
+ raise InvalidResultError("Missing filename")
- def _getFilename(self):
- return str(self.currentFileNode.firstChild.data)
+ return filename
def _getRevision(self):
- return str(self.currentFileNode.getAttribute("rev"))
+ """Returns the revision of the current <f> node"""
+ rev = self.currentFileNode.getAttribute("rev")
+ if rev == "":
+ raise InvalidResultError("A revision was missing from a file")
+ return rev
class BonsaiPoller(base.ChangeSource):
@@ -215,7 +255,7 @@
log.msg("Bonsai poll failed: %s" % res)
return res
- def _get_changes(self):
+ def _make_url(self):
args = ["treeid=%s" % self.tree, "module=%s" % self.module,
"branch=%s" % self.branch, "branchtype=match",
"sortby=Date", "date=explicit",
@@ -226,6 +266,11 @@
url = self.bonsaiURL
url += "/cvsquery.cgi?"
url += "&".join(args)
+
+ return url
+
+ def _get_changes(self):
+ url = self._make_url()
log.msg("Polling Bonsai tree at %s" % url)
self.lastPoll = time.time()
@@ -233,10 +278,17 @@
return defer.maybeDeferred(urlopen, url)
def _process_changes(self, query):
- bp = BonsaiParser(query)
files = []
- data = bp.getData()
- for cinode in data.nodes:
+ try:
+ bp = BonsaiParser(query)
+ result = bp.getData()
+ except InvalidResultError, e:
+ log.msg("Could not process Bonsai query: " + e.value)
+ return
+ except EmptyResult:
+ return
+
+ for cinode in result.nodes:
for file in cinode.files:
files.append(file.filename+' (revision '+file.revision+')')
c = changes.Change(who = cinode.who,
@@ -246,4 +298,3 @@
branch = self.branch)
self.parent.addChange(c)
self.lastChange = self.lastPoll
-
More information about the Commits
mailing list