[Zope3-checkins] CVS: Zope3/src/zope/app/fssync - committer.py:1.15.2.1 classes.py:1.4.2.1 configure.zcml:1.2.4.1 fsregistry.py:1.3.2.1 syncer.py:1.19.2.1
Grégoire Weber
zope@i-con.ch
Sun, 22 Jun 2003 10:24:05 -0400
Update of /cvs-repository/Zope3/src/zope/app/fssync
In directory cvs.zope.org:/tmp/cvs-serv24874/src/zope/app/fssync
Modified Files:
Tag: cw-mail-branch
classes.py configure.zcml fsregistry.py syncer.py
Added Files:
Tag: cw-mail-branch
committer.py
Log Message:
Synced up with HEAD
=== Added File Zope3/src/zope/app/fssync/committer.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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.
#
##############################################################################
"""Commit changes from the filesystem.
$Id: committer.py,v 1.15.2.1 2003/06/22 14:23:03 gregweb Exp $
"""
import os
import shutil
from zope.component import getAdapter, queryAdapter, getService
from zope.xmlpickle import dumps, loads
from zope.configuration.name import resolve
from zope.proxy import removeAllProxies
from zope.fssync.metadata import Metadata
from zope.fssync import fsutil
from zope.app.interfaces.fssync \
import IObjectEntry, IObjectDirectory, IObjectFile
from zope.app.context import ContextWrapper
from zope.app.interfaces.container import IContainer, IZopeContainer
from zope.app.fssync.classes import Default
from zope.app.traversing import getPath, traverseName, getName
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
class Checker(object):
"""Check that the filesystem is consistent with the object database.
The public API consists of __init__(), check() and errors() only.
"""
def __init__(self, metadata=None, raise_on_conflicts=False):
"""Constructor. Optionally pass a metadata database."""
if metadata is None:
metadata = Metadata()
self.metadata = metadata
self.raise_on_conflicts = raise_on_conflicts
self.conflicts = []
def errors(self):
"""Return a list of errors (conflicts).
The return value is a list of filesystem pathnames for which
a conflict exists. A conflict usually refers to a file that
was modified on the filesystem while the corresponding object
was also modified in the database. Other forms of conflicts
are possible, e.g. a file added while an object was added in
the corresponding place, or inconsistent labeling of the
filesystem objects (e.g. an existing file marked as removed,
or a non-existing file marked as added).
"""
return self.conflicts
def check(self, container, name, fspath):
"""Compare an object or object tree from the filesystem.
If the originals on the filesystem are not uptodate, errors
are reported by calling conflict().
Invalid object names are reported by raising
SynchronizationError.
"""
if (os.sep in name or
(os.altsep and os.altsep in name) or
name == os.curdir or
name == os.pardir or
name == "." or
name == ".." or
"/" in name):
# This name can't be mapped safely to the filesystem
# or it is a magic value for traverseName (".", "..", "/")
raise SynchronizationError("invalid separator in name %r" % name)
if not name:
self.check_dir(container, fspath)
else:
try:
traverseName(container, name)
except:
self.check_new(fspath)
else:
self.check_old(container, name, fspath)
# Now check extra and annotations
try:
obj = traverseName(container, name)
except:
pass
else:
adapter = get_adapter(obj)
extra = adapter.extra()
extrapath = fsutil.getextra(fspath)
if extra is not None and os.path.exists(extrapath):
self.check_dir(extra, extrapath)
ann = adapter.annotations()
annpath = fsutil.getannotations(fspath)
if ann is not None and os.path.exists(annpath):
self.check_dir(ann, annpath)
def check_dir(self, container, fspath):
"""Helper to check a directory."""
adapter = get_adapter(container)
nameset = {}
if IObjectDirectory.isImplementedBy(adapter):
for name, obj in adapter.contents():
nameset[name] = 1
else:
for name in container:
nameset[name] = 1
for name in self.metadata.getnames(fspath):
nameset[name] = 1
# Sort the list of keys for repeatability
names = nameset.keys()
names.sort()
for name in names:
self.check(container, name, os.path.join(fspath, name))
def check_new(self, fspath):
"""Helper to check a new object."""
entry = self.metadata.getentry(fspath)
if entry:
if entry.get("flag") != "added":
self.conflict(fspath)
else:
if not os.path.exists(fspath):
self.conflict(fspath)
if os.path.isdir(fspath):
# Recursively check registered contents
for name in self.metadata.getnames(fspath):
self.check_new(os.path.join(fspath, name))
def check_old(self, container, name, fspath):
"""Helper to check an existing object."""
entry = self.metadata.getentry(fspath)
if not entry:
self.conflict(fspath)
if "conflict" in entry:
self.conflict(fspath)
flag = entry.get("flag")
if flag == "removed":
if os.path.exists(fspath):
self.conflict(fspath)
else:
if not os.path.exists(fspath):
self.conflict(fspath)
obj = traverseName(container, name)
adapter = get_adapter(obj)
if IObjectDirectory.isImplementedBy(adapter):
if flag != "removed" or os.path.exists(fspath):
self.check_dir(obj, fspath)
else:
if flag == "added":
self.conflict(fspath)
oldfspath = fsutil.getoriginal(fspath)
if not os.path.exists(oldfspath):
self.conflict(fspath)
else:
olddata = read_file(oldfspath)
curdata = adapter.getBody()
if curdata != olddata:
self.conflict(fspath)
def conflict(self, fspath):
"""Helper to report a conflict.
Conflicts can be retrieved by calling errors().
"""
if self.raise_on_conflicts:
raise SynchronizationError(fspath)
if fspath not in self.conflicts:
self.conflicts.append(fspath)
class Committer(object):
"""Commit changes from the filesystem to the object database.
The filesystem's originals must consistent with the object
database; this should be checked beforehand by a Checker instance
with the same arguments.
The public API consists of __init__() and synch() only.
"""
def __init__(self, metadata=None):
"""Constructor. Optionally pass a metadata database."""
if metadata is None:
metadata = Metadata()
self.metadata = metadata
def synch(self, container, name, fspath):
"""Synchronize an object or object tree from the filesystem.
SynchronizationError is raised for errors that can't be
corrected by a update operation, including invalid object
names.
"""
if (os.sep in name or
(os.altsep and os.altsep in name) or
name == os.curdir or
name == os.pardir or
name == "." or
name == ".." or
"/" in name):
# This name can't be mapped safely to the filesystem
# or it is a magic value for traverseName (".", "..", "/")
raise SynchronizationError("invalid separator in name %r" % name)
if not name:
self.synch_dir(container, fspath)
else:
try:
traverseName(container, name)
except:
self.synch_new(container, name, fspath)
else:
self.synch_old(container, name, fspath)
# Now update extra and annotations
try:
obj = traverseName(container, name)
except:
pass
else:
adapter = get_adapter(obj)
extra = adapter.extra()
extrapath = fsutil.getextra(fspath)
if extra is not None and os.path.exists(extrapath):
self.synch_dir(extra, extrapath)
ann = adapter.annotations()
annpath = fsutil.getannotations(fspath)
if ann is not None and os.path.exists(annpath):
self.synch_dir(ann, annpath)
def synch_dir(self, container, fspath):
"""Helper to synchronize a directory."""
adapter = get_adapter(container)
nameset = {}
if IObjectDirectory.isImplementedBy(adapter):
for name, obj in adapter.contents():
nameset[name] = os.path.join(fspath, name)
else:
for name in container:
nameset[name] = os.path.join(fspath, name)
for name in self.metadata.getnames(fspath):
nameset[name] = os.path.join(fspath, name)
# Sort the list of keys for repeatability
names_paths = nameset.items()
names_paths.sort()
subdirs = []
# Do the non-directories first
for name, path in names_paths:
if os.path.isdir(path):
subdirs.append((name, path))
else:
self.synch(container, name, path)
# Now do the directories
for name, path in subdirs:
self.synch(container, name, path)
def synch_new(self, container, name, fspath):
"""Helper to synchronize a new object."""
entry = self.metadata.getentry(fspath)
if entry:
create_object(container, name, entry, fspath)
obj = traverseName(container, name)
adapter = get_adapter(obj)
if IObjectDirectory.isImplementedBy(adapter):
self.synch_dir(obj, fspath)
def synch_old(self, container, name, fspath):
"""Helper to synchronize an existing object."""
entry = self.metadata.getentry(fspath)
if entry.get("flag") == "removed":
delete_item(container, name)
return
if not entry:
# This object was not included on the filesystem; skip it
return
obj = traverseName(container, name)
adapter = get_adapter(obj)
if IObjectDirectory.isImplementedBy(adapter):
self.synch_dir(obj, fspath)
else:
if adapter.typeIdentifier() != entry.get("type"):
create_object(container, name, entry, fspath, replace=True)
else:
olddata = read_file(fsutil.getoriginal(fspath))
newdata = read_file(fspath)
if newdata != olddata:
if not entry.get("factory"):
# If there's no factory, we can't call setBody()
create_object(container, name, entry, fspath, True)
obj = traverseName(container, name)
else:
adapter.setBody(newdata)
# Now publish an event, but not for annotations or
# extras. To know which case we have, see if
# getName() works. XXX This is a hack.
try:
getName(obj)
except:
pass
else:
publish(obj, ObjectModifiedEvent(obj))
# Functions below this point are all helpers and not part of the
# API offered by this module. They can be functions because they
# don't use the metadata database or add to the list of conflicts.
def create_object(container, name, entry, fspath, replace=False):
"""Helper to create an item in a container or mapping."""
factory_name = entry.get("factory")
if factory_name:
# A given factory overrides everything
factory = resolve(factory_name)
obj = factory()
obj = ContextWrapper(obj, container, name=name)
adapter = get_adapter(obj)
if IObjectFile.isImplementedBy(adapter):
data = read_file(fspath)
adapter.setBody(data)
else:
# No factory; try using IFileFactory or IDirectoryFactory
as = getService(container, "Adapters")
isuffix = name.rfind(".")
if isuffix >= 0:
suffix = name[isuffix:]
else:
suffix = "."
if os.path.isdir(fspath):
iface = IDirectoryFactory
else:
iface = IFileFactory
factory = as.queryNamedAdapter(container, iface, suffix)
if factory is None:
factory = as.queryAdapter(container, iface)
if iface is IDirectoryFactory:
if factory:
obj = factory(name)
obj = removeAllProxies(obj)
else:
raise SynchronizationError(
"don't know how to create a directory",
container,
name)
else:
if factory:
data = read_file(fspath)
obj = factory(name, None, data)
obj = removeAllProxies(obj)
else:
# Oh well, assume the file is an xml pickle
obj = load_file(fspath)
set_item(container, name, obj, replace)
def set_item(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)
if newname != name:
raise SynchronizationError(
"Container generated new name for %s (new name %s)" %
(name, newname))
else:
# Not a container, must be a mapping
# (This is used for extras and annotations)
container[name] = obj
def delete_item(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(fspath):
"""Helper to load an xml pickle from a file."""
return loads(read_file(fspath, "r"))
def read_file(fspath, mode="rb"):
"""Helper to read the data from a file."""
assert mode in ("r", "rb")
f = open(fspath, mode)
try:
data = f.read()
finally:
f.close()
return data
def get_adapter(obj):
"""Helper to get the special fssync adapter."""
syncService = getService(obj, 'FSRegistryService')
return syncService.getSynchronizer(obj)
=== Zope3/src/zope/app/fssync/classes.py 1.4 => 1.4.2.1 ===
--- Zope3/src/zope/app/fssync/classes.py:1.4 Thu May 15 12:19:04 2003
+++ Zope3/src/zope/app/fssync/classes.py Sun Jun 22 10:23:03 2003
@@ -18,38 +18,19 @@
import os
-from zope.app.content.file import File
-from zope.app.content.folder import Folder
-from zope.app.interfaces.fssync import IFSAddView, IObjectFile
+from zope.app.interfaces.fssync import IObjectFile
+from zope.app.interfaces.annotation import IAnnotations
+from zope.component import queryAdapter
from zope.component.interfaces import IPresentationRequest
from zope.xmlpickle import dumps
-from zope.proxy.introspection import removeAllProxies
-
-class FSAddView(object):
- """See IFSAddView."""
-
- __implements__ = IFSAddView
-
- def __init__(self, context, request):
- self.context = context
- self.request = request
-
-class AddView(FSAddView):
- """Supports to create a file system representation of zope
- file type objects
- """
-
- def create(self, fs_path=None):
- if os.path.isdir(fs_path):
- return Folder()
- else:
- return File()
+from zope.proxy import removeAllProxies
+from zope.interface import implements
class AttrMapping(object):
"""Convenience object implementing a mapping on selected object attributes
"""
- def __init__(self, context, attrs, schema=None):
+ def __init__(self, context, attrs):
self.attrs = attrs
self.context = context
@@ -88,16 +69,20 @@
self.context = context
def extra(self):
- "See Zope.App.FSSync.IObjectEntry.IObjectEntry"
+ "See IObjectEntry"
return None
+ def annotations(self):
+ "See IObjectEntry"
+ return queryAdapter(self.context, IAnnotations)
+
def typeIdentifier(self):
- "See Zope.App.FSSync.IObjectEntry.IObjectEntry"
+ "See IObjectEntry"
class_ = self.context.__class__
return "%s.%s" % (class_.__module__, class_.__name__)
def factory(self):
- "See Zope.App.FSSync.IObjectEntry.IObjectEntry"
+ "See IObjectEntry"
# Return the dotted class name, assuming that it can be used
class_ = self.context.__class__
return "%s.%s" % (class_.__module__, class_.__name__)
@@ -105,7 +90,7 @@
class Default(ObjectEntryAdapter):
"""Default File-system representation for objects."""
- __implements__ = IObjectFile
+ implements(IObjectFile)
def __init__(self, context):
# XXX for now, remove all proxies.
@@ -118,20 +103,14 @@
return dumps(self.context)
def setBody(self, body):
- pass
+ "See IObjectFile"
+ raise NotImplementedError
def factory(self):
"See IObjectEntry"
# We have no factory, cause we're a pickle.
return None
-class FSAddRequest(object):
- """XXX docstring???"""
-
- __implements__ = IPresentationRequest
-
- def getPresentationType(self):
- return IFSAddView
-
- def getPresentationSkin(self):
- return 'default'
+ def annotations(self):
+ # The annotations are already stored in the pickle.
+ return None
=== Zope3/src/zope/app/fssync/configure.zcml 1.2 => 1.2.4.1 ===
--- Zope3/src/zope/app/fssync/configure.zcml:1.2 Mon May 5 14:01:01 2003
+++ Zope3/src/zope/app/fssync/configure.zcml Sun Jun 22 10:23:03 2003
@@ -10,11 +10,4 @@
component="zope.app.fssync.fsregistry.fsRegistry"
/>
- <view
- factory="zope.app.fssync.classes.AddView"
- for="zope.app.interfaces.fssync.IContentDirectory"
- type="zope.app.interfaces.fssync.IFSAddView"
- name="."
- />
-
</zopeConfigure>
=== Zope3/src/zope/app/fssync/fsregistry.py 1.3 => 1.3.2.1 ===
--- Zope3/src/zope/app/fssync/fsregistry.py:1.3 Thu May 15 14:45:33 2003
+++ Zope3/src/zope/app/fssync/fsregistry.py Sun Jun 22 10:23:03 2003
@@ -20,6 +20,7 @@
from zope.app.interfaces.fssync import IGlobalFSSyncService
from zope.exceptions import DuplicationError, NotFoundError
+from zope.interface import implements
class FSRegistry(object):
"""Registry Wrapper class.
@@ -27,7 +28,7 @@
This is a maping from Class -> Serializer Factory Method.
"""
- __implements__ = IGlobalFSSyncService
+ implements(IGlobalFSSyncService)
def __init__(self):
self._class_factory_reg = {}
=== Zope3/src/zope/app/fssync/syncer.py 1.19 => 1.19.2.1 ===
--- Zope3/src/zope/app/fssync/syncer.py:1.19 Wed May 21 16:29:45 2003
+++ Zope3/src/zope/app/fssync/syncer.py Sun Jun 22 10:23:03 2003
@@ -23,34 +23,33 @@
from zope.app.interfaces.fssync \
import IObjectEntry, IObjectDirectory, IObjectFile
-from zope.app.interfaces.annotation import IAnnotations
from zope.app.interfaces.container import IContainer
from zope.configuration.name import resolve
from zope.app.fssync.classes import Default
from zope.app.traversing import getPath
from zope.app.fssync.fsregistry import getSynchronizer
from zope.app.interfaces.file import IFileFactory
-from zope.proxy.introspection import removeAllProxies
+from zope.proxy import removeAllProxies
-def readFile(path):
- f = open(path)
+def readFile(path, mode="rb"):
+ f = open(path, mode)
try:
return f.read()
finally:
f.close()
-def writeFile(data, path):
- f = open(path, "w")
+def writeFile(data, path, mode="wb"):
+ f = open(path, mode)
try:
f.write(data)
finally:
f.close()
def loadFile(path):
- return loads(readFile(path))
+ return loads(readFile(path, "r"))
def dumpFile(obj, path):
- writeFile(dumps(obj), path)
+ writeFile(dumps(obj), path, "w")
def toFS(ob, name, location):
"""Check an object out to the file system
@@ -89,7 +88,7 @@
try:
objectPath = str(getPath(ob))
- except TypeError:
+ except (TypeError, KeyError):
objectPath = ''
else:
entries[name]['path'] = objectPath
@@ -111,7 +110,7 @@
toFS(edata, ename, extra_dir)
# Handle annotations
- annotations = queryAdapter(ob, IAnnotations)
+ annotations = adapter.annotations()
if annotations is not None:
annotation_dir = os.path.join(admin_dir, 'Annotations')
if not os.path.exists(annotation_dir):
@@ -133,219 +132,13 @@
else:
# Directory
assert IObjectDirectory.isImplementedBy(adapter)
- if os.path.exists(path):
- dir_entries = os.path.join(path, '@@Zope', 'Entries.xml')
- if os.path.exists(dir_entries):
- dumpFile({}, dir_entries)
- else:
+ if not os.path.exists(path):
os.mkdir(path)
+ admin_dir = os.path.join(path, '@@Zope')
+ if not os.path.exists(admin_dir):
+ os.mkdir(admin_dir)
+ dir_entries = os.path.join(admin_dir, 'Entries.xml')
+ dumpFile({}, dir_entries)
for cname, cob in adapter.contents():
toFS(cob, cname, path)
-
-
-class SynchronizationError(Exception):
- pass
-
-
-def _setItem(container, name, ob, old=False):
- # Set an item in a container or in a mapping
- if IContainer.isImplementedBy(container):
- if old:
- del container[name]
- newName = container.setObject(name, ob)
- if newName != name:
- raise SynchronizationError(
- "Container generated new name for %s (new name %s)" %
- (name, newName))
- else:
- # Not a container, must be a mapping
- container[name] = ob
-
-
-def _create(container, name, factory, path, old=False):
- # Create an item in a container or in a mapping
- if factory:
- # A given factory overrides everything
- newOb = resolve(factory)()
- else:
- # No factory; try using the newfangled IFileFactory feature
- as = getService(container, "Adapters")
- isuffix = name.rfind(".")
- if isuffix >= 0:
- suffix = name[isuffix:]
- else:
- suffix = "."
-
- factory = as.queryNamedAdapter(container, IFileFactory, suffix)
- if factory is None:
- factory = as.queryAdapter(container, IFileFactory)
-
- if factory:
- newOb = factory(name, None, readFile(path))
- newOb = removeAllProxies(newOb)
- else:
- # Oh well, do it the oldfashioned way
- newOb = loadFile(path)
-
- _setItem(container, name, newOb, old)
-
- return newOb
-
-
-def fromFS(container, name, location):
- """Synchromize a file from what's on the file system.
-
- container -- parent of new object
-
- name -- name of new object in container
-
- location -- filesystem directory containing name
- """
- if not name:
- # Special case: loading the root folder.
- # Don't make changes to the root, but change everything underneath.
- path = os.path.join(location, "root")
- if not os.path.isdir(path):
- raise SynchronizationError("root folder not found")
-
- dir_entries_path = os.path.join(path, '@@Zope', 'Entries.xml')
- if os.path.exists(dir_entries_path):
- dir_entries = loadFile(dir_entries_path)
- else:
- dir_entries = {}
- for cname in dir_entries:
- fromFS(container, cname, path)
-
- return
-
- # Look for location admin dir
- admin_dir = os.path.join(location, '@@Zope')
- if not os.path.exists(admin_dir):
- raise SynchronizationError("No @@Zope admin directory, %s" % admin_dir)
-
- # Open Entries file
- entries_path = os.path.join(admin_dir, "Entries.xml")
- entries = loadFile(entries_path)
- entry = entries[name]
- factory = entry.get('factory')
-
- # Get name path and check that name is not an absolute path
- path = os.path.join(location, name)
- if path == name:
- raise ValueError("Invalid absolute path name")
-
- # See if this is an existing object
- if name not in container:
- # Not there; we need to create a new object
- assert entry.get("flag") == "added", name
- newOb = _create(container, name, factory, path)
-
- else:
- # It's there; let's see if we need to delete it
- if entry.get("flag") == "removed":
- del container[name]
- return # That was easy!
-
- # No, updating. Let's see if we have the same kind of object
-
- # Get the object adapter
- ob = container[name]
- syncService = getService(ob, 'FSRegistryService')
- adapter = syncService.getSynchronizer(ob)
-
- # Replace the object if the type is different
- if adapter.typeIdentifier() != entry.get('type'):
- # We have a different object, replace the one that's there
-
- newOb = _create(container, name, factory, path, old=True)
-
- elif not factory:
- if entry.get('type') == '__builtin__.str':
- newOb = readFile(path)
- _setItem(container, name, newOb, old=True)
- else:
- # Special case pickle data
- oldOb = container[name]
- oldOb = removeAllProxies(oldOb)
- newOb = loadFile(path)
- try:
- # See if we can and should just copy the state
- oldOb._p_oid # Is it persistent?
- getstate = newOb.__getstate__
- except AttributeError:
- # Nope, we have to replace
- _setItem(container, name, newOb, old=True)
- else:
- oldOb.__setstate__(getstate())
- oldOb._p_changed = True
- # XXX else, what?
-
- # Get the object adapter again
- ob = container[name]
- syncService = getService(ob, 'FSRegistryService')
- adapter = syncService.getSynchronizer(ob)
-
- # Handle extra
- extra = adapter.extra()
- extra_dir = os.path.join(admin_dir, 'Extra', name)
- extra_entries_path = os.path.join(extra_dir, "@@Zope", "Entries.xml")
- if extra:
- if not os.path.exists(extra_entries_path):
- if entry.get("flag") != "added":
- # The file system has no extras, so delete all of the
- # object's extras.
- for key in list(extra):
- del extra[key]
- else:
- extra_entries = loadFile(extra_entries_path)
- for ename in extra_entries:
- fromFS(extra, ename, extra_dir)
- elif os.path.exists(extra_entries_path):
- extra_entries = loadFile(extra_entries_path)
- if extra_entries:
- raise SynchronizationError(
- "File-system extras for object with no extra data")
-
- # Handle annotations
- annotations = queryAdapter(ob, IAnnotations)
- annotation_dir = os.path.join(admin_dir, 'Annotations', name)
- annotation_entries_path = os.path.join(
- annotation_dir, "@@Zope", "Entries.xml")
- if annotations is not None:
- if not os.path.exists(annotation_entries_path):
- if entry.get("flag") != "added":
- # The file system has no annotations, so delete all of
- # the object's annotations.
- for key in list(annotations):
- del annotations[key]
- else:
- annotation_entries = loadFile(annotation_entries_path)
- for ename in annotation_entries:
- fromFS(annotations, ename, annotation_dir)
- elif os.path.exists(annotation_entries_path):
- annotation_entries = loadFile(annotation_entries_path)
- if annotation_entries:
- raise SynchronizationError(
- "File-system annotations for non annotatable object")
-
- # Handle data
- if IObjectFile.isImplementedBy(adapter):
- # File
- if os.path.isdir(path):
- raise SynchronizationError("Object is file, but data is directory")
- adapter.setBody(readFile(path))
-
- else:
- # Directory
- assert IObjectDirectory.isImplementedBy(adapter)
- if not os.path.isdir(path):
- raise SynchronizationError("Object is directory, but data is file")
-
- dir_entries_path = os.path.join(path, '@@Zope', 'Entries.xml')
- if os.path.exists(dir_entries_path):
- dir_entries = loadFile(dir_entries_path)
- else:
- dir_entries = {}
- for cname in dir_entries:
- fromFS(ob, cname, path)