code: #!/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 dummy@email.com
  
  
  '''
  /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()
  
entities: [['EMAIL_ADDRESS', 'dummy@email.com'], ['PERSON', 'Amar Takhar dummy@email.com'], ['LOCATION', 'sys.argv'], ['PERSON', 'buildbot'], ['PERSON', 'dryrun'], ['PERSON', 'buildmaster'], ['LOCATION', 'del changed[0]\n\n        change_info'], ['PERSON', 'del change_info[0]\n\n        '], ['PERSON', 'pbcf'], ['URL', 'buildbot.py'], ['URL', 'email.com'], ['URL', 'buildbot.py'], ['URL', 'sys.ve'], ['URL', 'sys.ar'], ['URL', 'sys.argv.in'], ['URL', 'sys.ar'], ['URL', 'sys.ar'], ['URL', 'sys.ar'], ['URL', 'sys.st'], ['URL', 'sys.st'], ['URL', 'twisted.int'], ['URL', 'twisted.py'], ['URL', 'twisted.cr'], ['URL', 'usage.er'], ['URL', 'commands.ge'], ['URL', 'commands.ge'], ['URL', 'opts.ge'], ['URL', 'opts.ge'], ['URL', 'opts.ge'], ['URL', 'reactor.co'], ['URL', 'credentials.Us'], ['URL', 'd.ad'], ['URL', 'self.se'], ['URL', 'remote.ca'], ['URL', 'opts.pa'], ['URL', 'usage.er'], ['URL', 'sys.ar'], ['URL', 'self.ge'], ['URL', 'changes.ke'], ['URL', 'self.se'], ['URL', 'reactor.st'], ['URL', 'reactor.st'], ['URL', 'd.ad'], ['URL', 'd.ad'], ['URL', 'reactor.ca'], ['URL', 'reactor.ru'], ['URL', 's.ru']]