configurationengine/source/plugins/symbian/ConeCRMLPlugin/CRMLPlugin/crml_comparator.py
changeset 0 2e8eeb919028
equal deleted inserted replaced
-1:000000000000 0:2e8eeb919028
       
     1 #
       
     2 # Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 # All rights reserved.
       
     4 # This component and the accompanying materials are made available
       
     5 # under the terms of "Eclipse Public License v1.0"
       
     6 # which accompanies this distribution, and is available
       
     7 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 #
       
     9 # Initial Contributors:
       
    10 # Nokia Corporation - initial contribution.
       
    11 #
       
    12 # Contributors:
       
    13 #
       
    14 # Description:
       
    15 #
       
    16 
       
    17 import logging
       
    18 from cone.public import plugin
       
    19 from crml_model import *
       
    20 
       
    21 class CrmlComparator(object):
       
    22     def __init__(self, resource_ref, repo):
       
    23         self.logger = logging.getLogger('cone.crml.comparator(%s)' % resource_ref)
       
    24         self.resource_ref = resource_ref
       
    25         self.repo = repo
       
    26     
       
    27     @classmethod
       
    28     def get_flat_comparison_id(cls, repo):
       
    29         """
       
    30         Return the flat comparison ID for the given repository.
       
    31         """
       
    32         return cls._num_to_str(repo.uid_value)
       
    33     
       
    34     @classmethod
       
    35     def get_flat_comparison_extra_data(cls, repo):
       
    36         return {'repo': repo}
       
    37     
       
    38     @classmethod
       
    39     def _num_to_str(cls, number):
       
    40         if isinstance(number, basestring):
       
    41             try:
       
    42                 number = long(number, 10)
       
    43             except ValueError:
       
    44                 number = long(number, 16)
       
    45         return "0x%08X" % number
       
    46     
       
    47     def flat_compare(self, target_resource_ref, target_repo):
       
    48         """
       
    49         Compare two CRML repository models.
       
    50         @return: A plugin.FlatComparisonResult object.
       
    51         """
       
    52         source_repo = self.repo
       
    53         
       
    54         result = plugin.FlatComparisonResult()
       
    55         
       
    56         source_repo_uid = self._num_to_str(source_repo.uid_value)
       
    57         target_repo_uid = self._num_to_str(target_repo.uid_value)
       
    58         
       
    59         if source_repo_uid != target_repo_uid:
       
    60             raise RuntimeError("Comparing CRML implementations instances that don't have the same repository UID (%r vs. %r)" % (source_repo_uid, target_repo_uid))
       
    61         
       
    62         # Default field contents for new entries
       
    63         default_field_content = {
       
    64             'data'      : {}}
       
    65         
       
    66         Entry = plugin.FlatComparisonResultEntry
       
    67         
       
    68         if self.resource_ref != target_resource_ref:
       
    69             result.modified.append(Entry(value_id       = 'file',
       
    70                                          source_value   = self.resource_ref,
       
    71                                          target_value   = target_resource_ref,
       
    72                                          data           = {'source_repo': source_repo,
       
    73                                                            'target_repo': target_repo}))
       
    74         
       
    75         # Compare repository attributes
       
    76         # -----------------------------
       
    77         repo_mods = self._flat_compare_object_attrs(
       
    78             key_id      = None,
       
    79             source_obj  = source_repo,
       
    80             target_obj  = target_repo,
       
    81             varnames    = ('uid_name', 'owner', 'backup', 'rfs', 'access'))
       
    82         content = default_field_content.copy()
       
    83         content['data'] = {'source_repo': source_repo,
       
    84                            'target_repo': target_repo}
       
    85         self._fill_in_entry_fields(repo_mods, content)
       
    86         result.modified.extend(repo_mods)
       
    87         
       
    88         source_data = self._get_flat_comparison_data(source_repo)
       
    89         target_data = self._get_flat_comparison_data(target_repo)
       
    90         
       
    91         # Find entries only in source
       
    92         # ---------------------------
       
    93         for id, crml_key in source_data.iteritems():
       
    94             if id not in target_data:
       
    95                 data = {'repo': source_repo,
       
    96                         'key':  crml_key}
       
    97                 result.only_in_source.append(Entry(sub_id=id, data=data))
       
    98         
       
    99         # Find entries only in target
       
   100         # ---------------------------
       
   101         for id, crml_key in target_data.iteritems():
       
   102             if id not in source_data:
       
   103                 data = {'repo': source_repo,
       
   104                         'key':  crml_key}
       
   105                 result.only_in_target.append(Entry(sub_id=id, data=data))
       
   106         
       
   107         # Find differing entries
       
   108         # ----------------------
       
   109         for id, source_key in source_data.iteritems():
       
   110             if id not in target_data: continue
       
   111             target_key = target_data[id]
       
   112             if source_key == target_key: continue
       
   113             
       
   114             # Get the comparison result for the key
       
   115             comp_result = self._get_flat_key_comparison_result(id, source_key, target_key)
       
   116             
       
   117             # Fill in the missing fields of the result entries
       
   118             content = default_field_content.copy()
       
   119             content['data'] = {'repo'   : source_repo,
       
   120                                'key'    : source_key}
       
   121             self._fill_in_entry_fields(comp_result.only_in_source, content)
       
   122             
       
   123             content = default_field_content.copy()
       
   124             content['data'] = {'repo'   : target_repo,
       
   125                                'key'    : target_key}
       
   126             self._fill_in_entry_fields(comp_result.only_in_target,  content)
       
   127             
       
   128             content = default_field_content.copy()
       
   129             content['data'] = {'source_repo'    : source_repo,
       
   130                                'target_repo'    : target_repo,
       
   131                                'source_key'     : source_key,
       
   132                                'target_key'     : target_key}
       
   133             self._fill_in_entry_fields(comp_result.modified, content)
       
   134             
       
   135             result.extend(comp_result)
       
   136         
       
   137         return result
       
   138     
       
   139     def _fill_in_entry_fields(self, entry_list, field_contents):
       
   140         for entry in entry_list:
       
   141             for varname, value in field_contents.iteritems():
       
   142                 if getattr(entry, varname) is None:
       
   143                     setattr(entry, varname, value)
       
   144     
       
   145     def _get_flat_comparison_data(self, repository):
       
   146         """
       
   147         Return a dictionary containing all keys in the repository.
       
   148         
       
   149         The dictionary will have the CRML key UIDs as the dictionary keys and
       
   150         the CRML key objects as the values.
       
   151         """
       
   152         data = {}
       
   153         for key in repository.keys:
       
   154             if isinstance(key, (CrmlSimpleKey, CrmlBitmaskKey)):
       
   155                 id = self._num_to_str(key.int)
       
   156             elif isinstance(key, CrmlKeyRange):
       
   157                 id = self._num_to_str(key.first_int) + '-' + self._num_to_str(key.last_int)
       
   158             data[id] = key
       
   159         return data
       
   160     
       
   161     def _get_flat_key_comparison_result(self, key_id, source_key, target_key):
       
   162         """
       
   163         Return a flat comparison result for a source and target CRML key pair.
       
   164         
       
   165         @param key_id: The ID of the key, e.g. '0x00000001' for a simple key or
       
   166             '0x00001000-0x00001FFF' for a key range.
       
   167         @param source_key: The source key object.
       
   168         @param target_key: The target key object.
       
   169         @return: A plugin.FlatComparisonResult object.
       
   170         """
       
   171         result = plugin.FlatComparisonResult()
       
   172         
       
   173         if type(source_key) == type(target_key):
       
   174             comp_funcs = {CrmlSimpleKey:   self._flat_compare_simple_keys,
       
   175                           CrmlBitmaskKey:  self._flat_compare_bitmask_keys,
       
   176                           CrmlKeyRange:    self._flat_compare_key_ranges}
       
   177             func = comp_funcs[type(source_key)]
       
   178             result.extend(func(key_id, source_key, target_key))
       
   179         else:
       
   180             # Perform base key comparison
       
   181             result.modified.extend(self._flat_compare_base_keys(key_id, source_key, target_key))
       
   182             
       
   183             # Add an entry for key type change
       
   184             type_ids = {CrmlSimpleKey:  'simple_key',
       
   185                         CrmlBitmaskKey: 'bitmask_key',
       
   186                         CrmlKeyRange:   'key_range'}
       
   187             entry = plugin.FlatComparisonResultEntry(
       
   188                 sub_id       = key_id,
       
   189                 value_id     = 'key_type',
       
   190                 source_value = type_ids[type(source_key)],
       
   191                 target_value = type_ids[type(target_key)])
       
   192             result.modified.append(entry)
       
   193         
       
   194         return result
       
   195     
       
   196     def _flat_compare_object_attrs(self, key_id, source_obj, target_obj, varnames):
       
   197         result = []
       
   198         for varname in varnames:
       
   199             sval = getattr(source_obj, varname)
       
   200             tval = getattr(target_obj, varname)
       
   201             
       
   202             if sval != tval:
       
   203                 if isinstance(sval, CrmlAccess):
       
   204                     result.extend(self._flat_compare_object_attrs(
       
   205                           key_id, sval, tval,
       
   206                           ('cap_rd', 'cap_wr', 'sid_rd', 'sid_wr')))
       
   207                 else:
       
   208                     entry = plugin.FlatComparisonResultEntry(
       
   209                         sub_id       = key_id,
       
   210                         value_id     = varname,
       
   211                         source_value = sval,
       
   212                         target_value = tval)
       
   213                     result.append(entry)
       
   214         return result
       
   215     
       
   216     def _flat_compare_base_keys(self, key_id, source_key, target_key, extra_varnames=[]):
       
   217         varnames = ['name', 'backup', 'read_only', 'access']
       
   218         varnames.extend(extra_varnames)
       
   219         return self._flat_compare_object_attrs(key_id, source_key, target_key, varnames)
       
   220     
       
   221     def _flat_compare_simple_keys(self, key_id, source_key, target_key):
       
   222         mod = self._flat_compare_base_keys(key_id, source_key, target_key,
       
   223                                            extra_varnames=['ref', 'type'])
       
   224         return plugin.FlatComparisonResult(modified=mod)
       
   225     
       
   226     def _flat_compare_bitmask_keys(self, key_id, source_key, target_key):
       
   227         mod = self._flat_compare_base_keys(key_id, source_key, target_key,
       
   228                                            extra_varnames=['type'])
       
   229         only_in_source = []
       
   230         only_in_target = []
       
   231         
       
   232         def get_bits_dict(key):
       
   233             bits = {}
       
   234             for bit in key.bits:
       
   235                 bits[bit.index] = bit
       
   236             return bits
       
   237         
       
   238         src_bits = get_bits_dict(source_key)
       
   239         tgt_bits = get_bits_dict(target_key)
       
   240         
       
   241         # Find bits only in source
       
   242         # ------------------------
       
   243         for index in src_bits.iterkeys():
       
   244             if index not in tgt_bits:
       
   245                 entry = plugin.FlatComparisonResultEntry(
       
   246                     sub_id = "%s (bit %s)" % (key_id, index))
       
   247                 only_in_source.append(entry)
       
   248         
       
   249         # Find bits only in target
       
   250         # ------------------------
       
   251         for index in tgt_bits.iterkeys():
       
   252             if index not in src_bits:
       
   253                 entry = plugin.FlatComparisonResultEntry(
       
   254                     sub_id = "%s (bit %s)" % (key_id, index))
       
   255                 only_in_target.append(entry)
       
   256         
       
   257         # Find modified bits
       
   258         # ------------------
       
   259         for index, src_bit in src_bits.iteritems():
       
   260             if index not in tgt_bits: continue
       
   261             tgt_bit = tgt_bits[index]
       
   262             
       
   263             mod.extend(self._flat_compare_object_attrs(
       
   264                 key_id      = "%s (bit %s)" % (key_id, index),
       
   265                 source_obj  = src_bit,
       
   266                 target_obj  = tgt_bit,
       
   267                 varnames    = ('ref', 'invert')))
       
   268         
       
   269         return plugin.FlatComparisonResult(modified         = mod,
       
   270                                            only_in_source   = only_in_source,
       
   271                                            only_in_target   = only_in_target)
       
   272     
       
   273     def _flat_compare_key_ranges(self, key_id, source_key, target_key):
       
   274         mod = self._flat_compare_base_keys(key_id, source_key, target_key,
       
   275                                            extra_varnames=['ref', 'index_bits', 'first_index'])
       
   276         only_in_source = []
       
   277         only_in_target = []
       
   278         
       
   279         # Use hexadecimal format for index bits
       
   280         for entry in mod:
       
   281             if entry.value_id == 'index_bits':
       
   282                 entry.source_value = self._num_to_str(entry.source_value)
       
   283                 entry.target_value = self._num_to_str(entry.target_value)
       
   284         
       
   285         def get_subkeys_dict(key):
       
   286             subkeys = {}
       
   287             for sk in key.subkeys:
       
   288                 subkeys[sk.int] = sk
       
   289             return subkeys
       
   290         
       
   291         src_subkeys = get_subkeys_dict(source_key)
       
   292         tgt_subkeys = get_subkeys_dict(target_key)
       
   293         
       
   294         # Find sub-keys only in source
       
   295         # ----------------------------
       
   296         for uid in src_subkeys.iterkeys():
       
   297             if uid not in tgt_subkeys:
       
   298                 entry = plugin.FlatComparisonResultEntry(
       
   299                     sub_id = "%s (sub-key %s)" % (key_id, self._num_to_str(uid)))
       
   300                 only_in_source.append(entry)
       
   301         
       
   302         # Find sub-keys only in target
       
   303         # ----------------------------
       
   304         for uid in tgt_subkeys.iterkeys():
       
   305             if uid not in src_subkeys:
       
   306                 entry = plugin.FlatComparisonResultEntry(
       
   307                     sub_id = "%s (sub-key %s)" % (key_id, self._num_to_str(uid)))
       
   308                 only_in_target.append(entry)
       
   309         
       
   310         # Find modified bits
       
   311         # ------------------
       
   312         for uid, src_subkey in src_subkeys.iteritems():
       
   313             if uid not in tgt_subkeys: continue
       
   314             tgt_subkey = tgt_subkeys[uid]
       
   315             
       
   316             mod.extend(self._flat_compare_object_attrs(
       
   317                 key_id      = "%s (sub-key %s)" % (key_id, self._num_to_str(uid)),
       
   318                 source_obj  = src_subkey,
       
   319                 target_obj  = tgt_subkey,
       
   320                 varnames    = ('ref', 'type', 'name')))
       
   321         
       
   322         return plugin.FlatComparisonResult(modified         = mod,
       
   323                                            only_in_source   = only_in_source,
       
   324                                            only_in_target   = only_in_target)