1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 import time
17 import tempfile
18 import os
19
20 from twisted.python import log
21 from twisted.internet import defer, utils
22
23 from buildbot.changes import base, changes
24
26 """This source will poll a remote git repo for changes and submit
27 them to the change master."""
28
29 compare_attrs = ["repourl", "branch", "workdir",
30 "pollInterval", "gitbin", "usetimestamps",
31 "category", "project"]
32
33 - def __init__(self, repourl, branch='master',
34 workdir=None, pollInterval=10*60,
35 gitbin='git', usetimestamps=True,
36 category=None, project=None,
37 pollinterval=-2):
58
69
71 status = ""
72 if not self.parent:
73 status = "[STOPPED - check log]"
74 str = 'GitPoller watching the remote git repository %s, branch: %s %s' \
75 % (self.repourl, self.branch, status)
76 return str
77
79 d = self._get_changes()
80 d.addCallback(self._process_changes)
81 d.addErrback(self._process_changes_failure)
82 d.addCallback(self._catch_up)
83 d.addErrback(self._catch_up_failure)
84 return d
85
91
98
100
101 args = ['log', rev, '--no-walk', r'--format=%ct']
102 d = utils.getProcessOutput(self.gitbin, args, path=self.workdir, env={}, errortoo=False )
103 d.addCallback(self._get_commit_timestamp_from_output)
104 return d
105
107 stripped_output = git_output.strip()
108 if self.usetimestamps:
109 try:
110 stamp = float(stripped_output)
111 except Exception, e:
112 log.msg('gitpoller: caught exception converting output \'%s\' to timestamp' % stripped_output)
113 raise e
114 self.commitInfo['timestamp'] = stamp
115 else:
116 self.commitInfo['timestamp'] = None
117 return self.commitInfo['timestamp']
118
120 args = ['log', rev, '--name-only', '--no-walk', r'--format=%n']
121 d = utils.getProcessOutput(self.gitbin, args, path=self.workdir, env={}, errortoo=False )
122 d.addCallback(self._get_commit_files_from_output)
123 return d
124
126 fileList = git_output.split()
127 self.commitInfo['files'] = fileList
128 return self.commitInfo['files']
129
131 args = ['log', rev, '--no-walk', r'--format=%aE']
132 d = utils.getProcessOutput(self.gitbin, args, path=self.workdir, env={}, errortoo=False )
133 d.addCallback(self._get_commit_name_from_output)
134 return d
135
137 stripped_output = git_output.strip()
138 if len(stripped_output) == 0:
139 raise EnvironmentError('could not get commit name for rev')
140 self.commitInfo['name'] = stripped_output
141 return self.commitInfo['name']
142
144 log.msg('gitpoller: polling git repo at %s' % self.repourl)
145
146 self.lastPoll = time.time()
147
148
149 args = ['fetch', self.repourl, self.branch]
150
151
152
153
154 d = utils.getProcessOutput(self.gitbin, args, path=self.workdir, env={}, errortoo=True )
155
156 return d
157
159
160 revListArgs = ['log', 'HEAD..FETCH_HEAD', r'--format=%H']
161 d = utils.getProcessOutput(self.gitbin, revListArgs, path=self.workdir, env={}, errortoo=False )
162 d.addCallback(self._process_changes_in_output)
163 return d
164
166 self.changeCount = 0
167
168
169 revList = git_output.split()
170 if revList:
171 revList.reverse()
172 self.changeCount = len(revList)
173
174 log.msg('gitpoller: processing %d changes: %s in "%s"' % (self.changeCount, revList, self.workdir) )
175
176 for rev in revList:
177 self.commitInfo = {}
178
179 deferreds = [
180 self._get_commit_timestamp(rev),
181 self._get_commit_name(rev),
182 self._get_commit_files(rev),
183 self._get_commit_comments(rev),
184 ]
185 dl = defer.DeferredList(deferreds)
186 dl.addCallback(self._add_change,rev)
187
188
190 log.msg('gitpoller: _add_change results: "%s", rev: "%s" in "%s"' % (results, rev, self.workdir))
191
192 c = changes.Change(who=self.commitInfo['name'],
193 revision=rev,
194 files=self.commitInfo['files'],
195 comments=self.commitInfo['comments'],
196 when=self.commitInfo['timestamp'],
197 branch=self.branch,
198 category=self.category,
199 project=self.project,
200 repository=self.repourl)
201 log.msg('gitpoller: change "%s" in "%s"' % (c, self.workdir))
202 self.parent.addChange(c)
203 self.lastChange = self.lastPoll
204
205
207 log.msg('gitpoller: repo poll failed')
208 log.err(f)
209
210 return None
211
213 if self.changeCount == 0:
214 log.msg('gitpoller: no changes, no catch_up')
215 return
216 log.msg('gitpoller: catching up to FETCH_HEAD')
217 args = ['reset', '--hard', 'FETCH_HEAD']
218 d = utils.getProcessOutputAndValue(self.gitbin, args, path=self.workdir, env={})
219 def convert_nonzero_to_failure(res):
220 (stdout, stderr, code) = res
221 if code != 0:
222 raise EnvironmentError('catch up failed with exit code: %d' % code)
223 d.addCallback(convert_nonzero_to_failure)
224 return d
225
227 log.err(f)
228 log.msg('gitpoller: please resolve issues in local repo: %s' % self.workdir)
229
230
231