Commit | Line | Data |
---|---|---|
68784b9e | 1 | # GNU MediaGoblin -- federated, autonomous media hosting |
cf29e8a8 | 2 | # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. |
68784b9e CAW |
3 | # |
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. | |
8 | # | |
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. | |
13 | # | |
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/>. | |
16 | ||
678d1a20 CAW |
17 | import os |
18 | import shutil | |
68784b9e CAW |
19 | import tempfile |
20 | ||
21 | ||
678d1a20 CAW |
22 | # Actual workbench stuff |
23 | # ---------------------- | |
68784b9e | 24 | |
52426ae0 | 25 | class Workbench(object): |
68784b9e | 26 | """ |
52426ae0 | 27 | Represent the directory for the workbench |
b67a983a E |
28 | |
29 | WARNING: DO NOT create Workbench objects on your own, | |
30 | let the WorkbenchManager do that for you! | |
68784b9e | 31 | """ |
52426ae0 | 32 | def __init__(self, dir): |
b67a983a E |
33 | """ |
34 | WARNING: DO NOT create Workbench objects on your own, | |
35 | let the WorkbenchManager do that for you! | |
36 | """ | |
52426ae0 | 37 | self.dir = dir |
68784b9e | 38 | |
52426ae0 E |
39 | def __unicode__(self): |
40 | return unicode(self.dir) | |
243c3843 | 41 | |
52426ae0 E |
42 | def __str__(self): |
43 | return str(self.dir) | |
243c3843 | 44 | |
52426ae0 | 45 | def __repr__(self): |
26729e02 JW |
46 | try: |
47 | return str(self) | |
48 | except AttributeError: | |
49 | return 'None' | |
68784b9e | 50 | |
52426ae0 E |
51 | def joinpath(self, *args): |
52 | return os.path.join(self.dir, *args) | |
68784b9e | 53 | |
52426ae0 | 54 | def localized_file(self, storage, filepath, |
68ffb136 CAW |
55 | filename_if_copying=None, |
56 | keep_extension_if_copying=True): | |
68784b9e CAW |
57 | """ |
58 | Possibly localize the file from this storage system (for read-only | |
59 | purposes, modifications should be written to a new file.). | |
60 | ||
61 | If the file is already local, just return the absolute filename of that | |
62 | local file. Otherwise, copy the file locally to the workbench, and | |
63 | return the absolute path of the new file. | |
64 | ||
678d1a20 CAW |
65 | If it is copying locally, we might want to require a filename like |
66 | "source.jpg" to ensure that we won't conflict with other filenames in | |
67 | our workbench... if that's the case, make sure filename_if_copying is | |
68 | set to something like 'source.jpg'. Relatedly, if you set | |
69 | keep_extension_if_copying, you don't have to set an extension on | |
70 | filename_if_copying yourself, it'll be set for you (assuming such an | |
71 | extension can be extacted from the filename in the filepath). | |
72 | ||
68784b9e | 73 | Returns: |
fdc50039 | 74 | localized_filename |
678d1a20 CAW |
75 | |
76 | Examples: | |
68ffb136 | 77 | >>> wb_manager.localized_file( |
678d1a20 CAW |
78 | ... '/our/workbench/subdir', local_storage, |
79 | ... ['path', 'to', 'foobar.jpg']) | |
fdc50039 | 80 | u'/local/storage/path/to/foobar.jpg' |
678d1a20 | 81 | |
68ffb136 | 82 | >>> wb_manager.localized_file( |
678d1a20 CAW |
83 | ... '/our/workbench/subdir', remote_storage, |
84 | ... ['path', 'to', 'foobar.jpg']) | |
fdc50039 | 85 | '/our/workbench/subdir/foobar.jpg' |
678d1a20 | 86 | |
68ffb136 | 87 | >>> wb_manager.localized_file( |
678d1a20 CAW |
88 | ... '/our/workbench/subdir', remote_storage, |
89 | ... ['path', 'to', 'foobar.jpg'], 'source.jpeg', False) | |
fdc50039 | 90 | '/our/workbench/subdir/foobar.jpeg' |
678d1a20 | 91 | |
68ffb136 | 92 | >>> wb_manager.localized_file( |
678d1a20 CAW |
93 | ... '/our/workbench/subdir', remote_storage, |
94 | ... ['path', 'to', 'foobar.jpg'], 'source', True) | |
fdc50039 | 95 | '/our/workbench/subdir/foobar.jpg' |
68784b9e | 96 | """ |
678d1a20 | 97 | if storage.local_storage: |
fdc50039 | 98 | return storage.get_local_path(filepath) |
678d1a20 CAW |
99 | else: |
100 | if filename_if_copying is None: | |
101 | dest_filename = filepath[-1] | |
102 | else: | |
103 | orig_filename, orig_ext = os.path.splitext(filepath[-1]) | |
104 | if keep_extension_if_copying and orig_ext: | |
f2b96ff0 | 105 | dest_filename = filename_if_copying + orig_ext |
678d1a20 CAW |
106 | else: |
107 | dest_filename = filename_if_copying | |
108 | ||
109 | full_dest_filename = os.path.join( | |
52426ae0 | 110 | self.dir, dest_filename) |
678d1a20 CAW |
111 | |
112 | # copy it over | |
113 | storage.copy_locally( | |
114 | filepath, full_dest_filename) | |
115 | ||
fdc50039 | 116 | return full_dest_filename |
52426ae0 | 117 | |
bd6fe977 | 118 | def destroy(self): |
b67a983a E |
119 | """ |
120 | Destroy this workbench! Deletes the directory and all its contents! | |
121 | ||
122 | WARNING: Does no checks for a sane value in self.dir! | |
123 | """ | |
124 | # just in case | |
125 | workbench = os.path.abspath(self.dir) | |
b67a983a | 126 | shutil.rmtree(workbench) |
b67a983a E |
127 | del self.dir |
128 | ||
c11c1994 SS |
129 | def __enter__(self): |
130 | """Make Workbench a context manager so we can use `with Workbench() as bench:`""" | |
131 | return self | |
132 | ||
133 | def __exit__(self, *args): | |
134 | """Clean up context manager, aka ourselves, deleting the workbench""" | |
bd6fe977 | 135 | self.destroy() |
c11c1994 | 136 | |
52426ae0 E |
137 | |
138 | class WorkbenchManager(object): | |
139 | """ | |
140 | A system for generating and destroying workbenches. | |
141 | ||
c11c1994 SS |
142 | Workbenches are actually just subdirectories of a (local) temporary |
143 | storage space for during the processing stage. The preferred way to | |
144 | create them is to use: | |
145 | ||
bd6fe977 | 146 | with workbenchmger.create() as workbench: |
c11c1994 SS |
147 | do stuff... |
148 | ||
149 | This will automatically clean up all temporary directories even in | |
150 | case of an exceptions. Also check the | |
151 | @mediagoblin.decorators.get_workbench decorator for a convenient | |
152 | wrapper. | |
52426ae0 E |
153 | """ |
154 | ||
155 | def __init__(self, base_workbench_dir): | |
156 | self.base_workbench_dir = os.path.abspath(base_workbench_dir) | |
157 | if not os.path.exists(self.base_workbench_dir): | |
158 | os.makedirs(self.base_workbench_dir) | |
243c3843 | 159 | |
bd6fe977 | 160 | def create(self): |
52426ae0 E |
161 | """ |
162 | Create and return the path to a new workbench (directory). | |
163 | """ | |
164 | return Workbench(tempfile.mkdtemp(dir=self.base_workbench_dir)) |