Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Restore BK slave-side step.

Note that Buildbot was not released with this step missing, so no
compatibility concerns exist.

Fixes #2223.  Refs #891.  Refs #2198.
  • Loading branch information...
commit ca6941b7e0e69e1aeb16a9892adfb9aab2465e34 1 parent 27055a7
@djmitche authored
View
4 MAINTAINERS.txt
@@ -58,6 +58,10 @@ Git VC
M: Amber Yust <ayust@yelp.com> (irc:Aaeriele)
U: http://trac.buildbot.net/wiki/git
+BitKeeper VC
+ S: Last-Rites
+ U: http://trac.buildbot.net/wiki/bk
+
Darcs VC
S: Orphaned
U: http://trac.buildbot.net/wiki/darcs
View
4 master/buildbot/steps/source/__init__.py
@@ -15,7 +15,7 @@
from buildbot.steps.source.base import Source
from buildbot.steps.source.oldsource import CVS, \
- SVN, Git, Darcs, Repo, Bzr, Mercurial, P4, Monotone
+ SVN, Git, Darcs, Repo, Bzr, Mercurial, P4, Monotone, BK
_hush_pyflakes = [ Source, CVS, SVN, \
- Git, Darcs, Repo, Bzr, Mercurial, P4, Monotone ]
+ Git, Darcs, Repo, Bzr, Mercurial, P4, Monotone, BK ]
View
73 master/buildbot/steps/source/oldsource.py
@@ -139,6 +139,79 @@ def start(self):
Source.start(self)
+
+class BK(SlaveSource):
+ """I perform BitKeeper checkout/update operations."""
+
+ name = 'bk'
+
+ renderables = [ 'bkurl', 'baseURL' ]
+
+ def __init__(self, bkurl=None, baseURL=None,
+ directory=None, extra_args=None, **kwargs):
+ """
+ @type bkurl: string
+ @param bkurl: the URL which points to the BitKeeper server.
+
+ @type baseURL: string
+ @param baseURL: if branches are enabled, this is the base URL to
+ which a branch name will be appended. It should
+ probably end in a slash. Use exactly one of
+ C{bkurl} and C{baseURL}.
+ """
+
+ self.bkurl = _ComputeRepositoryURL(bkurl)
+ self.baseURL = _ComputeRepositoryURL(baseURL)
+ self.extra_args = extra_args
+
+ Source.__init__(self, **kwargs)
+ self.addFactoryArguments(bkurl=bkurl,
+ baseURL=baseURL,
+ directory=directory,
+ extra_args=extra_args,
+ )
+
+ if bkurl and baseURL:
+ raise ValueError("you must use exactly one of bkurl and baseURL")
+
+
+ def computeSourceRevision(self, changes):
+ return changes.revision
+
+
+ def startVC(self, branch, revision, patch):
+
+ warnings = []
+ slavever = self.slaveVersion("bk")
+ if not slavever:
+ m = "slave does not have the 'bk' command"
+ raise BuildSlaveTooOldError(m)
+
+ if self.bkurl:
+ assert not branch # we need baseURL= to use branches
+ self.args['bkurl'] = self.bkurl
+ else:
+ self.args['bkurl'] = self.baseURL + branch
+ self.args['revision'] = revision
+ self.args['patch'] = patch
+ self.args['branch'] = branch
+ if self.extra_args is not None:
+ self.args['extra_args'] = self.extra_args
+
+ revstuff = []
+ revstuff.append("[branch]")
+ if revision is not None:
+ revstuff.append("r%s" % revision)
+ if patch is not None:
+ revstuff.append("[patch]")
+ self.description.extend(revstuff)
+ self.descriptionDone.extend(revstuff)
+
+ cmd = RemoteCommand("bk", self.args)
+ self.startCommand(cmd, warnings)
+
+
+
class CVS(SlaveSource):
"""I do CVS checkout/update operations.
View
4 master/buildbot/test/regressions/test_oldpaths.py
@@ -185,3 +185,7 @@ def test_steps_source_Monotone(self):
from buildbot.steps.source import Monotone
assert Monotone
+ def test_steps_source_BK(self):
+ from buildbot.steps.source import BK
+ assert BK
+
View
165 master/contrib/bk_buildbot.py
@@ -0,0 +1,165 @@
+#!/usr/local/bin/python
+#
+# BitKeeper hook script.
+#
+# svn_buildbot.py was used as a base for this file, if you find any bugs or
+# errors please email me.
+#
+# Amar Takhar <amar@ntp.org>
+
+
+'''
+/path/to/bk_buildbot.py --repository "$REPOS" --revision "$REV" --branch \
+"<branch>" --bbserver localhost --bbport 9989
+'''
+
+import commands
+import sys
+import os
+import re
+if sys.version_info < (2, 6):
+ import sets
+
+# We have hackish "-d" handling here rather than in the Options
+# subclass below because a common error will be to not have twisted in
+# PYTHONPATH; we want to be able to print that error to the log if
+# debug mode is on, so we set it up before the imports.
+
+DEBUG = None
+
+if '-d' in sys.argv:
+ i = sys.argv.index('-d')
+ DEBUG = sys.argv[i+1]
+ del sys.argv[i]
+ del sys.argv[i]
+
+if DEBUG:
+ f = open(DEBUG, 'a')
+ sys.stderr = f
+ sys.stdout = f
+
+
+from twisted.internet import defer, reactor
+from twisted.python import usage
+from twisted.spread import pb
+from twisted.cred import credentials
+
+
+class Options(usage.Options):
+ optParameters = [
+ ['repository', 'r', None,
+ "The repository that was changed."],
+ ['revision', 'v', None,
+ "The revision that we want to examine (default: latest)"],
+ ['branch', 'b', None,
+ "Name of the branch to insert into the branch field. (REQUIRED)"],
+ ['category', 'c', None,
+ "Schedular category."],
+ ['bbserver', 's', 'localhost',
+ "The hostname of the server that buildbot is running on"],
+ ['bbport', 'p', 8007,
+ "The port that buildbot is listening on"]
+ ]
+ optFlags = [
+ ['dryrun', 'n', "Do not actually send changes"],
+ ]
+
+ def __init__(self):
+ usage.Options.__init__(self)
+
+ def postOptions(self):
+ if self['repository'] is None:
+ raise usage.error("You must pass --repository")
+
+class ChangeSender:
+
+ def getChanges(self, opts):
+ """Generate and stash a list of Change dictionaries, ready to be sent
+ to the buildmaster's PBChangeSource."""
+
+ # first we extract information about the files that were changed
+ repo = opts['repository']
+ print "Repo:", repo
+ rev_arg = ''
+ if opts['revision']:
+ rev_arg = '-r"%s"' % (opts['revision'], )
+ changed = commands.getoutput("bk changes -v %s -d':GFILE:\\n' '%s'" % (
+ rev_arg, repo)).split('\n')
+
+ # Remove the first line, it's an info message you can't remove (annoying)
+ del changed[0]
+
+ change_info = commands.getoutput("bk changes %s -d':USER:\\n$each(:C:){(:C:)\\n}' '%s'" % (
+ rev_arg, repo)).split('\n')
+
+ # Remove the first line, it's an info message you can't remove (annoying)
+ del change_info[0]
+
+ who = change_info.pop(0)
+ branch = opts['branch']
+ message = '\n'.join(change_info)
+ revision = opts.get('revision')
+
+ changes = {'who': who,
+ 'branch': branch,
+ 'files': changed,
+ 'comments': message,
+ 'revision': revision}
+
+ if opts.get('category'):
+ changes['category'] = opts.get('category')
+
+ return changes
+
+
+ def sendChanges(self, opts, changes):
+ pbcf = pb.PBClientFactory()
+ reactor.connectTCP(opts['bbserver'], int(opts['bbport']), pbcf)
+ d = pbcf.login(credentials.UsernamePassword('change', 'changepw'))
+ d.addCallback(self.sendAllChanges, changes)
+ return d
+
+ def sendAllChanges(self, remote, changes):
+ dl = remote.callRemote('addChange', changes)
+ return dl
+
+ def run(self):
+ opts = Options()
+ try:
+ opts.parseOptions()
+ if not opts['branch']:
+ print "You must supply a branch with -b or --branch."
+ sys.exit(1);
+
+ except usage.error, ue:
+ print opts
+ print "%s: %s" % (sys.argv[0], ue)
+ sys.exit()
+
+ changes = self.getChanges(opts)
+ if opts['dryrun']:
+ for k in changes.keys():
+ print "[%10s]: %s" % (k, changes[k])
+ print "*NOT* sending any changes"
+ return
+
+ d = self.sendChanges(opts, changes)
+
+ def quit(*why):
+ print "quitting! because", why
+ reactor.stop()
+
+ def failed(f):
+ print "FAILURE: %s" % f
+ reactor.stop()
+
+ d.addErrback(failed)
+ d.addCallback(quit, "SUCCESS")
+ reactor.callLater(60, quit, "TIMEOUT")
+
+ reactor.run()
+
+
+if __name__ == '__main__':
+ s = ChangeSender()
+ s.run()
View
1  master/docs/developer/definitions.rst
@@ -31,6 +31,7 @@ Mercurial changeset sha1 hash different repos
Darcs ? none [2] different repos
Bazaar ? ? ?
Perforce ? ? ?
+BitKeeper changeset ? different repos
=========== =========== =========== ===================
* [1] note that CVS only tracks patches to individual files. Buildbot tries to
View
19 master/docs/manual/cfg-buildsteps.rst
@@ -1177,6 +1177,25 @@ introduced by a pending changeset.
Gerrit integration can be also triggered using forced build with ``gerrit_change``
property with value in format: ``change_number/patchset_number``.
+.. bb:step:: BK (Slave-Side)
+
+BitKeeper (Slave-Side)
+++++++++++++++++++++++
+
+The :bb:step:`BK <BK (Slave-Side)>` build step performs a `BitKeeper <http://www.bitkeeper.com/>`_
+checkout or update.
+
+The BitKeeper step takes the following arguments:
+
+``repourl``
+ (required unless ``baseURL`` is provided): the URL at which the
+ BitKeeper source repository is available.
+
+``baseURL``
+ (required unless ``repourl`` is provided): the base repository URL,
+ to which a branch name will be appended. It should probably end in a
+ slash.
+
.. bb:step:: Repo (Slave-Side)
Repo (Slave-Side)
View
2  master/docs/release-notes.rst
@@ -103,8 +103,6 @@ Slave
Deprecations, Removals, and Non-Compatible Changes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-* BK support has been removed in this release - see :bb:bug:`2198`.
-
Features
~~~~~~~~
View
116 slave/buildslave/commands/bk.py
@@ -0,0 +1,116 @@
+# This file is part of Buildbot. Buildbot is free software: you can
+# redistribute it and/or modify it under the terms of the GNU General Public
+# License as published by the Free Software Foundation, version 2.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright Buildbot Team Members
+
+import os
+
+from twisted.python import log
+
+from buildslave.commands.base import SourceBaseCommand
+from buildslave import runprocess
+
+
+class BK(SourceBaseCommand):
+ """BitKeeper-specific VC operation. In addition to the arguments
+ handled by SourceBaseCommand, this command reads the following keys:
+
+ ['bkurl'] (required): the BK repository string
+ """
+
+ header = "bk operation"
+
+ def setup(self, args):
+ SourceBaseCommand.setup(self, args)
+ self.bkurl = args['bkurl']
+ self.sourcedata = '"%s\n"' % self.bkurl
+
+ self.bk_args = []
+ if args.get('extra_args', None) is not None:
+ self.bk_args.extend(args['extra_args'])
+
+ def sourcedirIsUpdateable(self):
+ if os.path.exists(os.path.join(self.builder.basedir,
+ self.srcdir, ".buildbot-patched")):
+ return False
+ return os.path.isfile(os.path.join(self.builder.basedir,
+ self.srcdir, "BK/parent"))
+
+ def doVCUpdate(self):
+ bk = self.getCommand('bk')
+ # XXX revision is never used!! - bug #1715
+ # revision = self.args['revision'] or 'HEAD'
+ # update: possible for mode in ('copy', 'update')
+ d = os.path.join(self.builder.basedir, self.srcdir)
+
+ # Revision is ignored since the BK free client doesn't support it.
+ command = [bk, 'pull']
+ c = runprocess.RunProcess(self.builder, command, d,
+ sendRC=False, timeout=self.timeout,
+ keepStdout=True, logEnviron=self.logEnviron,
+ usePTY=False)
+ self.command = c
+ return c.start()
+
+ def doVCFull(self):
+ bk = self.getCommand('bk')
+
+ revision_arg = ''
+ if self.args['revision']:
+ revision_arg = "-r%s" % self.args['revision']
+
+ d = self.builder.basedir
+
+ command = [bk, 'clone', revision_arg] + self.bk_args + \
+ [self.bkurl, self.srcdir]
+ c = runprocess.RunProcess(self.builder, command, d,
+ sendRC=False, timeout=self.timeout,
+ logEnviron=self.logEnviron, usePTY=False)
+ self.command = c
+ return c.start()
+
+ def getBKVersionCommand(self):
+ """
+ Get the (shell) command used to determine BK revision number
+ of checked-out code
+
+ return: list of strings, passable as the command argument to RunProcess
+ """
+ bk = self.getCommand('bk')
+ return [bk, "changes", "-r+", "-d:REV:"]
+
+ def parseGotRevision(self):
+ c = runprocess.RunProcess(self.builder,
+ self.getBKVersionCommand(),
+ os.path.join(self.builder.basedir, self.srcdir),
+ environ=self.env, timeout=self.timeout,
+ sendStdout=False, sendStderr=False, sendRC=False,
+ keepStdout=True, logEnviron=self.logEnviron,
+ usePTY=False)
+ d = c.start()
+ def _parse(res):
+ r_raw = c.stdout.strip()
+ try:
+ r = r_raw
+ except:
+ msg = ("BK.parseGotRevision unable to parse output: (%s)" % r_raw)
+ log.msg(msg)
+ self.sendStatus({'header': msg + "\n"})
+ raise ValueError(msg)
+ return r
+ d.addCallback(_parse)
+ return d
+
+
+
+
View
1  slave/buildslave/commands/registry.py
@@ -22,6 +22,7 @@
"uploadDirectory" : "buildslave.commands.transfer.SlaveDirectoryUploadCommand",
"downloadFile" : "buildslave.commands.transfer.SlaveFileDownloadCommand",
"svn" : "buildslave.commands.svn.SVN",
+ "bk" : "buildslave.commands.bk.BK",
"cvs" : "buildslave.commands.cvs.CVS",
"darcs" : "buildslave.commands.darcs.Darcs",
"git" : "buildslave.commands.git.Git",
View
68 slave/buildslave/test/unit/test_commands_bk.py
@@ -0,0 +1,68 @@
+# This file is part of Buildbot. Buildbot is free software: you can
+# redistribute it and/or modify it under the terms of the GNU General Public
+# License as published by the Free Software Foundation, version 2.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright Buildbot Team Members
+
+from twisted.trial import unittest
+
+from buildslave.test.fake.runprocess import Expect
+from buildslave.test.util.sourcecommand import SourceCommandTestMixin
+from buildslave.commands import bk
+
+class TestBK(SourceCommandTestMixin, unittest.TestCase):
+
+ def setUp(self):
+ self.setUpCommand()
+
+ def tearDown(self):
+ self.tearDownCommand()
+
+ def test_simple(self):
+ self.patch_getCommand('bk', 'path/to/bk')
+ self.clean_environ()
+ self.make_command(bk.BK, dict(
+ workdir='workdir',
+ mode='copy',
+ revision='1.114',
+ bkurl='http://bkdemo.bkbits.net/bk_demo1',
+ ))
+
+ exp_environ = dict(PWD='.', LC_MESSAGES='C')
+ expects = [
+ Expect([ 'clobber', 'workdir' ],
+ self.basedir)
+ + 0,
+ Expect([ 'clobber', 'source' ],
+ self.basedir)
+ + 0,
+ Expect(['path/to/bk', 'clone', '-r1.114',
+ 'http://bkdemo.bkbits.net/bk_demo1', 'source'],
+ self.basedir,
+ sendRC=False, timeout=120, usePTY=False)
+ + 0,
+ Expect(['path/to/bk', 'changes', '-r+', '-d:REV:'],
+ self.basedir_source,
+ sendRC=False, usePTY=False, timeout=120, sendStderr=False,
+ sendStdout=False, keepStdout=True, environ=exp_environ)
+ + { 'stdout' : '1.114\n' } # TODO: is this what BK outputs?
+ + 0,
+ Expect([ 'copy', 'source', 'workdir'],
+ self.basedir)
+ + 0,
+ ]
+ self.patch_runprocess(*expects)
+
+ d = self.run_command()
+ # TODO: why the extra quotes?
+ d.addCallback(self.check_sourcedata, '"http://bkdemo.bkbits.net/bk_demo1\n"')
+ return d
Please sign in to comment.
Something went wrong with that request. Please try again.