[Checkins] SVN: z3c.versionedresource/trunk/ Here is the code for the versioned resources. See the main README.txt

Stephan Richter srichter at cosmos.phy.tufts.edu
Tue Aug 5 12:58:50 EDT 2008


Log message for revision 89405:
  Here is the code for the versioned resources. See the main README.txt 
  file in the code for motivation and the implementation.
  

Changed:
  A   z3c.versionedresource/trunk/
  A   z3c.versionedresource/trunk/CHANGES.txt
  A   z3c.versionedresource/trunk/README.txt
  A   z3c.versionedresource/trunk/bootstrap.py
  A   z3c.versionedresource/trunk/buildout.cfg
  A   z3c.versionedresource/trunk/setup.py
  A   z3c.versionedresource/trunk/src/
  A   z3c.versionedresource/trunk/src/z3c/
  A   z3c.versionedresource/trunk/src/z3c/__init__.py
  A   z3c.versionedresource/trunk/src/z3c/versionedresource/
  A   z3c.versionedresource/trunk/src/z3c/versionedresource/README.txt
  A   z3c.versionedresource/trunk/src/z3c/versionedresource/__init__.py
  A   z3c.versionedresource/trunk/src/z3c/versionedresource/interfaces.py
  A   z3c.versionedresource/trunk/src/z3c/versionedresource/list.py
  A   z3c.versionedresource/trunk/src/z3c/versionedresource/meta.zcml
  A   z3c.versionedresource/trunk/src/z3c/versionedresource/resource.py
  A   z3c.versionedresource/trunk/src/z3c/versionedresource/tests/
  A   z3c.versionedresource/trunk/src/z3c/versionedresource/tests/__init__.py
  A   z3c.versionedresource/trunk/src/z3c/versionedresource/tests/simple.zcml
  A   z3c.versionedresource/trunk/src/z3c/versionedresource/tests/test_doc.py
  A   z3c.versionedresource/trunk/src/z3c/versionedresource/tests/testfiles/
  A   z3c.versionedresource/trunk/src/z3c/versionedresource/tests/testfiles/subdir/
  A   z3c.versionedresource/trunk/src/z3c/versionedresource/tests/testfiles/subdir/subsubdir/
  A   z3c.versionedresource/trunk/src/z3c/versionedresource/tests/testfiles/subdir/subsubdir/subtest.gif
  A   z3c.versionedresource/trunk/src/z3c/versionedresource/tests/testfiles/subdir/test.gif
  A   z3c.versionedresource/trunk/src/z3c/versionedresource/tests/testfiles/test.gif
  A   z3c.versionedresource/trunk/src/z3c/versionedresource/tests/testfiles/test.txt
  A   z3c.versionedresource/trunk/src/z3c/versionedresource/version.py
  A   z3c.versionedresource/trunk/src/z3c/versionedresource/zcml.py

-=-
Added: z3c.versionedresource/trunk/CHANGES.txt
===================================================================
--- z3c.versionedresource/trunk/CHANGES.txt	                        (rev 0)
+++ z3c.versionedresource/trunk/CHANGES.txt	2008-08-05 16:58:50 UTC (rev 89405)
@@ -0,0 +1,8 @@
+=======
+CHANGES
+=======
+
+Version 0.1.0 (2008-??-??)
+--------------------------
+
+- Initial Release


Property changes on: z3c.versionedresource/trunk/CHANGES.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.versionedresource/trunk/README.txt
===================================================================
--- z3c.versionedresource/trunk/README.txt	                        (rev 0)
+++ z3c.versionedresource/trunk/README.txt	2008-08-05 16:58:50 UTC (rev 89405)
@@ -0,0 +1,2 @@
+Versioned Resources insert a version number in the URL of a resource, so that
+cache behavior can be customized.


Property changes on: z3c.versionedresource/trunk/README.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.versionedresource/trunk/bootstrap.py
===================================================================
--- z3c.versionedresource/trunk/bootstrap.py	                        (rev 0)
+++ z3c.versionedresource/trunk/bootstrap.py	2008-08-05 16:58:50 UTC (rev 89405)
@@ -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: z3c.versionedresource/trunk/bootstrap.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.versionedresource/trunk/buildout.cfg
===================================================================
--- z3c.versionedresource/trunk/buildout.cfg	                        (rev 0)
+++ z3c.versionedresource/trunk/buildout.cfg	2008-08-05 16:58:50 UTC (rev 89405)
@@ -0,0 +1,33 @@
+[buildout]
+develop = .
+parts = test coverage-test coverage-report resource-list python
+index = http://download.zope.org/zope3.4
+find-links=http://pypi.python.org/pypi/zope.app.publisher
+versions = versions
+
+[versions]
+zope.app.publisher=3.5.0
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = z3c.versionedresource [test]
+
+[coverage-test]
+recipe = zc.recipe.testrunner
+eggs = z3c.versionedresource [test]
+defaults = ['--coverage', '../../coverage']
+
+[coverage-report]
+recipe = zc.recipe.egg
+eggs = z3c.coverage
+scripts = coverage=coverage-report
+arguments = ('coverage', 'coverage/report')
+
+[resource-list]
+recipe = zc.recipe.egg
+eggs = z3c.versionedresource
+
+[python]
+recipe = zc.recipe.egg
+interpreter = python
+eggs = z3c.versionedresource

Added: z3c.versionedresource/trunk/setup.py
===================================================================
--- z3c.versionedresource/trunk/setup.py	                        (rev 0)
+++ z3c.versionedresource/trunk/setup.py	2008-08-05 16:58:50 UTC (rev 89405)
@@ -0,0 +1,76 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""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='z3c.versionedresource',
+    version='0.1.0',
+    author = "Stephan Richter and the Zope Community",
+    author_email = "zope3-dev at zope.org",
+    description = "Versioned Resources",
+    long_description=(
+        read('README.txt')
+        + '\n\n' +
+        'Detailed Documentation\n'
+        '**********************'
+        + '\n\n' +
+        read('src', 'z3c', 'versionedresource', 'README.txt')
+        + '\n\n' +
+        read('CHANGES.txt')
+        ),
+    license = "ZPL 2.1",
+    keywords = "zope3 resource version",
+    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/z3c.versionedresource',
+    packages = find_packages('src'),
+    package_dir = {'':'src'},
+    namespace_packages = ['z3c'],
+    extras_require = dict(
+        test = ['zope.testing',
+                'zope.app.testing',
+                'z3c.coverage'],
+        ),
+    install_requires = [
+        'setuptools',
+        'zope.component',
+        'zope.configuration',
+        'zope.interface',
+        'zope.security',
+        'zope.publisher',
+        'zope.app.publisher'
+        ],
+    include_package_data = True,
+    zip_safe = False,
+    entry_points = """
+        [console_scripts]
+        list-resources=z3c.versionedresource.list:main
+        """,
+    )


Property changes on: z3c.versionedresource/trunk/setup.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.versionedresource/trunk/src/z3c/__init__.py
===================================================================
--- z3c.versionedresource/trunk/src/z3c/__init__.py	                        (rev 0)
+++ z3c.versionedresource/trunk/src/z3c/__init__.py	2008-08-05 16:58:50 UTC (rev 89405)
@@ -0,0 +1,7 @@
+try:
+    # Declare this a namespace package if pkg_resources is available.
+    import pkg_resources
+    pkg_resources.declare_namespace('z3c')
+except ImportError:
+    pass
+


Property changes on: z3c.versionedresource/trunk/src/z3c/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.versionedresource/trunk/src/z3c/versionedresource/README.txt
===================================================================
--- z3c.versionedresource/trunk/src/z3c/versionedresource/README.txt	                        (rev 0)
+++ z3c.versionedresource/trunk/src/z3c/versionedresource/README.txt	2008-08-05 16:58:50 UTC (rev 89405)
@@ -0,0 +1,275 @@
+===================
+Versioned Resources
+===================
+
+When deploying scalable Web applications, it is important to serve all static
+resources such as Javascript code, CSS, and images as quickly as possible
+using as little resources as possible. On the hand, the resources must be
+known within the application, so that they can be properly referenced.
+
+Additionally, we want to set the expiration date as far in the future as
+possible. However, sometimes we need or want to update a resource before the
+expiration date has arrived. Yahoo has solved this problem by including a
+version number into the URL, which then allowed them to set the expiration
+date effectively to infinity.
+
+However, maintaining the versions manually is a nightmare, since you would not
+only need to change file or directory names all the time as you change them,
+but also adjust your code. This package aims to solve this problem by
+providing a central component to manage the versions of the resources and make
+versioning transparent to the developer.
+
+
+The Version Manager
+-------------------
+
+The Version Manager is a central component that provides the version to the
+system. It is up to the version manager to decide whether the version is for
+example based on a tag, a revision number, the package version number or a
+manually entered version.
+
+  >>> from z3c.versionedresource import version
+
+This package provides only a simple version manager, since I have found no
+other good version indicator that is available generically.
+
+  >>> manager = version.VersionManager('1.0.0')
+  >>> manager
+  <VersionManager '1.0.0'>
+
+The only constructor argument is the version itself. Versions must be ASCII
+strings. Let's now register the version manager, so that it is available for
+later use:
+
+  >>> import zope.component
+  >>> zope.component.provideUtility(manager)
+
+Clearly, there is not much to version managers and they are only interesting
+within the larger context of this package.
+
+
+Versioned Resource Traversal
+----------------------------
+
+Zope uses a special, empty-named view to traverse resources from a site like
+this::
+
+  <site>/@@/<resource-path>
+
+We would like to support URLs like this now::
+
+  <site>/@@/<version>/<resource-path>
+
+That means that we need a custom implementation of the resources view that can
+handle the version.
+
+  >>> from zope.publisher.browser import TestRequest
+  >>> from z3c.versionedresource import resource
+
+  >>> request = TestRequest()
+  >>> context = object()
+
+  >>> resources = resource.Resources(context, request)
+
+The resources object is a browser view:
+
+  >>> resources.__parent__ is context
+  True
+  >>> resources.__name__
+
+The view is also a browser publisher. But it dows not support a default:
+
+  >>> resources.browserDefault(request)
+  (<function empty at ...>, ())
+
+When traversing to a sub-item, the version can be specified:
+
+  >>> resources.publishTraverse(request, '1.0.0')
+  <zope.app.publisher.browser.resources.Resources ...>
+
+The result of the traversal is the original resources object. When asking for
+an unknown resource or version, a ``NotFound`` is raised:
+
+  >>> resources.publishTraverse(request, 'error')
+  Traceback (most recent call last):
+  ...
+  NotFound: Object: <z3c.versionedresource.resource.Resources ...>, name: 'error'
+
+Let's now register a resource, just to show that traversing to it works:
+
+  >>> import zope.interface
+  >>> from zope.app.publisher.browser.resource import Resource
+
+  >>> zope.component.provideAdapter(
+  ...     Resource, (TestRequest,), zope.interface.Interface, 'resource.css')
+
+We can now ask the resources object to traverse the resource:
+
+  >>> css = resources.publishTraverse(request, 'resource.css')
+  >>> css
+  <zope.app.publisher.browser.resource.Resource object at ...>
+
+Calling it will return the URL:
+
+  >>> css()
+  'http://127.0.0.1/@@/resource.css'
+
+Mmmh, so a regular resource does not honor the version element. That's because
+it's ``__call__()`` method defines how the URL is constructed, which is
+ignorant of the version.
+
+So let's use this package's implementation of a resource:
+
+  >>> zope.component.provideAdapter(
+  ...     resource.Resource,
+  ...     (TestRequest,), zope.interface.Interface, 'resource2.css')
+
+  >>> css = resources.publishTraverse(request, 'resource2.css')
+  >>> css
+  <z3c.versionedresource.resource.Resource object at ...>
+  >>> css()
+  'http://127.0.0.1/@@/1.0.0/resource2.css'
+
+
+Custom Resource Classes
+-----------------------
+
+The ``zope.app.publisher.browser`` package defines three major
+resources. As pointed out above, they have to be adjusted to produce a
+versioned URL and set the cache header to a long time.
+
+File Resource
+~~~~~~~~~~~~~
+
+The versioned file resource is identical to the default file resource, except
+that it has a versioned URL and a 10 year cache timeout.
+
+  >>> request = TestRequest()
+  >>> res = resource.FileResource(None, request)
+  >>> res.__name__ = 'ajax.js'
+  >>> res
+  <z3c.versionedresource.resource.FileResource object at ...>
+  >>> res.cacheTimeout
+  315360000
+  >>> res()
+  'http://127.0.0.1/@@/1.0.0/ajax.js'
+
+Two factories, one for files and one for images is used:
+
+  >>> import os.path
+  >>> import z3c.versionedresource.tests
+  >>> filesdir = os.path.join(
+  ...     os.path.dirname(z3c.versionedresource.tests.__file__),
+  ...     'testfiles')
+
+  >>> factory = resource.FileResourceFactory(
+  ...     os.path.join(filesdir, 'test.txt'), None, 'test.txt')
+  >>> factory
+  <z3c.versionedresource.resource.FileResourceFactory object at ...>
+  >>> factory(request)
+  <z3c.versionedresource.resource.FileResource object at ...>
+
+  >>> factory = resource.ImageResourceFactory(
+  ...     os.path.join(filesdir, 'test.gif'), None, 'test.gif')
+  >>> factory
+  <z3c.versionedresource.resource.ImageResourceFactory object at ...>
+  >>> factory(request)
+  <z3c.versionedresource.resource.FileResource object at ...>
+
+
+Directory Resource
+~~~~~~~~~~~~~~~~~~
+
+Let's now turn to directories. The trick here is that we need to set all the
+factories correctly. So let's create the resource first:
+
+  >>> from zope.app.publisher.browser.directoryresource import Directory
+
+  >>> request = TestRequest()
+  >>> res = resource.DirectoryResource(
+  ...     Directory(os.path.join(filesdir, 'subdir'), None, 'subdir'), request)
+  >>> res.__name__ = 'subdir'
+  >>> res
+  <z3c.versionedresource.resource.DirectoryResource object at ...>
+  >>> res()
+  'http://127.0.0.1/@@/1.0.0/subdir'
+
+Let's try to traverse to some files in the directory:
+
+  >>> res.publishTraverse(request, 'test.gif')
+  <z3c.versionedresource.resource.FileResource object at ...>
+
+We also have a factory for it:
+
+  >>> factory = resource.DirectoryResourceFactory(
+  ...     os.path.join(filesdir, 'subdir'), None, 'subdir')
+  >>> factory
+  <z3c.versionedresource.resource.DirectoryResourceFactory object at ...>
+  >>> factory(request)
+  <z3c.versionedresource.resource.DirectoryResource object at ...>
+
+
+Custom ZCML Directives
+----------------------
+
+To make the new resources easily usable, we also need custom resource
+directives:
+
+  >>> from zope.configuration import xmlconfig
+  >>> import z3c.versionedresource
+  >>> context = xmlconfig.file('meta.zcml', z3c.versionedresource)
+
+Let's register simple versioned resource:
+
+  >>> context = xmlconfig.string("""
+  ... <configure
+  ...     xmlns:browser="http://namespaces.zope.org/browser">
+  ...   <browser:versionedResource
+  ...       name="zcml-test.gif"
+  ...       image="%s"
+  ...       />
+  ... </configure>
+  ... """ %os.path.join(filesdir, 'test.gif') , context=context)
+
+Now we can access the resource:
+
+  >>> resources.publishTraverse(request, '1.0.0')\
+  ...          .publishTraverse(request, 'zcml-test.gif')()
+  'http://127.0.0.1/@@/1.0.0/zcml-test.gif'
+
+Let's now create a directory resource:
+
+  >>> context = xmlconfig.string("""
+  ... <configure
+  ...     xmlns:browser="http://namespaces.zope.org/browser">
+  ...   <browser:versionedResourceDirectory
+  ...       name="zcml-subdir"
+  ...       directory="%s"
+  ...       />
+  ... </configure>
+  ... """ %os.path.join(filesdir, 'subdir') , context=context)
+
+And access it:
+
+  >>> resources.publishTraverse(request, '1.0.0')\
+  ...          .publishTraverse(request, 'zcml-subdir')()
+  'http://127.0.0.1/@@/1.0.0/zcml-subdir'
+
+
+Lsiting All Resources
+---------------------
+
+Finally, there exists a script that will list all resources registered as
+versioned resources with the system.
+
+  >>> from z3c.versionedresource import list
+  >>> list.main(
+  ...   ['-u', 'http://zope.org',
+  ...    '-l', 'z3c.versionedresource.tests.test_doc.ITestLayer',
+  ...    os.path.join(os.path.dirname(list.__file__), 'tests', 'simple.zcml')])
+  http://zope.org/@@/1.0.0/real-subdir/test.gif
+  http://zope.org/@@/1.0.0/real-subdir/subsubdir/subtest.gif
+  http://zope.org/@@/1.0.0/zcml-subdir/test.gif
+  http://zope.org/@@/1.0.0/zcml-subdir/subsubdir/subtest.gif
+  http://zope.org/@@/1.0.0/real-test.gif
+  http://zope.org/@@/1.0.0/zcml-test.gif


Property changes on: z3c.versionedresource/trunk/src/z3c/versionedresource/README.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.versionedresource/trunk/src/z3c/versionedresource/__init__.py
===================================================================
--- z3c.versionedresource/trunk/src/z3c/versionedresource/__init__.py	                        (rev 0)
+++ z3c.versionedresource/trunk/src/z3c/versionedresource/__init__.py	2008-08-05 16:58:50 UTC (rev 89405)
@@ -0,0 +1 @@
+# Make a package.


Property changes on: z3c.versionedresource/trunk/src/z3c/versionedresource/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.versionedresource/trunk/src/z3c/versionedresource/interfaces.py
===================================================================
--- z3c.versionedresource/trunk/src/z3c/versionedresource/interfaces.py	                        (rev 0)
+++ z3c.versionedresource/trunk/src/z3c/versionedresource/interfaces.py	2008-08-05 16:58:50 UTC (rev 89405)
@@ -0,0 +1,31 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Versioned Resources Interfaces
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+import zope.interface
+import zope.schema
+
+class IVersionManager(zope.interface.Interface):
+    """A manager for resource versions."""
+
+    version = zope.schema.ASCIILine(
+        title=u'Version',
+        description=u'The versoin of the resources.',
+        required=True)
+
+class IVersionedResource(zope.interface.Interface):
+    """Versioned Resource"""


Property changes on: z3c.versionedresource/trunk/src/z3c/versionedresource/interfaces.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.versionedresource/trunk/src/z3c/versionedresource/list.py
===================================================================
--- z3c.versionedresource/trunk/src/z3c/versionedresource/list.py	                        (rev 0)
+++ z3c.versionedresource/trunk/src/z3c/versionedresource/list.py	2008-08-05 16:58:50 UTC (rev 89405)
@@ -0,0 +1,119 @@
+##############################################################################
+#
+# Copyright (c) 2008 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.
+#
+##############################################################################
+"""Resource List
+
+$Id$
+"""
+__docformat__ = 'restructuredtext'
+import optparse
+import os
+import zope.component
+import zope.interface
+from zope.configuration import xmlconfig
+from zope.publisher.browser import TestRequest
+from z3c.versionedresource import interfaces, resource
+
+
+def getAllResources(options):
+    # Run the configuration
+    context = xmlconfig.file(options.zcml)
+    # Get the layer interface
+    moduleName, layerName = options.layer.rsplit('.', 1)
+    module = __import__(moduleName, {}, {}, [1])
+    layer = getattr(module, layerName)
+    # Now we create a test request with that layer and our custom base URL.
+    request = TestRequest(environ={'SERVER_URL': options.url})
+    zope.interface.alsoProvides(request, layer)
+    # Next we look up all the resources
+    resources = zope.component.getAdapters(
+        (request,), interfaces.IVersionedResource)
+    paths = []
+    for name, res in resources:
+        # For file-based resources, just report their URL.
+        if not isinstance(res, resource.DirectoryResource):
+            paths.append(res())
+        # For directory resources, we want to walk the tree.
+        baseURL = res()
+        path = res.context.path
+        for root, dirs, files in os.walk(path):
+            if '.svn' in dirs:
+                dirs.remove('.svn')
+            relativePath = root.replace(path, '')
+            for file in files:
+                paths.append(baseURL + relativePath + '/' + file)
+    return paths
+
+###############################################################################
+# Command-line UI
+
+parser = optparse.OptionParser("%prog [options] ROOT-ZCML-FILE")
+
+config = optparse.OptionGroup(
+    parser, "Configuration", "Configuration of lookup and reporting parameters.")
+
+config.add_option(
+    '--url', '-u', action="store", dest='url',
+    help="""The base URL that is used to produce the resource URLs.""")
+
+config.add_option(
+    '--layer', '-l', action="store", dest='layer',
+    default='zope.interface.Interface',
+    help="""The layer for which to lookup the resources.""")
+
+parser.add_option_group(config)
+
+# Default setup
+default_setup_args = []
+
+def merge_options(options, defaults):
+    odict = options.__dict__
+    for name, value in defaults.__dict__.items():
+        if (value is not None) and (odict[name] is None):
+            odict[name] = value
+
+def get_options(args=None, defaults=None):
+
+    default_setup, _ = parser.parse_args(default_setup_args)
+    assert not _
+    if defaults:
+        defaults, _ = parser.parse_args(defaults)
+        assert not _
+        merge_options(defaults, default_setup)
+    else:
+        defaults = default_setup
+
+    if args is None:
+        args = sys.argv
+    original_args = args
+    options, positional = parser.parse_args(args)
+    merge_options(options, defaults)
+    options.original_args = original_args
+
+    if not positional or len(positional) < 1:
+        parser.error("No target user and/or packages specified.")
+    options.zcml = positional[0]
+
+    return options
+
+# Command-line UI
+###############################################################################
+
+def main(args=None):
+    if args is None:
+        args = sys.argv[1:]
+
+    options = get_options(args)
+    options.action = 'Add'
+    resources = getAllResources(options)
+    print '\n'.join(resources)


Property changes on: z3c.versionedresource/trunk/src/z3c/versionedresource/list.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.versionedresource/trunk/src/z3c/versionedresource/meta.zcml
===================================================================
--- z3c.versionedresource/trunk/src/z3c/versionedresource/meta.zcml	                        (rev 0)
+++ z3c.versionedresource/trunk/src/z3c/versionedresource/meta.zcml	2008-08-05 16:58:50 UTC (rev 89405)
@@ -0,0 +1,23 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:meta="http://namespaces.zope.org/meta"
+    xmlns:zcml="http://namespaces.zope.org/zcml">
+
+  <meta:directives namespace="http://namespaces.zope.org/browser">
+
+    <meta:directive
+        name="versionedResource"
+        schema="zope.app.publisher.browser.metadirectives.IResourceDirective"
+        handler=".zcml.resource"
+        />
+
+    <meta:directive
+        name="versionedResourceDirectory"
+        schema="
+          zope.app.publisher.browser.metadirectives.IResourceDirectoryDirective"
+        handler=".zcml.resourceDirectory"
+        />
+
+  </meta:directives>
+
+</configure>


Property changes on: z3c.versionedresource/trunk/src/z3c/versionedresource/meta.zcml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.versionedresource/trunk/src/z3c/versionedresource/resource.py
===================================================================
--- z3c.versionedresource/trunk/src/z3c/versionedresource/resource.py	                        (rev 0)
+++ z3c.versionedresource/trunk/src/z3c/versionedresource/resource.py	2008-08-05 16:58:50 UTC (rev 89405)
@@ -0,0 +1,83 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Versioned Resources Implementation
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+import zope.component
+from zope.publisher.interfaces import NotFound
+from zope.app.publisher.browser import resource, resources
+from zope.app.publisher.browser import directoryresource
+from zope.app.publisher.browser import fileresource
+from zope.app.publisher.browser import pagetemplateresource
+from z3c.versionedresource import interfaces
+
+class Resources(resources.Resources):
+
+    def publishTraverse(self, request, name):
+        '''See interface IBrowserPublisher'''
+        try:
+            return super(Resources, self).publishTraverse(request, name)
+        except NotFound:
+            pass
+
+        vm = zope.component.queryUtility(interfaces.IVersionManager)
+        if vm is None or vm.version != name:
+            raise NotFound(self, name)
+
+        res = resources.Resources(self.context, self.request)
+        res.__name__ = vm.version
+        return res
+
+
+class VersionResourceBase(object):
+
+    def _createUrl(self, baseUrl, name):
+        vm = zope.component.queryUtility(interfaces.IVersionManager)
+        return '%s/@@/%s/%s' %(baseUrl, vm.version, name)
+
+
+class Resource(VersionResourceBase, resource.Resource):
+    pass
+
+class FileResource(VersionResourceBase, fileresource.FileResource):
+    # 10 years expiration date
+    cacheTimeout = 10 * 365 * 24 * 3600
+
+class FileResourceFactory(fileresource.FileResourceFactory):
+    resourceClass = FileResource
+
+class ImageResourceFactory(fileresource.ImageResourceFactory):
+    resourceClass = FileResource
+
+class DirectoryResource(VersionResourceBase,
+                        directoryresource.DirectoryResource):
+
+    resource_factories = {
+        '.gif':  ImageResourceFactory,
+        '.png':  ImageResourceFactory,
+        '.jpg':  ImageResourceFactory,
+        '.pt':   pagetemplateresource.PageTemplateResourceFactory,
+        '.zpt':  pagetemplateresource.PageTemplateResourceFactory,
+        '.html': pagetemplateresource.PageTemplateResourceFactory,
+        }
+
+    default_factory = FileResourceFactory
+    directory_factory = None
+
+class DirectoryResourceFactory(directoryresource.DirectoryResourceFactory):
+    factoryClass = DirectoryResource
+
+DirectoryResource.directory_factory = DirectoryResourceFactory


Property changes on: z3c.versionedresource/trunk/src/z3c/versionedresource/resource.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.versionedresource/trunk/src/z3c/versionedresource/tests/__init__.py
===================================================================
--- z3c.versionedresource/trunk/src/z3c/versionedresource/tests/__init__.py	                        (rev 0)
+++ z3c.versionedresource/trunk/src/z3c/versionedresource/tests/__init__.py	2008-08-05 16:58:50 UTC (rev 89405)
@@ -0,0 +1 @@
+# Make a package.


Property changes on: z3c.versionedresource/trunk/src/z3c/versionedresource/tests/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.versionedresource/trunk/src/z3c/versionedresource/tests/simple.zcml
===================================================================
--- z3c.versionedresource/trunk/src/z3c/versionedresource/tests/simple.zcml	                        (rev 0)
+++ z3c.versionedresource/trunk/src/z3c/versionedresource/tests/simple.zcml	2008-08-05 16:58:50 UTC (rev 89405)
@@ -0,0 +1,18 @@
+<configure
+    xmlns:browser="http://namespaces.zope.org/browser"
+    package="z3c.versionedresource">
+
+  <include file="meta.zcml" />
+
+  <browser:versionedResource
+      name="real-test.gif"
+      image="tests/testfiles/test.gif"
+      layer=".tests.test_doc.ITestLayer"
+      />
+
+  <browser:versionedResourceDirectory
+      name="real-subdir"
+      directory="tests/testfiles/subdir"
+      layer=".tests.test_doc.ITestLayer"
+      />
+</configure>


Property changes on: z3c.versionedresource/trunk/src/z3c/versionedresource/tests/simple.zcml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.versionedresource/trunk/src/z3c/versionedresource/tests/test_doc.py
===================================================================
--- z3c.versionedresource/trunk/src/z3c/versionedresource/tests/test_doc.py	                        (rev 0)
+++ z3c.versionedresource/trunk/src/z3c/versionedresource/tests/test_doc.py	2008-08-05 16:58:50 UTC (rev 89405)
@@ -0,0 +1,33 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Versioned Resources Test Setup
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+import unittest
+from zope.testing import doctest
+from zope.app.testing import placelesssetup
+from zope.publisher.interfaces.browser import IDefaultBrowserLayer
+
+class ITestLayer(IDefaultBrowserLayer):
+    pass
+
+def test_suite():
+    return unittest.TestSuite((
+        doctest.DocFileSuite(
+            '../README.txt',
+            setUp=placelesssetup.setUp, tearDown=placelesssetup.tearDown,
+            optionflags=doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS),
+        ))


Property changes on: z3c.versionedresource/trunk/src/z3c/versionedresource/tests/test_doc.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.versionedresource/trunk/src/z3c/versionedresource/tests/testfiles/subdir/subsubdir/subtest.gif
===================================================================
(Binary files differ)


Property changes on: z3c.versionedresource/trunk/src/z3c/versionedresource/tests/testfiles/subdir/subsubdir/subtest.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: z3c.versionedresource/trunk/src/z3c/versionedresource/tests/testfiles/subdir/test.gif
===================================================================
(Binary files differ)


Property changes on: z3c.versionedresource/trunk/src/z3c/versionedresource/tests/testfiles/subdir/test.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: z3c.versionedresource/trunk/src/z3c/versionedresource/tests/testfiles/test.gif
===================================================================
(Binary files differ)


Property changes on: z3c.versionedresource/trunk/src/z3c/versionedresource/tests/testfiles/test.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: z3c.versionedresource/trunk/src/z3c/versionedresource/tests/testfiles/test.txt
===================================================================
--- z3c.versionedresource/trunk/src/z3c/versionedresource/tests/testfiles/test.txt	                        (rev 0)
+++ z3c.versionedresource/trunk/src/z3c/versionedresource/tests/testfiles/test.txt	2008-08-05 16:58:50 UTC (rev 89405)
@@ -0,0 +1,2 @@
+test
+data


Property changes on: z3c.versionedresource/trunk/src/z3c/versionedresource/tests/testfiles/test.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.versionedresource/trunk/src/z3c/versionedresource/version.py
===================================================================
--- z3c.versionedresource/trunk/src/z3c/versionedresource/version.py	                        (rev 0)
+++ z3c.versionedresource/trunk/src/z3c/versionedresource/version.py	2008-08-05 16:58:50 UTC (rev 89405)
@@ -0,0 +1,34 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Version Manager Implementation
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+
+import zope.interface
+from zope.schema.fieldproperty import FieldProperty
+from z3c.versionedresource import interfaces
+
+
+class VersionManager(object):
+    zope.interface.implements(interfaces.IVersionManager)
+
+    version = FieldProperty(interfaces.IVersionManager['version'])
+
+    def __init__(self, version):
+        self.version = version
+
+    def __repr__(self):
+        return '<%s %r>' %(self.__class__.__name__, self.version)


Property changes on: z3c.versionedresource/trunk/src/z3c/versionedresource/version.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.versionedresource/trunk/src/z3c/versionedresource/zcml.py
===================================================================
--- z3c.versionedresource/trunk/src/z3c/versionedresource/zcml.py	                        (rev 0)
+++ z3c.versionedresource/trunk/src/z3c/versionedresource/zcml.py	2008-08-05 16:58:50 UTC (rev 89405)
@@ -0,0 +1,91 @@
+##############################################################################
+#
+# Copyright (c) 2008 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.
+#
+##############################################################################
+"""Resource Directives
+
+$Id$
+"""
+__docformat__ = 'restructuredtext'
+import os
+from zope.app.publisher.browser.resourcemeta import ResourceFactoryWrapper
+from zope.app.publisher.browser.resourcemeta import allowed_names
+from zope.app.publisher.browser.pagetemplateresource import \
+     PageTemplateResourceFactory
+from zope.component.zcml import handler
+from zope.configuration.exceptions import ConfigurationError
+from zope.interface import Interface
+from zope.publisher.interfaces.browser import IBrowserRequest
+from zope.publisher.interfaces.browser import IDefaultBrowserLayer
+from zope.security.checker import CheckerPublic, NamesChecker
+
+from z3c.versionedresource import interfaces
+from z3c.versionedresource.resource import DirectoryResourceFactory
+from z3c.versionedresource.resource import FileResourceFactory
+from z3c.versionedresource.resource import ImageResourceFactory
+
+
+def resource(_context, name, layer=IDefaultBrowserLayer,
+             permission='zope.Public', factory=None,
+             file=None, image=None, template=None):
+
+    if permission == 'zope.Public':
+        permission = CheckerPublic
+
+    checker = NamesChecker(allowed_names, permission)
+
+    if (factory and (file or image or template)) or \
+       (file and (factory or image or template)) or \
+       (image and (factory or file or template)) or \
+       (template and (factory or file or image)):
+        raise ConfigurationError(
+            "Must use exactly one of factory or file or image or template"
+            " attributes for resource directives"
+            )
+
+    if factory is not None:
+        factory = ResourceFactoryWrapper(factory, checker, name)
+    elif file:
+        factory = FileResourceFactory(file, checker, name)
+    elif image:
+        factory = ImageResourceFactory(image, checker, name)
+    else:
+        factory = PageTemplateResourceFactory(template, checker, name)
+
+    _context.action(
+        discriminator = ('resource', name, IBrowserRequest, layer),
+        callable = handler,
+        args = ('registerAdapter', factory, (layer,),
+                interfaces.IVersionedResource, name, _context.info),
+        )
+
+
+def resourceDirectory(_context, name, directory, layer=IDefaultBrowserLayer,
+                      permission='zope.Public'):
+    if permission == 'zope.Public':
+        permission = CheckerPublic
+
+    checker = NamesChecker(allowed_names + ('__getitem__', 'get'),
+                           permission)
+
+    if not os.path.isdir(directory):
+        raise ConfigurationError(
+            "Directory %s does not exist" % directory
+            )
+
+    factory = DirectoryResourceFactory(directory, checker, name)
+    _context.action(
+        discriminator = ('resource', name, IBrowserRequest, layer),
+        callable = handler,
+        args = ('registerAdapter', factory, (layer,),
+                interfaces.IVersionedResource, name, _context.info),
+        )


Property changes on: z3c.versionedresource/trunk/src/z3c/versionedresource/zcml.py
___________________________________________________________________
Name: svn:keywords
   + Id



More information about the Checkins mailing list