27 try: |
28 try: |
28 from xml.etree import cElementTree as ElementTree |
29 from xml.etree import cElementTree as ElementTree |
29 except ImportError: |
30 except ImportError: |
30 from xml.etree import ElementTree |
31 from xml.etree import ElementTree |
31 |
32 |
32 from cone.public import api, utils, persistence, exceptions |
33 from cone.public import api, utils, persistence, exceptions, parsecontext |
33 from cone.public.api import Resource, Storage, Configuration, Folder |
34 from cone.public.api import Resource, Storage, Configuration, Folder |
34 from cone.storage import metadata, common |
35 from cone.storage import metadata, common |
35 from cone.confml import persistentconfml |
36 from cone.confml import persistentconfml |
36 |
37 |
37 |
38 |
44 |
45 |
45 class ZipStorage(common.StorageBase): |
46 class ZipStorage(common.StorageBase): |
46 """ |
47 """ |
47 A storage for zip file |
48 A storage for zip file |
48 """ |
49 """ |
49 TEMP_FILE = '_temp_%i.zip' % os.getpid() |
50 def __init__(self, path, mode, **kwargs): |
50 def __init__(self, path ,mode, **kwargs): |
|
51 """ |
51 """ |
52 Open the given filename object as a cpf zipfile |
52 Open the given filename object as a cpf zipfile |
53 """ |
53 """ |
54 self.mode = mode |
54 self.mode = mode |
55 self.persistentmodule = persistentconfml |
55 self.persistentmodule = persistentconfml |
59 self.logger.debug("ZipStorage path %s open in mode %s" % (path,self.mode)) |
59 self.logger.debug("ZipStorage path %s open in mode %s" % (path,self.mode)) |
60 try: |
60 try: |
61 # If opening the file in read/append mode check that the given file is a zipfile |
61 # If opening the file in read/append mode check that the given file is a zipfile |
62 if self.get_mode(mode) != self.MODE_WRITE: |
62 if self.get_mode(mode) != self.MODE_WRITE: |
63 if os.path.exists(path) and not zipfile.is_zipfile(path): |
63 if os.path.exists(path) and not zipfile.is_zipfile(path): |
64 raise ZipException("The file %s is not a zip file!" % path) |
64 raise ZipException("The file %s is not a zip file!" % path) |
|
65 # If creating a new file make sure that the path to the file exists |
|
66 elif self.get_mode(mode) in (self.MODE_APPEND, self.MODE_WRITE): |
|
67 dirname = os.path.dirname(path) |
|
68 if dirname != '' and not os.path.exists(dirname): |
|
69 os.makedirs(dirname) |
65 self.zipfile = zipfile.ZipFile(path,self.mode,self.compression) |
70 self.zipfile = zipfile.ZipFile(path,self.mode,self.compression) |
66 except IOError,e: |
71 except IOError,e: |
67 raise ZipException("ZipFile open error: %s" % e) |
72 raise ZipException("ZipFile open error: %s" % e) |
68 super(ZipStorage, self).__init__(path) |
73 super(ZipStorage, self).__init__(path, mode) |
69 |
74 |
70 def _zippath(self, path): |
75 def _zippath(self, path): |
71 """ |
76 """ |
72 Convert a norm path to zipfile path |
77 Convert a norm path to zipfile path |
73 """ |
78 """ |
138 zinfo = self.zipfile.getinfo(utils.resourceref.add_end_slash(path)) |
143 zinfo = self.zipfile.getinfo(utils.resourceref.add_end_slash(path)) |
139 return True |
144 return True |
140 except KeyError: |
145 except KeyError: |
141 return False |
146 return False |
142 |
147 |
143 def list_resources(self,path,recurse=False, empty_folders=False): |
148 def list_resources(self, path, **kwargs): |
144 """ |
149 """ |
145 Get an array of files in a folder |
150 Get an array of files in a folder |
146 """ |
151 """ |
147 path = utils.resourceref.remove_begin_slash(path) |
152 path = utils.resourceref.remove_begin_slash(path) |
148 fullpath = utils.resourceref.join_refs([self.get_current_path(),path]) |
153 fullpath = utils.resourceref.join_refs([self.get_current_path(),path]) |
151 filelist = self.zipfile.namelist() |
156 filelist = self.zipfile.namelist() |
152 for name in filelist: |
157 for name in filelist: |
153 (filepath,filename) = os.path.split(name) |
158 (filepath,filename) = os.path.split(name) |
154 curname = utils.resourceref.replace_dir(name, self.get_current_path(),'') |
159 curname = utils.resourceref.replace_dir(name, self.get_current_path(),'') |
155 # return directories only if specified |
160 # return directories only if specified |
156 if empty_folders == True or not self.is_dir(name): |
161 if kwargs.get('empty_folders', False) == True or not self.is_dir(name): |
157 # Skip the filename if it is marked as deleted |
162 # Skip the filename if it is marked as deleted |
158 if self.__has_open__(name) and self.__get_open__(name)[-1].get_mode() == api.Storage.MODE_DELETE: |
163 if self.__has_open__(name) and self.__get_open__(name)[-1].get_mode() == api.Storage.MODE_DELETE: |
159 continue |
164 continue |
160 if filepath == fullpath: |
165 if filepath == fullpath: |
161 retarray.append(curname) |
166 retarray.append(curname) |
162 elif recurse and filepath.startswith(fullpath): |
167 elif kwargs.get('recurse', False) and filepath.startswith(fullpath): |
163 retarray.append(curname) |
168 retarray.append(curname) |
164 #retarray = sorted(utils.distinct_array(retarray)) |
169 #retarray = sorted(utils.distinct_array(retarray)) |
165 return retarray |
170 return retarray |
166 |
171 |
167 def import_resources(self,paths,storage,empty_folders=False): |
172 def import_resources(self,paths,storage,empty_folders=False): |
168 for path in paths: |
173 for path in paths: |
|
174 path = utils.resourceref.remove_begin_slash(utils.resourceref.norm(path)) |
169 if not storage.is_resource(path) and empty_folders==False: |
175 if not storage.is_resource(path) and empty_folders==False: |
170 logging.getLogger('cone').warning("The given path is not a Resource in the storage %s! Ignoring from export!" % path) |
176 logging.getLogger('cone').warning("The given path is not a Resource in the storage %s! Ignoring from export!" % path) |
171 continue |
177 continue |
172 if storage.is_resource(path): |
178 if storage.is_resource(path): |
173 wres = self.open_resource(path,'wb') |
179 wres = self.open_resource(path,'wb') |
279 # Recreate the zip file if the zip has been modified to make a zip without |
285 # Recreate the zip file if the zip has been modified to make a zip without |
280 # duplicate local file entries |
286 # duplicate local file entries |
281 if self.modified: |
287 if self.modified: |
282 oldfile = None |
288 oldfile = None |
283 newzipfile = None |
289 newzipfile = None |
284 tmp_path = os.path.join(tempfile.gettempdir(), self.TEMP_FILE) |
290 fh, tmp_path = tempfile.mkstemp(suffix='.zip') |
285 os.rename(self.path, tmp_path) |
291 shutil.move(self.path, tmp_path) |
286 oldfile = zipfile.ZipFile(tmp_path,"r") |
292 oldfile = zipfile.ZipFile(tmp_path,"r") |
287 newzipfile = zipfile.ZipFile(self.path,"w",self.compression) |
293 newzipfile = zipfile.ZipFile(self.path,"w",self.compression) |
288 for fileinfo in oldfile.infolist(): |
294 for fileinfo in oldfile.infolist(): |
289 newzipfile.writestr(fileinfo, oldfile.read(fileinfo.filename)) |
295 newzipfile.writestr(fileinfo, oldfile.read(fileinfo.filename)) |
290 if oldfile: oldfile.close() |
296 if oldfile: oldfile.close() |
291 if newzipfile: newzipfile.close() |
297 if newzipfile: newzipfile.close() |
|
298 os.close(fh) |
292 os.unlink(tmp_path) |
299 os.unlink(tmp_path) |
293 self.zipfile = None |
300 self.zipfile = None |
294 else: |
301 else: |
295 raise exceptions.StorageException('Storage %s has been already closed!' % self.path) |
302 raise exceptions.StorageException('Storage %s has been already closed!' % self.path) |
296 |
303 |
320 if not utils.resourceref.get_ext(path) == "confml": |
327 if not utils.resourceref.get_ext(path) == "confml": |
321 raise exceptions.StorageException("Cannot load reference type %s" % utils.resourceref.get_ext(path)) |
328 raise exceptions.StorageException("Cannot load reference type %s" % utils.resourceref.get_ext(path)) |
322 if self.is_resource(path): |
329 if self.is_resource(path): |
323 res = self.open_resource(path,"r") |
330 res = self.open_resource(path,"r") |
324 # read the resource with persistentmodule |
331 # read the resource with persistentmodule |
|
332 parsecontext.get_confml_context().current_file = path |
325 try: |
333 try: |
326 obj = self.persistentmodule.loads(res.read()) |
334 obj = self.persistentmodule.loads(res.read()) |
327 obj.set_path(path) |
335 obj.set_path(path) |
328 res.close() |
336 res.close() |
329 return obj |
337 return obj |
330 except exceptions.ParseError,e: |
338 except exceptions.ParseError,e: |
331 logging.getLogger('cone').error("Resource %s parsing failed with exception: %s" % (path,e)) |
339 parsecontext.get_confml_context().handle_exception(e) |
|
340 #logging.getLogger('cone').error("Resource %s parsing failed with exception: %s" % (path,e)) |
332 # returning an empty config in case of xml parsing failure. |
341 # returning an empty config in case of xml parsing failure. |
333 return api.Configuration(path) |
342 return api.Configuration(path) |
334 else: |
343 else: |
335 raise exceptions.NotResource("No such %s resource!" % path) |
344 raise exceptions.NotResource("No such %s resource!" % path) |
336 |
345 |
370 def getvalue(self): |
379 def getvalue(self): |
371 return self.handle.getvalue() |
380 return self.handle.getvalue() |
372 |
381 |
373 def get_content_info(self): |
382 def get_content_info(self): |
374 if self.content_info == None: |
383 if self.content_info == None: |
375 self.content_info = utils.make_content_info(self, self.handle.getvalue()) |
384 self.content_info = api.make_content_info(self, self.handle.getvalue()) |
376 |
385 |
377 return self.content_info |
386 return self.content_info |