# copyright 2010-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr## This file is part of CubicWeb.## CubicWeb is free software: you can redistribute it and/or modify it under the# terms of the GNU Lesser General Public License as published by the Free# Software Foundation, either version 2.1 of the License, or (at your option)# any later version.## CubicWeb is distributed in the hope that it will be useful, but WITHOUT# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more# details.## You should have received a copy of the GNU Lesser General Public License along# with CubicWeb. If not, see <http://www.gnu.org/licenses/>."""hooks for repository sources synchronization"""_=unicodefromsocketimportgethostnamefromlogilab.common.decoratorsimportclear_cachefromcubicwebimportvalidation_errorfromcubicweb.predicatesimportis_instancefromcubicweb.serverimportSOURCE_TYPES,hookclassSourceHook(hook.Hook):__abstract__=Truecategory='cw.sources'# repo sources synchronization #################################################classSourceAddedOp(hook.Operation):entity=None# make pylint happydefpostcommit_event(self):self.cnx.repo.add_source(self.entity)classSourceAddedHook(SourceHook):__regid__='cw.sources.added'__select__=SourceHook.__select__&is_instance('CWSource')events=('after_add_entity',)def__call__(self):try:sourcecls=SOURCE_TYPES[self.entity.type]exceptKeyError:msg=_('Unknown source type')raisevalidation_error(self.entity,{('type','subject'):msg})# ignore creation of the system source done during database# initialisation, as config for this source is in a file and handling# is done separatly (no need for the operation either)ifself.entity.name!='system':sourcecls.check_conf_dict(self.entity.eid,self.entity.host_config,fail_if_unknown=notself._cw.vreg.config.repairing)SourceAddedOp(self._cw,entity=self.entity)classSourceRemovedOp(hook.Operation):uri=None# make pylint happydefpostcommit_event(self):self.cnx.repo.remove_source(self.uri)classSourceRemovedHook(SourceHook):__regid__='cw.sources.removed'__select__=SourceHook.__select__&is_instance('CWSource')events=('before_delete_entity',)def__call__(self):ifself.entity.name=='system':msg=_("You cannot remove the system source")raisevalidation_error(self.entity,{None:msg})SourceRemovedOp(self._cw,uri=self.entity.name)classSourceConfigUpdatedOp(hook.DataOperationMixIn,hook.Operation):defprecommit_event(self):self.__processed=[]forsourceinself.get_data():ifnotself.cnx.deleted_in_transaction(source.eid):conf=source.repo_source.check_config(source)self.__processed.append((source,conf))defpostcommit_event(self):forsource,confinself.__processed:source.repo_source.update_config(source,conf)classSourceRenamedOp(hook.LateOperation):oldname=newname=None# make pylint happydefprecommit_event(self):source=self.cnx.repo.sources_by_uri[self.oldname]sql='UPDATE entities SET asource=%(newname)s WHERE asource=%(oldname)s'self.cnx.system_sql(sql,{'oldname':self.oldname,'newname':self.newname})defpostcommit_event(self):repo=self.cnx.repo# XXX race conditionsource=repo.sources_by_uri.pop(self.oldname)source.uri=self.newnamesource.public_config['uri']=self.newnamerepo.sources_by_uri[self.newname]=sourcerepo._type_source_cache.clear()clear_cache(repo,'source_defs')classSourceUpdatedHook(SourceHook):__regid__='cw.sources.configupdate'__select__=SourceHook.__select__&is_instance('CWSource')events=('before_update_entity',)def__call__(self):if'name'inself.entity.cw_edited:oldname,newname=self.entity.cw_edited.oldnewvalue('name')ifoldname=='system':msg=_("You cannot rename the system source")raisevalidation_error(self.entity,{('name','subject'):msg})SourceRenamedOp(self._cw,oldname=oldname,newname=newname)if'config'inself.entity.cw_edited:ifself.entity.name=='system'andself.entity.config:msg=_("Configuration of the system source goes to ""the 'sources' file, not in the database")raisevalidation_error(self.entity,{('config','subject'):msg})SourceConfigUpdatedOp.get_instance(self._cw).add_data(self.entity)classSourceHostConfigUpdatedHook(SourceHook):__regid__='cw.sources.hostconfigupdate'__select__=SourceHook.__select__&is_instance('CWSourceHostConfig')events=('after_add_entity','after_update_entity','before_delete_entity',)def__call__(self):ifself.entity.match(gethostname()):ifself.event=='after_update_entity'and \not'config'inself.entity.cw_edited:returntry:SourceConfigUpdatedOp.get_instance(self._cw).add_data(self.entity.cwsource)exceptIndexError:# XXX no source linked to the host config yetpass# source mapping synchronization ################################################# Expect cw_for_source/cw_schema are immutable relations (i.e. can't change from# a source or schema to another).classSourceMappingImmutableHook(SourceHook):"""check cw_for_source and cw_schema are immutable relations XXX empty delete perms would be enough? """__regid__='cw.sources.mapping.immutable'__select__=SourceHook.__select__&hook.match_rtype('cw_for_source','cw_schema')events=('before_add_relation',)def__call__(self):ifnotself._cw.added_in_transaction(self.eidfrom):msg=_("You can't change this relation")raisevalidation_error(self.eidfrom,{self.rtype:msg})classSourceMappingChangedOp(hook.DataOperationMixIn,hook.Operation):defcheck_or_update(self,checkonly):cnx=self.cnx# take care, can't call get_data() twicetry:data=self.__dataexceptAttributeError:data=self.__data=self.get_data()forschemacfg,sourceindata:ifsourceisNone:source=schemacfg.cwsource.repo_sourceifcnx.added_in_transaction(schemacfg.eid):ifnotcnx.deleted_in_transaction(schemacfg.eid):source.add_schema_config(schemacfg,checkonly=checkonly)elifcnx.deleted_in_transaction(schemacfg.eid):source.del_schema_config(schemacfg,checkonly=checkonly)else:source.update_schema_config(schemacfg,checkonly=checkonly)defprecommit_event(self):self.check_or_update(True)defpostcommit_event(self):self.check_or_update(False)classSourceMappingChangedHook(SourceHook):__regid__='cw.sources.schemaconfig'__select__=SourceHook.__select__&is_instance('CWSourceSchemaConfig')events=('after_add_entity','after_update_entity')def__call__(self):ifself.event=='after_add_entity'or(self.event=='after_update_entity'and'options'inself.entity.cw_edited):SourceMappingChangedOp.get_instance(self._cw).add_data((self.entity,None))classSourceMappingDeleteHook(SourceHook):__regid__='cw.sources.delschemaconfig'__select__=SourceHook.__select__&hook.match_rtype('cw_for_source')events=('before_delete_relation',)def__call__(self):SourceMappingChangedOp.get_instance(self._cw).add_data((self._cw.entity_from_eid(self.eidfrom),self._cw.entity_from_eid(self.eidto).repo_source))