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.web import client
21
22 from buildbot.changes import base, changes
23
25 - def __init__(self, value="InvalidResultError"):
28 return repr(self.value)
29
32
35
38
40 """I hold a list of CiNodes"""
43
45 if len(self.nodes) != len(other.nodes):
46 return False
47 for i in range(len(self.nodes)):
48 if self.nodes[i].log != other.nodes[i].log \
49 or self.nodes[i].who != other.nodes[i].who \
50 or self.nodes[i].date != other.nodes[i].date \
51 or len(self.nodes[i].files) != len(other.nodes[i].files):
52 return -1
53
54 for j in range(len(self.nodes[i].files)):
55 if self.nodes[i].files[j].revision \
56 != other.nodes[i].files[j].revision \
57 or self.nodes[i].files[j].filename \
58 != other.nodes[i].files[j].filename:
59 return -1
60
61 return 0
62
64 """I hold information baout one <ci> node, including a list of files"""
65 - def __init__(self, log="", who="", date=0, files=[]):
66 self.log = log
67 self.who = who
68 self.date = date
69 self.files = files
70
72 """I hold information about one <f> node"""
73 - def __init__(self, revision="", filename=""):
76
78 """I parse the XML result from a bonsai cvsquery."""
79
81 try:
82
83
84
85
86 data = data.decode("latin1")
87 data = data.encode("ascii", "replace")
88 self.dom = minidom.parseString(data)
89 log.msg(data)
90 except:
91 raise InvalidResultError("Malformed XML in result")
92
93 self.ciNodes = self.dom.getElementsByTagName("ci")
94 self.currentCiNode = None
95 self.fileNodes = None
96 self.currentFileNode = None
97 self.bonsaiResult = self._parseData()
98
100 return self.bonsaiResult
101
103 """Returns data from a Bonsai cvsquery in a BonsaiResult object"""
104 nodes = []
105 try:
106 while self._nextCiNode():
107 files = []
108 try:
109 while self._nextFileNode():
110 files.append(FileNode(self._getRevision(),
111 self._getFilename()))
112 except NoMoreFileNodes:
113 pass
114 except InvalidResultError:
115 raise
116 cinode = CiNode(self._getLog(), self._getWho(),
117 self._getDate(), files)
118
119 if not cinode.log and nodes and \
120 not nodes[-1].log and \
121 cinode.who == nodes[-1].who and \
122 cinode.date == nodes[-1].date:
123 nodes[-1].files += cinode.files
124 else:
125 nodes.append(cinode)
126
127 except NoMoreCiNodes:
128 pass
129 except (InvalidResultError, EmptyResult):
130 raise
131
132 return BonsaiResult(nodes)
133
134
136 """Iterates to the next <ci> node and fills self.fileNodes with
137 child <f> nodes"""
138 try:
139 self.currentCiNode = self.ciNodes.pop(0)
140 if len(self.currentCiNode.getElementsByTagName("files")) > 1:
141 raise InvalidResultError("Multiple <files> for one <ci>")
142
143 self.fileNodes = self.currentCiNode.getElementsByTagName("f")
144 except IndexError:
145
146 if not self.currentCiNode:
147 raise EmptyResult
148 else:
149 raise NoMoreCiNodes
150
151 return True
152
154 """Iterates to the next <f> node"""
155 try:
156 self.currentFileNode = self.fileNodes.pop(0)
157 except IndexError:
158 raise NoMoreFileNodes
159
160 return True
161
163 """Returns the log of the current <ci> node"""
164 logs = self.currentCiNode.getElementsByTagName("log")
165 if len(logs) < 1:
166 raise InvalidResultError("No log present")
167 elif len(logs) > 1:
168 raise InvalidResultError("Multiple logs present")
169
170
171 if logs[0].firstChild:
172 return logs[0].firstChild.data
173 return ''
174
176 """Returns the e-mail address of the commiter"""
177
178 return str(self.currentCiNode.getAttribute("who"))
179
181 """Returns the date (unix time) of the commit"""
182
183 try:
184 commitDate = int(self.currentCiNode.getAttribute("date"))
185 except ValueError:
186 raise InvalidResultError
187
188 return commitDate
189
191 """Returns the filename of the current <f> node"""
192 try:
193 filename = self.currentFileNode.firstChild.data
194 except AttributeError:
195 raise InvalidResultError("Missing filename")
196
197 return filename
198
200 return self.currentFileNode.getAttribute("rev")
201
202
204 compare_attrs = ["bonsaiURL", "pollInterval", "tree",
205 "module", "branch", "cvsroot"]
206
207 parent = None
208
209 - def __init__(self, bonsaiURL, module, branch, tree="default",
210 cvsroot="/cvsroot", pollInterval=30, project=''):
211 self.bonsaiURL = bonsaiURL
212 self.module = module
213 self.branch = branch
214 self.tree = tree
215 self.cvsroot = cvsroot
216 self.repository = module != 'all' and module or ''
217 self.pollInterval = pollInterval
218 self.lastChange = time.time()
219 self.lastPoll = time.time()
220
222 str = ""
223 str += "Getting changes from the Bonsai service running at %s " \
224 % self.bonsaiURL
225 str += "<br>Using tree: %s, branch: %s, and module: %s" % (self.tree, \
226 self.branch, self.module)
227 return str
228
230 d = self._get_changes()
231 d.addCallback(self._process_changes)
232 return d
233
235 args = ["treeid=%s" % self.tree, "module=%s" % self.module,
236 "branch=%s" % self.branch, "branchtype=match",
237 "sortby=Date", "date=explicit",
238 "mindate=%d" % self.lastChange,
239 "maxdate=%d" % int(time.time()),
240 "cvsroot=%s" % self.cvsroot, "xml=1"]
241
242 url = self.bonsaiURL
243 url += "/cvsquery.cgi?"
244 url += "&".join(args)
245
246 return url
247
249 url = self._make_url()
250 log.msg("Polling Bonsai tree at %s" % url)
251
252 self.lastPoll = time.time()
253
254 return client.getPage(url, timeout=self.pollInterval)
255
276