# HG changeset patch # User Sylvain Thénault # Date 1282285788 -7200 # Node ID 747e423093fcca5775274783d8d4e1f1c38b5a75 # Parent aca6a2c357fd690cfe441f6c73f405221caf7821 [ms, c-c] new command checking for consistency / potentian flaws and enhancements of mapping file of a multi-sources instance diff -r aca6a2c357fd -r 747e423093fc server/checkintegrity.py --- a/server/checkintegrity.py Fri Aug 20 08:21:15 2010 +0200 +++ b/server/checkintegrity.py Fri Aug 20 08:29:48 2010 +0200 @@ -15,8 +15,12 @@ # # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . -"""Check integrity of a CubicWeb repository. Hum actually only the system database -is checked. +"""Integrity checking tool for instances: + +* integrity of a CubicWeb repository. Hum actually only the system database is + checked. + +* consistency of multi-sources instance mapping file """ from __future__ import with_statement @@ -28,7 +32,7 @@ from logilab.common.shellutils import ProgressBar -from cubicweb.schema import PURE_VIRTUAL_RTYPES +from cubicweb.schema import META_RTYPES, VIRTUAL_RTYPES, PURE_VIRTUAL_RTYPES from cubicweb.server.sqlutils import SQL_PREFIX from cubicweb.server.session import security_enabled @@ -325,3 +329,94 @@ session.set_pool() reindex_entities(repo.schema, session, withpb=withpb) cnx.commit() + + +def warning(msg, *args): + if args: + msg = msg % args + print 'WARNING: %s' % msg + +def error(msg, *args): + if args: + msg = msg % args + print 'ERROR: %s' % msg + +def check_mapping(schema, mapping, warning=warning, error=error): + # first check stuff found in mapping file exists in the schema + for attr in ('support_entities', 'support_relations'): + for ertype in mapping[attr].keys(): + try: + mapping[attr][ertype] = erschema = schema[ertype] + except KeyError: + error('reference to unknown type %s in %s', ertype, attr) + del mapping[attr][ertype] + else: + if erschema.final or erschema in META_RTYPES: + error('type %s should not be mapped in %s', ertype, attr) + del mapping[attr][ertype] + for attr in ('dont_cross_relations', 'cross_relations'): + for rtype in list(mapping[attr]): + try: + rschema = schema.rschema(rtype) + except KeyError: + error('reference to unknown relation type %s in %s', rtype, attr) + mapping[attr].remove(rtype) + else: + if rschema.final or rschema in VIRTUAL_RTYPES: + error('relation type %s should not be mapped in %s', + rtype, attr) + mapping[attr].remove(rtype) + # check relation in dont_cross_relations aren't in support_relations + for rschema in mapping['dont_cross_relations']: + if rschema in mapping['support_relations']: + warning('relation %s is in dont_cross_relations and in support_relations', + rschema) + # check relation in cross_relations are in support_relations + for rschema in mapping['cross_relations']: + if rschema not in mapping['support_relations']: + warning('relation %s is in cross_relations but not in support_relations', + rschema) + # check for relation in both cross_relations and dont_cross_relations + for rschema in mapping['cross_relations'] & mapping['dont_cross_relations']: + error('relation %s is in both cross_relations and dont_cross_relations', + rschema) + # now check for more handy things + seen = set() + for eschema in mapping['support_entities'].values(): + for rschema, ttypes, role in eschema.relation_definitions(): + if rschema in META_RTYPES: + continue + ttypes = [ttype for ttype in ttypes if ttype in mapping['support_entities']] + if not rschema in mapping['support_relations']: + somethingprinted = False + for ttype in ttypes: + rdef = rschema.role_rdef(eschema, ttype, role) + seen.add(rdef) + if rdef.role_cardinality(role) in '1+': + error('relation %s with %s as %s and target type %s is ' + 'mandatory but not supported', + rschema, eschema, role, ttype) + somethingprinted = True + elif ttype in mapping['support_entities']: + if rdef not in seen: + warning('%s could be supported', rdef) + somethingprinted = True + if rschema not in mapping['dont_cross_relations']: + if role == 'subject' and rschema.inlined: + error('inlined relation %s of %s should be supported', + rschema, eschema) + elif not somethingprinted and rschema not in seen: + print 'you may want to specify something for %s' % rschema + seen.add(rschema) + elif not ttypes: + warning('relation %s with %s as %s is supported but no target ' + 'type supported', rschema, role, eschema) + for rschema in mapping['support_relations'].values(): + if rschema in META_RTYPES: + continue + for subj, obj in rschema.rdefs: + if subj in mapping['support_entities'] and obj in mapping['support_entities']: + break + else: + error('relation %s is supported but none if its definitions ' + 'matches supported entities', rschema) diff -r aca6a2c357fd -r 747e423093fc server/serverctl.py --- a/server/serverctl.py Fri Aug 20 08:21:15 2010 +0200 +++ b/server/serverctl.py Fri Aug 20 08:29:48 2010 +0200 @@ -865,6 +865,34 @@ mih.cmd_synchronize_schema() +class CheckMappingCommand(Command): + """Check content of the mapping file of an external source. + + The mapping is checked against the instance's schema, searching for + inconsistencies or stuff you may have forgotten. It's higly recommanded to + run it when you setup a multi-sources instance. + + + the identifier of the instance. + + + the mapping file to check. + """ + name = 'check-mapping' + arguments = ' ' + min_args = max_args = 2 + + def run(self, args): + from cubicweb.server.checkintegrity import check_mapping + from cubicweb.server.sources.pyrorql import load_mapping_file + appid = pop_arg(args, 1, msg='No instance specified !') + mappingfile = pop_arg(args, msg='No mapping file specified !') + config = ServerConfiguration.config_for(appid) + config.quick_start = True + mih = config.migration_handler(connect=False, verbosity=1) + repo = mih.repo_connect() # necessary to get cubes + checkintegrity(config.load_schema(), load_mapping_file(mappingfile)) + register_commands( (CreateInstanceDBCommand, InitInstanceCommand, GrantUserOnInstanceCommand, @@ -876,4 +904,5 @@ CheckRepositoryCommand, RebuildFTICommand, SynchronizeInstanceSchemaCommand, + CheckMappingCommand, ) )