00001 import silme.io
00002 import silme.format
00003 from silme.io.clients import IOClient, FileFormatClient
00004 from silme.core.object import L10nPackage, L10nObject, Blob
00005
00006 import os
00007 import zipfile
00008 import re
00009 import shutil
00010 import tempfile
00011
00012 def register(Manager):
00013 Manager.register(JarClient)
00014
00015 class JarClient(FileFormatClient):
00016 name = 'jar'
00017 desc = "Jar Client"
00018 type = IOClient.__name__
00019 zfile = None
00020
00021 @classmethod
00022 def matches_path(cls, path):
00023 """
00024 tests if the ioclient should be used for this type of path
00025 example: jar:browser.jar!/content/branding/
00026 """
00027 return path.startswith('jar:') or path.endswith('.jar')
00028
00029 @classmethod
00030 def get_blob(cls, path, source=True):
00031 (p, j, i) = cls._explode_path(path)
00032 return FileFormat.get_blob(cls, path, uri=i, source=source)
00033
00034 @classmethod
00035 def get_entitylist(cls, path, source=False, code='default', parser=None):
00036 (p, j, i) = cls._explode_path(path)
00037 return FileFormat.get_entitylist(cls, path, uri=i, source=source, code=code, parser=parser)
00038
00039 @classmethod
00040 def get_l10nobject(cls, path, source=False, code='default', parser=None):
00041 (p, j, i) = cls._explode_path(path)
00042 return FileFormat.get_l10nobject(cls, path, uri=i, source=source, code=code, parser=parser)
00043
00044 @classmethod
00045 def get_l10npackage(cls, path,
00046 code='default',
00047 object_type='l10nobject',
00048 source=None,
00049 ignore=['CVS','.svn','.DS_Store', '.hg']):
00050 l10npackage = FileFormatClient.get_l10npackage(path, code, object_type, source, ignore)
00051 (b_source, oe_source) = cls._get_source_policy(source)
00052
00053 try:
00054 if not cls.zfile:
00055 cls._open_jar(path)
00056 except Exception,e:
00057 raise Exception('Could not load a jar file: ' + path + ': ' + str(e))
00058 for name in cls.zfile.namelist():
00059 dirname = os.path.dirname(name)
00060 filename = os.path.basename(name)
00061
00062 relpath = re.sub(os.path.dirname(path), '', dirname, 1)
00063 if relpath.startswith('/'):
00064 relpath = os.path.split(relpath)[1]
00065
00066 if cls._should_ignore(ignore, path=relpath, elem=[filename, dirname]):
00067 continue
00068
00069 try:
00070 parser = silme.format.Manager.get(path=filename)
00071 except Exception, e:
00072 l10npackage.add_object(cls.get_blob(name, source=True), relpath)
00073 else:
00074 if object_type=='blob':
00075 l10npackage.add_object(cls.get_blob(name, source=True), relpath)
00076 elif object_type=='entitylist':
00077 l10npackage.add_object(cls.get_entitylist(name, source=source,
00078 parser=parser), relpath)
00079 else:
00080 l10npackage.add_object(cls.get_l10nobject(name, source=source,
00081 parser=parser), relpath)
00082 cls._close_jar()
00083 return l10npackage
00084
00085 @classmethod
00086 def write_blob(cls, blob, path):
00087 cls.write_source(blob.source,
00088 path,
00089 blob.id,
00090 encoding=None)
00091
00092 @classmethod
00093 def write_entitylist(cls, elist, path, encoding=None):
00094 if encoding is None and hasattr(elist, 'encoding'):
00095 encoding = elist.encoding
00096 try:
00097 format_parser = silme.format.Manager.get(path=elist.id)
00098 except Exception:
00099 raise Exception('No parser for given object type')
00100 string = format_parser.dump_entitylist(elist)
00101 cls.write_source(string,
00102 path,
00103 elist.id,
00104 encoding)
00105 return True
00106
00107 @classmethod
00108 def write_l10nobject(cls, object, path, encoding=None):
00109 if encoding is None and hasattr(object, 'encoding'):
00110 encoding = object.encoding
00111 try:
00112 format_parser = silme.format.Manager.get(path=object.id)
00113 except Exception:
00114 raise Exception('No parser for given object type ('+object.id+')')
00115 string = format_parser.dump_l10nobject(object)
00116 cls.write_source(string,
00117 path,
00118 object.id,
00119 format_parser.encoding)
00120 return True
00121
00122 @classmethod
00123 def write_object(cls, object, path, encoding=None):
00124 if isinstance(object, L10nObject):
00125 cls.write_l10nobject(object, path, encoding=encoding)
00126 elif isinstance(object, EntityList):
00127 cls.write_entitylist(object, path, encoding=encoding)
00128 elif isinstance(object, Blob):
00129 cls.write_blob(object, path)
00130
00131 @classmethod
00132 def write_l10npackage(cls, l10npack, path, ipath=''):
00133 if not cls.zfile:
00134 cls._open_jar(os.path.join(path, l10npack.id+'.jar'), mode='w')
00135
00136 for object in l10npack.get_objects():
00137 cls.write_object(object, os.path.join(ipath, object.id))
00138 for pack in l10npack.get_packages():
00139 cls.write_l10npackage(pack, path, os.path.join(ipath, pack.id))
00140
00141 if cls.zfile:
00142 cls._close_jar()
00143
00144 @classmethod
00145 def write_source(cls, content, path, name, encoding=None):
00146 if not cls.zfile:
00147 (p, j, i) = cls._explode_path(path)
00148 cls._open_jar(j, mode='a')
00149 cls.zfile.writestr(os.path.join(i, name), content)
00150 cls._close_jar()
00151 else:
00152 cls.zfile.writestr(path, content)
00153 return True
00154
00155
00156
00157 @classmethod
00158 def _explode_path(cls, path):
00159 if path.startswith('jar:'):
00160 try:
00161 delim = path.index('!')
00162 except:
00163 delim = None
00164 protocol = path[0:4]
00165 jarpath = path[4:delim]
00166 internalpath = delim and path[delim+1:] or ''
00167 elif path.endswith('.jar'):
00168 protocol = None
00169 jarpath = path
00170 internalpath = None
00171 else:
00172 protocol = None
00173 jarpath = None
00174 internalpath = path
00175 return (protocol, jarpath, internalpath)
00176
00177 @classmethod
00178 def _open_jar(cls, path, mode='r'):
00179 '''
00180 Opens the given jar-file and returns a zipfile instance
00181 @param path: path to a jar-file
00182 '''
00183 if cls.zfile is not None:
00184 if cls.zfile.mode == mode:
00185 return True
00186 else:
00187 cls._close_jar()
00188 if mode is not 'w' and not zipfile.is_zipfile(path):
00189 raise Exception('Not a valid JAR-file: ' + path + ' !')
00190 cls.zfile = zipfile.ZipFile(path, mode)
00191
00192 @classmethod
00193 def _close_jar(cls):
00194 '''
00195 Close an open jar-file instance
00196 '''
00197 if cls.zfile is None:
00198 raise KeyError('It looks like there is nothing to be closed!')
00199 cls.zfile.close()
00200 cls.zfile = None
00201
00202 @classmethod
00203 def _read_with_encoding(cls, path, encoding):
00204 if cls.zfile is None:
00205 (protocol, jpath, ipath) = cls._explode_path(path)
00206 cls._open_jar(jpath)
00207 text = cls.zfile.read(ipath).decode(encoding)
00208 cls._close_jar()
00209 return text
00210 else:
00211 return cls.zfile.read(path).decode(encoding)
00212
00213 @classmethod
00214 def _read_without_encoding(cls, path):
00215 if cls.zfile is None:
00216 (protocol, jpath, ipath) = cls._explode_path(path)
00217 cls._open_jar(jpath)
00218 text = cls.zfile.read(ipath)
00219 cls._close_jar()
00220 return text
00221 else:
00222 return cls.zfile.read(path)
00223
00224 def zipfile_delete(self, file):
00225
00226 f = tempfile.mkstemp()
00227 os.remove(f[1])
00228 zfile = zipfile.ZipFile(f[1], mode='w')
00229 for item in self.infolist():
00230 buf = self.read(item.filename)
00231 if not item.filename==file:
00232 zfile.writestr(item, buf)
00233 zfile.close()
00234 shutil.move(zfile.filename, self.filename)
00235
00236 zipfile.ZipFile.delete = zipfile_delete