Skip to content
This repository has been archived by the owner on May 13, 2020. It is now read-only.

Commit

Permalink
trying git support, first with BTrees
Browse files Browse the repository at this point in the history
  • Loading branch information
Adam Groszer committed Jan 21, 2013
1 parent 4287e02 commit 923aea8
Show file tree
Hide file tree
Showing 3 changed files with 235 additions and 20 deletions.
5 changes: 4 additions & 1 deletion rackspace.ini
Expand Up @@ -67,11 +67,14 @@ excludeVersions = 3.10.4
tagurl = svn://svn.zope.org/repos/main/ZODB/tags/

[BTrees]
# versions before 4.0.4 were SVN based
package = BTrees
minVersion =
minVersion = 4.0.4
maxVersion =
excludeVersions = 4.0.0
targets = py26_32 py26_64 py27_32 py27_64
repotype = git
#repourl = https://github.com/zopefoundation/BTrees.git

[persistent]
package = persistent
Expand Down
205 changes: 205 additions & 0 deletions src/zope/wineggbuilder/base.py
@@ -0,0 +1,205 @@
##############################################################################
#
# 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.
#
##############################################################################
"""base classes
"""
__docformat__ = 'ReStructuredText'
import logging
import optparse
import os
import shutil
import subprocess
import sys
import stat
import urllib2
import xmlrpclib

LOGGER = logging.Logger('build')
formatter = logging.Formatter('%(levelname)s - %(message)s')

is_win32 = sys.platform == 'win32'

BUILD_SECTION = 'build'

class Command(object):
def __init__(self, cwd=None, captureOutput=True, exitOnError=True):
self.cwd = cwd
self.captureOutput = captureOutput
self.exitOnError = exitOnError

def do(self, cmd):
LOGGER.debug('Command: ' + cmd)
if self.captureOutput:
stdout = stderr = subprocess.PIPE
else:
stdout = stderr = None
p = subprocess.Popen(
cmd, stdout=stdout, stderr=stderr,
shell=True, cwd=self.cwd)
stdout, stderr = p.communicate()
if stdout is None:
stdout = "See output above"
if stderr is None:
stderr = "See output above"
if p.returncode != 0:
LOGGER.error(u'An error occurred while running command: %s' %cmd)
LOGGER.error('Error Output: \n%s' % stderr)
if self.exitOnError:
sys.exit(p.returncode)
else:
raise OSError(p.returncode)
LOGGER.debug('Output: \n%s' % stdout)
return stdout


class Git(object):
def __init__(self, exitOnError=True):
self.cmd = self.commandKlass(exitOnError=exitOnError)

def clone(self, url, folder):
command = 'git clone %s %s' % (url, folder)
return self.cmd.do(command)

def checkout(self, branch):
command = 'git checkout %s' % branch
return self.cmd.do(command)


class SVN(object):
user = None
passwd = None
forceAuth = False
#hook to enable testing
commandKlass = Command

#TODO: spaces in urls+folder names???

def __init__(self, user=None, passwd=None,
forceAuth=False, exitOnError=True):
self.user = user
self.passwd = passwd
self.forceAuth = forceAuth
self.cmd = self.commandKlass(exitOnError=exitOnError)

def _addAuth(self, command):
auth = ''
if self.user:
auth = '--username %s --password %s' % (self.user, self.passwd)

if self.forceAuth:
auth += ' --no-auth-cache'

command = command.replace('##__auth__##', auth)
return command

def info(self, url):
command = 'svn info --non-interactive ##__auth__## --xml %s' % url
command = self._addAuth(command)
return self.cmd.do(command)

def ls(self, url):
command = 'svn ls --non-interactive ##__auth__## --xml %s' % url
command = self._addAuth(command)
return self.cmd.do(command)

def cp(self, fromurl, tourl, comment):
command = 'svn cp --non-interactive ##__auth__## -m "%s" %s %s' %(
comment, fromurl, tourl)
command = self._addAuth(command)
self.cmd.do(command)

def co(self, url, folder):
command = 'svn co --non-interactive ##__auth__## %s %s' % (url, folder)
command = self._addAuth(command)
self.cmd.do(command)

def ci(self, folder, comment):
command = 'svn ci --non-interactive ##__auth__## -m "%s" %s' % (
comment, folder)
command = self._addAuth(command)
self.cmd.do(command)

class PYPI(object):
def __init__(self):
self.proxy = xmlrpclib.ServerProxy('http://pypi.python.org/pypi')

def list_packages(self):
pass

def package_releases(self, package_name, show_hidden=False):
return self.proxy.package_releases(package_name, show_hidden)

def release_urls(self, package_name, version):
pass

def release_data(self, package_name, version):
pass

def search(self, spec, operator=None):
pass

def changelog(self, since):
pass

class URLGetter(object):
def get(self, url):
req = urllib2.Request(url)
return urllib2.urlopen(req).read()

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 checkRO(function, path, excinfo):
if (function == os.remove
and excinfo[0] == WindowsError
and excinfo[1].winerror == 5):
#Access is denied
#because it's a readonly file
os.chmod(path, stat.S_IWRITE)
os.remove(path)

def rmtree(dirname):
if is_win32:
shutil.rmtree(dirname, ignore_errors=False, onerror=checkRO)
else:
shutil.rmtree(dirname)

parser = optparse.OptionParser()
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 displayed.")

parser.add_option(
"-d", "--dryrun", action="store_true",
dest="dryrun", default=False,
help="When specified, no upload is done.")

parser.add_option(
"-s", "--status", action="store_true",
dest="status", default=False,
help="When specified, detailed status is output at the end.")
45 changes: 26 additions & 19 deletions src/zope/wineggbuilder/build.py
Expand Up @@ -14,19 +14,11 @@
"""Main builder stuff
"""
__docformat__ = 'ReStructuredText'
import StringIO
import base64
import httplib
import logging
import optparse
import os
import pkg_resources
import re
import subprocess
import sys
import tempfile
import urllib2
import urlparse
from collections import defaultdict

import BeautifulSoup
Expand All @@ -37,6 +29,7 @@

LOGGER = base.LOGGER


def getOption(config, section, name, default=None):
try:
return config.get(section, name)
Expand Down Expand Up @@ -128,6 +121,7 @@ class Package(object):
pypiKlass = base.PYPI
urlGetterKlass = base.URLGetter
svnKlass = base.SVN
gitKlass = base.Git

def __init__(self, sectionName, config, options, compilers):
self.sectionName = sectionName
Expand All @@ -138,15 +132,22 @@ def read(self, sectionName, config, compilers):
self.name = config.get(sectionName, 'package')
self.pypiurl = getOption(config, sectionName, 'pypiurl',
'http://pypi.python.org/simple/%s/' % self.name)
self.tagurl = getOption(config, sectionName, 'tagurl',
'svn://svn.zope.org/repos/main/%s/tags' % self.name)
if self.tagurl.endswith('/'):
self.tagurl = self.tagurl[:-1]
self.repotype = getOption(config, sectionName, 'repotype', 'svn')
if self.repotype == 'svn':
self.tagurl = getOption(config, sectionName, 'tagurl',
'svn://svn.zope.org/repos/main/%s/tags' % self.name)
if self.tagurl.endswith('/'):
self.tagurl = self.tagurl[:-1]
if self.repotype == 'git':
self.repourl = getOption(config, sectionName, 'repourl',
'https://github.com/zopefoundation/%s.git' % self.name)
if self.repourl.endswith('/'):
self.repourl = self.repourl[:-1]
self.minVersion = getOption(config, sectionName, 'minVersion')
self.maxVersion = getOption(config, sectionName, 'maxVersion')
self.needSource = bool(getOption(config, sectionName, 'needSource', 'True'))
self.excludeVersions = getOption(
config, sectionName, 'excludeVersions' ,'').split()
config, sectionName, 'excludeVersions', '').split()
self.targets = []
for target in config.get(sectionName, 'targets').split():
self.targets.append(compilers[target])
Expand Down Expand Up @@ -198,7 +199,7 @@ def build(self, status):
verFiles = defaultdict(list)
simple = self.urlGetterKlass().get(self.pypiurl)
soup = BeautifulSoup.BeautifulSoup(simple)
VERSION = re.compile(self.name+r'-(\d+\.\d+(\.\d+\w*){0,2})')
VERSION = re.compile(self.name + r'-(\d+\.\d+(\.\d+\w*){0,2})')
gotSource = False

for tag in soup('a'):
Expand All @@ -220,7 +221,6 @@ def build(self, status):
if self.needSource and not gotSource:
LOGGER.info("No source release (.zip/.tar.gz/.tgz) found")

svn = self.svnKlass(exitOnError=False)
for version in versions:
#3 check whether we need a build
needs = []
Expand All @@ -236,11 +236,17 @@ def build(self, status):
tmpfolder = tempfile.mkdtemp('wineggbuilder')
try:
try:
#3.1 svn co tag
svnurl = "%s/%s" % (self.tagurl, version)
svn.co(svnurl, tmpfolder)
if self.repotype == 'svn':
#3.1 svn co tag
svn = self.svnKlass(exitOnError=False)
svnurl = "%s/%s" % (self.tagurl, version)
svn.co(svnurl, tmpfolder)
if self.repotype == 'git':
git = self.gitKlass(exitOnError=False)
git.clone(self.repourl, tmpfolder)
git.checkout(version)
except OSError:
status.setStatus(self, version, "SVN error")
status.setStatus(self, version, "SVN/Git error")
else:
#3.2 build missing
for target in needs:
Expand All @@ -251,6 +257,7 @@ def build(self, status):
#3.3 del temp folder
base.rmtree(tmpfolder)


class Status(object):
def __init__(self, packages, targets):
self.data = {}
Expand Down

0 comments on commit 923aea8

Please sign in to comment.