from django.conf import settings
from telemeta.models import MediaItem
+
class CollectionSerializer(object):
"""Provide backup-related features"""
- def __init__(self, collection):
+ def __init__(self, collection, dest_dir='.'):
self.collection = collection
+ self.coll_dir = dest_dir + "/" + str(self.collection.id)
+ if not os.path.exists(self.coll_dir):
+ os.makedirs(self.coll_dir)
def __get_file_md5(self, path):
"Compute the MD5 hash of a file (Python version of md5sum)"
def __get_media_filename(self, item):
return str(item.id) + ".wav"
- def store(self, dest_dir):
- """Serialize and store the collection with related items and media
- files into a subdirectory of the provided directory
- """
- coll_dir = dest_dir + "/" + str(self.collection.id)
- os.mkdir(coll_dir)
-
- xml = self.get_xml()
- file = open(coll_dir + "/collection.xml", "wb")
- file.write(xml.encode("utf-8"))
- file.close()
-
+ def store_files(self):
if self.collection.has_mediafile():
- md5_file = open(coll_dir + "/MD5SUM", "wb")
+ md5_file = open(self.coll_dir + "/MD5SUM", "wb")
items = self.collection.items.all()
for item in items:
if item.file:
dst_basename = self.__get_media_filename(item)
- dst = coll_dir + "/" + dst_basename
+ dst = self.coll_dir + "/" + dst_basename
shutil.copyfile(item.file.path, dst)
hash = self.__get_file_md5(dst)
md5_file.write(hash + " " + dst_basename + "\n")
md5_file.close()
+ def store_json(self, dest_dir):
+ """Serialize and store the collection with related items and media
+ files into a subdirectory of the provided directory
+ """
+ json = self.collection.get_json()
+ file = open(self.coll_dir + "/collection.json", "wb")
+ file.write(json)
+ file.close()
+ self.store_files()
+
+ def store_xml(self, dest_dir):
+ """Serialize and store the collection with related items and media
+ files into a subdirectory of the provided directory
+ """
+ xml = self.get_xml()
+ file = open(self.coll_dir + "/collection.xml", "wb")
+ file.write(xml.encode("utf-8"))
+ file.close()
+ self.store_files()
+
def get_xml(self):
"""Return a string containing the XML representation of the collection
and related items
item_doc.unlink()
doc.normalize()
- # libxml2 has prettier output than xml.dom:
- tree = libxml2.parseDoc(doc.toxml(encoding="utf-8"))
- doc.unlink()
- xml = unicode(tree.serialize(encoding="utf-8", format=1), "utf-8")
- tree.free()
-
- return xml
+ return doc.toxml()
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
-# you should have received as part of this distribution.
+# you should have received as part of this distribution.
#
# Author: Jonas Borgström <jonas@edgewall.com>
# Christopher Lenz <cmlenz@gmx.de>
# Olivier Guilyardi <olivier@samalyse.com>
-__all__ = ['Component', 'ExtensionPoint', 'implements', 'Interface',
- 'TelemetaError']
+__all__ = ['TelemetaError']
class TelemetaError(Exception):
"""Exception base class for errors in Telemeta."""
pass
-
-class Interface(object):
- """Marker base class for extension point interfaces."""
-
-class ExtensionPoint(property):
- """Marker class for extension points in components."""
-
- def __init__(self, interface):
- """Create the extension point.
-
- @param interface: the `Interface` subclass that defines the protocol
- for the extension point
- """
- property.__init__(self, self.extensions)
- self.interface = interface
- self.__doc__ = 'List of components that implement `%s`' % \
- self.interface.__name__
-
- def extensions(self, component):
- """Return a list of components that declare to implement the extension
- point interface."""
- extensions = ComponentMeta._registry.get(self.interface, [])
- return filter(None, [component.compmgr[cls] for cls in extensions])
-
- def __repr__(self):
- """Return a textual representation of the extension point."""
- return '<ExtensionPoint %s>' % self.interface.__name__
-
-
-class ComponentMeta(type):
- """Meta class for components.
-
- Takes care of component and extension point registration.
- """
- _components = []
- _registry = {}
-
- def __new__(cls, name, bases, d):
- """Create the component class."""
-
- d['_implements'] = _implements[:]
- del _implements[:]
-
- new_class = type.__new__(cls, name, bases, d)
- if name == 'Component':
- # Don't put the Component base class in the registry
- return new_class
-
- # Only override __init__ for Components not inheriting ComponentManager
- if True not in [issubclass(x, ComponentManager) for x in bases]:
- # Allow components to have a no-argument initializer so that
- # they don't need to worry about accepting the component manager
- # as argument and invoking the super-class initializer
- init = d.get('__init__')
- if not init:
- # Because we're replacing the initializer, we need to make sure
- # that any inherited initializers are also called.
- for init in [b.__init__._original for b in new_class.mro()
- if issubclass(b, Component)
- and '__init__' in b.__dict__]:
- break
- def maybe_init(self, compmgr, init=init, cls=new_class):
- if cls not in compmgr.components:
- compmgr.components[cls] = self
- if init:
- init(self)
- maybe_init._original = init
- new_class.__init__ = maybe_init
-
- if d.get('abstract'):
- # Don't put abstract component classes in the registry
- return new_class
-
- ComponentMeta._components.append(new_class)
- for interface in d.get('_implements', []):
- ComponentMeta._registry.setdefault(interface, []).append(new_class)
- for base in [base for base in bases if hasattr(base, '_implements')]:
- for interface in base._implements:
- ComponentMeta._registry.setdefault(interface, []).append(new_class)
-
- return new_class
-
-
-_implements = []
-
-def implements(*interfaces):
- """Can be used in the class definiton of `Component` subclasses to declare
- the extension points that are extended.
- """
- _implements.extend(interfaces)
-
-
-class Component(object):
- """Base class for components.
-
- Every component can declare what extension points it provides, as well as
- what extension points of other components it extends.
- """
- __metaclass__ = ComponentMeta
-
- def __new__(cls, *args, **kwargs):
- """Return an existing instance of the component if it has already been
- activated, otherwise create a new instance.
- """
- # If this component is also the component manager, just invoke that
- if issubclass(cls, ComponentManager):
- self = super(Component, cls).__new__(cls)
- self.compmgr = self
- return self
-
- # The normal case where the component is not also the component manager
- compmgr = args[0]
- self = compmgr.components.get(cls)
- if self is None:
- self = super(Component, cls).__new__(cls)
- self.compmgr = compmgr
- compmgr.component_activated(self)
- return self
-
-
-class ComponentManager(object):
- """The component manager keeps a pool of active components."""
-
- def __init__(self):
- """Initialize the component manager."""
- self.components = {}
- self.enabled = {}
- if isinstance(self, Component):
- self.components[self.__class__] = self
-
- def __contains__(self, cls):
- """Return wether the given class is in the list of active components."""
- return cls in self.components
-
- def __getitem__(self, cls):
- """Activate the component instance for the given class, or return the
- existing the instance if the component has already been activated."""
- if cls not in self.enabled:
- self.enabled[cls] = self.is_component_enabled(cls)
- if not self.enabled[cls]:
- return None
- component = self.components.get(cls)
- if not component:
- if cls not in ComponentMeta._components:
- raise TelemetaError, 'Component "%s" not registered' % cls.__name__
- try:
- component = cls(self)
- except TypeError, e:
- raise TelemetaError, 'Unable to instantiate component %r (%s)' \
- % (cls, e)
- return component
-
- def component_activated(self, component):
- """Can be overridden by sub-classes so that special initialization for
- components can be provided.
- """
-
- def is_component_enabled(self, cls):
- """Can be overridden by sub-classes to veto the activation of a
- component.
-
- If this method returns False, the component with the given class will
- not be available.
- """
- return True