1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Affero General Public License for more details.
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
21 import six
.moves
.urllib
.parse
as urlparse
23 from mediagoblin
.storage
import (
28 class FileObjectAwareFile(io
.FileIO
):
29 def write(self
, data
):
30 if hasattr(data
, 'read'):
31 # We can call data.read(). It means that the data is a file-like
32 # object, which should be saved RAM-friendly way
33 shutil
.copyfileobj(data
, self
)
35 super(FileObjectAwareFile
, self
).write(data
)
38 class BasicFileStorage(StorageInterface
):
40 Basic local filesystem implementation of storage API
45 def __init__(self
, base_dir
, base_url
=None, **kwargs
):
48 - base_dir: Base directory things will be served out of. MUST
50 - base_url: URL files will be served from
52 self
.base_dir
= base_dir
53 self
.base_url
= base_url
55 def _resolve_filepath(self
, filepath
):
57 Transform the given filepath into a local filesystem filepath.
60 self
.base_dir
, *clean_listy_filepath(filepath
))
62 def file_exists(self
, filepath
):
63 return os
.path
.exists(self
._resolve
_filepath
(filepath
))
65 def get_file(self
, filepath
, mode
='r'):
66 # Make directories if necessary
68 directory
= self
._resolve
_filepath
(filepath
[:-1])
69 if not os
.path
.exists(directory
):
70 os
.makedirs(directory
)
72 # Grab and return the file in the mode specified
73 return FileObjectAwareFile(self
._resolve
_filepath
(filepath
), mode
)
75 def delete_file(self
, filepath
):
76 """Delete file at filepath
78 Raises OSError in case filepath is a directory."""
80 os
.remove(self
._resolve
_filepath
(filepath
))
82 def delete_dir(self
, dirpath
, recursive
=False):
83 """returns True on succes, False on failure"""
85 dirpath
= self
._resolve
_filepath
(dirpath
)
87 # Shortcut the default and simple case of nonempty=F, recursive=F
90 shutil
.rmtree(dirpath
)
92 #TODO: log something here
94 else: # recursively delete everything
98 #TODO: log something here
102 def file_url(self
, filepath
):
103 if not self
.base_url
:
105 "base_url not set, cannot provide file urls")
107 return urlparse
.urljoin(
109 '/'.join(clean_listy_filepath(filepath
)))
111 def get_local_path(self
, filepath
):
112 return self
._resolve
_filepath
(filepath
)
114 def copy_local_to_storage(self
, filename
, filepath
):
116 Copy this file from locally to the storage system.
118 # Make directories if necessary
119 if len(filepath
) > 1:
120 directory
= self
._resolve
_filepath
(filepath
[:-1])
121 if not os
.path
.exists(directory
):
122 os
.makedirs(directory
)
123 # This uses chunked copying of 16kb buffers (Py2.7):
124 shutil
.copy(filename
, self
.get_local_path(filepath
))
126 def get_file_size(self
, filepath
):
127 return os
.stat(self
._resolve
_filepath
(filepath
)).st_size