2 # ex: set syntax=python:
6 from twisted
.python
import log
7 from twisted
.internet
import defer
, reactor
, utils
8 from twisted
.internet
.task
import LoopingCall
10 from buildbot
import util
11 from buildbot
.changes
import base
12 from buildbot
.changes
.changes
import Change
13 from buildbot
.process
.buildstep
import RemoteShellCommand
14 from buildbot
.steps
.source
import Source
18 tarlink_re
= re
.compile('<a href="([a-zA-Z0-9_\.-]+).tar.xz">')
20 def parsehtml(html
, archives
):
23 for link
in tarlink_re
.findall(html
):
24 for archive
in archives
:
25 if link
.startswith(archive
):
26 revision
= link
[len(archive
):]
27 svnpos
= revision
.find('svn')
29 revision
= int(revision
[svnpos
+ 3:])
30 if revision
> max_revision
:
32 max_revision
= revision
33 if revision
== max_revision
:
36 log
.msg("No valid links found")
38 elif len(links
) == len(archives
):
39 log
.msg("Parsing html index page: found all archives for revision: %d" % (max_revision
, ))
40 return (max_revision
, links
)
42 log
.msg("Latest revision (%d) is not complete: found the following links: %r" % (max_revision
, links
, ))
45 class TarPoller(base
.ChangeSource
, util
.ComparableMixin
):
47 compare_attrs
= ["tarball_root", "branch", "archives", "pollinterval",]
53 def __init__(self
, tarball_root
, branch
=None, archives
=None, pollinterval
=60):
54 self
.tarball_root
= tarball_root
56 self
.archives
= archives
57 self
.pollinterval
= pollinterval
58 self
.loop
= LoopingCall(self
.checktar
)
60 def startService(self
):
61 log
.msg("TarPoller(%s) starting" % self
.tarball_root
)
62 base
.ChangeSource
.startService(self
)
63 # Don't start the loop just yet because the reactor isn't running.
64 # Give it a chance to go and install our SIGCHLD handler before
66 reactor
.callLater(0, self
.loop
.start
, self
.pollinterval
)
68 def stopService(self
):
69 log
.msg("TarPoller(%s) shutting down" % self
.tarball_root
)
71 return base
.ChangeSource
.stopService(self
)
74 return "TarPoller watching %s" % self
.tarball_root
78 log
.msg("TarPoller(%s) overrun: timer fired but the previous "
79 "poll had not yet finished.")
80 self
.overrun_counter
+= 1
81 return defer
.succeed(None)
84 log
.msg("TarPoller polling")
85 d
= utils
.getProcessOutput("curl", ['-s', self
.tarball_root
], {})
86 d
.addCallback(parsehtml
, self
.archives
)
87 d
.addCallback(self
.create_changes
)
88 d
.addCallback(self
.submit_changes
)
90 d
.addCallbacks(self
.finished_ok
, self
.finished_failure
)
93 def create_changes(self
, info
):
95 # Got no consistent revision
96 log
.msg('TarPoller: got no consistent revision')
98 (revision
, links
) = info
99 if self
.last_revision
is None:
100 log
.msg('TarPoller: start revision is %r' % (revision
,))
101 self
.last_revision
= revision
103 if self
.last_revision
== revision
:
104 # No change from last revision
105 log
.msg('TarPoller: still at previous revision: %r' % (revision
,))
107 self
.last_revision
= revision
109 log
.msg('TarPoller: new revision found: %r' % (revision
,))
118 def submit_changes(self
, change
):
119 if change
is not None:
120 self
.master
.addChange(change
)
122 def finished_ok(self
, res
):
123 log
.msg("TarPoller finished polling")
124 log
.msg('_finished : %s' % res
)
129 def finished_failure(self
, f
):
130 log
.msg("TarPoller failed")
131 log
.msg('_finished : %s' % f
)
134 return None # eat the failure
139 def __init__(self
, rooturl
, archives
, **kwargs
):
141 Source
.__init
__(self
, **kwargs
)
142 self
.rooturl
= rooturl
143 self
.archives
= archives
146 def computeSourceRevision(self
, changes
):
147 if not changes
: return None
148 changelist
= [c
.revision
for c
in changes
]
149 if len(changelist
) == 0: return None
151 return changelist
[-1]
153 def startVC(self
, branch
, revision
, patch
):
154 d
= utils
.getProcessOutput("curl", ['-s', self
.rooturl
], {})
155 d
.addCallback(self
.doStartVC
, branch
, revision
, patch
)
156 d
.addErrback(self
.failed
)
158 def doStartVC(self
, html
, branch
, revision
, path
):
159 info
= parsehtml(html
, self
.archives
)
162 # Got no consistent revision
163 log
.msg('Tar: got no consistent revision')
164 self
.failed('Couldn\'t get consistent revision')
166 (revision
, links
) = info
168 cmdargs
= ['curl', '-s']
171 cmdargs
.append(self
.rooturl
+ link
+ '.tar.xz')
173 cmd
= RemoteShellCommand('build', command
=(cmdargs
))
174 self
.startCommand(cmd
)