Adding a copy_locally() method to the StorageInterface and giving it a test.
[mediagoblin.git] / mediagoblin / storage.py
index 5d7e70d6eb5d69b865bbce3b23e242aa337347a7..ba6ac0173d5d46811e64ca9e217b5409f469eba6 100644 (file)
@@ -16,6 +16,7 @@
 
 import os
 import re
+import shutil
 import urlparse
 import uuid
 
@@ -60,6 +61,9 @@ class StorageInterface(object):
     StorageInterface.
     """
 
+    # Whether this file store is on the local filesystem.
+    local_storage = False
+
     def __raise_not_implemented(self):
         """
         Raise a warning about some component not implemented by a
@@ -127,12 +131,43 @@ class StorageInterface(object):
         else:
             return filepath
 
+    def get_local_path(self, filepath):
+        """
+        If this is a local_storage implementation, give us a link to
+        the local filesystem reference to this file.
+
+        >>> storage_handler.get_local_path(['foo', 'bar', 'baz.jpg'])
+        u'/path/to/mounting/foo/bar/baz.jpg'
+        """
+        # Subclasses should override this method, if applicable.
+        self.__raise_not_implemented()
+
+    def copy_locally(self, filepath, dest_path):
+        """
+        Copy this file locally.
+
+        A basic working method for this is provided that should
+        function both for local_storage systems and remote storge
+        systems, but if more efficient systems for copying locally
+        apply to your system, override this method with something more
+        appropriate.
+        """
+        if self.local_storage:
+            shutil.copy(
+                self.get_local_path(filepath), dest_path)
+        else:
+            with self.get_file(filepath, 'rb') as source_file:
+                with file(dest_path, 'wb') as dest_file:
+                    dest_file.write(source_file.read())
+
 
 class BasicFileStorage(StorageInterface):
     """
     Basic local filesystem implementation of storage API
     """
 
+    local_storage = True
+
     def __init__(self, base_dir, base_url=None, **kwargs):
         """
         Keyword arguments:
@@ -177,6 +212,9 @@ class BasicFileStorage(StorageInterface):
             self.base_url,
             '/'.join(clean_listy_filepath(filepath)))
 
+    def get_local_path(self, filepath):
+        return self._resolve_filepath(filepath)
+
 
 ###########
 # Utilities
@@ -187,7 +225,7 @@ def clean_listy_filepath(listy_filepath):
     Take a listy filepath (like ['dir1', 'dir2', 'filename.jpg']) and
     clean out any nastiness from it.
 
-    For example:
+
     >>> clean_listy_filepath([u'/dir1/', u'foo/../nasty', u'linooks.jpg'])
     [u'dir1', u'foo_.._nasty', u'linooks.jpg']
 
@@ -253,3 +291,5 @@ def storage_system_from_paste_config(paste_config, storage_prefix):
 
     storage_class = util.import_component(storage_class)
     return storage_class(**config_params)
+
+