[Checkins] SVN: keas.build/ first upload

Adam Groszer agroszer at gmail.com
Tue Aug 11 04:54:51 EDT 2009


Log message for revision 102652:
  first upload

Changed:
  A   keas.build/branches/
  A   keas.build/tags/
  A   keas.build/trunk/
  A   keas.build/trunk/CHANGES.txt
  A   keas.build/trunk/README.txt
  A   keas.build/trunk/bootstrap.py
  A   keas.build/trunk/buildout.cfg
  A   keas.build/trunk/setup.py
  A   keas.build/trunk/src/
  A   keas.build/trunk/src/keas/
  A   keas.build/trunk/src/keas/__init__.py
  A   keas.build/trunk/src/keas/build/
  A   keas.build/trunk/src/keas/build/__init__.py
  A   keas.build/trunk/src/keas/build/base.py
  A   keas.build/trunk/src/keas/build/build.py
  A   keas.build/trunk/src/keas/build/deploy.py
  A   keas.build/trunk/src/keas/build/install.py
  A   keas.build/trunk/src/keas/build/package.py
  A   keas.build/trunk/src/keas/build/sample/
  A   keas.build/trunk/src/keas/build/sample/buildout.cfg
  A   keas.build/trunk/src/keas/build/sample/moo/
  A   keas.build/trunk/src/keas/build/sample/moo/Deploy.cfg
  A   keas.build/trunk/src/keas/build/sample/moo/Installers.cfg
  A   keas.build/trunk/src/keas/build/sample/moo/moo-Instance-Template.cfg
  A   keas.build/trunk/src/keas/build/sample/moo/moo-Project-Build.cfg
  A   keas.build/trunk/src/keas/build/sample/moo/moo-Release-Template.cfg
  A   keas.build/trunk/src/keas/build/ssh.py

-=-

Property changes on: keas.build/trunk
___________________________________________________________________
Added: svn:ignore
   + .installed.cfg
bin
develop-eggs
parts


Added: keas.build/trunk/CHANGES.txt
===================================================================
--- keas.build/trunk/CHANGES.txt	                        (rev 0)
+++ keas.build/trunk/CHANGES.txt	2009-08-11 08:54:50 UTC (rev 102652)
@@ -0,0 +1,15 @@
+=======
+CHANGES
+=======
+
+0.1.1
+-----
+
+- Bug Fix: If a proejct variant is specified for which no release have
+  been made, the build script now exits nicely with a human readable
+  error message.
+
+0.1.0
+-----
+
+- Initial release.


Property changes on: keas.build/trunk/CHANGES.txt
___________________________________________________________________
Added: svn:keywords
   + Date Author Id Revision
Added: svn:eol-style
   + native

Added: keas.build/trunk/README.txt
===================================================================
--- keas.build/trunk/README.txt	                        (rev 0)
+++ keas.build/trunk/README.txt	2009-08-11 08:54:50 UTC (rev 102652)
@@ -0,0 +1 @@
+A Build System for Keas.


Property changes on: keas.build/trunk/README.txt
___________________________________________________________________
Added: svn:keywords
   + Date Author Id Revision
Added: svn:eol-style
   + native

Added: keas.build/trunk/bootstrap.py
===================================================================
--- keas.build/trunk/bootstrap.py	                        (rev 0)
+++ keas.build/trunk/bootstrap.py	2009-08-11 08:54:50 UTC (rev 102652)
@@ -0,0 +1,52 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+
+$Id$
+"""
+
+import os, shutil, sys, tempfile, urllib2
+
+tmpeggs = tempfile.mkdtemp()
+
+ez = {}
+exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+                     ).read() in ez
+ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+import pkg_resources
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+if sys.platform == 'win32':
+    cmd = '"%s"' % cmd # work around spawn lamosity on windows
+
+ws = pkg_resources.working_set
+assert os.spawnle(
+    os.P_WAIT, sys.executable, sys.executable,
+    '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout',
+    dict(os.environ,
+         PYTHONPATH=
+         ws.find(pkg_resources.Requirement.parse('setuptools')).location
+         ),
+    ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout')
+import zc.buildout.buildout
+zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+shutil.rmtree(tmpeggs)


Property changes on: keas.build/trunk/bootstrap.py
___________________________________________________________________
Added: svn:keywords
   + Date Author Id Revision
Added: svn:eol-style
   + native

Added: keas.build/trunk/buildout.cfg
===================================================================
--- keas.build/trunk/buildout.cfg	                        (rev 0)
+++ keas.build/trunk/buildout.cfg	2009-08-11 08:54:50 UTC (rev 102652)
@@ -0,0 +1,30 @@
+[buildout]
+extends = http://download.zope.org/zope3.4/3.4.0/versions.cfg
+develop = .
+parts = scripts python test coverage-test coverage-report
+versions = versions
+
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = keas.build [test]
+
+[coverage-test]
+recipe = zc.recipe.testrunner
+eggs = keas.build [test]
+defaults = ['--coverage', '../../coverage']
+
+[coverage-report]
+recipe = zc.recipe.egg
+eggs = z3c.coverage
+scripts = coverage=coverage-report
+arguments = ('coverage', 'coverage/report')
+
+[python]
+recipe = zc.recipe.egg
+interpreter = python
+eggs = keas.build
+
+[scripts]
+recipe = zc.recipe.egg
+eggs = keas.build
\ No newline at end of file


Property changes on: keas.build/trunk/buildout.cfg
___________________________________________________________________
Added: svn:keywords
   + Date Author Id Revision
Added: svn:eol-style
   + native

Added: keas.build/trunk/setup.py
===================================================================
--- keas.build/trunk/setup.py	                        (rev 0)
+++ keas.build/trunk/setup.py	2009-08-11 08:54:50 UTC (rev 102652)
@@ -0,0 +1,72 @@
+##############################################################################
+#
+# Copyright (c) 2008 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Package setup.
+
+$Id$
+"""
+import os
+from setuptools import setup, find_packages
+
+def read(*rnames):
+    return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
+
+setup(
+    name='keas.build',
+    version = '0.1.3dev',
+    author = "Stephan Richter and the Zope Community",
+    author_email = "zope-dev at zope.org",
+    description='A Build System',
+    long_description=(
+        read('README.txt')
+        + '\n\n' +
+        read('CHANGES.txt')
+        ),
+    license = "ZPL 2.1",
+    keywords = "zope3 release build",
+    classifiers = [
+        'Development Status :: 4 - Beta',
+        'Environment :: Web Environment',
+        'Intended Audience :: Developers',
+        'License :: OSI Approved :: Zope Public License',
+        'Programming Language :: Python',
+        'Natural Language :: English',
+        'Operating System :: OS Independent',
+        'Topic :: Internet :: WWW/HTTP',
+        'Framework :: Zope3'],
+    url = 'http://pypi.python.org/pypi/keas.build',
+    packages = find_packages('src'),
+    include_package_data = True,
+    package_dir = {'': 'src'},
+    namespace_packages = ['keas'],
+    extras_require=dict(
+        test=[
+            'zope.testing',
+            ],
+        ),
+    install_requires=[
+        'BeautifulSoup',
+        #'pycrypto',
+        'Twisted',
+        'lxml',
+        'setuptools',
+        ],
+    zip_safe = False,
+    entry_points = """
+    [console_scripts]
+    build = keas.build.build:main
+    build-package = keas.build.package:main
+    install = keas.build.install:main
+    deploy = keas.build.deploy:main
+    """,
+    )


Property changes on: keas.build/trunk/setup.py
___________________________________________________________________
Added: svn:keywords
   + Date Author Id Revision
Added: svn:eol-style
   + native


Property changes on: keas.build/trunk/src
___________________________________________________________________
Added: svn:ignore
   + keas.build.egg-info


Added: keas.build/trunk/src/keas/__init__.py
===================================================================
--- keas.build/trunk/src/keas/__init__.py	                        (rev 0)
+++ keas.build/trunk/src/keas/__init__.py	2009-08-11 08:54:50 UTC (rev 102652)
@@ -0,0 +1,7 @@
+try:
+    # Declare this a namespace package if pkg_resources is available.
+    import pkg_resources
+    pkg_resources.declare_namespace(__name__)
+except ImportError:
+    pass
+


Property changes on: keas.build/trunk/src/keas/__init__.py
___________________________________________________________________
Added: svn:keywords
   + Date Author Id Revision
Added: svn:eol-style
   + native

Added: keas.build/trunk/src/keas/build/__init__.py
===================================================================
--- keas.build/trunk/src/keas/build/__init__.py	                        (rev 0)
+++ keas.build/trunk/src/keas/build/__init__.py	2009-08-11 08:54:50 UTC (rev 102652)
@@ -0,0 +1 @@
+# Make a package.


Property changes on: keas.build/trunk/src/keas/build/__init__.py
___________________________________________________________________
Added: svn:keywords
   + Date Author Id Revision
Added: svn:eol-style
   + native

Added: keas.build/trunk/src/keas/build/base.py
===================================================================
--- keas.build/trunk/src/keas/build/base.py	                        (rev 0)
+++ keas.build/trunk/src/keas/build/base.py	2009-08-11 08:54:50 UTC (rev 102652)
@@ -0,0 +1,147 @@
+##############################################################################
+#
+# Copyright (c) 2008 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Build a release
+
+$Id$
+"""
+__docformat__ = 'ReStructuredText'
+import StringIO
+import base64
+import httplib
+import logging
+import optparse
+import os
+import pkg_resources
+import subprocess
+import sys
+import urllib2
+import urlparse
+
+logger = logging.Logger('build')
+formatter = logging.Formatter('%(levelname)s - %(message)s')
+
+BUILD_SECTION = 'build'
+
+def do(cmd):
+    logger.debug('Command: ' + cmd)
+    p = subprocess.Popen(
+        cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
+    stdout, stderr = p.communicate()
+    if p.returncode != 0:
+        logger.error(u'An error occurred while running command: %s' %cmd)
+        logger.error('Error Output: \n' + stderr)
+        sys.exit(p.returncode)
+    logger.debug('Output: \n' + stdout)
+    return stdout
+
+def getInput(prompt, default, useDefaults):
+    if useDefaults:
+        return default
+    defaultStr = ''
+    if default:
+        defaultStr = ' [' + default + ']'
+    value = raw_input(prompt + defaultStr + ': ')
+    if not value:
+        return default
+    return value
+
+
+def uploadFile(path, url, username, password, offline):
+    filename = os.path.split(path)[-1]
+    if offline:
+        logger.info('Offline: File `%s` not uploaded.' %filename)
+    logger.debug('Uploading `%s` to %s' %(filename, url))
+    pieces = urlparse.urlparse(url)
+    Connection = httplib.HTTPConnection
+    if pieces[0] == 'https':
+        Connection = httplib.HTTPSConnection
+
+    base64string = base64.encodestring('%s:%s' % (username, password))[:-1]
+
+    conn = Connection(pieces[1])
+    conn.request(
+        'PUT',
+        pieces[2]+'/'+filename,
+        open(path, 'r').read(),
+        {"Authorization": "Basic %s" % base64string})
+
+    response = conn.getresponse()
+    if response.status != 201:
+        logger.error('Error uploading file. Code: %i (%s)' %(
+            response.status, response.reason))
+    else:
+        logger.info('File uploaded: %s' %filename)
+
+
+def guessNextVersion(version):
+    pieces = pkg_resources.parse_version(version)
+    newPieces = []
+    for piece in pieces:
+        try:
+            newPieces.append(int(piece))
+        except ValueError:
+            break
+    newPieces += [0]*(3-len(newPieces))
+    newPieces[-1] += 1
+    newVersion = '.'.join([str(piece) for piece in newPieces])
+    logger.debug('Last Version: %s -> %s' %(version, newVersion))
+    return newVersion
+
+
+parser = optparse.OptionParser()
+parser.add_option(
+    "-c", "--config-file", action="store",
+    dest="configFile", metavar="FILE",
+    help="The file containing the configuration of the project.")
+
+parser.add_option(
+    "-q", "--quiet", action="store_true",
+    dest="quiet", default=False,
+    help="When specified, no messages are displayed.")
+
+parser.add_option(
+    "-v", "--verbose", action="store_true",
+    dest="verbose", default=False,
+    help="When specified, debug information is created.")
+
+parser.add_option(
+    "-d", "--use-defaults", action="store_true",
+    dest="useDefaults", default=False,
+    help="When specified, no user input is required and the defaults are used.")
+
+parser.add_option(
+    "-o", "--offline-mode", action="store_true",
+    dest="offline", default=False,
+    help="When set, no server commands are executed.")
+
+parser.add_option(
+    "-n", "--next-version", action="store_true",
+    dest="nextVersion", default=False,
+    help="When set, the system guesses the next version to generate.")
+
+parser.add_option(
+    "-b", "--use-branch", action="store",
+    dest="branch", metavar="BRANCH", default=None,
+    help="When specified, this branch will be always used.")
+
+parser.add_option(
+    "--no-upload", action="store_true",
+    dest="noUpload", default=False,
+    help="When set, the generated configuration files are not uploaded.")
+
+parser.add_option(
+    "--no-branch-update", action="store_true",
+    dest="noBranchUpdate", default=False,
+    help=("When set, the branch is not updated with a new version after a "
+         "release is created."))


Property changes on: keas.build/trunk/src/keas/build/base.py
___________________________________________________________________
Added: svn:keywords
   + Date Author Id Revision
Added: svn:eol-style
   + native

Added: keas.build/trunk/src/keas/build/build.py
===================================================================
--- keas.build/trunk/src/keas/build/build.py	                        (rev 0)
+++ keas.build/trunk/src/keas/build/build.py	2009-08-11 08:54:50 UTC (rev 102652)
@@ -0,0 +1,167 @@
+##############################################################################
+#
+# Copyright (c) 2008 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Build a release
+
+$Id$
+"""
+__docformat__ = 'ReStructuredText'
+import BeautifulSoup
+import ConfigParser
+import StringIO
+import base64
+import logging
+import pkg_resources
+import re
+import sys
+import urllib2
+from keas.build import base, package
+
+logger = base.logger
+
+def findProjectVersions(project, config, options):
+    if options.offline:
+        logger.info('Offline: Skip looking for project versions.')
+        return []
+    url = config.get(base.BUILD_SECTION, 'buildout-server') + project + '/'
+    logger.debug('Package Index: ' + url)
+    req = urllib2.Request(url)
+
+    username = config.get(base.BUILD_SECTION, 'buildout-server-username')
+    password = config.get(base.BUILD_SECTION, 'buildout-server-password')
+    base64string = base64.encodestring('%s:%s' % (username, password))[:-1]
+    req.add_header("Authorization", "Basic %s" % base64string)
+
+    try:
+        soup = BeautifulSoup.BeautifulSoup(urllib2.urlopen(req).read())
+    except urllib2.HTTPError, err:
+        logger.error("There was an error accessing %s: %s" % (url, err))
+        return []
+    versions = [tag.contents[0][len(project)+1:-4]
+                for tag in soup('a')
+                if re.match(project+'-[0-9]', tag.contents[0])]
+
+    return sorted(versions, key=lambda x: pkg_resources.parse_version(x))
+
+
+def build(configFile, options):
+    # Read the configuration file.
+    logger.info('Loading configuration file: ' + configFile)
+    config = ConfigParser.RawConfigParser()
+    config.read(configFile)
+
+    # Create the project config parser
+    logger.info('Creating Project Configuration')
+    projectParser = ConfigParser.RawConfigParser()
+    if config.has_option(base.BUILD_SECTION, 'template'):
+        template = config.get(base.BUILD_SECTION, 'template')
+        logger.info('Loading Project Configuration Template: ' + template)
+        projectParser.read([template])
+    if not projectParser.has_section('versions'):
+        projectParser.add_section('versions')
+
+    # Determine all versions of the important packages
+    for pkg in config.get(base.BUILD_SECTION, 'packages').split():
+        customPath = None
+        if ':' in pkg:
+            pkg, customPath = pkg.split(':')
+        builder = package.PackageBuilder(pkg, options)
+        version = builder.runCLI(configFile, True)
+        projectParser.set('versions', pkg, version)
+
+    # Write the new configuration file to disk
+    projectName = config.get(base.BUILD_SECTION, 'name')
+    defaultVersion = configVersion = config.get(base.BUILD_SECTION, 'version')
+    projectVersions = findProjectVersions(projectName, config, options)
+    if projectVersions:
+        defaultVersion = projectVersions[-1]
+    if options.nextVersion or configVersion == '+':
+        defaultVersion = base.guessNextVersion(defaultVersion)
+    projectVersion = base.getInput(
+        'Project Version', defaultVersion, options.useDefaults)
+
+    projectConfigFilename = '%s-%s.cfg' %(projectName, projectVersion)
+    logger.info('Writing project configuration file: ' + projectConfigFilename)
+    projectParser.write(open(projectConfigFilename, 'w'))
+
+    # Upload the release file
+    if not options.offline and not options.noUpload:
+        base.uploadFile(
+            projectConfigFilename,
+            config.get(base.BUILD_SECTION, 'buildout-server')+'/'+projectName,
+            config.get(base.BUILD_SECTION, 'buildout-server-username'),
+            config.get(base.BUILD_SECTION, 'buildout-server-password'),
+            options.offline)
+
+    # Create deployment configurations
+    for section in config.sections():
+        if section == base.BUILD_SECTION:
+            continue
+        logger.info('Building deployment configuration: ' + section)
+        logger.info('Loading deploy template file: ' +
+                    config.get(section, 'template'))
+        template = file(config.get(section, 'template'), 'r').read()
+        vars = dict([(name, value) for name, value in config.items(section)
+                     if name != 'template'])
+        vars['project-name'] = projectName
+        vars['project-version'] = projectVersion
+        vars['instance-name'] = section
+        deployConfigText = template %vars
+        deployConfigFilename = '%s-%s-%s.cfg' %(
+            config.get(base.BUILD_SECTION, 'name'), section, projectVersion)
+        deployConfig = ConfigParser.RawConfigParser()
+        deployConfig.readfp(StringIO.StringIO(deployConfigText))
+        deployConfig.set('buildout', 'extends', projectConfigFilename)
+        logger.info('Writing deployment file: ' + deployConfigFilename)
+        deployConfig.write(open(deployConfigFilename, 'w'))
+
+        # Upload the deployment file
+        if not options.offline and not options.noUpload:
+            base.uploadFile(
+                deployConfigFilename,
+                config.get(
+                    base.BUILD_SECTION, 'buildout-server')+'/'+projectName,
+                config.get(base.BUILD_SECTION, 'buildout-server-username'),
+                config.get(base.BUILD_SECTION, 'buildout-server-password'),
+                options.offline)
+
+
+def main(args=None):
+    # Make sure we get the arguments.
+    if args is None:
+        args = sys.argv[1:]
+    if not args:
+        args = ['-h']
+
+    # Set up logger handler
+    handler = logging.StreamHandler(sys.stdout)
+    formatter = logging.Formatter('%(levelname)s - %(message)s')
+    handler.setFormatter(base.formatter)
+    logger.addHandler(handler)
+
+    # Parse arguments
+    options, args = base.parser.parse_args(args)
+
+    logger.setLevel(logging.INFO)
+    if options.verbose:
+        logger.setLevel(logging.DEBUG)
+    if options.quiet:
+        logger.setLevel(logging.FATAL)
+
+    build(options.configFile, options)
+
+    # Remove the handler again.
+    logger.removeHandler(handler)
+
+    # Exit cleanly.
+    sys.exit(0)


Property changes on: keas.build/trunk/src/keas/build/build.py
___________________________________________________________________
Added: svn:keywords
   + Date Author Id Revision
Added: svn:eol-style
   + native

Added: keas.build/trunk/src/keas/build/deploy.py
===================================================================
--- keas.build/trunk/src/keas/build/deploy.py	                        (rev 0)
+++ keas.build/trunk/src/keas/build/deploy.py	2009-08-11 08:54:50 UTC (rev 102652)
@@ -0,0 +1,119 @@
+##############################################################################
+#
+# Copyright (c) 2008 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Package Deployment
+
+$Id$
+"""
+__docformat__ = 'ReStructuredText'
+import ConfigParser
+import logging
+import optparse
+import subprocess
+import sys
+from keas.build import base, ssh
+
+logger = base.logger
+
+def doSSH(cmd, host, username, password):
+    logger.info('%s:%s@%s # %s' %(username, password, host, cmd))
+    # Since I am too stupid to understand twisted, we execute the ssh command
+    # in a sub-process.
+    line = sys.executable
+    line += ' -c "import sys; sys.path = %r; ' %sys.path
+    line += 'from keas.build import ssh; '
+    line += 'print ssh.run(%r, %r, %r, %r)"' %(cmd, host, username, password)
+    p = subprocess.Popen(
+        line,
+        stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
+    p.wait()
+    if p.returncode != 0:
+        logger.error(u'An error occurred while running command: %s' %cmd)
+        error = p.stderr.read()
+        logger.error('Error Output: \n' + error)
+        sys.exit(p.returncode)
+    error = p.stderr.read()
+    if error:
+        logger.error('Error Output: \n' + error)
+    output = p.stdout.read()
+    if output:
+        logger.debug('Output: \n' + output)
+    return output
+
+class Deployment(object):
+
+    def __init__(self, options):
+        self.options = options
+
+    def runCLI(self):
+        # 1. Read the configuration file.
+        logger.info('Loading configuration file: ' + self.options.configFile)
+        config = ConfigParser.RawConfigParser()
+        config.read(self.options.configFile)
+        # 2. Deploy each component listed in the configuration
+        for section in config.sections():
+            logger.info('Deploying ' + section)
+            for cmd in config.get(section, 'commands').strip().split('\n'):
+                logger.debug('Run command: ' + cmd)
+                result = doSSH(
+                    cmd,
+                    config.get(section, 'server'),
+                    config.get(section, 'username'),
+                    config.get(section, 'password'))
+                logger.debug(result)
+
+parser = optparse.OptionParser()
+parser.add_option(
+    "-c", "--config-file", action="store",
+    dest="configFile", metavar="FILE",
+    help="The file containing the deployment configuration.")
+
+parser.add_option(
+    "-q", "--quiet", action="store_true",
+    dest="quiet", default=False,
+    help="When specified, no messages are displayed.")
+
+parser.add_option(
+    "-v", "--verbose", action="store_true",
+    dest="verbose", default=False,
+    help="When specified, debug information is created.")
+
+def main(args=None):
+    # Make sure we get the arguments.
+    if args is None:
+        args = sys.argv[1:]
+    if not args:
+        args = ['-h']
+
+    # Set up logger handler
+    handler = logging.StreamHandler(sys.stdout)
+    handler.setFormatter(base.formatter)
+    logger.addHandler(handler)
+
+    # Parse arguments
+    options, args = parser.parse_args(args)
+
+    logger.setLevel(logging.INFO)
+    if options.verbose:
+        logger.setLevel(logging.DEBUG)
+    if options.quiet:
+        logger.setLevel(logging.FATAL)
+
+    deployment = Deployment(options)
+    deployment.runCLI()
+
+    # Remove the handler again.
+    logger.removeHandler(handler)
+
+    # Exit cleanly.
+    sys.exit(0)


Property changes on: keas.build/trunk/src/keas/build/deploy.py
___________________________________________________________________
Added: svn:keywords
   + Date Author Id Revision
Added: svn:eol-style
   + native

Added: keas.build/trunk/src/keas/build/install.py
===================================================================
--- keas.build/trunk/src/keas/build/install.py	                        (rev 0)
+++ keas.build/trunk/src/keas/build/install.py	2009-08-11 08:54:50 UTC (rev 102652)
@@ -0,0 +1,220 @@
+##############################################################################
+#
+# Copyright (c) 2008 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Package Builder
+
+$Id$
+"""
+__docformat__ = 'ReStructuredText'
+import BeautifulSoup
+import base64
+import logging
+import optparse
+import pkg_resources
+import re
+import sys
+import urllib2
+from keas.build import base
+
+logger = base.logger
+
+class Installer(object):
+
+    def __init__(self, options):
+        self.options = options
+
+    def getProjects(self):
+        logger.debug('Package Index: ' + self.options.url)
+        req = urllib2.Request(self.options.url)
+
+        if self.options.username:
+            base64string = base64.encodestring(
+                '%s:%s' % (self.options.username, self.options.password))[:-1]
+            req.add_header("Authorization", "Basic %s" % base64string)
+
+        soup = BeautifulSoup.BeautifulSoup(urllib2.urlopen(req).read())
+        projects = [tag.get('href').replace('/', '')
+                    for tag in soup('a')
+                    if tag.parent.name == 'td' and tag.get('href') != '/']
+        projects = sorted(projects)
+        logger.debug('Found projects: %s' %' '.join(projects))
+        return projects
+
+    def getVariants(self, project):
+        logger.debug('Package Index: ' + self.options.url)
+        req = urllib2.Request(self.options.url + project)
+
+        if self.options.username:
+            base64string = base64.encodestring(
+                '%s:%s' % (self.options.username, self.options.password))[:-1]
+            req.add_header("Authorization", "Basic %s" % base64string)
+
+        soup = BeautifulSoup.BeautifulSoup(urllib2.urlopen(req).read())
+        variants = []
+        for tag in soup('a'):
+            text = tag.contents[0]
+            if not text.startswith(project):
+                continue
+            if len(text.split('-')) != 3:
+                continue
+            variant = text.split('-')[1]
+            if variant in variants:
+                continue
+            variants.append(variant)
+        variants = sorted(variants)
+        logger.debug('Found variants: %s' %' '.join(variants))
+        return variants
+
+    def getVersions(self, project, variant):
+        logger.debug('Package Index: ' + self.options.url)
+        req = urllib2.Request(self.options.url + project)
+
+        if self.options.username:
+            base64string = base64.encodestring(
+                '%s:%s' % (self.options.username, self.options.password))[:-1]
+            req.add_header("Authorization", "Basic %s" % base64string)
+
+        soup = BeautifulSoup.BeautifulSoup(urllib2.urlopen(req).read())
+        versions = []
+        for tag in soup('a'):
+            text = tag.contents[0]
+            if not text.startswith(project+'-'+variant):
+                continue
+            version = text.split('-')[-1][:-4]
+            if version in versions:
+                continue
+            versions.append(version)
+        versions = sorted(
+            versions, key=lambda x: pkg_resources.parse_version(x))
+        logger.debug('Found versions: %s' %' '.join(versions))
+        return versions
+
+    def runCLI(self):
+        # 1. Get the project to be installed.
+        project = self.options.project
+        if project is None:
+            projects = self.getProjects()
+            print 'Projects'
+            for name in projects:
+                print '  * ' + name
+            project = base.getInput('Project', projects[0], False)
+        # 2. Get the variant of the project.
+        variant = self.options.variant
+        if variant is None:
+            variants = self.getVariants(project)
+            print 'Variants'
+            for name in variants:
+                print '  * ' + name
+            variant = base.getInput('Variant', variants[0], False)
+        # 3. Get the version of the project.
+        version = self.options.version
+        if version is None:
+            versions = self.getVersions(project, variant)
+            if len(versions) == 0:
+                print "Sorry, but there have not been any", project, variant, "releases yet."
+                sys.exit(0)
+            if self.options.latest:
+                version = versions[-1]
+            else:
+                print 'Versions'
+                for name in versions:
+                    print '  * ' + name
+                version = base.getInput('Version', versions[-1], False)
+        # 4. Install the package
+        base.do('%s -t 2 -%sc %s%s/%s-%s-%s.cfg' %(
+            self.options.buildout,
+            "vvvvv" if self.options.verbose else "",
+            self.options.url,
+            project,
+            project, variant, version))
+
+parser = optparse.OptionParser()
+parser.add_option(
+    "-u", "--url", action="store",
+    dest="url", metavar="URL",
+    help="The base URL at which the releases can be found.")
+
+parser.add_option(
+    "-p", "--project", action="store",
+    dest="project", metavar="PROJECT",
+    help="The name of the project to be installed.")
+
+parser.add_option(
+    "-V", "--variant", action="store",
+    dest="variant", metavar="VARIANT",
+    help="The variant of the project to be installed.")
+
+parser.add_option(
+    "-v", "--version", action="store",
+    dest="version", metavar="VERSION",
+    help="The version of the project to be installed.")
+
+parser.add_option(
+    "-l", "--latest", action="store_true",
+    dest="latest", default=False,
+    help="When specified, the latest version will be chosen.")
+
+parser.add_option(
+    "--username", action="store",
+    dest="username", metavar="USER", default=None,
+    help="The username needed to access the site.")
+
+parser.add_option(
+    "--password", action="store",
+    dest="password", metavar="PASSWORD",
+    help="The password needed to access the site.")
+
+parser.add_option(
+    "-b", "--buildout-path", action="store",
+    dest="buildout", metavar="PATH", default="buildout",
+    help="The path to the buildout executable.")
+
+parser.add_option(
+    "--quiet", action="store_true",
+    dest="quiet", default=False,
+    help="When specified, no messages are displayed.")
+
+parser.add_option(
+    "--verbose", action="store_true",
+    dest="verbose", default=False,
+    help="When specified, debug information is created.")
+
+def main(args=None):
+    # Make sure we get the arguments.
+    if args is None:
+        args = sys.argv[1:]
+    if not args:
+        args = ['-h']
+
+    # Set up logger handler
+    handler = logging.StreamHandler(sys.stdout)
+    handler.setFormatter(base.formatter)
+    logger.addHandler(handler)
+
+    # Parse arguments
+    options, args = parser.parse_args(args)
+
+    logger.setLevel(logging.INFO)
+    if options.verbose:
+        logger.setLevel(logging.DEBUG)
+    if options.quiet:
+        logger.setLevel(logging.FATAL)
+
+    installer = Installer(options)
+    installer.runCLI()
+
+    # Remove the handler again.
+    logger.removeHandler(handler)
+
+    # Exit cleanly.
+    sys.exit(0)


Property changes on: keas.build/trunk/src/keas/build/install.py
___________________________________________________________________
Added: svn:keywords
   + Date Author Id Revision
Added: svn:eol-style
   + native

Added: keas.build/trunk/src/keas/build/package.py
===================================================================
--- keas.build/trunk/src/keas/build/package.py	                        (rev 0)
+++ keas.build/trunk/src/keas/build/package.py	2009-08-11 08:54:50 UTC (rev 102652)
@@ -0,0 +1,329 @@
+##############################################################################
+#
+# Copyright (c) 2008 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Package Builder
+
+$Id$
+"""
+__docformat__ = 'ReStructuredText'
+import BeautifulSoup
+import ConfigParser
+import base64
+import logging
+import lxml.etree
+import optparse
+import os
+import pkg_resources
+import re
+import shutil
+import sys
+import tempfile
+import urllib
+import urllib2
+from keas.build import base
+
+logger = base.logger
+
+class PackageBuilder(object):
+
+    pkg = None
+    customPath = None
+    options = None
+
+    packageIndexUrl = None
+    packageIndexUsername = None
+    packageIndexPassword = None
+
+    svnRepositoryUrl = None
+    svnRepositoryUsername = None
+    svnRepositoryPassword = None
+
+    def __init__(self, pkg, options):
+        self.pkg = pkg
+        self.options = options
+
+    def getTagURL(self, version):
+        reposUrl = self.svnRepositoryUrl
+        if self.customPath:
+            reposUrl = urllib.basejoin(reposUrl, self.customPath)
+            tagUrl = reposUrl.split('%s')[0] + 'tags/%s-%s' %(self.pkg, version)
+        else:
+            tagUrl = reposUrl + 'tags/%s-%s' %(self.pkg, version)
+        logger.debug('Tag URL: ' + tagUrl)
+        return tagUrl
+
+    def getBranchURL(self, branch):
+        reposUrl = self.svnRepositoryUrl
+        if self.customPath:
+            reposUrl = urllib.basejoin(reposUrl, self.customPath)
+            branchUrl = reposUrl %('branches/' + branch)
+            if branch == 'trunk':
+                branchUrl = reposUrl %branch
+        else:
+            branchUrl = reposUrl + 'branches/' + branch + '/' + self.pkg + '/'
+            if branch == 'trunk':
+                branchUrl = reposUrl + 'trunk/' + self.pkg
+        logger.debug('Branch URL: ' + branchUrl)
+        return branchUrl
+
+    def getRevision(self, url):
+        xml = base.do('svn info --xml ' + url)
+        elem = lxml.etree.fromstring(xml)
+        revision = elem.xpath('/info/entry/commit/@revision')
+        if not revision:
+            revision = 0
+        else:
+            revision = int(revision[0])
+        logger.debug('Revision for %s: %i' %(url, revision))
+        return revision
+
+    def findVersions(self):
+        if self.options.offline:
+            logger.info('Offline: Skip looking for versions.')
+            return []
+        logger.debug('Package Index: ' + self.packageIndexUrl)
+        req = urllib2.Request(self.packageIndexUrl)
+
+        if self.packageIndexUsername:
+            base64string = base64.encodestring(
+                '%s:%s' % (self.packageIndexUsername,
+                           self.packageIndexPassword))[:-1]
+            req.add_header("Authorization", "Basic %s" % base64string)
+
+        soup = BeautifulSoup.BeautifulSoup(urllib2.urlopen(req).read())
+        versions = [tag.contents[0][len(self.pkg)+1:-7]
+                    for tag in soup('a')
+                    if tag.contents[0].startswith(self.pkg)]
+        logger.debug('All versions: ' + ' '.join(versions))
+
+        # filter versions by ones that came from the branch we are building from.
+        if self.options.branch and '-' in self.options.branch:
+            branchVersion = self.options.branch.split('-')[-1]
+            branchVersionParts = pkg_resources.parse_version(branchVersion)[:-1]
+            def fromBranch(v):
+                versionParts = pkg_resources.parse_version(v)
+                return versionParts[:len(branchVersionParts)] == branchVersionParts
+            versions = filter(fromBranch, versions)
+        return sorted(versions, key=lambda x: pkg_resources.parse_version(x))
+
+    def getBranches(self):
+        if self.options.offline:
+            logger.info('Offline: Skip looking for branches.')
+            return []
+        url = self.svnRepositoryUrl
+        if self.customPath:
+            url = urllib.basejoin(url, self.customPath.split('%s')[0])
+        url += 'branches'
+        logger.debug('Branches URL: ' + url)
+        req = urllib2.Request(url)
+
+        if self.svnRepositoryUsername:
+            base64string = base64.encodestring('%s:%s' % (
+                self.svnRepositoryUsername, self.svnRepositoryPassword))[:-1]
+            req.add_header("Authorization", "Basic %s" % base64string)
+
+        soup = BeautifulSoup.BeautifulSoup(urllib2.urlopen(req).read())
+        branches  = [tag.contents[0][:-1]
+                     for tag in soup('ul')[0]('a')
+                     if tag.contents[0] != '..']
+        logger.debug('Branches: ' + ' '.join(branches))
+        return branches
+
+    def hasChangedSince(self, version, branch):
+        # setup.py gets changed on the branch after the tag is created, so
+        # that the branch always has a later revision. So let's check the
+        # source directory instead.
+        branchUrl = self.getBranchURL(branch) + '/src'
+        tagUrl = self.getTagURL(version)
+        changed = self.getRevision(branchUrl) > self.getRevision(tagUrl)
+        if changed:
+            logger.info(
+                'Branch %r changed since the release of version %s' %(
+                branch, version))
+        return changed
+
+    def createRelease(self, version, branch):
+        logger.info('Creating release %r for %r from branch %r' %(
+            version, self.pkg, branch))
+        # 0. Skip creating releases in offline mode.
+        if self.options.offline:
+            logger.info('Offline: Skip creating a release.')
+            return
+        # 1. Create Release Tag
+        branchUrl = self.getBranchURL(branch)
+        tagUrl = self.getTagURL(version)
+
+        base.do('svn cp -m "Create release tag" %s %s' %(branchUrl, tagUrl))
+
+        # 2. Download tag
+        buildDir = tempfile.mkdtemp()
+        tagDir = os.path.join(buildDir, '%s-%s' %(self.pkg, version))
+        base.do('svn co %s %s' %(tagUrl, tagDir))
+
+        # 3. Create release
+        # 3.1. Remove setup.cfg
+        setupCfgPath = os.path.join(tagDir, 'setup.cfg')
+        if os.path.exists(setupCfgPath):
+            os.remove(setupCfgPath)
+        # 3.2. Update the version
+        setuppy = file(os.path.join(tagDir, 'setup.py'), 'r').read()
+        setuppy = re.sub(
+            "version ?= ?'(.*)',", "version = '%s'," %version, setuppy)
+        file(os.path.join(tagDir, 'setup.py'), 'w').write(setuppy)
+        # 3.3. Check it all in
+        base.do('svn ci -m "Prepare for release." %s' %(tagDir))
+        # 3.4. Create distribution
+        base.do('cd %s && python setup.py sdist' %(tagDir))
+
+        # 4. Upload the distribution
+        distributionFileName = os.path.join(
+            tagDir, 'dist', '%s-%s.tar.gz' %(self.pkg, version))
+        if not self.options.noUpload:
+            base.uploadFile(
+                distributionFileName,
+                self.packageIndexUrl,
+                self.packageIndexUsername, self.packageIndexPassword,
+                self.options.offline)
+
+        # 5. Update the start branch to the next devel version
+        if not self.options.noBranchUpdate:
+            # 5.1. Check out the branch.
+            branchDir = os.path.join(buildDir, 'branch')
+            base.do('svn co %s %s' %(branchUrl, branchDir))
+            # 5.2. Get the current version.
+            setuppy = file(os.path.join(branchDir, 'setup.py'), 'r').read()
+            currVersion = re.search("version ?= ?'(.*)',", setuppy).groups()[0]
+            # 5.3. Update setup/py to the next version of the currently
+            #      released one
+            newVersion = base.guessNextVersion(version) + 'dev'
+            setuppy = re.sub(
+                "version ?= ?'(.*)',", "version = '%s'," %newVersion, setuppy)
+            file(os.path.join(branchDir, 'setup.py'), 'w').write(setuppy)
+            # 5.4. Check in the changes.
+            base.do('svn ci -m "Update version number." %s' %(branchDir))
+
+        # 6. Cleanup
+        shutil.rmtree(buildDir)
+
+    def runCLI(self, configFile, askToCreateRelease=False):
+        logger.info('Start releasing new version of ' + self.pkg)
+        # 1. Read the configuration file.
+        logger.info('Loading configuration file: ' + configFile)
+        config = ConfigParser.RawConfigParser()
+        config.read(configFile)
+        # 1.1. Get package index info.
+        self.packageIndexUrl = config.get(
+            base.BUILD_SECTION, 'package-index')
+        self.packageIndexUsername = config.get(
+            base.BUILD_SECTION, 'package-index-username')
+        self.packageIndexPassword = config.get(
+            base.BUILD_SECTION, 'package-index-password')
+        # 1.2. Get svn repository info.
+        self.svnRepositoryUrl = config.get(
+            base.BUILD_SECTION, 'svn-repos')
+        self.svnRepositoryUsername = config.get(
+            base.BUILD_SECTION, 'svn-repos-username')
+        self.svnRepositoryPassword = config.get(
+            base.BUILD_SECTION, 'svn-repos-password')
+        # 1.3. Determine the possibly custom path.
+        for pkg in config.get(base.BUILD_SECTION, 'packages').split():
+            if pkg.startswith(self.pkg):
+                if ':' in pkg:
+                    self.customPath = pkg.split(':')[1]
+                break
+        # 2. Find all versions.
+        versions = self.findVersions()
+        logger.info('Existing %s versions: %s' % (
+            self.pkg, ' | '.join(reversed(versions))))
+        # 3. Determine the default version to suggest.
+        defaultVersion = None
+        if versions:
+            # 3.1. If the branch was specified, check whether it changed since
+            # the last release.
+            changed = False
+            if self.options.branch:
+                changed = self.hasChangedSince(
+                    versions[-1], self.options.branch)
+            # 3.2. If the branch changed and the next version should be
+            # suggested, let's find the next version.
+            if self.options.nextVersion and changed:
+                defaultVersion = base.guessNextVersion(versions[-1])
+            else:
+                defaultVersion = versions[-1]
+        while True:
+            version = base.getInput(
+                'Version for `%s`' %self.pkg, defaultVersion,
+                self.options.useDefaults and defaultVersion is not None)
+            if version not in versions and not self.options.offline:
+                if askToCreateRelease:
+                    print 'The release %s-%s does not exist.' %(pkg, version)
+                    doRelease = base.getInput(
+                        'Do you want to create it? yes/no', 'yes',
+                        self.options.useDefaults)
+                    if doRelease == 'no':
+                        continue
+                # 4. Now create a release for this version.
+                if not self.options.offline:
+                    # 4.1. Determine the branch from which to base the release
+                    # on.
+                    branch = self.options.branch
+                    if branch is None:
+                        print 'Available Branches:'
+                        for branch in self.getBranches():
+                            print '  * ' + branch
+                        print '  * trunk'
+                        branch = base.getInput(
+                            'What branch do you want to use?', 'trunk',
+                            self.options.useDefaults)
+                    # 4.2. Create the release.
+                    self.createRelease(version, branch)
+            break
+        # 5. Return the version number.
+        logger.info('Chosen version: ' + version)
+        return version
+
+
+def main(args=None):
+    # Make sure we get the arguments.
+    if args is None:
+        args = sys.argv[1:]
+    if not args:
+        args = ['-h']
+
+    # Set up logger handler
+    handler = logging.StreamHandler(sys.stdout)
+    handler.setFormatter(base.formatter)
+    logger.addHandler(handler)
+
+    # Parse arguments
+    options, args = base.parser.parse_args(args)
+
+    logger.setLevel(logging.INFO)
+    if options.verbose:
+        logger.setLevel(logging.DEBUG)
+    if options.quiet:
+        logger.setLevel(logging.FATAL)
+
+    if len(args) == 0:
+        print "No package was specified."
+        print "Usage: build-package [options] package1 package2 ..."
+        sys.exit(0)
+    for pkg in args:
+        builder = PackageBuilder(pkg, options)
+        builder.runCLI(options.configFile)
+
+    # Remove the handler again.
+    logger.removeHandler(handler)
+
+    # Exit cleanly.
+    sys.exit(0)


Property changes on: keas.build/trunk/src/keas/build/package.py
___________________________________________________________________
Added: svn:keywords
   + Date Author Id Revision
Added: svn:eol-style
   + native

Added: keas.build/trunk/src/keas/build/sample/buildout.cfg
===================================================================
--- keas.build/trunk/src/keas/build/sample/buildout.cfg	                        (rev 0)
+++ keas.build/trunk/src/keas/build/sample/buildout.cfg	2009-08-11 08:54:50 UTC (rev 102652)
@@ -0,0 +1,10 @@
+[buildout]
+develop = .
+parts = build-moo-project
+
+[build-moo-project]
+recipe = zc.recipe.egg
+eggs = keas.build
+scripts = build=build-moo-project
+initialization =
+    sys.argv[1:1] = ['-c', 'moo/moo-Project-Build.cfg']
\ No newline at end of file


Property changes on: keas.build/trunk/src/keas/build/sample/buildout.cfg
___________________________________________________________________
Added: svn:keywords
   + Date Author Id Revision
Added: svn:eol-style
   + native

Added: keas.build/trunk/src/keas/build/sample/moo/Deploy.cfg
===================================================================
--- keas.build/trunk/src/keas/build/sample/moo/Deploy.cfg	                        (rev 0)
+++ keas.build/trunk/src/keas/build/sample/moo/Deploy.cfg	2009-08-11 08:54:50 UTC (rev 102652)
@@ -0,0 +1,18 @@
+[server-1]
+server = server-1.foobar.com
+username = username
+password = password
+commands =
+    /opt/moo/bin/moo stop
+    /usr/bin/install-moo-dev -l
+    /opt/moo/bin/moo start
+
+[server-2]
+server = server-2.foobar.com
+username = admin
+password = password
+commands =
+    /opt/moo/bin/moo stop
+    /usr/bin/install-moo-release -l
+    /opt/moo/bin/moo start
+


Property changes on: keas.build/trunk/src/keas/build/sample/moo/Deploy.cfg
___________________________________________________________________
Added: svn:keywords
   + Date Author Id Revision
Added: svn:eol-style
   + native

Added: keas.build/trunk/src/keas/build/sample/moo/Installers.cfg
===================================================================
--- keas.build/trunk/src/keas/build/sample/moo/Installers.cfg	                        (rev 0)
+++ keas.build/trunk/src/keas/build/sample/moo/Installers.cfg	2009-08-11 08:54:50 UTC (rev 102652)
@@ -0,0 +1,31 @@
+[buildout]
+extends = http://download.zope.org/zope3.4/3.4.0/versions.cfg
+parts = install-moo-dev install-moo-release
+directory = /opt/moo/install
+extensions = lovely.buildouthttp
+find-links = http://eggs.foobar.com
+versions = versions
+
+[buildout-bin]
+recipe = zc.recipe.egg
+eggs = zc.buildout
+scripts = buildout
+
+[install-moo-dev]
+recipe = zc.recipe.egg
+eggs = keas.build
+scripts = install=install-moo-dev
+initialization =
+    sys.argv[1:1] = ['-u', 'http://eggs.foobar.com/',
+                     '--username', 'username', '--password', 'password',
+                     '-p', 'moo', '-V', 'Development']
+
+
+[install-moo-release]
+recipe = zc.recipe.egg
+eggs = keas.build
+scripts = install=install-moo-release
+initialization =
+    sys.argv[1:1] = ['-u', 'http://eggs.foobar.com/',
+                     '--username', 'username', '--password', 'password',
+                     '-p', 'moo', '-V', 'Release']


Property changes on: keas.build/trunk/src/keas/build/sample/moo/Installers.cfg
___________________________________________________________________
Added: svn:keywords
   + Date Author Id Revision
Added: svn:eol-style
   + native

Added: keas.build/trunk/src/keas/build/sample/moo/moo-Instance-Template.cfg
===================================================================
--- keas.build/trunk/src/keas/build/sample/moo/moo-Instance-Template.cfg	                        (rev 0)
+++ keas.build/trunk/src/keas/build/sample/moo/moo-Instance-Template.cfg	2009-08-11 08:54:50 UTC (rev 102652)
@@ -0,0 +1,42 @@
+[buildout]
+parts += moo
+directory = %(install-dir)s
+
+[database]
+recipe = zc.recipe.filestorage
+
+[moo]
+recipe = zc.zope3recipes:instance
+application = moo-app
+zope.conf =
+  <zodb>
+    cache-size 20000
+    <filestorage>
+      path ${database:path}
+      create true
+    </filestorage>
+  </zodb>
+
+  <server>
+    type WSGI-HTTP
+    address %(port)s
+  </server>
+
+  <eventlog>
+    level %(loglevel)s
+    <logfile>
+      formatter zope.exceptions.log.Formatter
+      path %(logdir)s/moo.log
+      max-size 50MB
+      old-files 5
+    </logfile>
+  </eventlog>
+
+  <accesslog>
+    <logfile>
+      level info
+      path %(logdir)s/moo-access.log
+      max-size 50MB
+      old-files 5
+    </logfile>
+  </accesslog>


Property changes on: keas.build/trunk/src/keas/build/sample/moo/moo-Instance-Template.cfg
___________________________________________________________________
Added: svn:keywords
   + Date Author Id Revision
Added: svn:eol-style
   + native

Added: keas.build/trunk/src/keas/build/sample/moo/moo-Project-Build.cfg
===================================================================
--- keas.build/trunk/src/keas/build/sample/moo/moo-Project-Build.cfg	                        (rev 0)
+++ keas.build/trunk/src/keas/build/sample/moo/moo-Project-Build.cfg	2009-08-11 08:54:50 UTC (rev 102652)
@@ -0,0 +1,31 @@
+[build]
+name = moo
+version = +
+template = moo/moo-Release-Template.cfg
+package-index = https://eggs.foobar.com/
+package-index-username = username
+package-index-password = password
+buildout-server = https://eggs.foobar.com/
+buildout-server-username = username
+buildout-server-password = password
+svn-repos = https://svn.zope.org/svn/
+svn-repos-username = username
+svn-repos-password = password
+packages = moo.base
+           moo.skin
+           moo.razor
+           moo.app
+
+[Development]
+template = moo/moo-Instance-Template.cfg
+port = 8080
+logdir = /var/log/moo
+install-dir = /opt/moo
+loglevel = debug
+
+[Release]
+template = moo/moo-Instance-Template.cfg
+port = 8081
+logdir = /var/log/moo
+install-dir = /opt/moo
+loglevel = warn
\ No newline at end of file


Property changes on: keas.build/trunk/src/keas/build/sample/moo/moo-Project-Build.cfg
___________________________________________________________________
Added: svn:keywords
   + Date Author Id Revision
Added: svn:eol-style
   + native

Added: keas.build/trunk/src/keas/build/sample/moo/moo-Release-Template.cfg
===================================================================
--- keas.build/trunk/src/keas/build/sample/moo/moo-Release-Template.cfg	                        (rev 0)
+++ keas.build/trunk/src/keas/build/sample/moo/moo-Release-Template.cfg	2009-08-11 08:54:50 UTC (rev 102652)
@@ -0,0 +1,39 @@
+[buildout]
+extends = http://download.zope.org/zope3.4/3.4.0/versions.cfg
+parts = test coverage-test coverage-report python
+extensions = lovely.buildouthttp
+find-links = http://eggs.foobar.com/
+versions = versions
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = moo.app
+
+[coverage-test]
+recipe = zc.recipe.testrunner
+eggs = moo.app
+defaults = ['--coverage', '../../coverage']
+
+[coverage-report]
+recipe = zc.recipe.egg
+eggs = z3c.coverage
+scripts = coverage=coverage-report
+arguments = ('coverage', 'coverage/report')
+
+[python]
+recipe = zc.recipe.egg
+interpreter = python
+eggs = moo.app
+
+[moo-app]
+recipe = zc.zope3recipes:app
+servers = zserver
+site.zcml = <include package="moo.app" file="app.zcml" />
+eggs = moo.app
+
+[zope3]
+location =
+
+[versions]
+lxml = 2.1.2
+mechanize = 0.1.8


Property changes on: keas.build/trunk/src/keas/build/sample/moo/moo-Release-Template.cfg
___________________________________________________________________
Added: svn:keywords
   + Date Author Id Revision
Added: svn:eol-style
   + native

Added: keas.build/trunk/src/keas/build/ssh.py
===================================================================
--- keas.build/trunk/src/keas/build/ssh.py	                        (rev 0)
+++ keas.build/trunk/src/keas/build/ssh.py	2009-08-11 08:54:50 UTC (rev 102652)
@@ -0,0 +1,110 @@
+##############################################################################
+#
+# Copyright (c) 2008 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""SSH tools
+
+$Id$
+"""
+import StringIO
+import logging
+import sys
+from twisted.conch.ssh import transport, userauth, connection, channel
+from twisted.conch.ssh.common import NS
+from twisted.internet import defer, protocol, reactor
+from keas.build import base
+
+class Transport(transport.SSHClientTransport):
+    user = None
+    password = None
+    cmd = None
+    output = None
+
+    def verifyHostKey(self, hostKey, fingerprint):
+        base.logger.debug('host key fingerprint: %s' % fingerprint)
+        return defer.succeed(1)
+
+    def connectionSecure(self):
+        conn = Connection()
+        conn.cmd = self.cmd
+        conn.output = self.output
+        self.requestService(UserAuth(self.user, self.password, conn))
+
+
+class UserAuth(userauth.SSHUserAuthClient):
+
+    def __init__(self, user, password, instance):
+        userauth.SSHUserAuthClient.__init__(self, user, instance)
+        self.password = password
+
+    def getPassword(self):
+        return defer.succeed(self.password)
+
+    def getPublicKey(self):
+        return  # Empty implementation: always use password auth
+
+
+class Connection(connection.SSHConnection):
+    cmd = None
+
+    def serviceStarted(self):
+        channel = Channel(2**16, 2**15, self)
+        channel.cmd = self.cmd
+        channel.output = self.output
+        self.openChannel(channel)
+
+
+class Channel(channel.SSHChannel):
+    name = 'session'    # must use this exact string
+    cmd = None
+    output = None
+
+    def openFailed(self, reason):
+        base.logger.error('"%s" failed: %s' % (self.cmd, reason))
+
+    def channelOpen(self, data):
+        self.welcome = data   # Might display/process welcome screen
+        d = self.conn.sendRequest(self, 'exec', NS(self.cmd), wantReply=1)
+
+    def dataReceived(self, data):
+        self.output.write(data)
+
+    def extReceived(self, dataType, data):
+        self.output.write(data)
+
+    def closed(self):
+        self.loseConnection()
+        reactor.stop()
+
+
+def run(cmd, host, username, password):
+    handler = logging.StreamHandler(sys.stdout)
+    handler.setFormatter(base.formatter)
+    base.logger.addHandler(handler)
+
+    output = StringIO.StringIO()
+    def createTransport(*args, **kwargs):
+        transport = Transport(*args, **kwargs)
+        transport.user = username
+        transport.password = password
+        transport.cmd = cmd
+        transport.output = output
+        return transport
+    protocol.ClientCreator(reactor, createTransport).connectTCP(host, 22)
+    reactor.run()
+
+    base.logger.removeHandler(handler)
+
+    return output.getvalue()
+
+if __name__ == '__main__':
+    print run(*sys.argv[1:])


Property changes on: keas.build/trunk/src/keas/build/ssh.py
___________________________________________________________________
Added: svn:keywords
   + Date Author Id Revision
Added: svn:eol-style
   + native



More information about the Checkins mailing list