[Zope3-checkins] CVS: Zope3/src/zope/app/fssync - committer.py:1.7
Guido van Rossum
guido@python.org
Mon, 2 Jun 2003 15:49:19 -0400
Update of /cvs-repository/Zope3/src/zope/app/fssync
In directory cvs.zope.org:/tmp/cvs-serv28592
Modified Files:
committer.py
Log Message:
- Adapt containers to IZopeContainer so that the appropriate hooks are
called.
- Post ObjectModifiedEvent and ObjectCreatedEvent when appropriate.
- Because this changes the ZopeDublinCore annotations and that causes
the up-to-date check to fail, ignore up-to-date conflicts for
annotations. This adds an ugly 'ignore_conflicts' flag passed
everywhere. (See XXX comment for a better solution.)
- Adapt the tests so they don't fail. There are no tests for the
added features though.
=== Zope3/src/zope/app/fssync/committer.py 1.6 => 1.7 ===
--- Zope3/src/zope/app/fssync/committer.py:1.6 Thu May 29 15:51:34 2003
+++ Zope3/src/zope/app/fssync/committer.py Mon Jun 2 15:48:48 2003
@@ -19,7 +19,7 @@
import os
import shutil
-from zope.component import queryAdapter, getService
+from zope.component import getAdapter, queryAdapter, getService
from zope.xmlpickle import dumps, loads
from zope.configuration.name import resolve
from zope.proxy import removeAllProxies
@@ -31,10 +31,13 @@
import IObjectEntry, IObjectDirectory, IObjectFile
from zope.app.interfaces.annotation import IAnnotations
-from zope.app.interfaces.container import IContainer
+from zope.app.interfaces.container import IContainer, IZopeContainer
from zope.app.fssync.classes import Default
from zope.app.traversing import getPath, traverseName
from zope.app.interfaces.file import IFileFactory, IDirectoryFactory
+from zope.app.event import publish
+from zope.app.event.objectevent import ObjectCreatedEvent
+from zope.app.event.objectevent import ObjectModifiedEvent
class SynchronizationError(Exception):
pass
@@ -52,12 +55,12 @@
self.metadata = metadata
self.conflicts = []
- def report_conflict(self, fspath):
+ def report_conflict(self, fspath, ignore_conflicts=False):
"""Helper to report a conflict.
Conflicts can be retrieved by calling get_errors().
"""
- if fspath not in self.conflicts:
+ if not ignore_conflicts and fspath not in self.conflicts:
self.conflicts.append(fspath)
def get_errors(self):
@@ -74,7 +77,7 @@
"""
return self.conflicts
- def synch(self, container, name, fspath):
+ def synch(self, container, name, fspath, ignore_conflicts=False):
"""Synchronize an object or object tree from the filesystem.
If the originals on the filesystem is not uptodate, errors are
@@ -97,14 +100,14 @@
raise SynchronizationError("invalid separator in name %r" % name)
if not name:
- self.synch_dir(container, fspath)
+ self.synch_dir(container, fspath, ignore_conflicts)
else:
try:
traverseName(container, name)
except:
- self.synch_new(container, name, fspath)
+ self.synch_new(container, name, fspath, ignore_conflicts)
else:
- self.synch_old(container, name, fspath)
+ self.synch_old(container, name, fspath, ignore_conflicts)
# Now update extra and annotations
try:
@@ -116,13 +119,21 @@
extra = adapter.extra()
extrapath = fsutil.getextra(fspath)
if extra is not None and os.path.exists(extrapath):
- self.synch_dir(extra, extrapath)
+ self.synch_dir(extra, extrapath, ignore_conflicts)
ann = queryAdapter(obj, IAnnotations)
annpath = fsutil.getannotations(fspath)
if ann is not None and os.path.exists(annpath):
- self.synch_dir(ann, annpath)
+ # XXX This isn't quite right. We ignore all
+ # conflicts when updating the annotations, because
+ # the normal cause of events is that the
+ # ZopeDublinCore metadata appears out of date when
+ # an object is modified or deleted. Probably the
+ # correct fix is to separate the up-to-date check
+ # out into a separate pass (again!), but for now
+ # ignoring out-of-date annotations is simpler.
+ self.synch_dir(ann, annpath, ignore_conflicts=True)
- def synch_dir(self, container, fspath):
+ def synch_dir(self, container, fspath, ignore_conflicts=False):
"""Helper to synchronize a directory."""
adapter = self.get_adapter(container)
nameset = {}
@@ -138,55 +149,56 @@
names = nameset.keys()
names.sort()
for name in names:
- self.synch(container, name, os.path.join(fspath, name))
+ self.synch(container, name, os.path.join(fspath, name),
+ ignore_conflicts)
- def synch_new(self, container, name, fspath):
+ def synch_new(self, container, name, fspath, ignore_conflicts=False):
"""Helper to synchronize a new object."""
entry = self.metadata.getentry(fspath)
if entry:
if entry.get("flag") != "added":
- self.report_conflict(fspath)
+ self.report_conflict(fspath, ignore_conflicts)
else:
del entry["flag"]
if not os.path.exists(fspath):
- self.report_conflict(fspath)
+ self.report_conflict(fspath, ignore_conflicts)
return
self.create_object(container, name, entry, fspath)
obj = traverseName(container, name)
adapter = self.get_adapter(obj)
if IObjectDirectory.isImplementedBy(adapter):
- self.synch_dir(obj, fspath)
+ self.synch_dir(obj, fspath, ignore_conflicts)
- def synch_old(self, container, name, fspath):
+ def synch_old(self, container, name, fspath, ignore_conflicts=False):
"""Helper to synchronize an existing object."""
entry = self.metadata.getentry(fspath)
if "conflict" in entry:
- self.report_conflict(fspath)
+ self.report_conflict(fspath, ignore_conflicts)
obj = traverseName(container, name)
adapter = self.get_adapter(obj)
if IObjectDirectory.isImplementedBy(adapter):
- self.synch_dir(obj, fspath)
+ self.synch_dir(obj, fspath, ignore_conflicts)
if entry.get("flag") == "removed":
- del container[name]
+ self.delete_item(container, name)
entry.clear()
self.remove_all(fspath)
else:
if entry.get("flag") == "added":
- self.report_conflict(fspath)
+ self.report_conflict(fspath, ignore_conflicts)
del entry["flag"]
oldfspath = fsutil.getoriginal(fspath)
if not os.path.exists(oldfspath):
- self.report_conflict(fspath)
+ self.report_conflict(fspath, ignore_conflicts)
olddata = None
else:
olddata = self.read_file(oldfspath)
curdata = adapter.getBody()
if curdata != olddata:
- self.report_conflict(fspath)
+ self.report_conflict(fspath, ignore_conflicts)
if entry.get("flag") == "removed":
if os.path.exists(fspath):
- self.report_conflict(fspath)
- del container[name]
+ self.report_conflict(fspath, ignore_conflicts)
+ self.delete_item(container, name)
entry.clear()
self.remove_all(fspath)
else:
@@ -197,6 +209,7 @@
newdata = self.read_file(fspath)
if newdata != olddata:
adapter.setBody(newdata)
+ publish(obj, ObjectModifiedEvent(obj))
newdata = adapter.getBody() # Normalize
self.write_file_and_original(newdata, fspath)
@@ -257,6 +270,9 @@
def set_item(self, container, name, obj, replace=False):
"""Helper to set an item in a container or mapping."""
if IContainer.isImplementedBy(container):
+ if not replace:
+ publish(container, ObjectCreatedEvent(obj))
+ container = getAdapter(container, IZopeContainer)
if replace:
del container[name]
newname = container.setObject(name, obj)
@@ -268,6 +284,12 @@
# Not a container, must be a mapping
# (This is used for extras and annotations)
container[name] = obj
+
+ def delete_item(self, container, name):
+ """Helper to delete an item from a container or mapping."""
+ if IContainer.isImplementedBy(container):
+ container = getAdapter(container, IZopeContainer)
+ del container[name]
def load_file(self, fspath):
"""Helper to load an xml pickle from a file."""