| Index: third_party/buildbot_7_12/buildbot/changes/bonsaipoller.py
|
| diff --git a/third_party/buildbot_7_12/buildbot/changes/bonsaipoller.py b/third_party/buildbot_7_12/buildbot/changes/bonsaipoller.py
|
| deleted file mode 100644
|
| index 8368828c28fa914066bcdc9637de11d7f5c02549..0000000000000000000000000000000000000000
|
| --- a/third_party/buildbot_7_12/buildbot/changes/bonsaipoller.py
|
| +++ /dev/null
|
| @@ -1,320 +0,0 @@
|
| -import time
|
| -from xml.dom import minidom
|
| -
|
| -from twisted.python import log, failure
|
| -from twisted.internet import reactor
|
| -from twisted.internet.task import LoopingCall
|
| -from twisted.web.client import getPage
|
| -
|
| -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, 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 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 <f> node"""
|
| - def __init__(self, revision="", filename=""):
|
| - self.revision = revision
|
| - self.filename = filename
|
| -
|
| -class BonsaiParser:
|
| - """I parse the XML result from a bonsai cvsquery."""
|
| -
|
| - def __init__(self, data):
|
| - try:
|
| - # this is a fix for non-ascii characters
|
| - # because bonsai does not give us an encoding to work with
|
| - # it impossible to be 100% sure what to decode it as but latin1 covers
|
| - # the broadest base
|
| - data = data.decode("latin1")
|
| - data = data.encode("ascii", "replace")
|
| - self.dom = minidom.parseString(data)
|
| - log.msg(data)
|
| - except:
|
| - 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):
|
| - return self.bonsaiResult
|
| -
|
| - 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
|
| - cinode = CiNode(self._getLog(), self._getWho(),
|
| - self._getDate(), files)
|
| - # hack around bonsai xml output bug for empty check-in comments
|
| - if not cinode.log and nodes and \
|
| - not nodes[-1].log and \
|
| - cinode.who == nodes[-1].who and \
|
| - cinode.date == nodes[-1].date:
|
| - nodes[-1].files += cinode.files
|
| - else:
|
| - nodes.append(cinode)
|
| -
|
| - 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:
|
| - 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:
|
| - raise EmptyResult
|
| - else:
|
| - raise NoMoreCiNodes
|
| -
|
| - 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):
|
| - """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")
|
| -
|
| - # catch empty check-in comments
|
| - if logs[0].firstChild:
|
| - return logs[0].firstChild.data
|
| - return ''
|
| -
|
| - def _getWho(self):
|
| - """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"""
|
| - # convert unicode number to regular one
|
| - try:
|
| - commitDate = int(self.currentCiNode.getAttribute("date"))
|
| - except ValueError:
|
| - raise InvalidResultError
|
| -
|
| - return commitDate
|
| -
|
| - def _getFilename(self):
|
| - """Returns the filename of the current <f> node"""
|
| - try:
|
| - filename = self.currentFileNode.firstChild.data
|
| - except AttributeError:
|
| - raise InvalidResultError("Missing filename")
|
| -
|
| - return filename
|
| -
|
| - def _getRevision(self):
|
| - return self.currentFileNode.getAttribute("rev")
|
| -
|
| -
|
| -class BonsaiPoller(base.ChangeSource):
|
| - """This source will poll a bonsai server for changes and submit
|
| - them to the change master."""
|
| -
|
| - compare_attrs = ["bonsaiURL", "pollInterval", "tree",
|
| - "module", "branch", "cvsroot"]
|
| -
|
| - parent = None # filled in when we're added
|
| - loop = None
|
| - volatile = ['loop']
|
| - working = False
|
| -
|
| - def __init__(self, bonsaiURL, module, branch, tree="default",
|
| - cvsroot="/cvsroot", pollInterval=30):
|
| - """
|
| - @type bonsaiURL: string
|
| - @param bonsaiURL: The base URL of the Bonsai server
|
| - (ie. http://bonsai.mozilla.org)
|
| - @type module: string
|
| - @param module: The module to look for changes in. Commonly
|
| - this is 'all'
|
| - @type branch: string
|
| - @param branch: The branch to look for changes in. This must
|
| - match the
|
| - 'branch' option for the Scheduler.
|
| - @type tree: string
|
| - @param tree: The tree to look for changes in. Commonly this
|
| - is 'all'
|
| - @type cvsroot: string
|
| - @param cvsroot: The cvsroot of the repository. Usually this is
|
| - '/cvsroot'
|
| - @type pollInterval: int
|
| - @param pollInterval: The time (in seconds) between queries for
|
| - changes
|
| - """
|
| -
|
| - self.bonsaiURL = bonsaiURL
|
| - self.module = module
|
| - self.branch = branch
|
| - self.tree = tree
|
| - self.cvsroot = cvsroot
|
| - self.pollInterval = pollInterval
|
| - self.lastChange = time.time()
|
| - self.lastPoll = time.time()
|
| -
|
| - def startService(self):
|
| - self.loop = LoopingCall(self.poll)
|
| - base.ChangeSource.startService(self)
|
| -
|
| - reactor.callLater(0, self.loop.start, self.pollInterval)
|
| -
|
| - def stopService(self):
|
| - self.loop.stop()
|
| - return base.ChangeSource.stopService(self)
|
| -
|
| - def describe(self):
|
| - str = ""
|
| - str += "Getting changes from the Bonsai service running at %s " \
|
| - % self.bonsaiURL
|
| - str += "<br>Using tree: %s, branch: %s, and module: %s" % (self.tree, \
|
| - self.branch, self.module)
|
| - return str
|
| -
|
| - def poll(self):
|
| - if self.working:
|
| - log.msg("Not polling Bonsai because last poll is still working")
|
| - else:
|
| - self.working = True
|
| - d = self._get_changes()
|
| - d.addCallback(self._process_changes)
|
| - d.addCallbacks(self._finished_ok, self._finished_failure)
|
| - return
|
| -
|
| - def _finished_ok(self, res):
|
| - assert self.working
|
| - self.working = False
|
| -
|
| - # check for failure -- this is probably never hit but the twisted docs
|
| - # are not clear enough to be sure. it is being kept "just in case"
|
| - if isinstance(res, failure.Failure):
|
| - log.msg("Bonsai poll failed: %s" % res)
|
| - return res
|
| -
|
| - def _finished_failure(self, res):
|
| - log.msg("Bonsai poll failed: %s" % res)
|
| - assert self.working
|
| - self.working = False
|
| - return None # eat the failure
|
| -
|
| - def _make_url(self):
|
| - args = ["treeid=%s" % self.tree, "module=%s" % self.module,
|
| - "branch=%s" % self.branch, "branchtype=match",
|
| - "sortby=Date", "date=explicit",
|
| - "mindate=%d" % self.lastChange,
|
| - "maxdate=%d" % int(time.time()),
|
| - "cvsroot=%s" % self.cvsroot, "xml=1"]
|
| - # build the bonsai URL
|
| - 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()
|
| - # get the page, in XML format
|
| - return getPage(url, timeout=self.pollInterval)
|
| -
|
| - def _process_changes(self, query):
|
| - 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:
|
| - files = [file.filename + ' (revision '+file.revision+')'
|
| - for file in cinode.files]
|
| - c = changes.Change(who = cinode.who,
|
| - files = files,
|
| - comments = cinode.log,
|
| - when = cinode.date,
|
| - branch = self.branch)
|
| - self.parent.addChange(c)
|
| - self.lastChange = self.lastPoll
|
|
|