buildframework/helium/tools/common/python/lib/ccm/conflict.py
changeset 179 d8ac696cc51f
parent 1 be27ed110b50
child 180 e02a83d4c571
child 592 3215c239276a
equal deleted inserted replaced
1:be27ed110b50 179:d8ac696cc51f
     1 #============================================================================ 
       
     2 #Name        : conflict.py 
       
     3 #Part of     : Helium 
       
     4 
       
     5 #Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     6 #All rights reserved.
       
     7 #This component and the accompanying materials are made available
       
     8 #under the terms of the License "Eclipse Public License v1.0"
       
     9 #which accompanies this distribution, and is available
       
    10 #at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
    11 #
       
    12 #Initial Contributors:
       
    13 #Nokia Corporation - initial contribution.
       
    14 #
       
    15 #Contributors:
       
    16 #
       
    17 #Description:
       
    18 #===============================================================================
       
    19 
       
    20 """ CCM conflict detection module. """
       
    21 
       
    22 
       
    23 import threading
       
    24 
       
    25 import ccm
       
    26 import threadpool
       
    27 
       
    28 
       
    29 def get_tasks_from_project(project):
       
    30     result = []
       
    31     for folder in project.folders:
       
    32         result.extend(get_tasks(folder))    
       
    33     result.extend(project.tasks)    
       
    34     return result
       
    35 
       
    36 
       
    37 def get_tasks_information_from_project(project):
       
    38     result = []
       
    39     for folder in project.folders:
       
    40         result.extend(get_tasks_information(folder))    
       
    41     for task in project.tasks:
       
    42         query = ccm.Query(folder.session, "name= '%s'and version='%s' and type='%s'and instance='%s'" % (task.name, task.version, task.type, task.instance),
       
    43                           ['objectname', 'owner', 'task_synopsis', 'displayname'],
       
    44                           ['ccmobject', 'string', 'string', 'string'])
       
    45         result.extend(query.execute().output)
       
    46     return result
       
    47 
       
    48 
       
    49 def get_tasks_information(folder):
       
    50     """ Get tasks from folder. If the folder is query based it uses the query to determine the list of task.
       
    51         But the folder contents itself remains untouch.
       
    52     """
       
    53     query = None
       
    54     if folder.is_query_based:
       
    55         query = ccm.Query(folder.session, "type='task' and " + folder.query,
       
    56                           ['objectname', 'owner', 'task_synopsis', 'displayname'],
       
    57                           ['ccmobject', 'string', 'string', 'string'])
       
    58     else:
       
    59         query = ccm.Query(folder.session, folder.objectname,
       
    60                           ['objectname', 'owner', 'task_synopsis', 'displayname'],
       
    61                           ['ccmobject', 'string', 'string', 'string'],
       
    62                           "folder -show tasks")        
       
    63     # executing the query
       
    64     return query.execute().output
       
    65 
       
    66 
       
    67 
       
    68 def get_tasks(folder):
       
    69     """ Get tasks from folder. If the folder is query based it uses the query to determine the list of task.
       
    70         But the folder contents itself remains untouch.
       
    71     """
       
    72     if folder.is_query_based:
       
    73         r = folder.session.execute("query -u -t task \"%s\" -f \"%%objectname\"" % folder.query, ccm.ObjectListResult(folder.session))
       
    74         return r.output
       
    75     else:
       
    76         return folder.tasks
       
    77 
       
    78 
       
    79 class ObjectAndTask:
       
    80     """ Wrapper object which link an object to a task. """
       
    81     def __init__(self, object, task):
       
    82         self.object = object
       
    83         self.task = task
       
    84         self.overridenby = []
       
    85     
       
    86     def has_successor_in_list(self, oatl):
       
    87         """ Has our object any successor in the list. """
       
    88         for oat in oatl:
       
    89             if self.object.__ne__(oat.object) and oat.object.is_recursive_successor_of_fast(self.object):
       
    90                 self.overridenby.append(oat)
       
    91                 return True
       
    92         return False
       
    93     
       
    94     def __repr__(self):
       
    95         return "<ObjectAndTask %s, %s>" % (self.object.objectname, self.task.objectname)
       
    96 
       
    97 
       
    98 class TaskModel:
       
    99     """ Task wrapper object which contains objectandtask object. """
       
   100     
       
   101     def __init__ (self, task):
       
   102         """ Init from task object. """
       
   103         self.task = task
       
   104         self.objectandtasks = {}        
       
   105         for object in self.task.objects:
       
   106             self.objectandtasks[str(object)] = ObjectAndTask(object, task)
       
   107 
       
   108     def is_useless(self):
       
   109         """ Is the task containing any usable objects. """
       
   110         count = 0
       
   111         for object in self.objectandtasks.keys():
       
   112             oat = self.objectandtasks[object]
       
   113             if len(oat.overridenby) > 0:
       
   114                 count += 1
       
   115         if len(self.objectandtasks.keys()) == 0 or count == len(self.objectandtasks.keys()):
       
   116             return True
       
   117         return False
       
   118                 
       
   119     
       
   120 def tasks_to_objectandtask(tasks):
       
   121     object_families = {}
       
   122     for task in tasks:
       
   123         for object in task.objects:
       
   124             if not object.family in object_families:
       
   125                 object_families[object.family] = []
       
   126             object_families[object.family].append(ObjectAndTask(object, task))
       
   127     return object_families
       
   128 
       
   129 
       
   130 def tasks_to_families_and_taskmodels(tasks, size=1):
       
   131     object_families = {}
       
   132     taskmodels = []
       
   133     lock = threading.Lock()
       
   134 
       
   135     def __work(task):
       
   136         tm = TaskModel(task)
       
   137         
       
   138         lock.acquire()
       
   139         taskmodels.append(tm)
       
   140         lock.release()
       
   141         
       
   142         for oatk in tm.objectandtasks.keys():
       
   143             oat = tm.objectandtasks[oatk]
       
   144             lock.acquire()
       
   145             if not oat.object.family in object_families:                
       
   146                 object_families[oat.object.family] = []            
       
   147             object_families[oat.object.family].append(oat)
       
   148             lock.release()
       
   149 
       
   150     
       
   151     if size > 1:
       
   152         pool = threadpool.ThreadPool(size)
       
   153         for task in tasks:
       
   154             pool.addWork(__work, args=[task])
       
   155         pool.wait()
       
   156     else:
       
   157         for task in tasks:
       
   158             __work(task)
       
   159     
       
   160     return (object_families, taskmodels)
       
   161 
       
   162 
       
   163 def check_task_conflicts(tasks, size=1):
       
   164     """ Validates objects a list of task.
       
   165         It returns a list of list of conflicting ObjectAndTask.
       
   166     """
       
   167     
       
   168     object_families, taskmodels = tasks_to_families_and_taskmodels(tasks, size)
       
   169     conflicts = []
       
   170     lock = threading.Lock()
       
   171 
       
   172     pool = threadpool.ThreadPool(size)
       
   173 
       
   174     def __work(family):
       
   175         result = []
       
   176         for oat in object_families[family]:
       
   177             if oat.has_successor_in_list(object_families[family]) == False:
       
   178                 add = True
       
   179                 for roat in result:
       
   180                     if roat.object == oat.object:
       
   181                         add = False
       
   182                         break
       
   183                 if add: 
       
   184                     result.append(oat)
       
   185                      
       
   186         if len(result)>1:
       
   187             lock.acquire()
       
   188             conflicts.append(result)
       
   189             lock.release()
       
   190 
       
   191     for family in object_families.keys():        
       
   192         pool.addWork(__work, args=[family])
       
   193     
       
   194     pool.wait()
       
   195     
       
   196     return conflicts, taskmodels
       
   197 
       
   198 
       
   199 class Conflict:
       
   200     def __init__(self, baseline, comment):
       
   201         self.baseline = baseline
       
   202         self._comment = comment
       
   203 
       
   204     def comment(self):
       
   205         return self._comment
       
   206 
       
   207 
       
   208 class MultipleObjectInBaselineConflict(Conflict):
       
   209     def __init__(self, baseline, objectlist):
       
   210         Conflict.__init__(self, baseline, "")        
       
   211         self.objectlist = objectlist
       
   212         
       
   213     def comment(self):
       
   214         output = "Multiple objects from the same family found under the baseline (%s).\n" % self.baseline.objectname
       
   215         output += "\n".join(lambda x: x.objectname, self.objectlist)
       
   216         return output
       
   217 
       
   218 
       
   219 class ObjectAndBaselineConflict(Conflict):
       
   220     def __init__(self, baseline, object, oat):
       
   221         Conflict.__init__(self, baseline, "")
       
   222         self.object = object
       
   223         self.oat = oat
       
   224     
       
   225     def comment(self):
       
   226         pass
       
   227     
       
   228     
       
   229 class ObjectNotFoundInBaselineConflict(Conflict):
       
   230     def __init__(self, baseline, object):
       
   231         Conflict.__init__(self, baseline, "")
       
   232         self.object = object
       
   233     
       
   234     def comment(self):
       
   235         return "No object fom '%s' family found under the baseline." % self.object.family
       
   236 
       
   237 
       
   238 def check_task_and_baseline_conflicts(tasks, baseline):
       
   239     """ Validates objects a list of task.
       
   240         It returns a list of list of conflicting ObjectAndTask.
       
   241     """
       
   242     
       
   243     object_families = tasks_to_objectandtask(tasks)
       
   244     conflicts = []
       
   245 
       
   246     for family in object_families:
       
   247         result = family[0].session.execute("query \"name='%s' and type='%s' and instance='%s'\" and recursive_is_member_of('%s', none) " % 
       
   248                                                         (family[0].name, family[0].type, family[0].instance, baseline.objectname),
       
   249                                                         ccm.ObjectListResult(family[0].session))
       
   250         if len(result.output) == 1:
       
   251             bo = result.output[0]
       
   252             potential_conflicts = []
       
   253             for oat in family:
       
   254                 if bo.recursive_predecessor_of(oat.object):
       
   255                     potential_conflicts.append(ObjectAndBaselineConflict(baseline, bo, oat, "Conflict between baseline object and task object"))
       
   256             if len(family) == len(potential_conflicts):
       
   257                 conflicts.extend(potential_conflicts)
       
   258         elif len(result.output) > 1:
       
   259             conflicts.append(MultipleObjectInBaselineConflict(baseline, result.output))
       
   260         else:
       
   261             conflicts.append(ObjectNotFoundInBaselineConflict(baseline, family[0]))
       
   262