|
- #!/usr/bin/env python
- # Copyright 2006 John-Mark Gurney <gurney_j@resnet.uoregon.edu>
- #
- # $Id$
- #
-
- import FileDIDL
- import errno
- import itertools
- import os
- import sets
- import stat
-
- from DIDLLite import StorageFolder, Item, VideoItem, AudioItem, TextItem, ImageItem, Resource
- from twisted.web import static
- from twisted.python import log
-
- __all__ = [ 'registerklassfun', 'FSObject', 'FSItem', 'FSVideoItem',
- 'FSAudioItem', 'FSTextItem', 'FSImageItem', 'mimetoklass',
- 'FSDirectory',
- ]
-
- mimedict = static.loadMimeTypes()
-
- klassfuns = []
-
- def registerklassfun(fun):
- klassfuns.append(fun)
-
- def statcmp(a, b, cmpattrs = [ 'st_ino', 'st_dev', 'st_size', 'st_mtime', ]):
- if a is None or b is None:
- return False
-
- for i in cmpattrs:
- if getattr(a, i) != getattr(b, i):
- return False
- return True
-
- class FSObject(object):
- def __init__(self, path):
- self.FSpath = path
- self.pstat = None
-
- def checkUpdate(self):
- # need to handle no such file or directory
- # push it up? but still need to handle disappearing
- try:
- nstat = os.stat(self.FSpath)
- if statcmp(self.pstat, nstat):
- return self
-
- self.pstat = nstat
- self.doUpdate()
- except OSError, x:
- log.msg('os.stat, OSError: %s' % x)
- if x.errno in (errno.ENOENT, errno.ENOTDIR, errno.EPERM, ):
- # We can't access it anymore, delete it
- self.cd.delItem(self.id)
- return None
- else:
- raise x
-
- return self
-
- def doUpdate(self):
- raise NotImplementedError
-
- class FSItem(FSObject, Item):
- def __init__(self, *args, **kwargs):
- FSObject.__init__(self, kwargs['path'])
- del kwargs['path']
- mimetype = kwargs['mimetype']
- del kwargs['mimetype']
- kwargs['content'] = static.File(self.FSpath)
- Item.__init__(self, *args, **kwargs)
- self.url = '%s/%s' % (self.cd.urlbase, self.id)
- self.mimetype = mimetype
-
- def doUpdate(self):
- self.res = Resource(self.url, 'http-get:*:%s:*' % self.mimetype)
- self.res.size = os.path.getsize(self.FSpath)
- Item.doUpdate(self)
-
- def defFS(path, fobj):
- if os.path.isdir(path):
- # new dir
- return FSDirectory, { 'path': path }
- elif os.path.isfile(path):
- # new file - fall through to below
- pass
- else:
- log.msg('skipping (not dir or reg): %s' % path)
- return None, None
-
- klass, mt = FileDIDL.buildClassMT(FSItem, path)
-
- return klass, { 'path': path, 'mimetype': mt }
-
- def dofileadd(cd, parent, path, name):
- klass = None
- fsname = os.path.join(path, name)
- try:
- fobj = open(fsname)
- except:
- fobj = None
- for i in itertools.chain(klassfuns, ( defFS, )):
- try:
- try:
- fobj.seek(0) # incase the call expects a clean file
- except:
- pass
-
- #log.msg('testing:', `i`, `fsname`, `fobj`)
- klass, kwargs = i(fsname, fobj)
- if klass is not None:
- break
- except:
- #import traceback
- #traceback.print_exc(file=log.logfile)
- pass
-
- if klass is None:
- return
-
- #log.msg('matched:', os.path.join(path, name), `i`, `klass`)
- return cd.addItem(parent, klass, name, **kwargs)
-
- class FSDirectory(FSObject, StorageFolder):
- def __init__(self, *args, **kwargs):
- path = kwargs['path']
- del kwargs['path']
- StorageFolder.__init__(self, *args, **kwargs)
- FSObject.__init__(self, path)
-
- # mapping from path to objectID
- self.pathObjmap = {}
-
- def doUpdate(self):
- # We need to rescan this dir, and see if our children has
- # changed any.
- doupdate = False
- children = sets.Set(os.listdir(self.FSpath))
- for i in self.pathObjmap.keys():
- if i not in children:
- doupdate = True
- # delete
- self.cd.delItem(self.pathObjmap[i])
- del self.pathObjmap[i]
-
- for i in children:
- if i in self.pathObjmap:
- continue
-
- # new object
- nf = dofileadd(self.cd, self.id, self.FSpath, i)
-
- if nf is not None:
- doupdate = True
- self.pathObjmap[i] = nf
-
- # sort our children
- self.sort(lambda x, y: cmp(x.title, y.title))
-
- # Pass up to handle UpdateID
- if doupdate:
- StorageFolder.doUpdate(self)
|