[Zope3-checkins] SVN: Zope3/trunk/ make ordering of schema managers
predictable
Fred L. Drake, Jr.
fdrake at gmail.com
Tue Jan 9 11:10:29 EST 2007
Log message for revision 71848:
make ordering of schema managers predictable
Changed:
U Zope3/trunk/doc/CHANGES.txt
U Zope3/trunk/src/zope/app/generations/README.txt
U Zope3/trunk/src/zope/app/generations/generations.py
-=-
Modified: Zope3/trunk/doc/CHANGES.txt
===================================================================
--- Zope3/trunk/doc/CHANGES.txt 2007-01-09 14:26:26 UTC (rev 71847)
+++ Zope3/trunk/doc/CHANGES.txt 2007-01-09 16:10:28 UTC (rev 71848)
@@ -10,6 +10,10 @@
New features
+ - zope.app.generations now guarantees the order in which schema managers
+ are invoked, allowing frameworks and extensions to have a predictable
+ evolution relationship.
+
- Removed unused and untested SFTP code from zope.app.twisted along with
all the SSH keys. Removed all the SSL keys also.
Modified: Zope3/trunk/src/zope/app/generations/README.txt
===================================================================
--- Zope3/trunk/src/zope/app/generations/README.txt 2007-01-09 14:26:26 UTC (rev 71847)
+++ Zope3/trunk/src/zope/app/generations/README.txt 2007-01-09 16:10:28 UTC (rev 71848)
@@ -186,6 +186,106 @@
just to check if you need to update or if you want to be lazy like the
subscriber which we have called previously.
+
+Ordering of schema managers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Frequently subsystems used to compose an application rely on other
+subsystems to operate properly. If both subsystems provide schema
+managers, it is often helpful to know the order in which the evolvers
+will be invoked. This allows a framework and it's clients to be able
+to evolve in concert, and the clients can know that the framework will
+be evolved before or after itself.
+
+This can be accomplished by controlling the names of the schema
+manager utilities. The schema managers are run in the order
+determined by sorting their names.
+
+ >>> manager1 = SchemaManager(minimum_generation=0, generation=0)
+ >>> manager2 = SchemaManager(minimum_generation=0, generation=0)
+
+ >>> ztapi.provideUtility(
+ ... ISchemaManager, manager1, name='another.app')
+ >>> ztapi.provideUtility(
+ ... ISchemaManager, manager1, name='another.app-extension')
+
+Notice how the name of the first package is used to create a namespace
+for dependent packages. This is not a requirement of the framework,
+but a convenient pattern for this usage.
+
+Let's evolve the database to establish these generations::
+
+ >>> event = DatabaseOpenedEventStub(db)
+ >>> evolveMinimumSubscriber(event)
+
+ >>> root[generations_key]['another.app']
+ 0
+ >>> root[generations_key]['another.app-extension']
+ 0
+
+Let's assume that for some reason each of these subsystems needs to
+add a generation, and that generation 1 of 'another.app-extension'
+depends on generation 1 of 'another.app'. We'll need to provide
+schema managers for each that record that they've been run so we can
+verify the result::
+
+ >>> ztapi.unprovideUtility(ISchemaManager, name='another.app')
+ >>> ztapi.unprovideUtility(ISchemaManager, name='another.app-extension')
+
+ >>> class FoundationSchemaManager(object):
+ ... implements(ISchemaManager)
+ ...
+ ... minimum_generation = 1
+ ... generation = 1
+ ...
+ ... def evolve(self, context, generation):
+ ... root = context.connection.root()
+ ... ordering = root.get('ordering', [])
+ ... if generation == 1:
+ ... ordering.append('foundation 1')
+ ... print 'foundation generation 1'
+ ... else:
+ ... raise ValueError("Bummer")
+ ... root['ordering'] = ordering # ping persistence
+ ... transaction.commit()
+
+ >>> class DependentSchemaManager(object):
+ ... implements(ISchemaManager)
+ ...
+ ... minimum_generation = 1
+ ... generation = 1
+ ...
+ ... def evolve(self, context, generation):
+ ... root = context.connection.root()
+ ... ordering = root.get('ordering', [])
+ ... if generation == 1:
+ ... ordering.append('dependent 1')
+ ... print 'dependent generation 1'
+ ... else:
+ ... raise ValueError("Bummer")
+ ... root['ordering'] = ordering # ping persistence
+ ... transaction.commit()
+
+ >>> manager1 = FoundationSchemaManager()
+ >>> manager2 = DependentSchemaManager()
+
+ >>> ztapi.provideUtility(
+ ... ISchemaManager, manager1, name='another.app')
+ >>> ztapi.provideUtility(
+ ... ISchemaManager, manager2, name='another.app-extension')
+
+Evolving the database now will always run the 'another.app' evolver
+before the 'another.app-extension' evolver::
+
+ >>> event = DatabaseOpenedEventStub(db)
+ >>> evolveMinimumSubscriber(event)
+ foundation generation 1
+ dependent generation 1
+
+ >>> root['ordering']
+ ['foundation 1', 'dependent 1']
+
+
Installation
------------
Modified: Zope3/trunk/src/zope/app/generations/generations.py
===================================================================
--- Zope3/trunk/src/zope/app/generations/generations.py 2007-01-09 14:26:26 UTC (rev 71847)
+++ Zope3/trunk/src/zope/app/generations/generations.py 2007-01-09 16:10:28 UTC (rev 71848)
@@ -369,7 +369,7 @@
generations = root[generations_key] = PersistentDict()
transaction.commit()
- for key, manager in findManagers():
+ for key, manager in sorted(findManagers()):
generation = generations.get(key)
if generation == manager.generation:
More information about the Zope3-Checkins
mailing list