Test suite runs and passes!
[zzz-floof.git] / floof / lib / file_storage.py
index 4469394..b30a662 100644 (file)
@@ -7,12 +7,6 @@ from pylons import config
 
 """
 Notes:
-# Here's one way to move stuff...
-shutil.copyfileobj(temp.file, dest_file)
-
-# we should probably store the basename of the original filename in the database somewhere
-temp_base = os.path.basename(temp.filename)
-
 # You can get a mime type like so:
 from mimetypes import guess_type
 guess_type(temp.filename)[0]
@@ -20,47 +14,51 @@ guess_type(temp.filename)[0]
 
 def get_path(space, hash):
     return "/" + os.path.join( space, hash[:2], hash[2:] )
-    
 
-def save_file(space, temp):   
-     
+
+def save_file(space, fileobj, hash=None):
+    """Saves the contents of fileobj to the given storage space.
+
+    If a hash is not provided, the SHA-1 sum of the file will be computed and
+    that will be used.  The ideal scenario here is to let the hash of the
+    original file be computed automatically, then create thumbnails et al. with
+    the same hash in a different space.
+
+    Returns the hashsum.
+    """
     dest_root = os.path.join( config['app_conf']['static_root'], space )
-    
-    # we don't know where we're going to save this stuff yet,
-    # so I guess we'll write it to another tempfile.  One we know the path of.
-    # I'm assuming the tempfile we get from pylons is set to delete itself 
-    # when it closes, and has no visible path.  Maybe I'm wrong?
-    intermediate_file_descriptor, intermediate_path = tempfile.mkstemp()
-    
-    # that function gives me an integer file descriptor for some reason.
-    intermediate_file = os.fdopen(intermediate_file_descriptor, "wb")
-    
-    sha1 = hashlib.sha1()
-    while 1:
-        data = temp.file.read(chunk_size)
-        if not data:
-            break
-        sha1.update(data)
-        intermediate_file.write(data)
 
-    temp.file.close()
-    intermediate_file.close()
-    hash = sha1.hexdigest()
+    # The incoming fileobj could be a tempfile that's already been unlinked --
+    # and probably is, as it's coming from a Pylons upload object.  Thus we
+    # have to copy the data rather than the file, and we may have to read the
+    # file anyway to hash it, so do both at the same time.
 
-    # git convention: first two characters are the directory
-    dest_dir = os.path.join( dest_root, hash[:2] )
-    dest_path =  os.path.join( dest_dir, hash[2:] )
+    # Need a named temporary file to write to; it gets renamed once the hash is
+    # computed
+    temp_fd, temp_path = tempfile.mkstemp()
+    temp_file = os.fdopen(temp_fd, "wb")
 
-    makedirs(dest_dir)
-    shutil.move(intermediate_path, dest_path)
+    sha1 = hashlib.sha1()
+    while True:
+        data = fileobj.read(chunk_size)
+        if not data:
+            break
 
-    return hash
+        if not hash:
+            sha1.update(data)
+        temp_file.write(data)
 
+    temp_file.close()
+    if not hash:
+        hash = sha1.hexdigest()
 
+    # Git convention: first two characters are the directory
+    dest_dir  = os.path.join(dest_root, hash[:2])
+    dest_path = os.path.join(dest_dir,  hash[2:])
 
-def makedirs(dir):
-    try:
-         os.makedirs(dir)
-    except OSError:
-         pass
+    if not os.path.exists(dest_dir):
+        os.makedirs(dest_dir)
+    print dest_path
+    shutil.move(temp_path, dest_path)
 
+    return hash