diff -r 058bb3dc685f -r 0b59724cb3f2 hooks/syncsources.py --- a/hooks/syncsources.py Mon Jan 04 18:40:30 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,208 +0,0 @@ -# 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 . -"""hooks for repository sources synchronization""" - -from cubicweb import _ - -from socket import gethostname - -from logilab.common.decorators import clear_cache - -from cubicweb import validation_error -from cubicweb.predicates import is_instance -from cubicweb.server import SOURCE_TYPES, hook - -class SourceHook(hook.Hook): - __abstract__ = True - category = 'cw.sources' - - -# repo sources synchronization ################################################# - -class SourceAddedOp(hook.Operation): - entity = None # make pylint happy - def postcommit_event(self): - self.cnx.repo.add_source(self.entity) - -class SourceAddedHook(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] - except KeyError: - msg = _('Unknown source type') - raise validation_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) - if self.entity.name != 'system': - sourcecls.check_conf_dict(self.entity.eid, self.entity.host_config, - fail_if_unknown=not self._cw.vreg.config.repairing) - SourceAddedOp(self._cw, entity=self.entity) - - -class SourceRemovedOp(hook.Operation): - uri = None # make pylint happy - def postcommit_event(self): - self.cnx.repo.remove_source(self.uri) - -class SourceRemovedHook(SourceHook): - __regid__ = 'cw.sources.removed' - __select__ = SourceHook.__select__ & is_instance('CWSource') - events = ('before_delete_entity',) - def __call__(self): - if self.entity.name == 'system': - msg = _("You cannot remove the system source") - raise validation_error(self.entity, {None: msg}) - SourceRemovedOp(self._cw, uri=self.entity.name) - - -class SourceConfigUpdatedOp(hook.DataOperationMixIn, hook.Operation): - - def precommit_event(self): - self.__processed = [] - for source in self.get_data(): - if not self.cnx.deleted_in_transaction(source.eid): - conf = source.repo_source.check_config(source) - self.__processed.append( (source, conf) ) - - def postcommit_event(self): - for source, conf in self.__processed: - source.repo_source.update_config(source, conf) - - -class SourceRenamedOp(hook.LateOperation): - oldname = newname = None # make pylint happy - - def precommit_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}) - - def postcommit_event(self): - repo = self.cnx.repo - # XXX race condition - source = repo.sources_by_uri.pop(self.oldname) - source.uri = self.newname - source.public_config['uri'] = self.newname - repo.sources_by_uri[self.newname] = source - repo._type_source_cache.clear() - clear_cache(repo, 'source_defs') - - -class SourceUpdatedHook(SourceHook): - __regid__ = 'cw.sources.configupdate' - __select__ = SourceHook.__select__ & is_instance('CWSource') - events = ('before_update_entity',) - def __call__(self): - if 'name' in self.entity.cw_edited: - oldname, newname = self.entity.cw_edited.oldnewvalue('name') - if oldname == 'system': - msg = _("You cannot rename the system source") - raise validation_error(self.entity, {('name', 'subject'): msg}) - SourceRenamedOp(self._cw, oldname=oldname, newname=newname) - if 'config' in self.entity.cw_edited or 'url' in self.entity.cw_edited: - if self.entity.name == 'system' and self.entity.config: - msg = _("Configuration of the system source goes to " - "the 'sources' file, not in the database") - raise validation_error(self.entity, {('config', 'subject'): msg}) - SourceConfigUpdatedOp.get_instance(self._cw).add_data(self.entity) - - -class SourceHostConfigUpdatedHook(SourceHook): - __regid__ = 'cw.sources.hostconfigupdate' - __select__ = SourceHook.__select__ & is_instance('CWSourceHostConfig') - events = ('after_add_entity', 'after_update_entity', 'before_delete_entity',) - def __call__(self): - if self.entity.match(gethostname()): - if self.event == 'after_update_entity' and \ - not 'config' in self.entity.cw_edited: - return - try: - SourceConfigUpdatedOp.get_instance(self._cw).add_data(self.entity.cwsource) - except IndexError: - # XXX no source linked to the host config yet - pass - - -# source mapping synchronization ############################################### -# -# Expect cw_for_source/cw_schema are immutable relations (i.e. can't change from -# a source or schema to another). - -class SourceMappingImmutableHook(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): - if not self._cw.added_in_transaction(self.eidfrom): - msg = _("You can't change this relation") - raise validation_error(self.eidfrom, {self.rtype: msg}) - - -class SourceMappingChangedOp(hook.DataOperationMixIn, hook.Operation): - def check_or_update(self, checkonly): - cnx = self.cnx - # take care, can't call get_data() twice - try: - data = self.__data - except AttributeError: - data = self.__data = self.get_data() - for schemacfg, source in data: - if source is None: - source = schemacfg.cwsource.repo_source - if cnx.added_in_transaction(schemacfg.eid): - if not cnx.deleted_in_transaction(schemacfg.eid): - source.add_schema_config(schemacfg, checkonly=checkonly) - elif cnx.deleted_in_transaction(schemacfg.eid): - source.del_schema_config(schemacfg, checkonly=checkonly) - else: - source.update_schema_config(schemacfg, checkonly=checkonly) - - def precommit_event(self): - self.check_or_update(True) - - def postcommit_event(self): - self.check_or_update(False) - - -class SourceMappingChangedHook(SourceHook): - __regid__ = 'cw.sources.schemaconfig' - __select__ = SourceHook.__select__ & is_instance('CWSourceSchemaConfig') - events = ('after_add_entity', 'after_update_entity') - def __call__(self): - if self.event == 'after_add_entity' or ( - self.event == 'after_update_entity' and 'options' in self.entity.cw_edited): - SourceMappingChangedOp.get_instance(self._cw).add_data( - (self.entity, None) ) - -class SourceMappingDeleteHook(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) )