configurationengine/source/cone/storage/zipstorage.py
changeset 3 e7e0ae78773e
parent 0 2e8eeb919028
child 5 d2c80f5cab53
equal deleted inserted replaced
2:87cfa131b535 3:e7e0ae78773e
    11 #
    11 #
    12 # Contributors:
    12 # Contributors:
    13 #
    13 #
    14 # Description: 
    14 # Description: 
    15 #
    15 #
       
    16 import shutil
    16 
    17 
    17 import zipfile,zlib, StringIO, os, logging
    18 import zipfile,zlib, StringIO, os, logging
    18 import datetime
    19 import datetime
    19 import tempfile
    20 import tempfile
    20 
    21 
    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