view autobot/process/factory.py @ 197:854ac4008ac8

Exactly one of property and extract_fn must be set
author Jeff Hammel <jhammel@mozilla.com>
date Wed, 02 Feb 2011 14:52:09 -0800
parents 524b8b215a01
children 38fc07fb6aad
line wrap: on
line source

"""
generic factories 
"""

from autobot.steps import CreateVirtualenv
from buildbot.process.factory import BuildFactory
from buildbot.steps.shell import SetProperty
from buildbot.steps.shell import ShellCommand
from buildbot.steps.shell import WithProperties


### utility functions; could go elsewhere

def find(*args):
  """
  returns a command to echo the found file cross-platform
  """
  args = ['[ -e "%s" ]; then echo "${PWD}/%s"' % (arg, arg) for arg in args]
  command = 'if %s; else false; fi' % '; elif '.join(args)
  return ['bash', '-c', command]

### factories

class FirefoxDownloaderFactory(BuildFactory):
  """
  factory to aid in downloading Firefox
  """

  def __init__(self, platform, base_url=None):

    # must have the os specified!
    assert platform.get('os'), "platform['os'] must be one of (linux, win, mac)"

    # determine the (damn) url
    script = 'get-latest-tinderbox'
    if base_url:
      command = [script, '-u', base_url]
    else:
      command = [script]
    self.addStep(SetProperty(property='firefox_url',
                             command=command,
                             haltOnFailure=True
                             ))

    # get the filename
    def firefox_bundle_name(returncode, stdout, stderr):
      """
      extract the end part of the URL ~ the basename
      """
      return {'firefox_bundle': stdout.rsplit('/', 1)[-1]}

    self.addStep(SetProperty(command=['echo', WithProperties('%(firefox_url)s')],
                             extract_fn=firefox_bundle_name))

    # download Firefox
    self.addStep(ShellCommand(command=['wget',
                                       WithProperties('%(firefox_url)s'),
                                       '-O',
                                       WithProperties('%(firefox_bundle)s')],
                              haltOnFailure=True))

    # three cases:
    # - linux has firefox in a .tar.bz2 file
    # - mac has firefox in a .dmg file [TODO]
    # - windows has firefox in a .zip file
    


class SourceFactory(BuildFactory):
  """
  base class for factories with VCS sources
  """

  sources = {'git': [], 'hg': []}
  default_branches = {'git': 'master', 'hg': 'default'}

  def __init__(self, git=None, hg=None):

    BuildFactory.__init__(self)

    # override class-level defaults
    if git is not None:
      self.sources['git'] = git
    if hg is not None:
      self.sources['hg'] = hg

    # sanitize sources
    for source_type in self.sources:
      if isinstance(self.sources[source_type], basestring):
        self.sources[source_type] = self.sources[source_type].split()
      for index, source in enumerate(self.sources[source_type]):
        if isinstance(source, basestring):
          branch = None
          if '#' in source:
            source, branch = source.rsplit('#', 1)
          
        else:
          source, branch = source
        if branch is None:
          branch = self.default_branches.get(source_type, None)
        self.sources[source_type][index] = (source, branch)

  def checkout(self, **kwargs):
    """
    checkout all sources
    """
    # TODO: do the right thing with branches (they're currently ignored)
    # TODO: should give more fine-grained control

    # clone hg repositories
    for hg_source, branch in self.sources.get('hg', ()):
      self.addStep(ShellCommand(command=['hg', 'clone', hg_source],
                                **kwargs))

    # clone the git repositories
    for git_source, branch in self.sources.get('git', ()):
      self.addStep(ShellCommand(command=['git', 'clone', git_source],
                                **kwargs))
               
class VirtualenvFactory(SourceFactory):
  """
  create a virtualenv and install some python packages in it
  """

  def __init__(self, name='env', hg=None, git=None, checkout=True):
    """
    - name : of the virtualenv
    - hg: sources of python packages with setuptools setup.pys
    - git: git sources of python package
    """
    SourceFactory.__init__(self, hg=hg, git=git)

    # wipe any vestiges
    self.addStep(ShellCommand(command=['rm', '-rf', name]))

    # create a virtualenv
    self.addStep(CreateVirtualenv(name))

    # set properities related to the virtualenv:
    # - virtualenv location
    # - scripts location
    # - python location
    self.addStep(SetProperty(property='virtualenv',
                             command=['pwd'],
                             workdir='build/'+name))
    self.addStep(SetProperty(property='scripts',
                             command=find('Scripts', 'bin'),
                             workdir=WithProperties('%(virtualenv)s')))
    self.findScript('python')

    # add a source directory
    self.addStep(ShellCommand(command=['mkdir', '-p', 'src'],
                              workdir=WithProperties('%(virtualenv)s')))

    # checkout sources
    if checkout:
      self.checkout(workdir=WithProperties('%(virtualenv)s/src'),
                    haltOnFailure=True)


  def findScript(self, script):
    """
    find the name of the script cross-platform
    - script: unix-style name of the script
    """
    self.addStep(SetProperty(property=script,
                             command=find(script, script + '.exe'),
                             workdir=WithProperties('%(scripts)s')))

class PythonSourceFactory(VirtualenvFactory):
  """
  setup several python packages
  """

  def __init__(self, platform=None, name='env', hg=None, git=None):

    # setup the environment
    VirtualenvFactory.__init__(self, name=name, hg=hg, git=git)

    # install the packages
    sources = []
    for hg_source, branch in self.sources.get('hg', ()):
      package = hg_source.rstrip('/').rsplit('/', 1)[-1]
      sources.append(package)
    for git_source, branch in self.sources.get('git', ()):
      package = git_source.rstrip('/').rsplit('/', 1)[-1]
      if package.endswith('.git'):
        package = package[:-4]
      sources.append(package)
    for package in sources:
      self.addStep(ShellCommand(command=[WithProperties('%(python)s'), 'setup.py', 'install'],
                                workdir=WithProperties('%(virtualenv)s/src/' + package),
                                description='install ' + package,
                                haltOnFailure=True))