[Checkins] SVN: lovely.recipe/trunk/ see CHANGES.txt

Jodok Batlogg jodok.batlogg at lovelysystems.com
Fri Oct 3 12:16:01 EDT 2008


Log message for revision 91711:
  see CHANGES.txt

Changed:
  U   lovely.recipe/trunk/CHANGES.txt
  U   lovely.recipe/trunk/buildout.cfg
  U   lovely.recipe/trunk/setup.py
  A   lovely.recipe/trunk/src/lovely/recipe/egg/
  A   lovely.recipe/trunk/src/lovely/recipe/egg/README.txt
  A   lovely.recipe/trunk/src/lovely/recipe/egg/__init__.py
  A   lovely.recipe/trunk/src/lovely/recipe/egg/tests.py

-=-
Modified: lovely.recipe/trunk/CHANGES.txt
===================================================================
--- lovely.recipe/trunk/CHANGES.txt	2008-10-03 16:04:20 UTC (rev 91710)
+++ lovely.recipe/trunk/CHANGES.txt	2008-10-03 16:16:00 UTC (rev 91711)
@@ -2,13 +2,18 @@
 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
 ==================
 

Modified: lovely.recipe/trunk/buildout.cfg
===================================================================
--- lovely.recipe/trunk/buildout.cfg	2008-10-03 16:04:20 UTC (rev 91710)
+++ lovely.recipe/trunk/buildout.cfg	2008-10-03 16:16:00 UTC (rev 91711)
@@ -5,5 +5,5 @@
 
 [test]
 recipe = zc.recipe.testrunner
-eggs = lovely.recipe
+eggs = lovely.recipe[zope]
 

Modified: lovely.recipe/trunk/setup.py
===================================================================
--- lovely.recipe/trunk/setup.py	2008-10-03 16:04:20 UTC (rev 91710)
+++ lovely.recipe/trunk/setup.py	2008-10-03 16:16:00 UTC (rev 91711)
@@ -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 at lovelysystems.com",
     license = "ZPL 2.1",
@@ -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,

Added: lovely.recipe/trunk/src/lovely/recipe/egg/README.txt
===================================================================
--- lovely.recipe/trunk/src/lovely/recipe/egg/README.txt	                        (rev 0)
+++ lovely.recipe/trunk/src/lovely/recipe/egg/README.txt	2008-10-03 16:16:00 UTC (rev 91711)
@@ -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',
+      ]...
+

Added: lovely.recipe/trunk/src/lovely/recipe/egg/__init__.py
===================================================================
--- lovely.recipe/trunk/src/lovely/recipe/egg/__init__.py	                        (rev 0)
+++ lovely.recipe/trunk/src/lovely/recipe/egg/__init__.py	2008-10-03 16:16:00 UTC (rev 91711)
@@ -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

Added: lovely.recipe/trunk/src/lovely/recipe/egg/tests.py
===================================================================
--- lovely.recipe/trunk/src/lovely/recipe/egg/tests.py	                        (rev 0)
+++ lovely.recipe/trunk/src/lovely/recipe/egg/tests.py	2008-10-03 16:16:00 UTC (rev 91711)
@@ -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])
+            )))
+



More information about the Checkins mailing list