53 """ |
53 """ |
54 self.mode = mode |
54 self.mode = mode |
55 self.persistentmodule = persistentconfml |
55 self.persistentmodule = persistentconfml |
56 self.compression = zipfile.ZIP_DEFLATED |
56 self.compression = zipfile.ZIP_DEFLATED |
57 self.modified = False |
57 self.modified = False |
|
58 self.cache = {} |
58 self.logger = logging.getLogger('cone') |
59 self.logger = logging.getLogger('cone') |
59 self.logger.debug("ZipStorage path %s open in mode %s" % (path,self.mode)) |
60 self.logger.debug("ZipStorage path %s open in mode %s" % (path,self.mode)) |
60 try: |
61 try: |
61 # If opening the file in read/append mode check that the given file is a zipfile |
62 # 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: |
63 if self.get_mode(mode) != self.MODE_WRITE: |
282 if self.zipfile: |
283 if self.zipfile: |
283 super(ZipStorage,self).close() |
284 super(ZipStorage,self).close() |
284 self.zipfile.close() |
285 self.zipfile.close() |
285 # Recreate the zip file if the zip has been modified to make a zip without |
286 # Recreate the zip file if the zip has been modified to make a zip without |
286 # duplicate local file entries |
287 # duplicate local file entries |
287 if self.modified: |
288 else: |
288 oldfile = None |
289 raise exceptions.StorageException('Storage %s has been already closed!' % self.path) |
289 newzipfile = None |
290 |
290 fh, tmp_path = tempfile.mkstemp(suffix='.zip') |
291 if self.modified or self.cache: |
291 shutil.move(self.path, tmp_path) |
292 logging.getLogger('cone').debug("Recreating the ZIP output file") |
292 oldfile = zipfile.ZipFile(tmp_path,"r") |
293 oldfile = None |
293 newzipfile = zipfile.ZipFile(self.path,"w",self.compression) |
294 newzipfile = None |
294 for fileinfo in oldfile.infolist(): |
295 fh, tmp_path = tempfile.mkstemp(suffix='.zip') |
|
296 shutil.move(self.path, tmp_path) |
|
297 oldfile = zipfile.ZipFile(tmp_path,"r") |
|
298 newzipfile = zipfile.ZipFile(self.path,"w",self.compression) |
|
299 for fileinfo in oldfile.infolist(): |
|
300 if fileinfo.filename not in self.cache.keys(): |
295 newzipfile.writestr(fileinfo, oldfile.read(fileinfo.filename)) |
301 newzipfile.writestr(fileinfo, oldfile.read(fileinfo.filename)) |
296 if oldfile: oldfile.close() |
302 for filename in sorted(self.cache.keys()): |
297 if newzipfile: newzipfile.close() |
303 logging.getLogger('cone').debug("Adding pre-cached file %s." % filename) |
298 os.close(fh) |
304 newzipfile.write(self.cache[filename], arcname=filename) |
299 os.unlink(tmp_path) |
305 if oldfile: oldfile.close() |
300 self.zipfile = None |
306 if newzipfile: newzipfile.close() |
301 else: |
307 os.close(fh) |
302 raise exceptions.StorageException('Storage %s has been already closed!' % self.path) |
308 os.unlink(tmp_path) |
|
309 logging.getLogger('cone').debug("Recreating the ZIP output file completed.") |
|
310 |
|
311 self.zipfile = None |
303 |
312 |
304 def unload(self, path, object): |
313 def unload(self, path, object): |
305 """ |
314 """ |
306 Dump a given object to the storage (reference is fetched from the object) |
315 Dump a given object to the storage (reference is fetched from the object) |
307 @param object: The object to dump to the storage, which is expected to be an instance |
316 @param object: The object to dump to the storage, which is expected to be an instance |