loops.integrator: integrating filesystem directories working
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1691 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
		
							parent
							
								
									9133b0fb52
								
							
						
					
					
						commit
						ea09e0d836
					
				
					 5 changed files with 84 additions and 16 deletions
				
			
		
							
								
								
									
										12
									
								
								common.py
									
										
									
									
									
								
							
							
						
						
									
										12
									
								
								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):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue