From ea09e0d836c4ea78233d665ed57e798f7bf5b796 Mon Sep 17 00:00:00 2001 From: helmutm Date: Sun, 15 Apr 2007 08:45:12 +0000 Subject: [PATCH] loops.integrator: integrating filesystem directories working git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1691 fd906abe-77d9-0310-91a1-e0d9ade77398 --- common.py | 12 ++++++++++++ integrator/README.txt | 27 +++++++++++++++++++++++--- integrator/collection.py | 41 ++++++++++++++++++++++++++++++---------- tests/setup.py | 15 ++++++++++++--- versioning/README.txt | 5 +++++ 5 files changed, 84 insertions(+), 16 deletions(-) diff --git a/common.py b/common.py index e6e4449..dd6bd65 100644 --- a/common.py +++ b/common.py @@ -31,10 +31,22 @@ from zope.interface import implements from zope.cachedescriptors.property import Lazy from cybertools.storage.interfaces import IStorageInfo +from cybertools.typology.interfaces import IType from loops.interfaces import ILoopsObject, ILoopsContained, IConcept, IResource from loops.interfaces import IResourceAdapter +def adapted(obj): + t = IType(obj, None) + if t is not None: + ti = t.typeInterface + if ti is not None: + adapted = ti(obj, None) + if adapted is not None: + return adapted + return obj + + # type interface adapters class AdapterBase(object): diff --git a/integrator/README.txt b/integrator/README.txt index 670e057..215ee1f 100644 --- a/integrator/README.txt +++ b/integrator/README.txt @@ -86,9 +86,17 @@ Let's now create the corresponding resource objects. u'programming_beautifulprogram.pdf' >>> xf1.title u'BeautifulProgram' + >>> xf1.contentType + 'application/pdf' - >>> for r in res: - ... del resources[r.__name__] + >>> from loops.common import adapted + >>> aXf1 = adapted(xf1) + >>> aXf1.storageName + 'fullpath' + >>> aXf1.storageParams + {'subdirectory': '...topics'} + + >>> for r in res: del resources[r.__name__] Working with the External Collection ------------------------------------ @@ -102,7 +110,20 @@ Working with the External Collection [(u'programming_beautifulprogram.pdf', u'BeautifulProgram', 'fullpath'), (u'programming_zope_zope3.txt', u'zope3', 'fullpath')] -To do: Check storage parameters. +If one of the referenced objects is not found any more it will be deleted. +So if we change one of the collection parameters probably all old resources +will be removed and newly created. + + >>> import os + >>> aColl01.address = os.path.join('topics', 'programming') + >>> aColl01.update() + >>> res = sorted(coll01.getResources(), key=lambda x: getName(x)) + >>> len(res) + 2 + >>> xf1 = res[0] + >>> aXf1 = adapted(xf1) + >>> aXf1.storageParams + {'subdirectory': '...programming'} Fin de partie diff --git a/integrator/collection.py b/integrator/collection.py index 529236f..f9fc25f 100644 --- a/integrator/collection.py +++ b/integrator/collection.py @@ -26,19 +26,20 @@ $Id$ from datetime import datetime import os, re, stat -from zope import component -from zope.lifecycleevent import ObjectModifiedEvent -from zope.event import notify from zope.app.container.interfaces import INameChooser -from zope.component import adapts -from zope.interface import implements, Attribute from zope.cachedescriptors.property import Lazy +from zope import component +from zope.component import adapts +from zope.contenttype import guess_content_type +from zope.event import notify +from zope.lifecycleevent import ObjectModifiedEvent +from zope.interface import implements, Attribute from zope.schema.interfaces import IField from zope.traversing.api import getName, getParent from cybertools.text import mimetypes from cybertools.typology.interfaces import IType -from loops.common import AdapterBase +from loops.common import AdapterBase, adapted from loops.interfaces import IResource, IConcept from loops.integrator.interfaces import IExternalCollection from loops.integrator.interfaces import IExternalCollectionProvider @@ -63,12 +64,16 @@ class ExternalCollectionAdapter(AdapterBase): def update(self): existing = self.context.getResources() - old = dict((obj.externalAddress, obj) for obj in existing) + old = dict((adapted(obj).externalAddress, obj) for obj in existing) new = [] + oldFound = [] provider = component.getUtility(IExternalCollectionProvider, name=self.providerName or '') for addr, mdate in provider.collect(self): if addr in old: + # may be it would be better to return a file's hash + # for checking for changes... + oldFound.append(addr) if mdate > self.lastUpdated: # force reindexing notify(ObjectModifiedEvent(old[addr])) @@ -78,8 +83,23 @@ class ExternalCollectionAdapter(AdapterBase): newResources = provider.createExtFileObjects(self, new) for r in newResources: self.context.assignResource(r) + for addr in old: + if addr not in oldFound: + # not part of the collection any more + self.remove(old[addr]) self.lastUpdated = datetime.today() + def clear(self): + for obj in self.context.getResources(): + self.remove(obj) + + def remove(self, obj): + del self.resourceManager[getName(obj)] + + @Lazy + def resourceManager(self): + return self.context.getLoopsRoot().getResourceManager() + class DirectoryCollectionProvider(object): """ A utility that provides access to files in a directory. @@ -95,8 +115,6 @@ class DirectoryCollectionProvider(object): del dirs[dirs.index('.svn')] for f in files: if pattern.match(f): - # may be it would be better to return a file's hash - # for checking for changes... mtime = os.stat(os.path.join(path, f))[stat.ST_MTIME] yield (os.path.join(path[len(directory)+1:], f), datetime.fromtimestamp(mtime)) @@ -115,7 +133,10 @@ class DirectoryCollectionProvider(object): resourceType=extFileType, externalAddress=addr, storageName='fullpath', - storageParams=dict(subdirectory=directory)) + storageParams=dict(subdirectory=directory), + contentType = guess_content_type(addr, + default='application/octet-stream')[0] + ) yield obj def getDirectory(self, client): diff --git a/tests/setup.py b/tests/setup.py index 97401f8..a937d88 100644 --- a/tests/setup.py +++ b/tests/setup.py @@ -9,20 +9,23 @@ from zope.app.catalog.catalog import Catalog from zope.app.catalog.interfaces import ICatalog from zope.app.catalog.field import FieldIndex from zope.app.catalog.text import TextIndex +from zope.app.container.interfaces import IObjectRemovedEvent from cybertools.relation.tests import IntIdsStub from cybertools.relation.registry import RelationRegistry -from cybertools.relation.interfaces import IRelationRegistry +from cybertools.relation.interfaces import IRelation, IRelationRegistry +from cybertools.relation.interfaces import IRelationInvalidatedEvent from cybertools.relation.registry import IndexableRelationAdapter +from cybertools.relation.registry import invalidateRelations, removeRelation from cybertools.typology.interfaces import IType from loops import Loops from loops import util from loops.common import NameChooser -from loops.interfaces import IIndexAttributes, IDocument +from loops.interfaces import ILoopsObject, IIndexAttributes, IDocument, IFile from loops.concept import Concept from loops.concept import IndexAttributes as ConceptIndexAttributes -from loops.resource import Resource +from loops.resource import Resource, FileAdapter from loops.resource import IndexAttributes as ResourceIndexAttributes from loops.setup import SetupManager, addObject from loops.type import LoopsType, ConceptType, ResourceType, TypeConcept @@ -46,8 +49,14 @@ class TestSite(object): component.provideAdapter(ConceptType) component.provideAdapter(ResourceType, (IDocument,)) component.provideAdapter(TypeConcept) + component.provideAdapter(FileAdapter, provides=IFile) component.provideAdapter(NameChooser) + component.getSiteManager().registerHandler(invalidateRelations, + (ILoopsObject, IObjectRemovedEvent)) + component.getSiteManager().registerHandler(removeRelation, + (IRelation, IRelationInvalidatedEvent)) + catalog = self.catalog = Catalog() component.provideUtility(catalog, ICatalog) catalog['loops_title'] = TextIndex('title', IIndexAttributes, True) diff --git a/versioning/README.txt b/versioning/README.txt index 63b9a5d..1cedfc8 100644 --- a/versioning/README.txt +++ b/versioning/README.txt @@ -132,3 +132,8 @@ In addition it is possible to explicitly retrieve a certain version: >>> IVersionable(getVersion(d001v1_2, TestRequest(form=dict(version='1.1')))).versionId '1.1' + +Fin de partie +============= + + >>> placefulTearDown()