Skip to content
This repository has been archived by the owner on Apr 24, 2019. It is now read-only.

Commit

Permalink
see CHANGES.txt
Browse files Browse the repository at this point in the history
  • Loading branch information
jodok committed Oct 3, 2008
1 parent 43c98da commit 7969d12
Show file tree
Hide file tree
Showing 6 changed files with 329 additions and 9 deletions.
11 changes: 8 additions & 3 deletions CHANGES.txt
Expand Up @@ -2,12 +2,17 @@
Changes for lovely.recipe
=========================


After
=====

BIG TODO: add tests for lovely.recipe.zeo and lovely.recipe.zope to test and
to show what this all is for.
- added the lovely.recipe:eggbox recipe

- INCOMPATIBLE CHANGE: moved zope recipies into an extra called "zope"
this requires one to write the extra in the recipe declaraion like
this lovely.recipe[zope]:<name>

- BIG TODO: add tests for lovely.recipe.zeo and lovely.recipe.zope to
test and to show what this all is for.

2008/07/16 0.3.1b8
==================
Expand Down
2 changes: 1 addition & 1 deletion buildout.cfg
Expand Up @@ -5,5 +5,5 @@ parts = test

[test]
recipe = zc.recipe.testrunner
eggs = lovely.recipe
eggs = lovely.recipe[zope]

12 changes: 7 additions & 5 deletions setup.py
Expand Up @@ -9,12 +9,13 @@
instance = lovely.recipe.zope.zope:LovelyInstance
app = lovely.recipe.zope.zope:LovelyApp
server = lovely.recipe.zeo:LovelyServer
eggbox = lovely.recipe.egg:EggBox
"""

setup (
name='lovely.recipe',
description = "set of helper recipies for zc.buildout",
version='0.3.1b8',
version='1.0.0a1',
author = "Lovely Systems",
author_email = "office@lovelysystems.com",
license = "ZPL 2.1",
Expand All @@ -24,14 +25,15 @@
include_package_data = True,
package_dir = {'':'src'},
namespace_packages = ['lovely', 'lovely.recipe'],
install_requires = ['setuptools',
'zc.buildout',
'zc.recipe.egg',
extras_require = dict(zope=[
'zope.app.locales',
'zc.zope3recipes',
'zc.zodbrecipes',
'zope.app.locales>=3.4.5',
'ZConfig',
'ZConfig']),
install_requires = ['setuptools',
'zc.buildout',
'zc.recipe.egg',
],
entry_points = entry_points,
zip_safe = True,
Expand Down
99 changes: 99 additions & 0 deletions src/lovely/recipe/egg/README.txt
@@ -0,0 +1,99 @@
=======================
Egg Box Buildout Recipe
=======================

This recipe is derivd from zc.recipe.egg, but instead of just creating
paths, it generates a directory structure for each top-level
namespace. It is also possible to automatically zip the generated
directories which is espacially usefull if used in Google Appengine
environments. The recipies path option is filled with the created path
so it can be referenced by other buildout sections which may want to
use the recipe.

>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... parts = packages
... find-links = http://download.zope.org/distribution
...
... [packages]
... recipe = lovely.recipe:eggbox
... eggs = zope.dublincore
... zope.formlib
... pytz
... """)
>>> print system(buildout),
Installing packages.

We now have a zip file for each top-level directory. Note that the
zip-files are ending with .egg for pkg_resources compatibility.

>>> ls(sample_buildout + '/parts/packages')
- BTrees.egg
- RestrictedPython.egg
- ThreadedAsync.egg
- ZConfig.egg
- ZEO.egg
- ZODB.egg
- ZopeUndo.egg
- persistent.egg
- pytz.egg
- transaction.egg
- zdaemon.egg
- zodbcode.egg
- zope.egg

It is possible to disable zipping. And also to exclude or include
patterns of files. So for example we can strip down pytz. We can also
create a script.

>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... parts = packages test
... find-links = http://download.zope.org/distribution
...
... [packages]
... zip = False
... recipe = lovely.recipe:eggbox
... eggs = pytz
... excludes = ^pytz/zoneinfo/Mexico/.*
...
... [test]
... recipe = zc.recipe.egg:scripts
... eggs = lovely.recipe
... extra-paths = ${packages:path}
... interpreter = py
... """)
>>> print system(buildout),
Uninstalling packages.
Installing packages.
Installing test.
Generated interpreter '/sample-buildout/bin/py'.

>>> ls(sample_buildout + '/parts/packages')
d pytz
>>> ls(sample_buildout + '/parts/packages/pytz/pytz/zoneinfo/Mexico')
Traceback (most recent call last):
...
OSError...No such file or directory: .../Mexico'

>>> ls(sample_buildout + '/parts/packages/pytz/pytz/zoneinfo/America')
- Adak
- Anchorage
- Anguilla
- ...

Note that we still have the same directory structure as the zipped
version with a directory for each top-level namespace.


The test section uses the path of our packages section.

>>> cat(sample_buildout + '/bin/py')
#!...
import sys
<BLANKLINE>
sys.path[0:0] = [.../sample-buildout/parts/packages/pytz',
]...

175 changes: 175 additions & 0 deletions src/lovely/recipe/egg/__init__.py
@@ -0,0 +1,175 @@
import logging, os
import zc.recipe.egg
import shutil
import re
import pkg_resources
from zc.buildout.easy_install import _script

log = logging.getLogger(__name__)

SKIPPED_LIBDIRS = ('site-packages',)

class EggBox(zc.recipe.egg.Scripts):

src_exclude = re.compile(r'.*/site-packages')
includes = []
excludes = [re.compile(r'(EGG-INFO)|(.*\.egg-info)|(.*\.pyc)|(.*\.svn/.*)'),
re.compile(r'(^[^/]+\.txt)|(^setup\.[^/]+)|(^.[A-Z]+(\.[^/]+)?$)'),
]

def __init__(self, buildout, name, options):
options['parts-directory'] = buildout['buildout']['parts-directory']
super(EggBox, self).__init__(buildout, name, options)
# we need to do this on init because the signature cannot be
# created if the egg is not already there
self.ws = self.working_set()[1]
self.zip = self.options.get('zip') != 'False'
self.location = self.options.get(
'location',
os.path.join(self.options['parts-directory'], self.name))
if options.get('includes'):
self.includes += map(re.compile, options.get('includes').strip().split())
if options.get('excludes'):
self.excludes += map(re.compile, options.get('excludes').strip().split())
self._mk_zips()

def progress_filter(self, packages):
def _pf(src, dst, packages=packages, includes=self.includes,
excludes=self.excludes):
for pat in includes:
import pdb;pdb.set_trace()
if not pat.match(src):
return None
for pat in excludes:
if pat.match(src):
return None
return dst
return _pf

def genScript(self, paths):
pass

def install(self):
scripts = self.options.get('scripts')
reqs, ws = self.working_set()
if scripts or scripts is None:
if scripts is not None:
scripts = scripts.split()
scripts = dict([
('=' in s) and s.split('=', 1) or (s, s)
for s in scripts
])

for s in self.options.get('entry-points', '').split():
parsed = self.parse_entry_point(s)
if not parsed:
log.error(
"Cannot parse the entry point %s.", s)
raise zc.buildout.UserError("Invalid entry point")
reqs.append(parsed.groups())
return self._mk_scripts(
reqs, ws, self.options['executable'],
self.options['bin-directory'],
scripts=scripts,
extra_paths=self.extra_paths,
interpreter=self.options.get('interpreter'),
initialization=self.options.get('initialization', ''),
arguments=self.options.get('arguments', ''),
)
return ()
update = install

def _mk_zips(self):
from setuptools import archive_util
from setuptools.command.bdist_egg import make_zipfile
if os.path.isdir(self.location):
shutil.rmtree(self.location)
os.mkdir(self.location)
dsts = []
for src, names in self.ws.entry_keys.items():
if self.src_exclude.match(src):
continue
log.debug("Adding archive %r %r" % (src, names))
archive_util.unpack_archive(
src, self.location, progress_filter=self.progress_filter(names))

# let us put the things in seperate paths so we dont have to
# care if we are zipped or not, we just have to add any
# subitem in the packcage directory to the paht, not the
# package directory itself
tmp = os.path.join(self.location, '.tmp')
for name in os.listdir(self.location):
if name == '.tmp':
continue
os.mkdir(tmp)
d = os.path.join(self.location, name)
td = os.path.join(tmp, name)
os.rename(d, td)
os.rename(tmp, d)

if self.zip:
for name in os.listdir(self.location):
d = os.path.join(self.location, name)
# hm we need to call this .egg because of
# pkg_resources.resource_filename
z = os.path.join(self.location, name + '.egg')
make_zipfile(z, d)
shutil.rmtree(d)
path = []
for name in os.listdir(self.location):
path.append(os.path.join(self.location, name))
self.options['path'] = '\n'.join(path)
self.path = path

def _mk_scripts(self, reqs, working_set, executable, dest,
scripts=None,
extra_paths=(),
arguments='',
interpreter=None,
initialization='',
):
path = list(self.path)
path.extend(extra_paths)
path = repr(path)[1:-1].replace(', ', ',\n ')
generated = []

if isinstance(reqs, str):
raise TypeError('Expected iterable of requirements or entry points,'
' got string.')

if initialization:
initialization = '\n'+initialization+'\n'

entry_points = []
for req in reqs:
if isinstance(req, str):
req = pkg_resources.Requirement.parse(req)
dist = working_set.find(req)
for name in pkg_resources.get_entry_map(dist, 'console_scripts'):
entry_point = dist.get_entry_info('console_scripts', name)
entry_points.append(
(name, entry_point.module_name,
'.'.join(entry_point.attrs))
)
else:
entry_points.append(req)

for name, module_name, attrs in entry_points:
if scripts is not None:
sname = scripts.get(name)
if sname is None:
continue
else:
sname = name

sname = os.path.join(dest, sname)
generated.extend(
_script(module_name, attrs, path, sname, executable, arguments,
initialization)
)

if interpreter:
sname = os.path.join(dest, interpreter)
generated.extend(_pyscript(path, sname, executable))

return generated
39 changes: 39 additions & 0 deletions src/lovely/recipe/egg/tests.py
@@ -0,0 +1,39 @@
##############################################################################
#
# Copyright (c) 2007 Lovely Systems 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.
#
##############################################################################
"""
$Id: tests.py 85690 2008-04-24 08:09:41Z jukart $
"""
__docformat__ = 'restructuredtext'

from zc.buildout import testing
import doctest, unittest
from zope.testing import doctest, renormalizing

from lovely.recipe.testing import setUpBuildout


def test_suite():

return unittest.TestSuite((
doctest.DocFileSuite(
'README.txt',
setUp=setUpBuildout,
optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
tearDown=testing.buildoutTearDown,
checker=renormalizing.RENormalizing([
testing.normalize_path,
testing.normalize_script,
testing.normalize_egg_py])
)))

0 comments on commit 7969d12

Please sign in to comment.