1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 import time
17 from xml.dom import minidom
18
19 from twisted.python import log
20 from twisted.internet import defer
21 from twisted.web import client
22
23 from buildbot.changes import base
24 from buildbot.util import epoch2datetime
27 - def __init__(self, value="InvalidResultError"):
30 return repr(self.value)
31
34
37
40
42 """I hold a list of CiNodes"""
45
47 if len(self.nodes) != len(other.nodes):
48 return False
49 for i in range(len(self.nodes)):
50 if self.nodes[i].log != other.nodes[i].log \
51 or self.nodes[i].who != other.nodes[i].who \
52 or self.nodes[i].date != other.nodes[i].date \
53 or len(self.nodes[i].files) != len(other.nodes[i].files):
54 return -1
55
56 for j in range(len(self.nodes[i].files)):
57 if self.nodes[i].files[j].revision \
58 != other.nodes[i].files[j].revision \
59 or self.nodes[i].files[j].filename \
60 != other.nodes[i].files[j].filename:
61 return -1
62
63 return 0
64
66 """I hold information baout one <ci> node, including a list of files"""
67 - def __init__(self, log="", who="", date=0, files=[]):
68 self.log = log
69 self.who = who
70 self.date = date
71 self.files = files
72
74 """I hold information about one <f> node"""
75 - def __init__(self, revision="", filename=""):
78
80 """I parse the XML result from a bonsai cvsquery."""
81
83 try:
84
85
86
87
88 data = data.decode("latin1")
89 data = data.encode("ascii", "replace")
90 self.dom = minidom.parseString(data)
91 log.msg(data)
92 except:
93 raise InvalidResultError("Malformed XML in result")
94
95 self.ciNodes = self.dom.getElementsByTagName("ci")
96 self.currentCiNode = None
97 self.fileNodes = None
98 self.currentFileNode = None
99 self.bonsaiResult = self._parseData()
100
102 return self.bonsaiResult
103
105 """Returns data from a Bonsai cvsquery in a BonsaiResult object"""
106 nodes = []
107 try:
108 while self._nextCiNode():
109 files = []
110 try:
111 while self._nextFileNode():
112 files.append(FileNode(self._getRevision(),
113 self._getFilename()))
114 except NoMoreFileNodes:
115 pass
116 except InvalidResultError:
117 raise
118 cinode = CiNode(self._getLog(), self._getWho(),
119 self._getDate(), files)
120
121 if not cinode.log and nodes and \
122 not nodes[-1].log and \
123 cinode.who == nodes[-1].who and \
124 cinode.date == nodes[-1].date:
125 nodes[-1].files += cinode.files
126 else:
127 nodes.append(cinode)
128
129 except NoMoreCiNodes:
130 pass
131 except (InvalidResultError, EmptyResult):
132 raise
133
134 return BonsaiResult(nodes)
135
136
138 """Iterates to the next <ci> node and fills self.fileNodes with
139 child <f> nodes"""
140 try:
141 self.currentCiNode = self.ciNodes.pop(0)
142 if len(self.currentCiNode.getElementsByTagName("files")) > 1:
143 raise InvalidResultError("Multiple <files> for one <ci>")
144
145 self.fileNodes = self.currentCiNode.getElementsByTagName("f")
146 except IndexError:
147
148 if not self.currentCiNode:
149 raise EmptyResult
150 else:
151 raise NoMoreCiNodes
152
153 return True
154
156 """Iterates to the next <f> node"""
157 try:
158 self.currentFileNode = self.fileNodes.pop(0)
159 except IndexError:
160 raise NoMoreFileNodes
161
162 return True
163
165 """Returns the log of the current <ci> node"""
166 logs = self.currentCiNode.getElementsByTagName("log")
167 if len(logs) < 1:
168 raise InvalidResultError("No log present")
169 elif len(logs) > 1:
170 raise InvalidResultError("Multiple logs present")
171
172
173 if logs[0].firstChild:
174 return logs[0].firstChild.data
175 return ''
176
178 """Returns the e-mail address of the commiter"""
179
180 return str(self.currentCiNode.getAttribute("who"))
181
183 """Returns the date (unix time) of the commit"""
184
185 try:
186 commitDate = int(self.currentCiNode.getAttribute("date"))
187 except ValueError:
188 raise InvalidResultError
189
190 return commitDate
191
193 """Returns the filename of the current <f> node"""
194 try:
195 filename = self.currentFileNode.firstChild.data
196 except AttributeError:
197 raise InvalidResultError("Missing filename")
198
199 return filename
200
202 return self.currentFileNode.getAttribute("rev")
203
206 compare_attrs = ["bonsaiURL", "pollInterval", "tree",
207 "module", "branch", "cvsroot"]
208
209 - def __init__(self, bonsaiURL, module, branch, tree="default",
210 cvsroot="/cvsroot", pollInterval=30, project=''):
222
224 str = ""
225 str += "Getting changes from the Bonsai service running at %s " \
226 % self.bonsaiURL
227 str += "<br>Using tree: %s, branch: %s, and module: %s" % (self.tree, \
228 self.branch, self.module)
229 return str
230
232 d = self._get_changes()
233 d.addCallback(self._process_changes)
234 return d
235
237 args = ["treeid=%s" % self.tree, "module=%s" % self.module,
238 "branch=%s" % self.branch, "branchtype=match",
239 "sortby=Date", "date=explicit",
240 "mindate=%d" % self.lastChange,
241 "maxdate=%d" % int(time.time()),
242 "cvsroot=%s" % self.cvsroot, "xml=1"]
243
244 url = self.bonsaiURL
245 url += "/cvsquery.cgi?"
246 url += "&".join(args)
247
248 return url
249
251 url = self._make_url()
252 log.msg("Polling Bonsai tree at %s" % url)
253
254 self.lastPoll = time.time()
255
256 return client.getPage(url, timeout=self.pollInterval)
257
258 @defer.inlineCallbacks
278