Permalink
Browse files

Merge branch 'magic-__new__'

Conflicts:
	master/buildbot/steps/master.py
	master/buildbot/steps/shell.py
	master/buildbot/steps/source/base.py
	master/buildbot/steps/source/git.py
	master/buildbot/steps/source/svn.py
	master/docs/developer/cls-buildsteps.rst
  • Loading branch information...
2 parents 56adff3 + 51ae9da commit 9eb7be702d9c64be4f8dad30fee24a30f2bb0237 @tomprince tomprince committed May 13, 2012
View
9 master/buildbot/config.py
@@ -547,15 +547,6 @@ def check_lock(l):
for l in b.locks:
check_lock(l)
- # factories don't necessarily need to implement a .steps attribute
- # but in practice most do, so we'll check that if it exists
- if not hasattr(b.factory, 'steps'):
- continue
- for s in b.factory.steps:
- for l in s[1].get('locks', []):
- check_lock(l)
-
-
def check_builders(self, errors):
# look both for duplicate builder names, and for builders pointing
# to unknown slaves
View
5 master/buildbot/interfaces.py
@@ -1204,3 +1204,8 @@ def render(value):
class IScheduler(Interface):
pass
+
+class IBuildStepFactory(Interface):
+ def buildStep():
+ """
+ """
View
11 master/buildbot/process/build.py
@@ -297,15 +297,8 @@ def setupBuild(self, expectations):
stepnames = {}
sps = []
- for factory, args in self.stepFactories:
- args = args.copy()
- try:
- step = factory(**args)
- except:
- log.msg("error while creating step, factory=%s, args=%s"
- % (factory, args))
- raise
-
+ for factory in self.stepFactories:
+ step = factory.buildStep()
step.setBuild(self)
step.setBuildSlave(self.slavebuilder.slave)
if callable (self.workdir):
View
43 master/buildbot/process/buildstep.py
@@ -383,7 +383,29 @@ def _start(self):
def __repr__(self):
return "<RemoteShellCommand '%s'>" % repr(self.command)
-class BuildStep(properties.PropertiesMixin):
+class _BuildStepFactory(util.ComparableMixin):
+ """
+ This is a wrapper to record the arguments passed to as BuildStep subclass.
+ We use an instance of this class, rather than a closure mostly to make it
+ easier to test that the right factories are getting created.
+ """
+ compare_attrs = ['factory', 'args', 'kwargs' ]
+ implements(interfaces.IBuildStepFactory)
+
+ def __init__(self, factory, *args, **kwargs):
+ self.factory = factory
+ self.args = args
+ self.kwargs = kwargs
+
+ def buildStep(self):
+ try:
+ return self.factory(*self.args, **self.kwargs)
+ except:
+ log.msg("error while creating step, factory=%s, args=%s, kwargs=%s"
+ % (self.factory, self.args, self.kwargs))
+ raise
+
+class BuildStep(object, properties.PropertiesMixin):
haltOnFailure = False
flunkOnWarnings = False
@@ -426,7 +448,6 @@ class BuildStep(properties.PropertiesMixin):
progress = None
def __init__(self, **kwargs):
- self.factory = (self.__class__, dict(kwargs))
for p in self.__class__.parms:
if kwargs.has_key(p):
setattr(self, p, kwargs[p])
@@ -440,6 +461,11 @@ def __init__(self, **kwargs):
self._acquiringLock = None
self.stopped = False
+ def __new__(klass, *args, **kwargs):
+ self = object.__new__(klass)
+ self._factory = _BuildStepFactory(klass, *args, **kwargs)
+ return self
+
def describe(self, done=False):
return [self.name]
@@ -453,10 +479,11 @@ def setDefaultWorkdir(self, workdir):
pass
def addFactoryArguments(self, **kwargs):
- self.factory[1].update(kwargs)
+ # this is here for backwards compatability
+ pass
- def getStepFactory(self):
- return self.factory
+ def _getStepFactory(self):
+ return self._factory
def setStepStatus(self, step_status):
self.step_status = step_status
@@ -732,6 +759,9 @@ def _maybeEvaluate(value, *args, **kwargs):
return value
components.registerAdapter(
+ BuildStep._getStepFactory,
+ BuildStep, interfaces.IBuildStepFactory)
+components.registerAdapter(
lambda step : interfaces.IProperties(step.build),
BuildStep, interfaces.IProperties)
@@ -759,9 +789,6 @@ class LoggingBuildStep(BuildStep):
def __init__(self, logfiles={}, lazylogfiles=False, log_eval_func=None,
*args, **kwargs):
BuildStep.__init__(self, *args, **kwargs)
- self.addFactoryArguments(logfiles=logfiles,
- lazylogfiles=lazylogfiles,
- log_eval_func=log_eval_func)
if logfiles and not isinstance(logfiles, dict):
config.error(
View
53 master/buildbot/process/factory.py
@@ -13,23 +13,11 @@
#
# Copyright Buildbot Team Members
-import warnings
-
-from twisted.python import deprecate, versions
-
-from buildbot import util
+from buildbot import interfaces, util
from buildbot.process.build import Build
-from buildbot.process.buildstep import BuildStep
from buildbot.steps.source import CVS, SVN
from buildbot.steps.shell import Configure, Compile, Test, PerlModuleTest
-# deprecated, use BuildFactory.addStep
-@deprecate.deprecated(versions.Version("buildbot", 0, 8, 6))
-def s(steptype, **kwargs):
- # convenience function for master.cfg files, to create step
- # specification tuples
- return (steptype, kwargs)
-
class ArgumentsInTheWrongPlace(Exception):
"""When calling BuildFactory.addStep(stepinstance), addStep() only takes
one argument. You passed extra arguments to addStep(), which you probably
@@ -54,18 +42,9 @@ class BuildFactory(util.ComparableMixin):
compare_attrs = ['buildClass', 'steps', 'useProgress', 'workdir']
def __init__(self, steps=None):
- if steps is None:
- steps = []
- self.steps = [self._makeStepFactory(s) for s in steps]
-
- def _makeStepFactory(self, step_or_factory):
- if isinstance(step_or_factory, BuildStep):
- return step_or_factory.getStepFactory()
- warnings.warn(
- "Passing a BuildStep subclass to factory.addStep is deprecated. " +
- "Please pass a BuildStep instance instead. Support will be dropped in v0.8.7.",
- DeprecationWarning, stacklevel=3)
- return step_or_factory
+ self.steps = []
+ if steps:
+ self.addSteps(steps)
def newBuild(self, requests):
"""Create a new Build instance.
@@ -79,22 +58,8 @@ def newBuild(self, requests):
b.setStepFactories(self.steps)
return b
- def addStep(self, step_or_factory, **kwargs):
- if isinstance(step_or_factory, BuildStep):
- if kwargs:
- raise ArgumentsInTheWrongPlace()
- s = step_or_factory.getStepFactory()
- elif type(step_or_factory) == type(BuildStep) and \
- issubclass(step_or_factory, BuildStep):
- s = (step_or_factory, dict(kwargs))
- warnings.warn(
- "Passing a BuildStep subclass to factory.addStep is deprecated. " +
- "Please pass a BuildStep instance instead. Support will be dropped in v0.8.7.",
- DeprecationWarning, stacklevel=2)
-
- else:
- raise ValueError('%r is not a BuildStep nor BuildStep subclass' % step_or_factory)
- self.steps.append(s)
+ def addStep(self, step):
+ self.steps.append(interfaces.IBuildStepFactory(step))
def addSteps(self, steps):
for s in steps:
@@ -199,7 +164,7 @@ def __init__(self, cvsroot, cvsmodule,
mode = "clobber"
if cvsCopy:
mode = "copy"
- source = s(CVS, cvsroot=cvsroot, cvsmodule=cvsmodule, mode=mode)
+ source = CVS(cvsroot=cvsroot, cvsmodule=cvsmodule, mode=mode)
GNUAutoconf.__init__(self, source,
configure=configure, configureEnv=configureEnv,
compile=compile,
@@ -213,7 +178,7 @@ def __init__(self, cvsroot, cvsmodule,
compile="make all",
test="make check", cvsCopy=False):
mode = "update"
- source = s(CVS, cvsroot=cvsroot, cvsmodule=cvsmodule, mode=mode)
+ source = CVS(cvsroot=cvsroot, cvsmodule=cvsmodule, mode=mode)
GNUAutoconf.__init__(self, source,
configure=configure, configureEnv=configureEnv,
compile=compile,
@@ -225,7 +190,7 @@ def __init__(self, svnurl,
configure=None, configureEnv={},
compile="make all",
test="make check"):
- source = s(SVN, svnurl=svnurl, mode="update")
+ source = SVN(svnurl=svnurl, mode="update")
GNUAutoconf.__init__(self, source,
configure=configure, configureEnv=configureEnv,
compile=compile,
View
9 master/buildbot/process/mtrlogobserver.py
@@ -296,15 +296,6 @@ def __init__(self, dbpool=None, test_type=None, test_info="",
self.mtr_subdir = mtr_subdir
self.progressMetrics += ('tests',)
- self.addFactoryArguments(dbpool=self.dbpool,
- test_type=self.test_type,
- test_info=self.test_info,
- autoCreateTables=self.autoCreateTables,
- textLimit=self.textLimit,
- testNameLimit=self.testNameLimit,
- parallel=self.parallel,
- mtr_subdir=self.mtr_subdir)
-
def start(self):
# Add mysql server logfiles.
for mtr in range(0, self.parallel+1):
View
5 master/buildbot/steps/master.py
@@ -39,11 +39,6 @@ def __init__(self, command,
env=None, path=None, usePTY=0,
**kwargs):
BuildStep.__init__(self, **kwargs)
- self.addFactoryArguments(description=description,
- descriptionDone=descriptionDone,
- descriptionSuffix=descriptionSuffix,
- env=env, path=path, usePTY=usePTY,
- command=command)
self.command=command
if description:
View
1 master/buildbot/steps/maxq.py
@@ -26,7 +26,6 @@ def __init__(self, testdir=None, **kwargs):
config.error("please pass testdir")
kwargs['command'] = 'run_maxq.py %s' % (testdir,)
ShellCommand.__init__(self, **kwargs)
- self.addFactoryArguments(testdir=testdir)
def commandComplete(self, cmd):
output = cmd.logs['stdio'].getText()
View
10 master/buildbot/steps/package/rpm/rpmbuild.py
@@ -41,16 +41,6 @@ def __init__(self,
vcsRevision=False,
**kwargs):
ShellCommand.__init__(self, **kwargs)
- self.addFactoryArguments(topdir=topdir,
- builddir=builddir,
- rpmdir=rpmdir,
- sourcedir=sourcedir,
- specdir=specdir,
- srcrpmdir=srcrpmdir,
- specfile=specfile,
- dist=dist,
- autoRelease=autoRelease,
- vcsRevision=vcsRevision)
self.rpmbuild = (
'rpmbuild --define "_topdir %s" --define "_builddir %s"'
' --define "_rpmdir %s" --define "_sourcedir %s"'
View
11 master/buildbot/steps/python.py
@@ -260,17 +260,6 @@ def __init__(self, sphinx_sourcedir='.', sphinx_builddir=None,
command.extend([sphinx_sourcedir, sphinx_builddir])
self.setCommand(command)
- self.addFactoryArguments(
- sphinx = sphinx,
- sphinx_sourcedir = sphinx_sourcedir,
- sphinx_builddir = sphinx_builddir,
- sphinx_builder = sphinx_builder,
- tags = tags,
- defines = defines,
- mode = mode,
- )
-
-
def createSummary(self, log):
msgs = ['WARNING', 'ERROR', 'SEVERE']
View
12 master/buildbot/steps/python_twisted.py
@@ -47,7 +47,6 @@ class HLint(ShellCommand):
def __init__(self, python=None, **kwargs):
ShellCommand.__init__(self, **kwargs)
- self.addFactoryArguments(python=python)
self.python = python
def start(self):
@@ -287,17 +286,6 @@ def __init__(self, reactor=UNSPECIFIED, python=None, trial=None,
timeout.
"""
ShellCommand.__init__(self, **kwargs)
- self.addFactoryArguments(reactor=reactor,
- python=python,
- trial=trial,
- testpath=testpath,
- tests=tests,
- testChanges=testChanges,
- recurse=recurse,
- randomly=randomly,
- trialMode=trialMode,
- trialArgs=trialArgs,
- )
if python:
self.python = python
View
17 master/buildbot/steps/shell.py
@@ -115,18 +115,11 @@ def __init__(self, workdir=None,
buildstep_kwargs[k] = kwargs[k]
del kwargs[k]
buildstep.LoggingBuildStep.__init__(self, **buildstep_kwargs)
- self.addFactoryArguments(workdir=workdir,
- description=description,
- descriptionDone=descriptionDone,
- descriptionSuffix=descriptionSuffix,
- command=command)
# everything left over goes to the RemoteShellCommand
kwargs['workdir'] = workdir # including a copy of 'workdir'
kwargs['usePTY'] = usePTY
self.remote_kwargs = kwargs
- # we need to stash the RemoteShellCommand's args too
- self.addFactoryArguments(**kwargs)
def setBuild(self, build):
buildstep.LoggingBuildStep.setBuild(self, build)
@@ -321,10 +314,6 @@ def __init__(self, property=None, extract_fn=None, strip=True, **kwargs):
ShellCommand.__init__(self, **kwargs)
- self.addFactoryArguments(property=self.property)
- self.addFactoryArguments(extract_fn=self.extract_fn)
- self.addFactoryArguments(strip=self.strip)
-
self.property_changes = {}
def commandComplete(self, cmd):
@@ -423,12 +412,6 @@ def __init__(self,
# And upcall to let the base class do its work
ShellCommand.__init__(self, **kwargs)
- self.addFactoryArguments(warningPattern=warningPattern,
- directoryEnterPattern=directoryEnterPattern,
- directoryLeavePattern=directoryLeavePattern,
- warningExtractor=warningExtractor,
- maxWarnCount=maxWarnCount,
- suppressionFile=suppressionFile)
self.suppressions = []
self.directoryStack = []
View
5 master/buildbot/steps/slave.py
@@ -30,8 +30,6 @@ class SetPropertiesFromEnv(buildstep.BuildStep):
def __init__(self, variables, source="SlaveEnvironment", **kwargs):
buildstep.BuildStep.__init__(self, **kwargs)
- self.addFactoryArguments(variables = variables,
- source = source)
self.variables = variables
self.source = source
@@ -74,7 +72,6 @@ class FileExists(buildstep.BuildStep):
def __init__(self, file, **kwargs):
buildstep.BuildStep.__init__(self, **kwargs)
- self.addFactoryArguments(file = file)
self.file = file
def start(self):
@@ -115,7 +112,6 @@ class RemoveDirectory(buildstep.BuildStep):
def __init__(self, dir, **kwargs):
buildstep.BuildStep.__init__(self, **kwargs)
- self.addFactoryArguments(dir = dir)
self.dir = dir
def start(self):
@@ -150,7 +146,6 @@ class MakeDirectory(buildstep.BuildStep):
def __init__(self, dir, **kwargs):
buildstep.BuildStep.__init__(self, **kwargs)
- self.addFactoryArguments(dir = dir)
self.dir = dir
def start(self):
View
12 master/buildbot/steps/source/base.py
@@ -142,18 +142,6 @@ def __init__(self, workdir=None, mode='update', alwaysUseLatest=False,
"""
LoggingBuildStep.__init__(self, **kwargs)
- self.addFactoryArguments(workdir=workdir,
- mode=mode,
- alwaysUseLatest=alwaysUseLatest,
- timeout=timeout,
- retry=retry,
- logEnviron=logEnviron,
- env=env,
- description=description,
- descriptionDone=descriptionDone,
- descriptionSuffix=descriptionSuffix,
- codebase=codebase
- )
assert mode in ("update", "copy", "clobber", "export")
if retry:
View
6 master/buildbot/steps/source/bzr.py
@@ -34,12 +34,6 @@ def __init__(self, repourl=None, baseURL=None, mode='incremental',
self.mode = mode
self.method = method
Source.__init__(self, **kwargs)
- self.addFactoryArguments(repourl=repourl,
- mode=mode,
- method=method,
- baseURL=baseURL,
- defaultBranch=defaultBranch,
- )
if repourl and baseURL:
raise ValueError("you must provide exactly one of repourl and"
" baseURL")
View
8 master/buildbot/steps/source/cvs.py
@@ -43,14 +43,6 @@ def __init__(self, cvsroot=None, cvsmodule='', mode='incremental',
self.method = method
self.srcdir = 'source'
Source.__init__(self, **kwargs)
- self.addFactoryArguments(cvsroot=cvsroot,
- cvsmodule=cvsmodule,
- mode=mode,
- method=method,
- global_options=global_options,
- extra_options=extra_options,
- login=login,
- )
def startVC(self, branch, revision, patch):
self.revision = revision
View
13 master/buildbot/steps/source/git.py
@@ -110,19 +110,6 @@ def __init__(self, repourl=None, branch='HEAD', mode='incremental',
self.mode = mode
self.getDescription = getDescription
Source.__init__(self, **kwargs)
- self.addFactoryArguments(branch=branch,
- mode=mode,
- method=method,
- progress=progress,
- repourl=repourl,
- submodules=submodules,
- shallow=shallow,
- retryFetch=retryFetch,
- clobberOnFailure=
- clobberOnFailure,
- getDescription=
- getDescription
- )
assert self.mode in ['incremental', 'full']
assert self.repourl is not None
View
8 master/buildbot/steps/source/mercurial.py
@@ -71,14 +71,6 @@ def __init__(self, repourl=None, mode='incremental',
self.clobberOnBranchChange = clobberOnBranchChange
self.mode = mode
Source.__init__(self, **kwargs)
- self.addFactoryArguments(repourl=repourl,
- mode=mode,
- method=method,
- defaultBranch=defaultBranch,
- branchType=branchType,
- clobberOnBranchChange=
- clobberOnBranchChange,
- )
errors = []
if self.mode not in self.possible_modes:
View
69 master/buildbot/steps/source/oldsource.py
@@ -62,7 +62,6 @@ def getRenderingFor(self, props):
-
class CVS(Source):
"""I do CVS checkout/update operations.
@@ -164,16 +163,6 @@ def __init__(self, cvsroot=None, cvsmodule="",
self.cvsroot = _ComputeRepositoryURL(cvsroot)
Source.__init__(self, **kwargs)
- self.addFactoryArguments(cvsroot=cvsroot,
- cvsmodule=cvsmodule,
- global_options=global_options,
- checkout_options=checkout_options,
- export_options=export_options,
- extra_options=extra_options,
- branch=branch,
- checkoutDelay=checkoutDelay,
- login=login,
- )
self.args.update({'cvsmodule': cvsmodule,
'global_options': global_options,
@@ -310,18 +299,6 @@ def __init__(self, svnurl=None, baseURL=None, defaultBranch=None,
self.depth = depth
Source.__init__(self, **kwargs)
- self.addFactoryArguments(svnurl=svnurl,
- baseURL=baseURL,
- defaultBranch=defaultBranch,
- directory=directory,
- username=username,
- password=password,
- extra_args=extra_args,
- keep_on_purge=keep_on_purge,
- ignore_ignores=ignore_ignores,
- always_purge=always_purge,
- depth=depth,
- )
if svnurl and baseURL:
raise ValueError("you must use either svnurl OR baseURL")
@@ -466,10 +443,6 @@ def __init__(self, repourl=None, baseURL=None, defaultBranch=None,
self.baseURL = _ComputeRepositoryURL(baseURL)
self.branch = defaultBranch
Source.__init__(self, **kwargs)
- self.addFactoryArguments(repourl=repourl,
- baseURL=baseURL,
- defaultBranch=defaultBranch,
- )
assert self.args['mode'] != "export", \
"Darcs does not have an 'export' mode"
if repourl and baseURL:
@@ -564,14 +537,6 @@ def __init__(self, repourl=None,
Source.__init__(self, **kwargs)
self.repourl = _ComputeRepositoryURL(repourl)
self.branch = branch
- self.addFactoryArguments(repourl=repourl,
- branch=branch,
- submodules=submodules,
- ignore_ignores=ignore_ignores,
- reference=reference,
- shallow=shallow,
- progress=progress,
- )
self.args.update({'submodules': submodules,
'ignore_ignores': ignore_ignores,
'reference': reference,
@@ -640,11 +605,6 @@ def __init__(self,
"""
Source.__init__(self, **kwargs)
self.manifest_url = _ComputeRepositoryURL(manifest_url)
- self.addFactoryArguments(manifest_url=manifest_url,
- manifest_branch=manifest_branch,
- manifest_file=manifest_file,
- tarball=tarball,
- )
self.args.update({'manifest_branch': manifest_branch,
'manifest_file': manifest_file,
'tarball': tarball,
@@ -788,11 +748,6 @@ def __init__(self, repourl=None, baseURL=None, defaultBranch=None,
self.baseURL = _ComputeRepositoryURL(baseURL)
self.branch = defaultBranch
Source.__init__(self, **kwargs)
- self.addFactoryArguments(repourl=repourl,
- baseURL=baseURL,
- defaultBranch=defaultBranch,
- forceSharedRepo=forceSharedRepo
- )
self.args.update({'forceSharedRepo': forceSharedRepo})
if repourl and baseURL:
raise ValueError("you must provide exactly one of repourl and"
@@ -878,12 +833,6 @@ def __init__(self, repourl=None, baseURL=None, defaultBranch=None,
self.branchType = branchType
self.clobberOnBranchChange = clobberOnBranchChange
Source.__init__(self, **kwargs)
- self.addFactoryArguments(repourl=repourl,
- baseURL=baseURL,
- defaultBranch=defaultBranch,
- branchType=branchType,
- clobberOnBranchChange=clobberOnBranchChange,
- )
if repourl and baseURL:
raise ValueError("you must provide exactly one of repourl and"
" baseURL")
@@ -975,15 +924,6 @@ def __init__(self, p4base=None, defaultBranch=None, p4port=None, p4user=None,
self.p4base = _ComputeRepositoryURL(p4base)
self.branch = defaultBranch
Source.__init__(self, **kwargs)
- self.addFactoryArguments(p4base=p4base,
- defaultBranch=defaultBranch,
- p4port=p4port,
- p4user=p4user,
- p4passwd=p4passwd,
- p4extra_views=p4extra_views,
- p4line_end=p4line_end,
- p4client=p4client,
- )
self.args['p4port'] = p4port
self.args['p4user'] = p4user
self.args['p4passwd'] = p4passwd
@@ -1042,11 +982,6 @@ def __init__(self, p4port, p4user, p4passwd, p4client, **kwargs):
assert kwargs['mode'] == "copy", "P4Sync can only be used in mode=copy"
self.branch = None
Source.__init__(self, **kwargs)
- self.addFactoryArguments(p4port=p4port,
- p4user=p4user,
- p4passwd=p4passwd,
- p4client=p4client,
- )
self.args['p4port'] = p4port
self.args['p4user'] = p4user
self.args['p4passwd'] = p4passwd
@@ -1093,10 +1028,6 @@ def __init__(self, repourl=None, branch=None, progress=False, **kwargs):
raise ValueError("you must provide a repository uri in 'repourl'")
if (not branch):
raise ValueError("you must provide a default branch in 'branch'")
- self.addFactoryArguments(repourl=repourl,
- branch=branch,
- progress=progress,
- )
self.args.update({'branch': branch,
'progress': progress,
})
View
9 master/buildbot/steps/source/svn.py
@@ -48,15 +48,6 @@ def __init__(self, repourl=None, mode='incremental',
self.method=method
self.mode = mode
Source.__init__(self, **kwargs)
- self.addFactoryArguments(repourl=repourl,
- mode=mode,
- method=method,
- password=password,
- username=username,
- extra_args=extra_args,
- keep_on_purge=keep_on_purge,
- depth=depth,
- )
errors = []
if self.mode not in self.possible_modes:
errors.append("mode %s is not one of %s" % (self.mode, self.possible_modes))
View
1 master/buildbot/steps/subunit.py
@@ -24,7 +24,6 @@ class SubunitShellCommand(ShellCommand):
def __init__(self, failureOnNoTests=False, *args, **kwargs):
ShellCommand.__init__(self, *args, **kwargs)
self.failureOnNoTests = failureOnNoTests
- self.addFactoryArguments(failureOnNoTests=failureOnNoTests)
# importing here gets around an import loop
from buildbot.process import subunitlogobserver
View
32 master/buildbot/steps/transfer.py
@@ -229,15 +229,6 @@ def __init__(self, slavesrc, masterdest,
keepstamp=False, url=None,
**buildstep_kwargs):
BuildStep.__init__(self, **buildstep_kwargs)
- self.addFactoryArguments(slavesrc=slavesrc,
- masterdest=masterdest,
- workdir=workdir,
- maxsize=maxsize,
- blocksize=blocksize,
- mode=mode,
- keepstamp=keepstamp,
- url=url,
- )
self.slavesrc = slavesrc
self.masterdest = masterdest
@@ -309,14 +300,6 @@ def __init__(self, slavesrc, masterdest,
workdir=None, maxsize=None, blocksize=16*1024,
compress=None, url=None, **buildstep_kwargs):
BuildStep.__init__(self, **buildstep_kwargs)
- self.addFactoryArguments(slavesrc=slavesrc,
- masterdest=masterdest,
- workdir=workdir,
- maxsize=maxsize,
- blocksize=blocksize,
- compress=compress,
- url=url,
- )
self.slavesrc = slavesrc
self.masterdest = masterdest
@@ -428,13 +411,6 @@ def __init__(self, mastersrc, slavedest,
workdir=None, maxsize=None, blocksize=16*1024, mode=None,
**buildstep_kwargs):
BuildStep.__init__(self, **buildstep_kwargs)
- self.addFactoryArguments(mastersrc=mastersrc,
- slavedest=slavedest,
- workdir=workdir,
- maxsize=maxsize,
- blocksize=blocksize,
- mode=mode,
- )
self.mastersrc = mastersrc
self.slavedest = slavedest
@@ -499,13 +475,6 @@ def __init__(self, s, slavedest,
workdir=None, maxsize=None, blocksize=16*1024, mode=None,
**buildstep_kwargs):
BuildStep.__init__(self, **buildstep_kwargs)
- self.addFactoryArguments(s=s,
- slavedest=slavedest,
- workdir=workdir,
- maxsize=maxsize,
- blocksize=blocksize,
- mode=mode,
- )
self.s = s
self.slavedest = slavedest
@@ -558,7 +527,6 @@ def __init__(self, o, slavedest, **buildstep_kwargs):
del buildstep_kwargs['s']
s = json.dumps(o)
StringDownload.__init__(self, s=s, slavedest=slavedest, **buildstep_kwargs)
- self.addFactoryArguments(o=o)
class JSONPropertiesDownload(StringDownload):
View
7 master/buildbot/steps/trigger.py
@@ -56,13 +56,6 @@ def __init__(self, schedulerNames=[], sourceStamp=None, updateSourceStamp=None,
self.running = False
self.ended = False
LoggingBuildStep.__init__(self, **kwargs)
- self.addFactoryArguments(schedulerNames=schedulerNames,
- sourceStamp=sourceStamp,
- updateSourceStamp=updateSourceStamp,
- alwaysUseLatest=alwaysUseLatest,
- waitForFinish=waitForFinish,
- set_properties=set_properties,
- copy_properties=copy_properties)
def interrupt(self, reason):
if self.running and not self.ended:
View
12 master/buildbot/steps/vstudio.py
@@ -131,17 +131,6 @@ def __init__(self,
self.PATH = PATH
# always upcall !
ShellCommand.__init__(self, **kwargs)
- self.addFactoryArguments(
- installdir = installdir,
- mode = mode,
- projectfile = projectfile,
- config = config,
- useenv = useenv,
- project = project,
- INCLUDE = INCLUDE,
- LIB = LIB,
- PATH = PATH
- )
def setupLogfiles(self, cmd, logfiles):
logwarnings = self.addLog("warnings")
@@ -305,7 +294,6 @@ def __init__(self, arch = "x86", **kwargs):
# always upcall !
VisualStudio.__init__(self, **kwargs)
- self.addFactoryArguments(arch = arch)
def setupEnvironment(self, cmd):
VisualStudio.setupEnvironment(self, cmd)
View
22 master/buildbot/test/unit/test_config.py
@@ -700,13 +700,12 @@ def setup_basic_attrs(self):
self.cfg.slaves = [ mock.Mock() ]
self.cfg.builders = [ b1, b2 ]
- def setup_builder_locks(self, builder_lock=None, dup_builder_lock=False,
- step_lock=None, dup_step_lock=False):
+ def setup_builder_locks(self, builder_lock=None, dup_builder_lock=False):
def bldr(name):
b = mock.Mock()
b.name = name
b.locks = []
- b.factory.steps = [ ('cls', dict(locks=[])) ]
+ b.factory.steps = [ ('cls', (), dict(locks=[])) ]
return b
def lock(name):
@@ -720,11 +719,6 @@ def lock(name):
b1.locks.append(lock(builder_lock))
if dup_builder_lock:
b2.locks.append(lock(builder_lock))
- if step_lock:
- s1, s2 = b1.factory.steps[0][1], b2.factory.steps[0][1]
- s1['locks'].append(lock(step_lock))
- if dup_step_lock:
- s2['locks'].append(lock(step_lock))
# tests
@@ -767,23 +761,13 @@ def test_check_schedulers(self):
self.assertNoConfigErrors(self.errors)
- def test_check_locks_step_and_builder(self):
- self.setup_builder_locks(builder_lock='l', step_lock='l')
- self.cfg.check_locks(self.errors)
- self.assertConfigError(self.errors, "Two locks share")
-
def test_check_locks_dup_builder_lock(self):
self.setup_builder_locks(builder_lock='l', dup_builder_lock=True)
self.cfg.check_locks(self.errors)
self.assertConfigError(self.errors, "Two locks share")
- def test_check_locks_dup_step_lock(self):
- self.setup_builder_locks(step_lock='l', dup_step_lock=True)
- self.cfg.check_locks(self.errors)
- self.assertConfigError(self.errors, "Two locks share")
-
def test_check_locks(self):
- self.setup_builder_locks(builder_lock='bl', step_lock='sl')
+ self.setup_builder_locks(builder_lock='bl')
self.cfg.check_locks(self.errors)
self.assertNoConfigErrors(self.errors)
View
29 master/buildbot/test/unit/test_process_build.py
@@ -84,6 +84,15 @@ class FakeBuildStatus(Mock):
class FakeBuilderStatus:
implements(interfaces.IBuilderStatus)
+class FakeStepFactory(object):
+ """Fake step factory that just returns a fixed step object."""
+ implements(interfaces.IBuildStepFactory)
+ def __init__(self, step):
+ self.step = step
+
+ def buildStep(self):
+ return self.step
+
class TestBuild(unittest.TestCase):
def setUp(self):
@@ -103,7 +112,7 @@ def testRunSuccessfulBuild(self):
step = Mock()
step.return_value = step
step.startStep.return_value = SUCCESS
- b.setStepFactories([(step, {})])
+ b.setStepFactories([FakeStepFactory(step)])
slavebuilder = Mock()
@@ -118,7 +127,7 @@ def testStopBuild(self):
step = Mock()
step.return_value = step
- b.setStepFactories([(step, {})])
+ b.setStepFactories([FakeStepFactory(step)])
slavebuilder = Mock()
@@ -149,8 +158,8 @@ def testAlwaysRunStepStopBuild(self):
step2.return_value = step2
step2.alwaysRun = True
b.setStepFactories([
- (step1, {}),
- (step2, {}),
+ FakeStepFactory(step1),
+ FakeStepFactory(step2),
])
slavebuilder = Mock()
@@ -197,7 +206,7 @@ def claim(owner, access):
step = Mock()
step.return_value = step
step.startStep.return_value = SUCCESS
- b.setStepFactories([(step, {})])
+ b.setStepFactories([FakeStepFactory(step)])
b.startBuild(FakeBuildStatus(), None, slavebuilder)
@@ -226,7 +235,7 @@ def claim(owner, access):
step = Mock()
step.return_value = step
step.startStep.return_value = SUCCESS
- b.setStepFactories([(step, {})])
+ b.setStepFactories([FakeStepFactory(step)])
real_lock.claim(Mock(), l.access('counting'))
@@ -253,7 +262,7 @@ def testStopBuildWaitingForLocks(self):
step.return_value = step
step.startStep.return_value = SUCCESS
step.alwaysRun = False
- b.setStepFactories([(step, {})])
+ b.setStepFactories([FakeStepFactory(step)])
real_lock.claim(Mock(), l.access('counting'))
@@ -286,7 +295,7 @@ def testStopBuildWaitingForLocks_lostRemote(self):
step.return_value = step
step.startStep.return_value = SUCCESS
step.alwaysRun = False
- b.setStepFactories([(step, {})])
+ b.setStepFactories([FakeStepFactory(step)])
real_lock.claim(Mock(), l.access('counting'))
@@ -317,9 +326,7 @@ def testStopBuildWaitingForStepLocks(self):
real_lock = b.builder.botmaster.getLockByID(l).getLock(slavebuilder)
step = LoggingBuildStep(locks=[lock_access])
- def factory(*args):
- return step
- b.setStepFactories([(factory, {})])
+ b.setStepFactories([FakeStepFactory(step)])
real_lock.claim(Mock(), l.access('counting'))
View
25 master/buildbot/test/unit/test_process_factory.py
@@ -14,42 +14,33 @@
# Copyright Buildbot Team Members
from twisted.trial import unittest
-from mock import Mock
-from buildbot.process.factory import BuildFactory, ArgumentsInTheWrongPlace, s
-from buildbot.process.buildstep import BuildStep
+from buildbot.process.factory import BuildFactory
+from buildbot.process.buildstep import BuildStep, _BuildStepFactory
class TestBuildFactory(unittest.TestCase):
def test_init(self):
step = BuildStep()
factory = BuildFactory([step])
- self.assertEqual(factory.steps, [(BuildStep, {})])
-
- def test_init_deprecated(self):
- factory = BuildFactory([s(BuildStep)])
- self.assertEqual(factory.steps, [(BuildStep, {})])
+ self.assertEqual(factory.steps, [_BuildStepFactory(BuildStep)])
def test_addStep(self):
step = BuildStep()
factory = BuildFactory()
factory.addStep(step)
- self.assertEqual(factory.steps, [(BuildStep, {})])
-
- def test_addStep_deprecated(self):
- factory = BuildFactory()
- factory.addStep(BuildStep)
- self.assertEqual(factory.steps, [(BuildStep, {})])
+ self.assertEqual(factory.steps, [_BuildStepFactory(BuildStep)])
def test_addStep_notAStep(self):
factory = BuildFactory()
- self.assertRaises(ValueError, factory.addStep, Mock())
+ # This fails because object isn't adaptable to IBuildStepFactory
+ self.assertRaises(TypeError, factory.addStep, object())
def test_addStep_ArgumentsInTheWrongPlace(self):
factory = BuildFactory()
- self.assertRaises(ArgumentsInTheWrongPlace, factory.addStep, BuildStep(), name="name")
+ self.assertRaises(TypeError, factory.addStep, BuildStep(), name="name")
def test_addSteps(self):
factory = BuildFactory()
factory.addSteps([BuildStep(), BuildStep()])
- self.assertEqual(factory.steps, [(BuildStep, {}), (BuildStep, {})])
+ self.assertEqual(factory.steps, [_BuildStepFactory(BuildStep), _BuildStepFactory(BuildStep)])
View
6 master/buildbot/test/util/steps.py
@@ -71,10 +71,8 @@ def setupStep(self, step, slave_version={'*':"99.99"}, slave_env={}):
@param slave_env: environment from the slave at slave startup
"""
- # yes, Virginia, "factory" refers both to the tuple and its first
- # element TODO: fix that up
- factory, args = step.getStepFactory()
- step = self.step = factory(**args)
+ factory = interfaces.IBuildStepFactory(step)
+ step = self.step = factory.buildStep()
# step.build
View
331 master/docs/developer/cls-buildsteps.rst
@@ -3,17 +3,16 @@ BuildSteps
.. py:module:: buildbot.process.buildstep
-There are a few parent classes that are used as base classes for real
-buildsteps. This section describes the base classes. The "leaf" classes are
-described in :doc:`../manual/cfg-buildsteps`.
+There are a few parent classes that are used as base classes for real buildsteps.
+This section describes the base classes. The "leaf" classes are described in :doc:`../manual/cfg-buildsteps`.
BuildStep
---------
.. py:class:: BuildStep(name, locks, haltOnFailure, flunkOnWarnings, flunkOnFailure, warnOnWarnings, warnOnFailure, alwaysRun, progressMetrics, useProgress, doStepIf, hideStepIf)
- All constructor arguments must be given as keyword arguments. Each
- constructor parameter is copied to the corresponding attribute.
+ All constructor arguments must be given as keyword arguments.
+ Each constructor parameter is copied to the corresponding attribute.
.. py:attribute:: name
@@ -25,14 +24,13 @@ BuildStep
.. py:attribute:: progressMetrics
- List of names of metrics that should be used to track the progress of
- this build, and build ETA's for users. This is generally set in the
+ List of names of metrics that should be used to track the progress of this build, and build ETA's for users.
+ This is generally set in the
.. py:attribute:: useProgress
- If true (the default), then ETAs will be calculated for this step using
- progress metrics. If the step is known to have unpredictable timing
- (e.g., an incremental build), then this should be set to false.
+ If true (the default), then ETAs will be calculated for this step using progress metrics.
+ If the step is known to have unpredictable timing (e.g., an incremental build), then this should be set to false.
.. py:attribute:: doStepIf
@@ -41,82 +39,56 @@ BuildStep
.. py:attribute:: hideStepIf
- A callable or bool to determine whether this step should be shown in the
- waterfall and build details pages. See :ref:`Buildstep-Common-Parameters` for details.
+ A callable or bool to determine whether this step should be shown in the waterfall and build details pages.
+ See :ref:`Buildstep-Common-Parameters` for details.
The following attributes affect the behavior of the containing build:
.. py:attribute:: haltOnFailure
- If true, the build will halt on a failure of this step, and not execute
- subsequent tests (except those with ``alwaysRun``).
+ If true, the build will halt on a failure of this step, and not execute subsequent tests (except those with ``alwaysRun``).
.. py:attribute:: flunkOnWarnings
- If true, the build will be marked as a failure if this step ends with
- warnings.
+ If true, the build will be marked as a failure if this step ends with warnings.
.. py:attribute:: flunkOnFailure
If true, the build will be marked as a failure if this step fails.
.. py:attribute:: warnOnWarnings
- If true, the build will be marked as warnings, or worse, if this step
- ends with warnings.
+ If true, the build will be marked as warnings, or worse, if this step ends with warnings.
.. py:attribute:: warnOnFailure
- If true, the build will be marked as warnings, or worse, if this step
- fails.
+ If true, the build will be marked as warnings, or worse, if this step fails.
.. py:attribute:: alwaysRun
- If true, the step will run even if a previous step halts the build with
- ``haltOnFailure``.
-
- A step acts as a factory for more steps. See
- :ref:`Writing-BuildStep-Constructors` for advice on writing subclass
- constructors. The following methods handle this factory behavior.
-
- .. py:method:: addFactoryArguments(..)
-
- Add the given keyword arguments to the arguments used to create new
- step instances;
-
- .. py:method:: getStepFactory()
-
- :returns: tuple of (class, keyword arguments)
-
- Get a factory for new instances of this step. The step can be created
- by calling the class with the given keyword arguments.
+ If true, the step will run even if a previous step halts the build with ``haltOnFailure``.
- A few important pieces of information are not available when a step is
- constructed, and are added later. These are set by the following methods;
- the order in which these methods are called is not defined.
+ A few important pieces of information are not available when a step is constructed, and are added later.
+ These are set by the following methods; the order in which these methods are called is not defined.
.. py:method:: setBuild(build)
- :param build: the :class:`~buildbot.process.build.Build` instance
- controlling this step.
+ :param build: the :class:`~buildbot.process.build.Build` instance controlling this step.
- This method is called during setup to set the build instance
- controlling this slave. Subclasses can override this to get access to
- the build object as soon as it is available. The default
- implementation sets the :attr:`build` attribute.
+ This method is called during setup to set the build instance controlling this slave.
+ Subclasses can override this to get access to the build object as soon as it is available.
+ The default implementation sets the :attr:`build` attribute.
.. py:attribute:: build
The build object controlling this step.
.. py:method:: setBuildSlave(build)
- :param build: the :class:`~buildbot.buildslave.BuildSlave` instance on
- which this step will run.
+ :param build: the :class:`~buildbot.buildslave.BuildSlave` instance on which this step will run.
- Similarly, this method is called with the build slave that will run
- this step. The default implementation sets the :attr:`buildslave`
- attribute.
+ Similarly, this method is called with the build slave that will run this step.
+ The default implementation sets the :attr:`buildslave` attribute.
.. py:attribute:: buildslave
@@ -126,36 +98,30 @@ BuildStep
:param workdir: the default workdir, from the build
- This method is called at build startup with the default workdir for the
- build. Steps which allow a workdir to be specified, but want to
- override it with the build's default workdir, can use this method to
- apply the default.
+ This method is called at build startup with the default workdir for the build.
+ Steps which allow a workdir to be specified, but want to override it with the build's default workdir, can use this method to apply the default.
.. py:method:: setStepStatus(status)
:param status: step status
:type status: :class:`~buildbot.status.buildstep.BuildStepStatus`
- This method is called to set the status instance to which the step
- should report. The default implementation sets :attr:`step_status`.
+ This method is called to set the status instance to which the step should report.
+ The default implementation sets :attr:`step_status`.
.. py:attribute:: step_status
- The :class:`~buildbot.status.buildstep.BuildStepStatus` object tracking
- the status of this step.
+ The :class:`~buildbot.status.buildstep.BuildStepStatus` object tracking the status of this step.
.. py:method:: setupProgress()
- This method is called during build setup to give the step a chance to
- set up progress tracking. It is only called if the build has
- :attr:`useProgress` set. There is rarely any reason to override this
- method.
+ This method is called during build setup to give the step a chance to set up progress tracking.
+ It is only called if the build has :attr:`useProgress` set.
+ There is rarely any reason to override this method.
.. py:attribute:: progress
- If the step is tracking progress, this is a
- :class:`~buildbot.status.progress.StepProgress` instance performing
- that task.
+ If the step is tracking progress, this is a :class:`~buildbot.status.progress.StepProgress` instance performing that task.
Exeuction of the step itself is governed by the following methods and attributes.
@@ -168,34 +134,29 @@ BuildStep
Begin the step. This is the build's interface to step execution.
Subclasses should override :meth:`start` to implement custom behaviors.
- The method returns a Deferred that fires when the step finishes. It
- fires with a tuple of ``(result, [extra text])``, where ``result`` is
- one of the constants from :mod:`buildbot.status.builder`. The extra
- text is a list of short strings which should be appended to the Build's
- text results. For example, a test step may add ``17 failures`` to the
- Build's status by this mechanism.
+ The method returns a Deferred that fires when the step finishes.
+ It fires with a tuple of ``(result, [extra text])``, where ``result`` is one of the constants from :mod:`buildbot.status.builder`.
+ The extra text is a list of short strings which should be appended to the Build's text results.
+ For example, a test step may add ``17 failures`` to the Build's status by this mechanism.
- The deferred will errback if the step encounters an exception,
- including an exception on the slave side (or if the slave goes away
- altogether). Normal build/test failures will *not* cause an errback.
+ The deferred will errback if the step encounters an exception, including an exception on the slave side (or if the slave goes away altogether).
+ Normal build/test failures will *not* cause an errback.
.. py:method:: start()
:returns: ``None`` or :data:`~buildbot.status.results.SKIPPED`,
optionally via a Deferred.
- Begin the step. Subclasses should override this method to do local
- processing, fire off remote commands, etc. The parent method raises
- :exc:`NotImplementedError`.
+ Begin the step.
+ Subclasses should override this method to do local processing, fire off remote commands, etc.
+ The parent method raises :exc:`NotImplementedError`.
- When the step is done, it should call :meth:`finished`, with a result
- -- a constant from :mod:`buildbot.status.results`. The result will be
- handed off to the :class:`~buildbot.process.build.Build`.
+ When the step is done, it should call :meth:`finished`, with a result -- a constant from :mod:`buildbot.status.results`.
+ The result will be handed off to the :class:`~buildbot.process.build.Build`.
- If the step encounters an exception, it should call :meth:`failed` with
- a Failure object. This method automatically fails the whole build with
- an exception. A common idiom is to add :meth:`failed` as an errback on
- a Deferred::
+ If the step encounters an exception, it should call :meth:`failed` with a Failure object.
+ This method automatically fails the whole build with an exception.
+ A common idiom is to add :meth:`failed` as an errback on a Deferred::
cmd = RemoteCommand(args)
d = self.runCommand(cmd)
@@ -204,78 +165,61 @@ BuildStep
d.addCallback(succeed)
d.addErrback(self.failed)
- If the step decides it does not need to be run, :meth:`start` can
- return the constant :data:`~buildbot.status.results.SKIPPED`. In this
- case, it is not necessary to call :meth:`finished` directly.
+ If the step decides it does not need to be run, :meth:`start` can return the constant :data:`~buildbot.status.results.SKIPPED`.
+ In this case, it is not necessary to call :meth:`finished` directly.
.. py:method:: finished(results)
:param results: a constant from :mod:`~buildbot.status.results`
- A call to this method indicates that the step is finished and the build
- should analyze the results and perhaps proceed to the next step. The
- step should not perform any additional processing after calling this
- method.
+ A call to this method indicates that the step is finished and the build should analyze the results and perhaps proceed to the next step.
+ The step should not perform any additional processing after calling this method.
.. py:method:: failed(failure)
:param failure: a :class:`~twisted.python.failure.Failure` instance
- Similar to :meth:`finished`, this method indicates that the step is
- finished, but handles exceptions with appropriate logging and
- diagnostics.
+ Similar to :meth:`finished`, this method indicates that the step is finished, but handles exceptions with appropriate logging and diagnostics.
- This method handles :exc:`BuildStepFailed` specially, by calling
- ``finished(FAILURE)``. This provides subclasses with a shortcut to
- stop execution of a step by raising this failure in a context where
- :meth:`failed` will catch it.
+ This method handles :exc:`BuildStepFailed` specially, by calling ``finished(FAILURE)``.
+ This provides subclasses with a shortcut to stop execution of a step by raising this failure in a context where :meth:`failed` will catch it.
.. py:method:: interrupt(reason)
:param reason: why the build was interrupted
:type reason: string or :class:`~twisted.python.failure.Failure`
- This method is used from various control interfaces to stop a running
- step. The step should be brought to a halt as quickly as possible, by
- cancelling a remote command, killing a local process, etc. The step
- must still finish with either :meth:`finished` or :meth:`failed`.
+ This method is used from various control interfaces to stop a running step.
+ The step should be brought to a halt as quickly as possible, by cancelling a remote command, killing a local process, etc.
+ The step must still finish with either :meth:`finished` or :meth:`failed`.
- The ``reason`` parameter can be a string or, when a slave is lost
- during step processing, a :exc:`~twisted.internet.error.ConnectionLost`
- failure.
+ The ``reason`` parameter can be a string or, when a slave is lost during step processing, a :exc:`~twisted.internet.error.ConnectionLost` failure.
- The parent method handles any pending lock operations, and should be
- called by implementations in subclasses.
+ The parent method handles any pending lock operations, and should be called by implementations in subclasses.
.. py:attribute:: stopped
- If false, then the step is running. If true, the step is not running,
- or has been interrupted.
+ If false, then the step is running. If true, the step is not running, or has been interrupted.
- This method provides a convenient way to summarize the status of the step
- for status displays:
+ This method provides a convenient way to summarize the status of the step for status displays:
.. py:method:: describe(done=False)
:param done: If true, the step is finished.
:returns: list of strings
- Describe the step succinctly. The return value should be a sequence of
- short strings suitable for display in a horizontally constrained space.
+ Describe the step succinctly.
+ The return value should be a sequence of short strings suitable for display in a horizontally constrained space.
.. note::
- Be careful not to assume that the step has been started in this
- method. In relatively rare circumstances, steps are described
- before they have started. Ideally, unit tests should be used to
- ensure that this method is resilient.
+ Be careful not to assume that the step has been started in this method.
+ In relatively rare circumstances, steps are described before they have started.
+ Ideally, unit tests should be used to ensure that this method is resilient.
- Build steps support progress metrics - values that increase roughly
- linearly during the execution of the step, and can thus be used to
- calculate an expected completion time for a running step. A metric may be
- a count of lines logged, tests executed, or files compiled. The build
- mechanics will take care of translating this progress information into an
- ETA for the user.
+ Build steps support progress metrics - values that increase roughly linearly during the execution of the step, and can thus be used to calculate an expected completion time for a running step.
+ A metric may be a count of lines logged, tests executed, or files compiled.
+ The build mechanics will take care of translating this progress information into an ETA for the user.
.. py:method:: setProgress(metric, value)
@@ -284,13 +228,13 @@ BuildStep
:param value: the new value for the metric
:type value: integer
- Update a progress metric. This should be called by subclasses that can
- provide useful progress-tracking information.
+ Update a progress metric.
+ This should be called by subclasses that can provide useful progress-tracking information.
The specified metric name must be included in :attr:`progressMetrics`.
- The following methods are provided as utilities to subclasses. These
- methods should only be invoked after the step is started.
+ The following methods are provided as utilities to subclasses.
+ These methods should only be invoked after the step is started.
.. py:method:: slaveVersion(command, oldVersion=None)
@@ -299,19 +243,14 @@ BuildStep
:param oldVersion: return value if the slave does not specify a version
:returns: string
- Fetch the version of the named command, as specified on the slave. In
- practice, all commands on a slave have the same version, but passing
- ``command`` is still useful to ensure that the command is implemented
- on the slave. If the command is not implemented on the slave,
- :meth:`slaveVersion` will return ``None``.
+ Fetch the version of the named command, as specified on the slave.
+ In practice, all commands on a slave have the same version, but passing ``command`` is still useful to ensure that the command is implemented on the slave.
+ If the command is not implemented on the slave, :meth:`slaveVersion` will return ``None``.
- Versions take the form ``x.y`` where ``x`` and ``y`` are integers, and
- are compared as expected for version numbers.
+ Versions take the form ``x.y`` where ``x`` and ``y`` are integers, and are compared as expected for version numbers.
- Buildbot versions older than 0.5.0 did not support version queries; in
- this case, :meth:`slaveVersion` will return ``oldVersion``. Since such
- ancient versions of Buildbot are no longer in use, this functionality
- is largely vestigial.
+ Buildbot versions older than 0.5.0 did not support version queries; in this case, :meth:`slaveVersion` will return ``oldVersion``.
+ Since such ancient versions of Buildbot are no longer in use, this functionality is largely vestigial.
.. py:method:: slaveVersionIsOlderThan(command, minversion)
@@ -320,8 +259,7 @@ BuildStep
:param minversion: minimum version
:returns: boolean
- This method returns true if ``command`` is not implemented on the
- slave, or if it is older than ``minversion``.
+ This method returns true if ``command`` is not implemented on the slave, or if it is older than ``minversion``.
.. py:method:: getSlaveName()
@@ -333,31 +271,26 @@ BuildStep
:returns: Deferred
- This method connects the given command to the step's buildslave and
- runs it, returning the Deferred from
- :meth:`~buildbot.process.buildstep.RemoteCommand.run`.
+ This method connects the given command to the step's buildslave and runs it, returning the Deferred from :meth:`~buildbot.process.buildstep.RemoteCommand.run`.
.. py:method:: addURL(name, url)
:param name: URL name
:param url: the URL
- Add a link to the given ``url``, with the given ``name`` to displays of
- this step. This allows a step to provide links to data that is not
- available in the log files.
+ Add a link to the given ``url``, with the given ``name`` to displays of this step.
+ This allows a step to provide links to data that is not available in the log files.
- The :class:`BuildStep` class provides minimal support for log handling,
- that is extended by the :class:`LoggingBuildStep` class. The following
- methods provide some useful behaviors. These methods can be called while
- the step is running, but not before.
+ The :class:`BuildStep` class provides minimal support for log handling, that is extended by the :class:`LoggingBuildStep` class.
+ The following methods provide some useful behaviors.
+ These methods can be called while the step is running, but not before.
.. py:method:: addLog(name)
:param name: log name
:returns: :class:`~buildbot.status.logfile.LogFile` instance
- Add a new logfile with the given name to the step, and return the log
- file instance.
+ Add a new logfile with the given name to the step, and return the log file instance.
.. py:method:: getLog(name)
@@ -372,27 +305,24 @@ BuildStep
:param name: log name
:param text: content of the logfile
- This method adds a new log and sets ``text`` as its content. This is
- often useful to add a short logfile describing activities performed on
- the master. The logfile is immediately closed, and no further data can
- be added.
+ This method adds a new log and sets ``text`` as its content.
+ This is often useful to add a short logfile describing activities performed on the master.
+ The logfile is immediately closed, and no further data can be added.
.. py:method:: addHTMLLog(name, html)
:param name: log name
:param html: content of the logfile
- Similar to :meth:`addCompleteLog`, this adds a logfile containing
- pre-formatted HTML, allowing more expressiveness than the text format
- supported by :meth:`addCompleteLog`.
+ Similar to :meth:`addCompleteLog`, this adds a logfile containing pre-formatted HTML, allowing more expressiveness than the text format supported by :meth:`addCompleteLog`.
.. py:method:: addLogObserver(logname, observer)
:param logname: log name
:param observer: log observer instance
- Add a log observer for the named log. The named log need not have been
- added already: the observer will be connected when the log is added.
+ Add a log observer for the named log.
+ The named log need not have been added already: the observer will be connected when the log is added.
See :ref:`Adding-LogObservers` for more information on log observers.
@@ -407,29 +337,25 @@ LoggingBuildStep
The remaining arguments are passed to the :class:`BuildStep` constructor.
- This subclass of :class:`BuildStep` is designed to help its subclasses run
- remote commands that produce standard I/O logfiles. It:
+ This subclass of :class:`BuildStep` is designed to help its subclasses run remote commands that produce standard I/O logfiles.
+ It:
* tracks progress using the length of the stdout logfile
* provides hooks for summarizing and evaluating the command's result
* supports lazy logfiles
- * handles the mechanics of starting, interrupting, and finishing remote
- commands
+ * handles the mechanics of starting, interrupting, and finishing remote commands
* detects lost slaves and finishes with a status of
:data:`~buildbot.status.results.RETRY`
.. py:attribute:: logfiles
- The logfiles to track, as described for :bb:step:`ShellCommand`. The
- contents of the class-level ``logfiles`` attribute are combined with
- those passed to the constructor, so subclasses may add log files with a
- class attribute::
+ The logfiles to track, as described for :bb:step:`ShellCommand`.
+ The contents of the class-level ``logfiles`` attribute are combined with those passed to the constructor, so subclasses may add log files with a class attribute::
class MyStep(LoggingBuildStep):
logfiles = dict(debug='debug.log')
- Note that lazy logfiles cannot be specified using this method; they
- must be provided as constructor arguments.
+ Note that lazy logfiles cannot be specified using this method; they must be provided as constructor arguments.
.. py:method:: startCommand(command)
@@ -438,87 +364,70 @@ LoggingBuildStep
.. note::
- This method permits an optional ``errorMessages`` parameter,
- allowing errors detected early in the command process to be logged.
+ This method permits an optional ``errorMessages`` parameter, allowing errors detected early in the command process to be logged.
It will be removed, and its use is deprecated.
- Handle all of the mechanics of running the given command. This sets
- up all required logfiles, keeps status text up to date, and calls the
- utility hooks described below. When the command is finished, the step
- is finished as well, making this class is unsuitable for steps that
- run more than one command in sequence.
+ Handle all of the mechanics of running the given command.
+ This sets up all required logfiles, keeps status text up to date, and calls the utility hooks described below.
+ When the command is finished, the step is finished as well, making this class is unsuitable for steps that run more than one command in sequence.
- Subclasses should override
- :meth:`~buildbot.process.buildstep.BuildStep.start` and, after setting
- up an appropriate command, call this method. ::
+ Subclasses should override :meth:`~buildbot.process.buildstep.BuildStep.start` and, after setting up an appropriate command, call this method. ::
def start(self):
cmd = RemoteShellCommand(..)
self.startCommand(cmd, warnings)
To refine the status output, override one or more of the following methods.
- The :class:`LoggingBuildStep` implementations are stubs, so there is no
- need to call the parent method.
+ The :class:`LoggingBuildStep` implementations are stubs, so there is no need to call the parent method.
.. py:method:: commandComplete(command)
:param command: the just-completed remote command
- This is a general-purpose hook method for subclasses. It will be called
- after the remote command has finished, but before any of the other hook
- functions are called.
+ This is a general-purpose hook method for subclasses.
+ It will be called after the remote command has finished, but before any of the other hook functions are called.
.. py:method:: createSummary(stdio)
:param stdio: stdio :class:`~buildbot.status.logfile.LogFile`
- This hook is designed to perform any summarization of the step, based
- either on the contents of the stdio logfile, or on instance attributes
- set earlier in the step processing. Implementations of this method
- often call e.g., :meth:`~BuildStep.addURL`.
+ This hook is designed to perform any summarization of the step, based either on the contents of the stdio logfile, or on instance attributes set earlier in the step processing.
+ Implementations of this method often call e.g., :meth:`~BuildStep.addURL`.
.. py:method:: evaluateCommand(command)
:param command: the just-completed remote command
:returns: step result from :mod:`buildbot.status.results`
- This hook should decide what result the step should have. The default
- implementation invokes ``log_eval_func`` if it exists, and looks at
- :attr:`~buildbot.process.buildstep.RemoteCommand.rc` to distinguish
- :data:`~buildbot.status.results.SUCCESS` from
- :data:`~buildbot.status.results.FAILURE`.
+ This hook should decide what result the step should have.
+ The default implementation invokes ``log_eval_func`` if it exists, and looks at :attr:`~buildbot.process.buildstep.RemoteCommand.rc` to distinguish :data:`~buildbot.status.results.SUCCESS` from :data:`~buildbot.status.results.FAILURE`.
- The remaining methods provide an embarassment of ways to set the summary of
- the step that appears in the various status interfaces. The easiest way to
- affect this output is to override :meth:`~BuildStep.describe`. If that is
- not flexible enough, override :meth:`getText` and/or :meth:`getText2`.
+ The remaining methods provide an embarassment of ways to set the summary of the step that appears in the various status interfaces.
+ The easiest way to affect this output is to override :meth:`~BuildStep.describe`.
+ If that is not flexible enough, override :meth:`getText` and/or :meth:`getText2`.
.. py:method:: getText(command, results)
:param command: the just-completed remote command
:param results: step result from :meth:`evaluateCommand`
:returns: a list of short strings
- This method is the primary means of describing the step. The default
- implementation calls :meth:`~BuildStep.describe`, which is usally the
- easiest method to override, and then appends a string describing the
- step status if it was not successful.
+ This method is the primary means of describing the step.
+ The default implementation calls :meth:`~BuildStep.describe`, which is usally the easiest method to override, and then appends a string describing the step status if it was not successful.
.. py:method:: getText2(command, results)
:param command: the just-completed remote command
:param results: step result from :meth:`evaluateCommand`
:returns: a list of short strings
- Like :meth:`getText`, this method summarizes the step's result, but it
- is only called when that result affects the build, either by making it
- halt, flunk, or end with warnings.
+ Like :meth:`getText`, this method summarizes the step's result, but it is only called when that result affects the build, either by making it halt, flunk, or end with warnings.
Exceptions
----------
.. py:exception:: BuildStepFailed
- This exception indicates that the buildstep has failed. It is useful as a
- way to skip all subsequent processing when a step goes wrong. It is
- handled by :meth:`BuildStep.failed`.
+ This exception indicates that the buildstep has failed.
+ It is useful as a way to skip all subsequent processing when a step goes wrong.
+ It is handled by :meth:`BuildStep.failed`.
View
88 master/docs/manual/customization.rst
@@ -525,69 +525,37 @@ Properties Objects
Writing New BuildSteps
----------------------
-While it is a good idea to keep your build process self-contained in
-the source code tree, sometimes it is convenient to put more
-intelligence into your Buildbot configuration. One way to do this is
-to write a custom :class:`BuildStep`. Once written, this Step can be used in
-the :file:`master.cfg` file.
-
-The best reason for writing a custom :class:`BuildStep` is to better parse the
-results of the command being run. For example, a :class:`BuildStep` that knows
-about JUnit could look at the logfiles to determine which tests had
-been run, how many passed and how many failed, and then report more
-detailed information than a simple ``rc==0`` -based `good/bad`
-decision.
-
-Buildbot has acquired a large fleet of build steps, and sports a number of
-knobs and hooks to make steps easier to write. This section may seem a bit
-overwhelming, but most custom steps will only need to apply one or two of the
-techniques outlined here.
-
-For complete documentation of the build step interfaces, see
-:doc:`../developer/cls-buildsteps`.
+While it is a good idea to keep your build process self-contained in the source code tree, sometimes it is convenient to put more intelligence into your Buildbot configuration.
+One way to do this is to write a custom :class:`BuildStep`.
+Once written, this Step can be used in the :file:`master.cfg` file.
+
+The best reason for writing a custom :class:`BuildStep` is to better parse the results of the command being run.
+For example, a :class:`BuildStep` that knows about JUnit could look at the logfiles to determine which tests had been run, how many passed and how many failed, and then report more detailed information than a simple ``rc==0`` -based `good/bad` decision.
+
+Buildbot has acquired a large fleet of build steps, and sports a number of knobs and hooks to make steps easier to write.
+This section may seem a bit overwhelming, but most custom steps will only need to apply one or two of the techniques outlined here.
+
+For complete documentation of the build step interfaces, see :doc:`../developer/cls-buildsteps`.
.. _Writing-BuildStep-Constructors:
Writing BuildStep Constructors
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Build steps act as their own factories, so their constructors are a bit more
-complex than necessary. In the configuration file, a
-:class:`~buildbot.process.buildstep.BuildStep` object is instantiated, but
-because steps store state locally while executing, this object cannot be used
-during builds. Instead, the build machinery calls the step's
-:meth:`~buildbot.process.buildstep.BuildStep.getStepFactory` method to get a
-tuple of a callable and keyword arguments that should be used to create a new
-instance.
+Build steps act as their own factories, so their constructors are a bit more complex than necessary.
+In the configuration file, a :class:`~buildbot.process.buildstep.BuildStep` object is instantiated, but because steps store state locally while executing, this object cannot be used during builds.
Consider the use of a :class:`BuildStep` in :file:`master.cfg`::
f.addStep(MyStep(someopt="stuff", anotheropt=1))
-This creates a single instance of class ``MyStep``. However, Buildbot needs a
-new object each time the step is executed. this is accomplished by storing the
-information required to instantiate a new object in the
-:attr:`~buildbot.process.buildstep.BuildStep.factory` attribute. When the time
-comes to construct a new :class:`~buildbot.process.build.Build`,
-:class:`~buildbot.process.factory.BuildFactory` consults this attribute (via
-:meth:`~buildbot.process.buildstep.BuildStep.getStepFactory`) and instantiates
-a new step object.
-
-When writing a new step class, then, keep in mind are that you cannot do
-anything "interesting" in the constructor -- limit yourself to checking and
-storing arguments. Each constructor in a sequence of :class:`BuildStep`
-subclasses must ensure the following:
+This creates a single instance of class ``MyStep``.
+However, Buildbot needs a new object each time the step is executed.
+An instance of :class:`~buildbot.process.buildstep.BuildStep` rembers how it was constructed, and can create copies of itself.
+When writing a new step class, then, keep in mind are that you cannot do anything "interesting" in the constructor -- limit yourself to checking and storing arguments.
-* the parent class's constructor is called with all otherwise-unspecified
- keyword arguments.
-
-* all keyword arguments for the class itself are passed to
- :meth:`addFactoryArguments`.
-
-Keep a ``**kwargs`` argument on the end of your options, and pass that up to
-the parent class's constructor. If the class overrides constructor arguments
-for the parent class, those should be updated in ``kwargs``, rather than passed
-directly (which will cause errors during instantiation).
+It is customary to call the parent class's constructor with all otherwise-unspecified keyword arguments.
+Keep a ``**kwargs`` argument on the end of your options, and pass that up to the parent class's constructor.
The whole thing looks like this::
@@ -613,36 +581,24 @@ The whole thing looks like this::
self.frob_how_many = how_many
self.frob_how = frob_how
- # and record arguments for later
- self.addFactoryArguments(
- frob_what=frob_what,
- frob_how_many=frob_how_many,
- frob_how=frob_how)
-
class FastFrobnify(Frobnify):
def __init__(self,
speed=5,
**kwargs)
Frobnify.__init__(self, **kwargs)
self.speed = speed
- self.addFactoryArguments(
- speed=speed)
Running Commands
~~~~~~~~~~~~~~~~
-To spawn a command in the buildslave, create a
-:class:`~buildbot.process.buildstep.RemoteCommand` instance in your step's
-``start`` method and run it with
-:meth:`~buildbot.process.buildstep.BuildStep.runCommand`::
+To spawn a command in the buildslave, create a :class:`~buildbot.process.buildstep.RemoteCommand` instance in your step's ``start`` method and run it with :meth:`~buildbot.process.buildstep.BuildStep.runCommand`::
cmd = RemoteCommand(args)
d = self.runCommand(cmd)
To add a LogFile, use :meth:`~buildbot.process.buildstep.BuildStep.addLog`.
-Make sure the log gets closed when it finishes. When giving a Logfile to a
-:class:`~buildbot.process.buildstep.RemoteShellCommand`, just ask it to close
-the log when the command completes::
+Make sure the log gets closed when it finishes.
+When giving a Logfile to a :class:`~buildbot.process.buildstep.RemoteShellCommand`, just ask it to close the log when the command completes::
log = self.addLog('output')
cmd.useLog(log, closeWhenFinished=True)

0 comments on commit 9eb7be7

Please sign in to comment.