Skip to content

Commit

Permalink
Merge branch 'master' of git://github.com/djmitche/buildbot into cons…
Browse files Browse the repository at this point in the history
…ole_clean
  • Loading branch information
nsylvain committed Sep 11, 2009
2 parents 702d705 + e67b8e0 commit baed1a3
Show file tree
Hide file tree
Showing 14 changed files with 189 additions and 90 deletions.
38 changes: 27 additions & 11 deletions buildbot/changes/changes.py
@@ -1,4 +1,3 @@

import sys, os, time
from cPickle import dump

Expand All @@ -9,6 +8,7 @@
from twisted.web import html

from buildbot import interfaces, util
from buildbot.process.properties import Properties

html_tmpl = """
<p>Changed by: <b>%(who)s</b><br />
Expand All @@ -22,6 +22,9 @@
Comments:
%(comments)s
Properties:
%(properties)s
</p>
"""

Expand Down Expand Up @@ -55,7 +58,7 @@ class Change:

def __init__(self, who, files, comments, isdir=0, links=None,
revision=None, when=None, branch=None, category=None,
revlink=''):
revlink='', properties={}):
self.who = who
self.comments = comments
self.isdir = isdir
Expand All @@ -69,6 +72,8 @@ def __init__(self, who, files, comments, isdir=0, links=None,
self.branch = branch
self.category = category
self.revlink = revlink
self.properties = Properties()
self.properties.update(properties, "Change")

# keep a sorted list of the files, for easier display
self.files = files[:]
Expand All @@ -79,7 +84,8 @@ def asText(self):
data += self.getFileContents()
data += "At: %s\n" % self.getTime()
data += "Changed By: %s\n" % self.who
data += "Comments: %s\n\n" % self.comments
data += "Comments: %s" % self.comments
data += "Properties: \n%s\n\n" % self.getProperties()
return data

def asHTML(self):
Expand All @@ -91,26 +97,30 @@ def asHTML(self):
links.append('<a href="%s"><b>%s</b></a>' % (link[0], file))
else:
links.append('<b>%s</b>' % file)
revlink = ""
if self.revision:
if getattr(self, 'revlink', ""):
revision = 'Revision: <a href="%s"><b>%s</b></a>\n' % (
self.revlink, self.revision)
else:
revision = "Revision: <b>%s</b><br />\n" % self.revision
else:
revision = None
revision = ''

branch = ""
if self.branch:
branch = "Branch: <b>%s</b><br />\n" % self.branch

kwargs = { 'who' : html.escape(self.who),
'at' : self.getTime(),
'files' : html.UL(links) + '\n',
'revision': revision,
'branch' : branch,
'comments': html.PRE(self.comments) }
properties = []
for prop in self.properties.asList():
properties.append("%s: %s<br />" % (prop[0], prop[1]))

kwargs = { 'who' : html.escape(self.who),
'at' : self.getTime(),
'files' : html.UL(links) + '\n',
'revision' : revision,
'branch' : branch,
'comments' : html.PRE(self.comments),
'properties': html.UL(properties) + '\n' }
return html_tmpl % kwargs

def get_HTML_box(self, url):
Expand Down Expand Up @@ -163,6 +173,12 @@ def getFileContents(self):
data += " %s\n" % f
return data

def getProperties(self):
data = ""
for prop in self.properties.asList():
data += " %s: %s" % (prop[0], prop[1])
return data

class ChangeMaster(service.MultiService):

"""This is the master-side service which receives file change
Expand Down
1 change: 1 addition & 0 deletions buildbot/changes/pb.py
Expand Up @@ -36,6 +36,7 @@ def perspective_addChange(self, changedict):
revision=changedict.get('revision'),
category=changedict.get('category'),
when=changedict.get('when'),
properties=changedict.get('properties', {})
)
self.changemaster.addChange(change)

Expand Down
5 changes: 3 additions & 2 deletions buildbot/clients/sendchange.py
Expand Up @@ -10,12 +10,13 @@ def __init__(self, master, user=None):
self.port = int(self.port)
self.num_changes = 0

def send(self, branch, revision, comments, files, user=None, category=None, when=None):
def send(self, branch, revision, comments, files, user=None, category=None,
when=None, properties={}):
if user is None:
user = self.user
change = {'who': user, 'files': files, 'comments': comments,
'branch': branch, 'revision': revision, 'category': category,
'when': when}
'when': when, 'properties': properties}
self.num_changes += 1

f = pb.PBClientFactory()
Expand Down
4 changes: 4 additions & 0 deletions buildbot/process/base.py
Expand Up @@ -291,6 +291,10 @@ def setupProperties(self):
for rq in self.requests:
props.updateFromProperties(rq.properties)

# and finally, from the SourceStamp, which has properties via Change
for change in self.source.changes:
props.updateFromProperties(change.properties)

# now set some properties of our own, corresponding to the
# build itself
props.setProperty("buildername", self.builder.name, "Build")
Expand Down
19 changes: 18 additions & 1 deletion buildbot/scripts/runner.py
Expand Up @@ -719,6 +719,10 @@ def statusgui(config):
c.run()

class SendChangeOptions(usage.Options):
def __init__(self):
usage.Options.__init__(self)
self['properties'] = {}

optParameters = [
("master", "m", None,
"Location of the buildmaster's PBListener (host:port)"),
Expand All @@ -728,6 +732,8 @@ class SendChangeOptions(usage.Options):
("revision", "r", None, "Revision specifier (string)"),
("revision_number", "n", None, "Revision specifier (integer)"),
("revision_file", None, None, "Filename containing revision spec"),
("property", "p", None,
"A property for the change, in the format: name:value"),
("comments", "m", None, "log message"),
("logfile", "F", None,
"Read the log messages from this file (- for stdin)"),
Expand All @@ -737,6 +743,9 @@ def getSynopsis(self):
return "Usage: buildbot sendchange [options] filenames.."
def parseArgs(self, *args):
self['files'] = args
def opt_property(self, property):
name,value = property.split(':')
self['properties'][name] = value


def sendchange(config, runReactor=False):
Expand All @@ -750,6 +759,7 @@ def sendchange(config, runReactor=False):
branch = config.get('branch', opts.get('branch'))
category = config.get('category', opts.get('category'))
revision = config.get('revision')
properties = config.get('properties', {})
if config.get('when'):
when = float(config.get('when'))
else:
Expand All @@ -776,7 +786,8 @@ def sendchange(config, runReactor=False):
assert master, "you must provide the master location"

s = Sender(master, user)
d = s.send(branch, revision, comments, files, category=category, when=when)
d = s.send(branch, revision, comments, files, category=category, when=when,
properties=properties)
if runReactor:
d.addCallbacks(s.printSuccess, s.printFailure)
d.addBoth(s.stop)
Expand Down Expand Up @@ -837,6 +848,12 @@ class TryOptions(usage.Options):
"Run the trial build on this Builder. Can be used multiple times."],
["properties", None, None,
"A set of properties made available in the build environment, format:prop=value,propb=valueb..."],

["try-topfile", None, None,
"Name of a file at the top of the tree, used to find the top. Only needed for SVN and CVS."],
["try-topdir", None, None,
"Path to the top of the working copy. Only needed for SVN and CVS."],

]

optFlags = [
Expand Down
2 changes: 1 addition & 1 deletion buildbot/scripts/tryclient.py
Expand Up @@ -415,7 +415,7 @@ def createJob(self):
vc = self.getopt("vc", "try_vc")
if vc in ("cvs", "svn"):
# we need to find the tree-top
topdir = self.getopt("try_topdir", "try_topdir")
topdir = self.getopt("try-topdir", "try_topdir")
if topdir:
treedir = os.path.expanduser(topdir)
else:
Expand Down
99 changes: 48 additions & 51 deletions buildbot/slave/commands.py
Expand Up @@ -2051,6 +2051,7 @@ class Git(SourceBase):

def setup(self, args):
SourceBase.setup(self, args)
self.vcexe = getCommand("git")
self.repourl = args['repourl']
self.branch = args.get('branch')
if not self.branch:
Expand All @@ -2072,6 +2073,17 @@ def sourcedirIsUpdateable(self):
def readSourcedata(self):
return open(self.sourcedatafile, "r").read()

def _dovccmd(self, command, cb=None, **kwargs):
c = ShellCommand(self.builder, [self.vcexe] + command, self._fullSrcdir(),
sendRC=False, timeout=self.timeout,
maxTime=self.maxTime, usePTY=False, **kwargs)
self.command = c
d = c.start()
if cb:
d.addCallback(self._abandonOnFailure)
d.addCallback(cb)
return d

# If the repourl matches the sourcedata file, then
# we can say that the sourcedata matches. We can
# ignore branch changes, since Git can work with
Expand All @@ -2086,84 +2098,69 @@ def sourcedataMatches(self):
return False
return True

def _didSubmodules(self, res):
command = ['git', 'submodule', 'update', '--init']
c = ShellCommand(self.builder, command, self._fullSrcdir(),
sendRC=False, timeout=self.timeout,
maxTime=self.maxTime, usePTY=False)
self.command = c
return c.start()
def _cleanSubmodules(self, res):
return self._dovccmd(['submodule', 'foreach', 'git', 'clean', '-dfx'])

def _updateSubmodules(self, res):
return self._dovccmd(['submodule', 'update'], self._cleanSubmodules)

def _initSubmodules(self, res):
if self.submodules:
return self._dovccmd(['submodule', 'init'], self._updateSubmodules)
else:
return defer.succeed(0)

def _didFetch(self, res):
if self.revision:
head = self.revision
else:
head = 'FETCH_HEAD'

command = ['git', 'reset', '--hard', head]
c = ShellCommand(self.builder, command, self._fullSrcdir(),
sendRC=False, timeout=self.timeout,
maxTime=self.maxTime, usePTY=False)
self.command = c
d = c.start()
if self.submodules:
d.addCallback(self._abandonOnFailure)
d.addCallback(self._didSubmodules)
return d
command = ['reset', '--hard', head]
return self._dovccmd(command, self._initSubmodules)

# Update first runs "git clean", removing local changes, This,
# combined with the later "git reset" equates clobbering the repo,
# but it's much more efficient.
def doVCUpdate(self):
command = ['git', 'clean', '-f', '-d', '-x']
c = ShellCommand(self.builder, command, self._fullSrcdir(),
sendRC=False, timeout=self.timeout,
maxTime=self.maxTime, usePTY=False)
self.command = c
d = c.start()
d.addCallback(self._abandonOnFailure)
d.addCallback(self._didClean)
return d
command = ['clean', '-f', '-d', '-x']
return self._dovccmd(command, self._didClean)

def _didClean(self, dummy):
command = ['git', 'fetch', '-t', self.repourl, self.branch]
def _doFetch(self, dummy):
command = ['fetch', '-t', self.repourl, self.branch]
self.sendStatus({"header": "fetching branch %s from %s\n"
% (self.branch, self.repourl)})
c = ShellCommand(self.builder, command, self._fullSrcdir(),
sendRC=False, timeout=self.timeout,
maxTime=self.maxTime, usePTY=False)
self.command = c
d = c.start()
d.addCallback(self._abandonOnFailure)
d.addCallback(self._didFetch)
return d
return self._dovccmd(command, self._didFetch)

def _didClean(self, dummy):
# After a clean, try to use the given revision if we have one.
if self.revision:
# We know what revision we want. See if we have it.
d = self._dovccmd(['reset', '--hard', self.revision],
self._initSubmodules)
# If we are unable to reset to the specified version, we
# must do a fetch first and retry.
d.addErrback(self._doFetch)
return d
else:
# No known revision, go grab the latest.
return self._doFetch(None)

def _didInit(self, res):
return self.doVCUpdate()

def doVCFull(self):
os.mkdir(self._fullSrcdir())
c = ShellCommand(self.builder, ['git', 'init'], self._fullSrcdir(),
sendRC=False, timeout=self.timeout,
maxTime=self.maxTime, usePTY=False)
self.command = c
d = c.start()
d.addCallback(self._abandonOnFailure)
d.addCallback(self._didInit)
return d
return self._dovccmd(['init'], self._didInit)

def parseGotRevision(self):
command = ['git', 'rev-parse', 'HEAD']
c = ShellCommand(self.builder, command, self._fullSrcdir(),
sendRC=False, keepStdout=True, usePTY=False)
d = c.start()
command = ['rev-parse', 'HEAD']
def _parse(res):
hash = c.stdout.strip()
hash = self.command.stdout.strip()
if len(hash) != 40:
return None
return hash
d.addCallback(_parse)
return d
return self._dovccmd(command, _parse, keepStdout=True)

registerSlaveCommand("git", Git, command_version)

Expand Down
1 change: 0 additions & 1 deletion buildbot/sourcestamp.py
@@ -1,4 +1,3 @@

from zope.interface import implements
from buildbot import util, interfaces

Expand Down
9 changes: 9 additions & 0 deletions buildbot/status/web/base.py
Expand Up @@ -101,6 +101,15 @@ def make_force_build_form(forceURL, useUserPasswd, on_all=False):
"<input type='text' name='branch' />")
+ make_row("Revision to build:",
"<input type='text' name='revision' />")
+ make_row("Property 1, ",
"Name: <input type='text' name='prop1name' /> " + \
"Value: <input type='text' name='prop1value' />")
+ make_row("Property 2, ",
"Name: <input type='text' name='prop2name' /> " + \
"Value: <input type='text' name='prop2value' />")
+ make_row("Property 3, ",
"Name: <input type='text' name='prop3name' /> " + \
"Value: <input type='text' name='prop3value' />")
+ '<input type="submit" value="Force Build" /></form>\n')

def td(text="", parms={}, **props):
Expand Down

0 comments on commit baed1a3

Please sign in to comment.