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 |
|