introduced dependency to lgc > 0.47 for new stacklevel argument to deprecated + new db backup/restore api
"""custom storages for the system source"""fromosimportunlink,pathasospfromcubicweb.server.hookimportOperationETYPE_ATTR_STORAGE={}defset_attribute_storage(repo,etype,attr,storage):ETYPE_ATTR_STORAGE.setdefault(etype,{})[attr]=storagerepo.system_source.map_attribute(etype,attr,storage.sqlgen_callback)classStorage(object):"""abstract storage"""defsqlgen_callback(self,generator,relation,linkedvar):"""sql generator callback when some attribute with a custom storage is accessed """raiseNotImplementedError()defentity_added(self,entity,attr):"""an entity using this storage for attr has been added"""raiseNotImplementedError()defentity_updated(self,entity,attr):"""an entity using this storage for attr has been updatded"""raiseNotImplementedError()defentity_deleted(self,entity,attr):"""an entity using this storage for attr has been deleted"""raiseNotImplementedError()# TODO# * make it configurable without code# * better file path attribution# * handle backup/restoreclassBytesFileSystemStorage(Storage):"""store Bytes attribute value on the file system"""def__init__(self,defaultdir):self.default_directory=defaultdirdefsqlgen_callback(self,generator,linkedvar,relation):"""sql generator callback when some attribute with a custom storage is accessed """linkedvar.accept(generator)return'_fsopen(%s.cw_%s)'%(linkedvar._q_sql.split('.',1)[0],# table namerelation.r_type)# attribute namedefentity_added(self,entity,attr):"""an entity using this storage for attr has been added"""ifnotentity._cw.transaction_data.get('fs_importing'):try:value=entity.pop(attr)exceptKeyError:passelse:fpath=self.new_fs_path(entity,attr)# bytes storage used to store file's pathentity[attr]=Binary(fpath)file(fpath,'w').write(value.getvalue())AddFileOp(entity._cw,filepath=fpath)# else entity[attr] is expected to be an already existant file pathdefentity_updated(self,entity,attr):"""an entity using this storage for attr has been updatded"""try:value=entity.pop(attr)exceptKeyError:passelse:fpath=self.current_fs_path(entity,attr)UpdateFileOp(entity._cw,filepath=fpath,filedata=value.getvalue())defentity_deleted(self,entity,attr):"""an entity using this storage for attr has been deleted"""DeleteFileOp(entity._cw,filepath=self.current_fs_path(entity,attr))defnew_fs_path(self,entity,attr):fpath=osp.join(self.default_directory,'%s_%s_%s'%(self.default_directory,entity.eid,attr))whileosp.exists(fspath):fspath='_'+fspathreturnfspathdefcurrent_fs_path(self,entity,attr):cu=entity._cw.system_sql('SELECT cw_%s.%s WHERE cw_eid=%s'%(entity.__regid__,attr,entity.eid))returncu.fetchone()[0]classAddFileOp(Operation):defrollback_event(self):try:unlink(self.filepath)except:passclassDeleteFileOp(Operation):defcommit_event(self):try:unlink(self.filepath)except:passclassUpdateFileOp(Operation):defprecommit_event(self):try:file(self.filepath,'w').write(self.filedata)except:pass