[Checkins] SVN: zmi.core/trunk/s Copy browser package from zope.app.generations.

Yusei Tahara yusei at domen.cx
Sat Nov 21 02:14:15 EST 2009


Log message for revision 105933:
  Copy browser package from zope.app.generations.
  

Changed:
  U   zmi.core/trunk/setup.py
  U   zmi.core/trunk/src/zmi/core/configure.zcml
  A   zmi.core/trunk/src/zmi/core/generations/__init__.py
  A   zmi.core/trunk/src/zmi/core/generations/configure.zcml
  A   zmi.core/trunk/src/zmi/core/generations/managerdetails.pt
  A   zmi.core/trunk/src/zmi/core/generations/managerdetails.py
  A   zmi.core/trunk/src/zmi/core/generations/managers.pt
  A   zmi.core/trunk/src/zmi/core/generations/managers.py
  A   zmi.core/trunk/src/zmi/core/generations/tests.py

-=-
Modified: zmi.core/trunk/setup.py
===================================================================
--- zmi.core/trunk/setup.py	2009-11-21 06:58:58 UTC (rev 105932)
+++ zmi.core/trunk/setup.py	2009-11-21 07:14:14 UTC (rev 105933)
@@ -59,6 +59,7 @@
                         'zope.app.exception',
                         'zope.app.file',
                         'zope.app.folder',
+                        'zope.app.generations',
                         'zope.app.i18n',
                         'zope.app.i18nfile',
                         'zope.app.intid',

Modified: zmi.core/trunk/src/zmi/core/configure.zcml
===================================================================
--- zmi.core/trunk/src/zmi/core/configure.zcml	2009-11-21 06:58:58 UTC (rev 105932)
+++ zmi.core/trunk/src/zmi/core/configure.zcml	2009-11-21 07:14:14 UTC (rev 105933)
@@ -10,6 +10,7 @@
   <include package=".exception" />
   <include package=".file" />
   <include package=".folder" />
+  <include package=".generations" />
   <include package=".i18n" />
   <include package=".i18nfile" />
   <include package=".intid" />

Added: zmi.core/trunk/src/zmi/core/generations/__init__.py
===================================================================
--- zmi.core/trunk/src/zmi/core/generations/__init__.py	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/generations/__init__.py	2009-11-21 07:14:14 UTC (rev 105933)
@@ -0,0 +1 @@
+# Make this directory a package.

Added: zmi.core/trunk/src/zmi/core/generations/configure.zcml
===================================================================
--- zmi.core/trunk/src/zmi/core/generations/configure.zcml	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/generations/configure.zcml	2009-11-21 07:14:14 UTC (rev 105933)
@@ -0,0 +1,23 @@
+<zope:configure 
+   xmlns:zope="http://namespaces.zope.org/zope"
+   xmlns="http://namespaces.zope.org/browser"
+   >
+
+<page
+    name="generations.html"
+    menu="zmi_views" title="Database Schemas"
+    for="zope.app.applicationcontrol.interfaces.IApplicationControl"
+    class=".managers.Managers"
+    template="managers.pt"
+    permission="zope.ManageApplication"
+    />
+
+<page
+    name="generations_managerdetails.html"
+    for="zope.app.applicationcontrol.interfaces.IApplicationControl"
+    class=".managerdetails.ManagerDetails"
+    template="managerdetails.pt"
+    permission="zope.ManageApplication"
+    />
+
+</zope:configure>

Added: zmi.core/trunk/src/zmi/core/generations/managerdetails.pt
===================================================================
--- zmi.core/trunk/src/zmi/core/generations/managerdetails.pt	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/generations/managerdetails.pt	2009-11-21 07:14:14 UTC (rev 105933)
@@ -0,0 +1,30 @@
+<html metal:use-macro="context/@@standard_macros/view" i18n:domain="zope">
+<head>
+<title metal:fill-slot="title">Manager Details</title>
+</head>
+<body>
+<div metal:fill-slot="body">
+
+<h1 i18n:translate="">
+ <b i18n:name="application_id" tal:content="view/id" />
+ Application Manager Details
+</h1>
+<br/>
+
+<tal:block repeat="evolver view/getEvolvers">
+
+<h2 i18n:translate="">
+  Evolver 
+  from Generation <b i18n:name="from" tal:content="evolver/from"/>
+  to Generation <b i18n:name="to" tal:content="evolver/to"/>
+</h2>
+<br />
+<div tal:content="structure evolver/info">
+  Evolution information.
+</div>
+
+</tal:block>
+
+</div>
+</body>
+</html>

Added: zmi.core/trunk/src/zmi/core/generations/managerdetails.py
===================================================================
--- zmi.core/trunk/src/zmi/core/generations/managerdetails.py	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/generations/managerdetails.py	2009-11-21 07:14:14 UTC (rev 105933)
@@ -0,0 +1,87 @@
+##############################################################################
+#
+# Copyright (c) 2004 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.
+#
+##############################################################################
+"""Manager Details View
+
+$Id: managerdetails.py 85608 2008-04-22 18:34:09Z lgs $
+"""
+__docformat__ = "reStructuredText"
+import zope.component
+
+from zope.app.generations.interfaces import ISchemaManager
+from zope.app.renderer.rest import ReStructuredTextToHTMLRenderer
+
+class ManagerDetails(object):
+    r"""Show Details of a particular Schema Manager's Evolvers
+
+    This method needs to use the component architecture, so
+    we'll set it up:
+
+      >>> from zope.app.testing.placelesssetup import setUp, tearDown
+      >>> setUp()
+
+    We need to define some schema managers.  We'll define just one:
+
+      >>> from zope.app.generations.generations import SchemaManager
+      >>> from zope.app.testing import ztapi
+      >>> app1 = SchemaManager(0, 3, 'zope.app.generations.demo')
+      >>> ztapi.provideUtility(ISchemaManager, app1, 'foo.app1')
+
+    Now let's create the view:
+
+      >>> from zope.publisher.browser import TestRequest
+      >>> details = ManagerDetails()
+      >>> details.context = None
+      >>> details.request = TestRequest(environ={'id': 'foo.app1'})
+
+    Let's now see that the view gets the ID correctly from the request:
+
+      >>> details.id
+      'foo.app1'
+
+    Now check that we get all the info from the evolvers:
+
+      >>> info = details.getEvolvers()
+      >>> for item in info:
+      ...     print sorted(item.items())
+      [('from', 0), ('info', u'<p>Evolver 1</p>\n'), ('to', 1)]
+      [('from', 1), ('info', u'<p>Evolver 2</p>\n'), ('to', 2)]
+      [('from', 2), ('info', ''), ('to', 3)]
+
+    We'd better clean up:
+
+      >>> tearDown()
+    """
+
+    id = property(lambda self: self.request['id'])
+
+    def getEvolvers(self):
+        id = self.id
+        manager = zope.component.getUtility(ISchemaManager, id)
+
+        evolvers = []
+
+        for gen in range(manager.minimum_generation, manager.generation):
+
+            info = manager.getInfo(gen+1)
+            if info is None:
+                info = ''
+            else:
+                # XXX: the renderer *expects* unicode as input encoding (ajung)
+                renderer = ReStructuredTextToHTMLRenderer(
+                    unicode(info), self.request)
+                info = renderer.render()
+
+            evolvers.append({'from': gen, 'to': gen+1, 'info': info})
+
+        return evolvers

Added: zmi.core/trunk/src/zmi/core/generations/managers.pt
===================================================================
--- zmi.core/trunk/src/zmi/core/generations/managers.pt	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/generations/managers.pt	2009-11-21 07:14:14 UTC (rev 105933)
@@ -0,0 +1,62 @@
+<html metal:use-macro="context/@@standard_macros/view" i18n:domain="zope">
+<head>
+<title metal:fill-slot="title">Database Generations</title>
+</head>
+<body>
+<div metal:fill-slot="body">
+
+<span i18n:translate="">Database generations</span>
+
+<form tal:attributes="action request/URL"
+      tal:define="status view/evolve" 
+      >
+
+<p tal:condition="status">
+<span tal:condition="status/to" i18n:translate=""
+      >The database was updated to generation <span
+      i18n:name=generation
+      tal:content="status/to">2</span> for <span
+            i18n:name=application
+            tal:content="status/app"
+            >foo.bar</span>.</span>
+<span tal:condition="not: status/to" i18n:translate=""
+      >The database is up to date for <span 
+      i18n:name=application
+      tal:content="status/app"
+      >foo.bar</span>.</span>
+</p>
+
+<table border="1">
+
+<tr>
+    <th i18n:translate="">Application</th>
+    <th i18n:translate="">Minimum Generation</th>
+    <th i18n:translate="">Maximum Generation</th>
+    <th i18n:translate="">Current Database Generation</th>
+    <th i18n:translate="">Evolve?</th>
+</tr>
+<tr tal:repeat="app view/applications">
+    <td>
+      <a href=""
+         tal:attributes=
+             "href string:generations_managerdetails.html?id=${app/id}"
+         tal:content="app/id">foo.bar</a>
+    </td>
+    <td tal:content="app/min">1</td>
+    <td tal:content="app/max">10</td>
+    <td tal:content="app/generation">2</td>
+    <td>
+       <input type="submit" value=" evolve " name="evolve"
+              tal:condition="app/evolve"
+              tal:attributes="name app/evolve"
+              >
+       <span tal:condition="not: app/evolve"
+             i18n:translate=""
+             >No, up to date</span>
+    </td>
+</tr>
+</table>
+</form>
+</div>
+</body>
+</html>

Added: zmi.core/trunk/src/zmi/core/generations/managers.py
===================================================================
--- zmi.core/trunk/src/zmi/core/generations/managers.py	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/generations/managers.py	2009-11-21 07:14:14 UTC (rev 105933)
@@ -0,0 +1,298 @@
+##############################################################################
+#
+# Copyright (c) 2004 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.
+#
+##############################################################################
+"""UI for browsing database schema managers
+
+$Id: managers.py 85608 2008-04-22 18:34:09Z lgs $
+"""
+__docformat__ = 'restructuredtext'
+
+import transaction
+
+import zope.component
+
+from zope.app.generations.interfaces import ISchemaManager
+from zope.app.generations.generations import generations_key, Context
+
+request_key_format = "evolve-app-%s"
+
+class Managers(object):
+
+    def __init__(self, context, request):
+        self.context = context
+        self.request = request
+
+    def _getdb(self):
+        # TODO: There needs to be a better api for this
+        return self.request.publication.db
+
+    def evolve(self):
+        """Perform a requested evolution
+
+           This method needs to use the component architecture, so
+           we'll set it up:
+
+             >>> from zope.app.testing.placelesssetup import setUp, tearDown
+             >>> setUp()
+
+           We also need a test request:
+
+             >>> from zope.publisher.browser import TestRequest
+             >>> request = TestRequest()
+
+           We also need to give it a publication with a database:
+
+             >>> class Publication(object):
+             ...     pass
+
+             >>> request.setPublication(Publication())
+             >>> from ZODB.tests.util import DB
+             >>> db = DB()
+             >>> request.publication.db = db
+
+           We need to define some schema managers.  We'll define two
+           using the demo package:
+
+             >>> from zope.app.generations.generations import SchemaManager
+             >>> from zope.app.testing import ztapi
+             >>> app1 = SchemaManager(0, 1, 'zope.app.generations.demo')
+             >>> ztapi.provideUtility(ISchemaManager, app1, 'foo.app1')
+             >>> app2 = SchemaManager(0, 0, 'zope.app.generations.demo')
+             >>> ztapi.provideUtility(ISchemaManager, app2, 'foo.app2')
+
+           And we need to record some data for them in the database.
+
+             >>> from zope.app.generations.generations import evolve
+             >>> evolve(db)
+
+           This sets up the data and actually evolves app1:
+
+             >>> conn = db.open()
+             >>> conn.root()[generations_key]['foo.app1']
+             1
+             >>> conn.root()[generations_key]['foo.app2']
+             0
+
+           To evolve a data base schema, the user clicks on a submit
+           button. If they click on the button for add1, a item will
+           be added to the request, which we simulate:
+
+             >>> request.form['evolve-app-foo.app1'] = 'evolve'
+
+           We'll also increase the generation of app1:
+
+             >>> app1.generation = 2
+
+           Now we can create our view:
+
+             >>> view = Managers(None, request)
+
+           Now, if we call its `evolve` method, it should see that the
+           app1 evolve button was pressed and evolve app1 to the next
+           generation.
+
+             >>> status = view.evolve()
+             >>> conn.sync()
+             >>> conn.root()[generations_key]['foo.app1']
+             2
+
+           The demo evolver just writes the generation to a database key:
+
+             >>> from zope.app.generations.demo import key
+             >>> conn.root()[key]
+             ('installed', 'installed', 2)
+
+           Note that, because the demo package has an install script,
+           we have entries for that script.
+             
+           Which the returned status should indicate:
+
+             >>> status['app']
+             u'foo.app1'
+             >>> status['to']
+             2
+
+           Now, given that the database is at the maximum generation
+           for app1, we can't evolve it further.  Calling evolve again
+           won't evolve anything:
+
+             >>> status = view.evolve()
+             >>> conn.sync()
+             >>> conn.root()[generations_key]['foo.app1']
+             2
+             >>> conn.root()[key]
+             ('installed', 'installed', 2)
+             
+           as the status will indicate by returning a 'to' generation
+           of 0:
+
+             >>> status['app']
+             u'foo.app1'
+             >>> status['to']
+             0
+
+           If the request doesn't have the key:
+
+             >>> request.form.clear()
+
+           Then calling evolve does nothing:
+
+             >>> view.evolve()
+             >>> conn.sync()
+             >>> conn.root()[generations_key]['foo.app1']
+             2
+             >>> conn.root()[key]
+             ('installed', 'installed', 2)
+
+           We'd better clean upp:
+
+             >>> db.close()
+             >>> tearDown()
+           """
+
+        self.managers = managers = dict(
+            zope.component.getUtilitiesFor(ISchemaManager))
+        db = self._getdb()
+        conn = db.open()
+        try:
+            generations = conn.root().get(generations_key, ())
+            request = self.request
+            for key in generations:
+                generation = generations[key]
+                rkey = request_key_format % key
+                if rkey in request:
+                    manager = managers[key]
+                    if generation >= manager.generation:
+                        return {'app': key, 'to': 0}
+                    context = Context()
+                    context.connection = conn
+                    generation += 1
+                    manager.evolve(context, generation)
+                    generations[key] = generation
+                    transaction.commit()
+                    return {'app': key, 'to': generation}
+
+            return None
+        finally:
+            transaction.abort()
+            conn.close()
+
+    def applications(self):
+        """Get information about database-generation status
+
+           This method needs to use the component architecture, so
+           we'll set it up:
+
+             >>> from zope.app.testing.placelesssetup import setUp, tearDown
+             >>> setUp()
+
+           We also need a test request:
+
+             >>> from zope.publisher.browser import TestRequest
+             >>> request = TestRequest()
+
+           We also need to give it a publication with a database:
+
+             >>> class Publication(object):
+             ...     pass
+
+             >>> request.setPublication(Publication())
+             >>> from ZODB.tests.util import DB
+             >>> db = DB()
+             >>> request.publication.db = db
+
+           We need to define some schema managers.  We'll define two
+           using the demo package:
+
+             >>> from zope.app.generations.generations import SchemaManager
+             >>> from zope.app.testing import ztapi
+             >>> app1 = SchemaManager(0, 1, 'zope.app.generations.demo')
+             >>> ztapi.provideUtility(ISchemaManager, app1, 'foo.app1')
+             >>> app2 = SchemaManager(0, 0, 'zope.app.generations.demo')
+             >>> ztapi.provideUtility(ISchemaManager, app2, 'foo.app2')
+
+           And we need to record some data for them in the database.
+
+             >>> from zope.app.generations.generations import evolve
+             >>> evolve(db)
+
+           This sets up the data and actually evolves app1:
+
+             >>> conn = db.open()
+             >>> conn.root()[generations_key]['foo.app1']
+             1
+             >>> conn.root()[generations_key]['foo.app2']
+             0
+
+           Now, let's increment app1's generation:
+
+             >>> app1.generation += 1
+
+           so we can evolve it.
+
+           Now we can create our view:
+
+             >>> view = Managers(None, request)
+
+           We call its applications method to get data about
+           application generations. We are required to call evolve
+           first:
+
+             >>> view.evolve()
+             >>> data = list(view.applications())
+             >>> data.sort(lambda d1, d2: cmp(d1['id'], d2['id']))
+
+             >>> for info in data:
+             ...     print info['id']
+             ...     print info['min'], info['max'], info['generation']
+             ...     print 'evolve?', info['evolve'] or None
+             foo.app1
+             0 2 1
+             evolve? evolve-app-foo.app1
+             foo.app2
+             0 0 0
+             evolve? None
+
+           We'd better clean up:
+
+             >>> db.close()
+             >>> tearDown()
+
+        """
+        result = []
+
+        db = self._getdb()
+        conn = db.open()
+        try:
+            managers = self.managers
+            generations = conn.root().get(generations_key, ())
+            for key in generations:
+                generation = generations[key]
+                manager = managers.get(key)
+                if manager is None:
+                    continue
+
+                result.append({
+                    'id': key,
+                    'min': manager.minimum_generation,
+                    'max': manager.generation,
+                    'generation': generation,
+                    'evolve': (generation < manager.generation
+                               and request_key_format % key
+                               or ''
+                               ),
+                    })
+
+            return result
+        finally:
+            conn.close()

Added: zmi.core/trunk/src/zmi/core/generations/tests.py
===================================================================
--- zmi.core/trunk/src/zmi/core/generations/tests.py	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/generations/tests.py	2009-11-21 07:14:14 UTC (rev 105933)
@@ -0,0 +1,92 @@
+##############################################################################
+#
+# Copyright (c) 2004 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.
+#
+##############################################################################
+"""Generation-browser tests
+
+$Id: tests.py 95085 2009-01-27 08:43:42Z icemac $
+"""
+import unittest
+from zope.testing.doctestunit import DocTestSuite
+from zope.app.generations.testing import GenerationsLayer
+from zope.app.testing import ztapi, functional
+from zope.app.generations.generations import SchemaManager, generations_key
+from zope.app.generations.interfaces import ISchemaManager
+
+class TestDatabaseSchema(functional.BrowserTestCase):
+
+    def test(self):
+        root = self.getRootFolder()._p_jar.root()
+        appkey = 'zope.app.generations.demo'
+        root[generations_key][appkey] = 0
+        self.commit()
+        manager = SchemaManager(0, 3, 'zope.app.generations.demo')
+
+        ztapi.provideUtility(ISchemaManager, manager, appkey)
+
+        response = self.publish('/++etc++process/@@generations.html',
+                                basic='globalmgr:globalmgrpw')
+        body = response.getBody()
+        body = ' '.join(body.split())
+        expect = ('zope.app.generations.demo</a> </td> '
+                  '<td>0</td> <td>3</td> <td>0</td> '
+                  '<td> <input type="submit" value=" evolve " '
+                  'name="evolve-app-zope.app.generations.demo"> </td>')
+        self.assert_(body.find(expect) > 0)
+
+        response = self.publish('/++etc++process/@@generations.html'
+                                '?evolve-app-zope.app.generations.demo=evolve',
+                                basic='globalmgr:globalmgrpw')
+        body = response.getBody()
+        body = ' '.join(body.split())
+        expect = ('zope.app.generations.demo</a> </td> '
+                  '<td>0</td> <td>3</td> <td>1</td> '
+                  '<td> <input type="submit" value=" evolve " '
+                  'name="evolve-app-zope.app.generations.demo"> </td>')
+        self.assert_(body.find(expect) > 0)
+
+        response = self.publish('/++etc++process/@@generations.html'
+                                '?evolve-app-zope.app.generations.demo=evolve',
+                                basic='globalmgr:globalmgrpw')
+        body = response.getBody()
+        body = ' '.join(body.split())
+        expect = ('zope.app.generations.demo</a> </td> '
+                  '<td>0</td> <td>3</td> <td>2</td> '
+                  '<td> <input type="submit" value=" evolve " '
+                  'name="evolve-app-zope.app.generations.demo"> </td>')
+        self.assert_(body.find(expect) > 0)
+
+        response = self.publish('/++etc++process/@@generations.html'
+                                '?evolve-app-zope.app.generations.demo=evolve',
+                                basic='globalmgr:globalmgrpw')
+        body = response.getBody()
+        body = ' '.join(body.split())
+        expect = ('zope.app.generations.demo</a> </td> '
+                  '<td>0</td> <td>3</td> <td>3</td> '
+                  '<td> <span>')
+        self.assert_(body.find(expect) > 0)
+
+        ztapi.unprovideUtility(ISchemaManager, appkey)
+
+
+
+def test_suite():
+    TestDatabaseSchema.layer = GenerationsLayer
+    return unittest.TestSuite((
+        DocTestSuite('zmi.core.generations.managers'),
+        DocTestSuite('zmi.core.generations.managerdetails'),
+        unittest.makeSuite(TestDatabaseSchema),
+        ))
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')
+



More information about the checkins mailing list