diff -r 000000000000 -r 2e8eeb919028 configurationengine/source/plugins/symbian/ConeCRMLPlugin/CRMLPlugin/crml_comparator.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/configurationengine/source/plugins/symbian/ConeCRMLPlugin/CRMLPlugin/crml_comparator.py Thu Mar 11 17:04:37 2010 +0200 @@ -0,0 +1,324 @@ +# +# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +# All rights reserved. +# This component and the accompanying materials are made available +# under the terms of "Eclipse Public License v1.0" +# which accompanies this distribution, and is available +# at the URL "http://www.eclipse.org/legal/epl-v10.html". +# +# Initial Contributors: +# Nokia Corporation - initial contribution. +# +# Contributors: +# +# Description: +# + +import logging +from cone.public import plugin +from crml_model import * + +class CrmlComparator(object): + def __init__(self, resource_ref, repo): + self.logger = logging.getLogger('cone.crml.comparator(%s)' % resource_ref) + self.resource_ref = resource_ref + self.repo = repo + + @classmethod + def get_flat_comparison_id(cls, repo): + """ + Return the flat comparison ID for the given repository. + """ + return cls._num_to_str(repo.uid_value) + + @classmethod + def get_flat_comparison_extra_data(cls, repo): + return {'repo': repo} + + @classmethod + def _num_to_str(cls, number): + if isinstance(number, basestring): + try: + number = long(number, 10) + except ValueError: + number = long(number, 16) + return "0x%08X" % number + + def flat_compare(self, target_resource_ref, target_repo): + """ + Compare two CRML repository models. + @return: A plugin.FlatComparisonResult object. + """ + source_repo = self.repo + + result = plugin.FlatComparisonResult() + + source_repo_uid = self._num_to_str(source_repo.uid_value) + target_repo_uid = self._num_to_str(target_repo.uid_value) + + if source_repo_uid != target_repo_uid: + raise RuntimeError("Comparing CRML implementations instances that don't have the same repository UID (%r vs. %r)" % (source_repo_uid, target_repo_uid)) + + # Default field contents for new entries + default_field_content = { + 'data' : {}} + + Entry = plugin.FlatComparisonResultEntry + + if self.resource_ref != target_resource_ref: + result.modified.append(Entry(value_id = 'file', + source_value = self.resource_ref, + target_value = target_resource_ref, + data = {'source_repo': source_repo, + 'target_repo': target_repo})) + + # Compare repository attributes + # ----------------------------- + repo_mods = self._flat_compare_object_attrs( + key_id = None, + source_obj = source_repo, + target_obj = target_repo, + varnames = ('uid_name', 'owner', 'backup', 'rfs', 'access')) + content = default_field_content.copy() + content['data'] = {'source_repo': source_repo, + 'target_repo': target_repo} + self._fill_in_entry_fields(repo_mods, content) + result.modified.extend(repo_mods) + + source_data = self._get_flat_comparison_data(source_repo) + target_data = self._get_flat_comparison_data(target_repo) + + # Find entries only in source + # --------------------------- + for id, crml_key in source_data.iteritems(): + if id not in target_data: + data = {'repo': source_repo, + 'key': crml_key} + result.only_in_source.append(Entry(sub_id=id, data=data)) + + # Find entries only in target + # --------------------------- + for id, crml_key in target_data.iteritems(): + if id not in source_data: + data = {'repo': source_repo, + 'key': crml_key} + result.only_in_target.append(Entry(sub_id=id, data=data)) + + # Find differing entries + # ---------------------- + for id, source_key in source_data.iteritems(): + if id not in target_data: continue + target_key = target_data[id] + if source_key == target_key: continue + + # Get the comparison result for the key + comp_result = self._get_flat_key_comparison_result(id, source_key, target_key) + + # Fill in the missing fields of the result entries + content = default_field_content.copy() + content['data'] = {'repo' : source_repo, + 'key' : source_key} + self._fill_in_entry_fields(comp_result.only_in_source, content) + + content = default_field_content.copy() + content['data'] = {'repo' : target_repo, + 'key' : target_key} + self._fill_in_entry_fields(comp_result.only_in_target, content) + + content = default_field_content.copy() + content['data'] = {'source_repo' : source_repo, + 'target_repo' : target_repo, + 'source_key' : source_key, + 'target_key' : target_key} + self._fill_in_entry_fields(comp_result.modified, content) + + result.extend(comp_result) + + return result + + def _fill_in_entry_fields(self, entry_list, field_contents): + for entry in entry_list: + for varname, value in field_contents.iteritems(): + if getattr(entry, varname) is None: + setattr(entry, varname, value) + + def _get_flat_comparison_data(self, repository): + """ + Return a dictionary containing all keys in the repository. + + The dictionary will have the CRML key UIDs as the dictionary keys and + the CRML key objects as the values. + """ + data = {} + for key in repository.keys: + if isinstance(key, (CrmlSimpleKey, CrmlBitmaskKey)): + id = self._num_to_str(key.int) + elif isinstance(key, CrmlKeyRange): + id = self._num_to_str(key.first_int) + '-' + self._num_to_str(key.last_int) + data[id] = key + return data + + def _get_flat_key_comparison_result(self, key_id, source_key, target_key): + """ + Return a flat comparison result for a source and target CRML key pair. + + @param key_id: The ID of the key, e.g. '0x00000001' for a simple key or + '0x00001000-0x00001FFF' for a key range. + @param source_key: The source key object. + @param target_key: The target key object. + @return: A plugin.FlatComparisonResult object. + """ + result = plugin.FlatComparisonResult() + + if type(source_key) == type(target_key): + comp_funcs = {CrmlSimpleKey: self._flat_compare_simple_keys, + CrmlBitmaskKey: self._flat_compare_bitmask_keys, + CrmlKeyRange: self._flat_compare_key_ranges} + func = comp_funcs[type(source_key)] + result.extend(func(key_id, source_key, target_key)) + else: + # Perform base key comparison + result.modified.extend(self._flat_compare_base_keys(key_id, source_key, target_key)) + + # Add an entry for key type change + type_ids = {CrmlSimpleKey: 'simple_key', + CrmlBitmaskKey: 'bitmask_key', + CrmlKeyRange: 'key_range'} + entry = plugin.FlatComparisonResultEntry( + sub_id = key_id, + value_id = 'key_type', + source_value = type_ids[type(source_key)], + target_value = type_ids[type(target_key)]) + result.modified.append(entry) + + return result + + def _flat_compare_object_attrs(self, key_id, source_obj, target_obj, varnames): + result = [] + for varname in varnames: + sval = getattr(source_obj, varname) + tval = getattr(target_obj, varname) + + if sval != tval: + if isinstance(sval, CrmlAccess): + result.extend(self._flat_compare_object_attrs( + key_id, sval, tval, + ('cap_rd', 'cap_wr', 'sid_rd', 'sid_wr'))) + else: + entry = plugin.FlatComparisonResultEntry( + sub_id = key_id, + value_id = varname, + source_value = sval, + target_value = tval) + result.append(entry) + return result + + def _flat_compare_base_keys(self, key_id, source_key, target_key, extra_varnames=[]): + varnames = ['name', 'backup', 'read_only', 'access'] + varnames.extend(extra_varnames) + return self._flat_compare_object_attrs(key_id, source_key, target_key, varnames) + + def _flat_compare_simple_keys(self, key_id, source_key, target_key): + mod = self._flat_compare_base_keys(key_id, source_key, target_key, + extra_varnames=['ref', 'type']) + return plugin.FlatComparisonResult(modified=mod) + + def _flat_compare_bitmask_keys(self, key_id, source_key, target_key): + mod = self._flat_compare_base_keys(key_id, source_key, target_key, + extra_varnames=['type']) + only_in_source = [] + only_in_target = [] + + def get_bits_dict(key): + bits = {} + for bit in key.bits: + bits[bit.index] = bit + return bits + + src_bits = get_bits_dict(source_key) + tgt_bits = get_bits_dict(target_key) + + # Find bits only in source + # ------------------------ + for index in src_bits.iterkeys(): + if index not in tgt_bits: + entry = plugin.FlatComparisonResultEntry( + sub_id = "%s (bit %s)" % (key_id, index)) + only_in_source.append(entry) + + # Find bits only in target + # ------------------------ + for index in tgt_bits.iterkeys(): + if index not in src_bits: + entry = plugin.FlatComparisonResultEntry( + sub_id = "%s (bit %s)" % (key_id, index)) + only_in_target.append(entry) + + # Find modified bits + # ------------------ + for index, src_bit in src_bits.iteritems(): + if index not in tgt_bits: continue + tgt_bit = tgt_bits[index] + + mod.extend(self._flat_compare_object_attrs( + key_id = "%s (bit %s)" % (key_id, index), + source_obj = src_bit, + target_obj = tgt_bit, + varnames = ('ref', 'invert'))) + + return plugin.FlatComparisonResult(modified = mod, + only_in_source = only_in_source, + only_in_target = only_in_target) + + def _flat_compare_key_ranges(self, key_id, source_key, target_key): + mod = self._flat_compare_base_keys(key_id, source_key, target_key, + extra_varnames=['ref', 'index_bits', 'first_index']) + only_in_source = [] + only_in_target = [] + + # Use hexadecimal format for index bits + for entry in mod: + if entry.value_id == 'index_bits': + entry.source_value = self._num_to_str(entry.source_value) + entry.target_value = self._num_to_str(entry.target_value) + + def get_subkeys_dict(key): + subkeys = {} + for sk in key.subkeys: + subkeys[sk.int] = sk + return subkeys + + src_subkeys = get_subkeys_dict(source_key) + tgt_subkeys = get_subkeys_dict(target_key) + + # Find sub-keys only in source + # ---------------------------- + for uid in src_subkeys.iterkeys(): + if uid not in tgt_subkeys: + entry = plugin.FlatComparisonResultEntry( + sub_id = "%s (sub-key %s)" % (key_id, self._num_to_str(uid))) + only_in_source.append(entry) + + # Find sub-keys only in target + # ---------------------------- + for uid in tgt_subkeys.iterkeys(): + if uid not in src_subkeys: + entry = plugin.FlatComparisonResultEntry( + sub_id = "%s (sub-key %s)" % (key_id, self._num_to_str(uid))) + only_in_target.append(entry) + + # Find modified bits + # ------------------ + for uid, src_subkey in src_subkeys.iteritems(): + if uid not in tgt_subkeys: continue + tgt_subkey = tgt_subkeys[uid] + + mod.extend(self._flat_compare_object_attrs( + key_id = "%s (sub-key %s)" % (key_id, self._num_to_str(uid)), + source_obj = src_subkey, + target_obj = tgt_subkey, + varnames = ('ref', 'type', 'name'))) + + return plugin.FlatComparisonResult(modified = mod, + only_in_source = only_in_source, + only_in_target = only_in_target)