587
|
1 |
#============================================================================
|
|
2 |
#Name : preparation.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 |
""" This package implements the new update work area functionality.
|
|
21 |
|
|
22 |
"""
|
|
23 |
|
|
24 |
import logging
|
|
25 |
import os
|
|
26 |
import time
|
|
27 |
|
|
28 |
import ccm
|
|
29 |
import ccm.extra
|
|
30 |
import fileutils
|
588
|
31 |
from xml.dom.minidom import getDOMImplementation
|
|
32 |
|
587
|
33 |
|
|
34 |
# Uncomment this line to enable logging in this module, or configure logging elsewhere
|
|
35 |
logging.basicConfig(level=logging.INFO)
|
|
36 |
_logger = logging.getLogger("preparation.ccmgetinput")
|
|
37 |
|
|
38 |
|
|
39 |
DEFAULT_THREADS = 1
|
|
40 |
THREADS_MIN_TOTAL = 1
|
|
41 |
THREADS_MAX_TOTAL = 10
|
|
42 |
|
|
43 |
|
|
44 |
def find(function, seq):
|
|
45 |
"""Return first item in sequence where f(item) == True."""
|
|
46 |
for item in seq:
|
|
47 |
if function(item):
|
|
48 |
return item
|
|
49 |
return None
|
|
50 |
|
|
51 |
|
|
52 |
class PreparationAction(object):
|
|
53 |
""" Implements an abstract preparation function. """
|
|
54 |
|
|
55 |
def __init__(self, config, builder):
|
|
56 |
self._config = config
|
|
57 |
self._builder = builder
|
|
58 |
|
|
59 |
def check(self):
|
|
60 |
""" Checks if project is available in synergy. """
|
|
61 |
self._check_object(self._config.name)
|
|
62 |
|
|
63 |
def _check_object(self, fpn):
|
|
64 |
""" Check if ccmobject exists in synergy database. """
|
|
65 |
session = self.get_session()
|
|
66 |
ccm_object = session.create(fpn)
|
|
67 |
if ccm_object.exists():
|
|
68 |
_logger.info("Checking '%s'...Ok" % fpn)
|
|
69 |
else:
|
|
70 |
_logger.info("Checking '%s'...Not Found!" % fpn)
|
|
71 |
raise Exception("Could not find object %s in the database." % fpn)
|
|
72 |
|
|
73 |
def execute(self):
|
|
74 |
""" This method needs to be overridden by child class.
|
|
75 |
|
|
76 |
It should implement the action to achieve.
|
|
77 |
"""
|
|
78 |
pass
|
|
79 |
|
|
80 |
def cleanup(self):
|
|
81 |
""" This method needs to be overridden by child class.
|
|
82 |
It should implement the action to achieve.
|
|
83 |
"""
|
|
84 |
pass
|
588
|
85 |
|
|
86 |
def extract_release_data(self):
|
|
87 |
""" This method is used to retrieve current project
|
|
88 |
environment data. (e.g. project name)
|
|
89 |
"""
|
|
90 |
return None
|
587
|
91 |
|
|
92 |
def get_session(self):
|
588
|
93 |
""" Helper that retrieve the session from the builder. Setting threads correctly. """
|
587
|
94 |
if self._config.has_key('database'):
|
|
95 |
return self._builder.session(self._config['database'], self.get_threads())
|
|
96 |
if not self._config.has_key('host'):
|
|
97 |
raise Exception("Database engine host configuration is not found")
|
|
98 |
elif not self._config.has_key('dbpath'):
|
|
99 |
raise Exception("Database path configuration is not found")
|
|
100 |
else:
|
|
101 |
return self._builder.session(None, self.get_threads(), self._config['host'], self._config['dbpath'])
|
|
102 |
|
|
103 |
def get_threads(self):
|
|
104 |
""" Returning the number of threads that should be used. """
|
|
105 |
threads = self._config.get_int('threads', DEFAULT_THREADS)
|
|
106 |
if threads < THREADS_MIN_TOTAL:
|
|
107 |
threads = THREADS_MIN_TOTAL
|
|
108 |
if threads > THREADS_MAX_TOTAL:
|
|
109 |
threads = THREADS_MAX_TOTAL
|
|
110 |
return threads
|
|
111 |
|
|
112 |
|
|
113 |
class PreparationSnapshot(PreparationAction):
|
|
114 |
""" Implements a Snapshot preparation function.
|
|
115 |
|
|
116 |
Support the parallel snapshotter.
|
|
117 |
"""
|
|
118 |
|
|
119 |
def __init__(self, config, builder):
|
|
120 |
""" Initialization. """
|
|
121 |
PreparationAction.__init__(self, config, builder)
|
|
122 |
|
|
123 |
def cleanup(self):
|
|
124 |
""" Method that implement the cleanup of create snapshots """
|
|
125 |
session = self.get_session()
|
|
126 |
project = session.create(self._config.name)
|
|
127 |
|
645
|
128 |
session.home = self._config['dir']
|
|
129 |
path = os.path.join(session.home, project.name)
|
|
130 |
project.work_area(False, True, True, path=path)
|
|
131 |
|
587
|
132 |
target_dir = os.path.normpath(os.path.join(self._config['dir'], project.name))
|
|
133 |
_logger.info("Deleting snapshot under %s." % target_dir)
|
|
134 |
if os.path.exists(target_dir):
|
|
135 |
_logger.info("Deleting '%s'." % target_dir)
|
|
136 |
fileutils.rmtree(target_dir)
|
|
137 |
|
|
138 |
def execute(self):
|
|
139 |
""" Method that implements snapshoting of the project into a folder. """
|
|
140 |
_logger.info("=== Stage=snapshot = %s" % self._config.name)
|
|
141 |
_logger.info("++ Started at %s" % time.strftime("%H:%M:%S", time.localtime()))
|
|
142 |
session = self.get_session()
|
|
143 |
project = session.create(self._config.name)
|
|
144 |
|
|
145 |
target_dir = os.path.normpath(os.path.join(self._config['dir'], project.name))
|
|
146 |
_logger.info("Looking for snapshot under %s." % target_dir)
|
|
147 |
if not self._check_version(project, target_dir):
|
|
148 |
if not os.path.exists(target_dir):
|
|
149 |
_logger.info("Creating '%s'." % target_dir)
|
|
150 |
os.makedirs(target_dir)
|
|
151 |
else:
|
|
152 |
_logger.info("Project needs to be updated, so deleting '%s'." % target_dir)
|
|
153 |
fileutils.rmtree(target_dir)
|
|
154 |
|
|
155 |
try:
|
|
156 |
_logger.info("Snapshotting project.")
|
|
157 |
if self.get_threads() == 1:
|
|
158 |
_logger.info(project.snapshot(target_dir, True))
|
|
159 |
else:
|
|
160 |
_logger.info(ccm.extra.FastSnapshot(project, target_dir, self.get_threads()))
|
|
161 |
|
|
162 |
# writing version file
|
|
163 |
_logger.info("Saving project version information.")
|
|
164 |
versionfile = open(os.path.join(self._config['dir'], project.name, 'project.version'), "w+")
|
|
165 |
versionfile.write(str(project))
|
|
166 |
versionfile.close()
|
|
167 |
except Exception, exc:
|
|
168 |
if isinstance(exc, ccm.extra.CCMExtraException):
|
|
169 |
for sexc in exc.subexceptions:
|
|
170 |
_logger.info(sexc)
|
|
171 |
_logger.info("ERROR: snapshotting %s" % self._config.name)
|
|
172 |
_logger.info(exc)
|
|
173 |
raise exc
|
|
174 |
else:
|
|
175 |
_logger.info("Project snapshot is still up to date. Nothing to do.")
|
|
176 |
|
|
177 |
_logger.info("++ Finished at %s" % time.strftime("%H:%M:%S", time.localtime()))
|
|
178 |
|
|
179 |
def _check_version(self, project, targetdir):
|
|
180 |
""" Check the version file for snaphot and identify if the project has to be snapshot or not.
|
|
181 |
Returns True if the content of the file matches the project to snapshot (nothing to do).
|
|
182 |
Returns falls either if the file is missing, or the content is different.
|
|
183 |
"""
|
|
184 |
versionfile = os.path.join(targetdir, 'project.version')
|
|
185 |
if (os.path.exists(versionfile)):
|
|
186 |
file_ = open(versionfile, "r")
|
|
187 |
projectname = file_.read().strip()
|
|
188 |
file_.close()
|
|
189 |
if (projectname == project.objectname):
|
|
190 |
return True
|
|
191 |
return False
|
|
192 |
|
|
193 |
|
|
194 |
class PreparationCheckout(PreparationAction):
|
|
195 |
""" Handle the checkout and update of project content. """
|
|
196 |
def __init__(self, config, builder):
|
|
197 |
""" Initialization. """
|
|
198 |
PreparationAction.__init__(self, config, builder)
|
|
199 |
self.__role = None
|
|
200 |
|
|
201 |
def check(self):
|
|
202 |
""" Checks if all synergy resources are available. """
|
|
203 |
PreparationAction.check(self)
|
|
204 |
if self._config.has_key('release'):
|
|
205 |
self._check_object(str(self._config['release']))
|
|
206 |
else:
|
|
207 |
raise Exception("'release' property is not defined for %s" % self._config.name)
|
|
208 |
|
|
209 |
for task in self.__get_tasks():
|
|
210 |
self._check_object("Task %s" % task)
|
|
211 |
for folder in self.__get_folders():
|
|
212 |
self._check_object("Folder %s" % folder)
|
|
213 |
|
|
214 |
for project in self.__get_subbaselines():
|
|
215 |
self._check_object(project)
|
645
|
216 |
|
|
217 |
if (not os.path.exists(self._config['dir'])):
|
|
218 |
os.makedirs(self._config['dir'])
|
587
|
219 |
|
|
220 |
# checking if the purpose exists
|
|
221 |
if self._config.has_key('purpose'):
|
|
222 |
session = self.get_session()
|
|
223 |
purposes = session.purposes()
|
|
224 |
if purposes.has_key(str(self._config['purpose'])):
|
|
225 |
_logger.info("Checking purpose '%s'...Ok" % (self._config['purpose']))
|
|
226 |
else:
|
|
227 |
_logger.info("Checking purpose '%s'...Not Found!" % (self._config['purpose']))
|
|
228 |
raise Exception("Could not find purpose %s in the database." % self._config['purpose'])
|
|
229 |
|
|
230 |
role = session.role
|
|
231 |
co_role = ccm.get_role_for_purpose(session, str(self._config['purpose']))
|
|
232 |
_logger.info("Try to switch user to role: %s" % co_role)
|
|
233 |
session.role = co_role
|
|
234 |
session.role = role
|
|
235 |
|
|
236 |
def cleanup(self):
|
|
237 |
""" Method that implement the deletion of checked out projects. """
|
|
238 |
session = self.get_session()
|
|
239 |
project = session.create(self._config.name)
|
|
240 |
|
|
241 |
session.home = self._config['dir']
|
|
242 |
|
|
243 |
result = self.__find_project(project)
|
645
|
244 |
|
|
245 |
path = os.path.join(session.home, project.name)
|
|
246 |
project.work_area(False, True, True, path=path)
|
|
247 |
|
587
|
248 |
if (result != None):
|
|
249 |
_logger.info("Project found: '%s'" % result)
|
|
250 |
role = session.role
|
|
251 |
co_role = ccm.get_role_for_purpose(session, str(self._config['purpose']))
|
|
252 |
session.role = co_role
|
|
253 |
try:
|
588
|
254 |
delResult = result.delete(scope='project_and_subproject_hierarchy')
|
587
|
255 |
finally:
|
|
256 |
session.role = role
|
|
257 |
ccm.log_result(delResult, ccm.CHECKOUT_LOG_RULES, _logger)
|
|
258 |
|
588
|
259 |
def extract_release_data(self):
|
|
260 |
""" Extracting data for a checked out project. """
|
|
261 |
data = None
|
|
262 |
session = self.get_session()
|
|
263 |
project = session.create(self._config.name)
|
587
|
264 |
|
588
|
265 |
session.home = self._config['dir']
|
|
266 |
|
|
267 |
result = self.__find_project(project)
|
|
268 |
if (result != None) and (self._config.get_boolean('releasable', False)):
|
|
269 |
if 'baseline.release' in self._config:
|
|
270 |
data = {}
|
|
271 |
_logger.info("Releasing: '%s'" % result)
|
|
272 |
data['name'] = result.objectname
|
|
273 |
data['database'] = session.database()
|
|
274 |
data['role'] = ccm.get_role_for_purpose(session, str(self._config['purpose']))
|
|
275 |
data['dir'] = os.path.normpath(self._config['dir'])
|
|
276 |
data['pst'] = result.name
|
|
277 |
data['release'] = self._config['baseline.release']
|
|
278 |
else:
|
|
279 |
_logger.warning("Could not release " + result.objectname + " because the 'baseline.release' property is missing.")
|
|
280 |
return data
|
|
281 |
|
587
|
282 |
def execute(self):
|
|
283 |
""" Creates a checkout of the project, or updates an existing checkout if one is found.
|
|
284 |
|
|
285 |
The work area is maintained as part of this.
|
|
286 |
"""
|
|
287 |
_logger.info("=== Stage=checkout = %s" % self._config.name)
|
|
288 |
_logger.info("++ Started at %s" % time.strftime("%H:%M:%S", time.localtime()))
|
|
289 |
session = self.get_session()
|
|
290 |
project = session.create(self._config.name)
|
|
291 |
|
|
292 |
session.home = self._config['dir']
|
|
293 |
|
|
294 |
result = self.__find_project(project)
|
|
295 |
# for testing: result = session.create("ppd_sw-fa1f5132#wbernard2:project:sa1spp#1")
|
|
296 |
if (result != None):
|
|
297 |
_logger.info("Project found: '%s'" % result)
|
|
298 |
|
|
299 |
# setting up the project
|
|
300 |
self.__setup_project(project, result)
|
|
301 |
else:
|
|
302 |
_logger.info("Checking out from '%s'." % project)
|
|
303 |
|
|
304 |
purpose = None
|
|
305 |
if self._config.has_key('purpose'):
|
|
306 |
purpose = self._config['purpose']
|
|
307 |
_logger.info("Using purpose: '%s'" % purpose)
|
|
308 |
|
|
309 |
version = None
|
|
310 |
if self._config.has_key('version'):
|
|
311 |
version = self._config['version']
|
|
312 |
_logger.info("Using version: '%s'" % version)
|
|
313 |
|
|
314 |
try:
|
645
|
315 |
if (not self._config.get_boolean('use.default_wa_path', True)):
|
|
316 |
wa_path = self._config['dir']
|
|
317 |
_logger.info("Using work area path to checkout directly")
|
|
318 |
result = project.checkout(session.create(self._config['release']), version=version, purpose=purpose, path=wa_path)
|
|
319 |
else:
|
|
320 |
result = project.checkout(session.create(self._config['release']), version=version, purpose=purpose)
|
|
321 |
ccm.log_result(result, ccm.CHECKOUT_LOG_RULES, _logger)
|
587
|
322 |
self.__setRole(session)
|
|
323 |
except ccm.CCMException, exc:
|
|
324 |
ccm.log_result(exc.result, ccm.CHECKOUT_LOG_RULES, _logger)
|
|
325 |
raise exc
|
|
326 |
finally:
|
|
327 |
self.__restoreRole(session)
|
|
328 |
_logger.info('Checkout complete')
|
|
329 |
|
|
330 |
if result.project != None and result.project.exists():
|
|
331 |
_logger.info("Project checked out: '%s'" % result.project)
|
|
332 |
|
|
333 |
try:
|
|
334 |
self.__setRole(session)
|
|
335 |
_logger.info("Maintaining the workarea...")
|
|
336 |
if self.get_threads() == 1:
|
|
337 |
output = result.project.work_area(True, True, True, self._config['dir'], result.project.name)
|
|
338 |
else:
|
|
339 |
output = ccm.extra.FastMaintainWorkArea(result.project, self._config['dir'], result.project.name, self.get_threads())
|
|
340 |
ccm.log_result(output, ccm.CHECKOUT_LOG_RULES, _logger)
|
|
341 |
finally:
|
|
342 |
self.__restoreRole(session)
|
|
343 |
self.__setup_project(project, result.project)
|
|
344 |
else:
|
|
345 |
raise Exception("Error checking out '%s'" % project)
|
|
346 |
|
|
347 |
_logger.info("++ Finished at %s" % time.strftime("%H:%M:%S", time.localtime()))
|
|
348 |
|
|
349 |
def __find_project(self, project):
|
|
350 |
""" Private method. """
|
|
351 |
if (os.path.exists(os.path.join(self._config['dir'], project.name, "project.version"))):
|
|
352 |
_logger.info("Snapshot to checkout deleting '%s'." % os.path.join(self._config['dir'], project.name))
|
|
353 |
fileutils.rmtree(os.path.join(self._config['dir'], project.name))
|
|
354 |
return None
|
|
355 |
|
|
356 |
path = os.path.join(self._config['dir'], project.name, project.name)
|
|
357 |
try:
|
|
358 |
result = project.session.get_workarea_info(path)
|
|
359 |
if(result == None):
|
|
360 |
fileutils.rmtree(path)
|
|
361 |
return result
|
|
362 |
return result['project']
|
|
363 |
except ccm.CCMException:
|
|
364 |
# Delete the project dir if found
|
|
365 |
if os.path.exists(os.path.dirname(path)):
|
|
366 |
fileutils.rmtree(os.path.dirname(path))
|
|
367 |
return None
|
|
368 |
|
|
369 |
def __setRole(self, session):
|
|
370 |
""" Updating the role of a session. """
|
|
371 |
self.__role = session.role
|
|
372 |
if self._config.has_key('purpose'):
|
|
373 |
co_role = ccm.get_role_for_purpose(session, self._config['purpose'])
|
|
374 |
_logger.info("Switching user to role: %s" % co_role)
|
|
375 |
session.role = co_role
|
628
|
376 |
_logger.info("Switched user to role: %s" % session.role)
|
587
|
377 |
|
|
378 |
|
|
379 |
def __restoreRole(self, session):
|
|
380 |
""" Restoring to default user role. """
|
|
381 |
if self.__role:
|
|
382 |
_logger.info("Switching user to role: %s" % self.__role)
|
|
383 |
|
|
384 |
session.role = self.__role
|
|
385 |
self.__role = None
|
628
|
386 |
_logger.info("Switched user to role: %s" % session.role)
|
587
|
387 |
|
|
388 |
|
|
389 |
def __setup_project(self, project, coproject):
|
|
390 |
""" Private method. """
|
|
391 |
session = self.get_session()
|
|
392 |
self.__setRole(session)
|
|
393 |
|
|
394 |
newprojs = []
|
|
395 |
if not self._config.get_boolean('use.reconfigure.template', False):
|
|
396 |
_logger.info("Validating release")
|
|
397 |
self.__set_release(coproject)
|
|
398 |
_logger.info("Setting update properties to manual")
|
|
399 |
coproject.set_update_method('manual', True)
|
|
400 |
_logger.info("Setting the baseline to '%s'" % project)
|
|
401 |
coproject.set_baseline(project, True)
|
|
402 |
self.__set_subbaselines(coproject)
|
|
403 |
_logger.info("Cleaning up update properties")
|
|
404 |
self._clean_update_properties(coproject)
|
|
405 |
_logger.info("Setting update properties.")
|
|
406 |
self._set_tasks_and_folders(coproject)
|
|
407 |
_logger.info("Applying update properties.")
|
|
408 |
coproject.apply_update_properties(baseline=False)
|
|
409 |
else:
|
|
410 |
_logger.info("Validating release")
|
|
411 |
self.__set_release(coproject)
|
|
412 |
|
|
413 |
replace_subprojects = True
|
|
414 |
if not self._config.get_boolean('replace.subprojects', True):
|
|
415 |
_logger.info("NOT replacing subprojects")
|
|
416 |
replace_subprojects = False
|
|
417 |
update_keepgoing = True
|
|
418 |
if self._config.get_boolean('update.failonerror', False):
|
|
419 |
_logger.info("The build will fail with update errors")
|
|
420 |
update_keepgoing = False
|
|
421 |
_logger.info("Updating...")
|
|
422 |
result = coproject.update(True, replace_subprojects, update_keepgoing, result=ccm.UpdateResultSimple(coproject.session))
|
|
423 |
|
|
424 |
if self._config.get_boolean('fix.missing.baselines', False) and replace_subprojects:
|
|
425 |
newprojs = self.__fix_baseline(coproject)
|
|
426 |
if len(newprojs) > 0:
|
|
427 |
result = coproject.update(True, replace_subprojects, update_keepgoing, result=ccm.UpdateResultSimple(coproject.session))
|
|
428 |
ccm.log_result(result, ccm.UPDATE_LOG_RULES, _logger)
|
|
429 |
_logger.info("Detected additional projects into baseline - Maintaining the whole toplevel project again...")
|
|
430 |
coproject.work_area(True, True)
|
|
431 |
else:
|
|
432 |
ccm.log_result(result, ccm.UPDATE_LOG_RULES, _logger)
|
|
433 |
else:
|
|
434 |
ccm.log_result(result, ccm.UPDATE_LOG_RULES, _logger)
|
|
435 |
|
|
436 |
# Running sync
|
|
437 |
self._sync(coproject)
|
|
438 |
|
|
439 |
# Running check conflicts
|
|
440 |
self._check_conflicts(coproject)
|
|
441 |
|
|
442 |
self.__restoreRole(session)
|
|
443 |
|
|
444 |
def _sync(self, coproject):
|
|
445 |
""" Run the sync if the 'sync' property is defined to true in the
|
|
446 |
configuration
|
|
447 |
"""
|
|
448 |
if self._config.get_boolean('sync', False):
|
|
449 |
_logger.info("Synchronizing...")
|
|
450 |
result = coproject.sync(True, True)
|
|
451 |
ccm.log_result(result, ccm.SYNC_LOG_RULES, _logger)
|
|
452 |
|
|
453 |
|
|
454 |
def __set_release(self, project):
|
|
455 |
""" Update the release of the project hierarchy if required. """
|
|
456 |
release = project.session.create(self._config['release'])
|
|
457 |
_logger.info("Current release: '%s'" % project.release)
|
|
458 |
_logger.info("Configuration release: '%s'" % release)
|
|
459 |
if project.release != release:
|
|
460 |
_logger.info("Updating release on the project hierarchy.")
|
|
461 |
for subp in [project] + project.subprojects:
|
|
462 |
subp.release = release
|
|
463 |
|
|
464 |
def __fix_baseline(self, coproject):
|
|
465 |
""" Check for project in a different status, then check them out. """
|
|
466 |
newprojs = []
|
|
467 |
_logger.info("Looking for new projects in the check out.")
|
|
468 |
status = coproject['status']
|
|
469 |
for subproj in coproject.subprojects:
|
|
470 |
if subproj['status'] == status:
|
|
471 |
continue
|
|
472 |
_logger.info("New project detected in the checkout '%s'" % subproj.objectname)
|
|
473 |
purpose = None
|
|
474 |
if self._config.has_key('purpose'):
|
|
475 |
purpose = self._config['purpose']
|
|
476 |
_logger.info("Using purpose: '%s'" % purpose)
|
|
477 |
|
|
478 |
version = None
|
|
479 |
if self._config.has_key('version'):
|
|
480 |
version = self._config['version']
|
|
481 |
_logger.info("Using version: '%s'" % version)
|
|
482 |
|
|
483 |
result = subproj.checkout(subproj.session.create(self._config['release']), version=version, purpose=purpose, subprojects=False)
|
|
484 |
_logger.info('Checkout complete')
|
|
485 |
if result.project != None and result.project.exists():
|
|
486 |
newcop = result.project
|
|
487 |
newprojs.append(newcop)
|
|
488 |
|
|
489 |
_logger.info("Setting is_relative to true")
|
|
490 |
if "is_relative" in newcop.keys():
|
|
491 |
newcop["is_relative"] = "TRUE"
|
|
492 |
else:
|
|
493 |
newcop.create_attribute("is_relative", "boolean", "TRUE")
|
|
494 |
|
|
495 |
if not self._config.get_boolean('use.reconfigure.template', False):
|
|
496 |
newcop.set_update_method('manual', False)
|
|
497 |
|
|
498 |
_logger.info("Setting the baseline to '%s'" % subproj)
|
|
499 |
newcop.set_baseline(subproj, True)
|
|
500 |
|
|
501 |
_logger.info("Cleaning up update properties")
|
|
502 |
self._clean_update_properties(newcop)
|
|
503 |
|
|
504 |
_logger.info("Setting update properties.")
|
|
505 |
self._set_tasks_and_folders(newcop)
|
|
506 |
return newprojs
|
|
507 |
|
|
508 |
def _check_conflicts(self, coproject):
|
|
509 |
""" Private method. """
|
|
510 |
conflictsobjects = self._config.get_boolean('show.conflicts.objects', False)
|
|
511 |
|
|
512 |
if self._config.get_boolean('show.conflicts', False) or conflictsobjects:
|
|
513 |
result = coproject.conflicts(True, not conflictsobjects)
|
|
514 |
ccm.log_result(result, ccm.CONFLICTS_LOG_RULES, _logger)
|
|
515 |
# for project in result.keys():
|
|
516 |
# for error in result[project]:
|
|
517 |
# if 'object' in error:
|
|
518 |
# _logger.info("CONFLICTS: %s" % error['comment'])
|
|
519 |
# else:
|
|
520 |
# _logger.info("CONFLICTS: %s" % error['comment'])
|
|
521 |
|
|
522 |
@staticmethod
|
|
523 |
def _clean_update_properties(project):
|
|
524 |
""" Private method. """
|
|
525 |
for task in project.tasks:
|
|
526 |
project.remove_task(task)
|
|
527 |
for folder in project.folders:
|
|
528 |
project.remove_folder(folder)
|
|
529 |
|
|
530 |
@staticmethod
|
|
531 |
def __find_subproject(subprojects, project):
|
|
532 |
""" Private method. """
|
|
533 |
for subproj in subprojects:
|
|
534 |
if subproj.is_same_family(project):
|
|
535 |
return subproj
|
|
536 |
raise Exception("Error could not identify check out project for '%s'" % project)
|
|
537 |
|
|
538 |
def __set_subbaselines(self, project):
|
|
539 |
""" Private method. """
|
|
540 |
if len(self.__get_subbaselines()) > 0:
|
|
541 |
subprojects = project.subprojects
|
|
542 |
for subbaseline in self.__get_subbaselines():
|
|
543 |
subbaseline = project.session.create(subbaseline)
|
|
544 |
subproj = self.__find_subproject(subprojects, subbaseline)
|
|
545 |
_logger.info("Setting subproject '%s' baseline to '%s'" % (subproj, subbaseline))
|
|
546 |
subproj.set_baseline(subbaseline, True)
|
|
547 |
|
|
548 |
def __get_array(self, key):
|
|
549 |
""" Private method. """
|
|
550 |
result = []
|
|
551 |
if (self._config.has_key(key)):
|
|
552 |
if isinstance(self._config[key], type([])):
|
|
553 |
for value in self._config[key]:
|
|
554 |
value = value.strip()
|
|
555 |
if len(value) > 0:
|
|
556 |
result.append(value)
|
|
557 |
else:
|
|
558 |
value = self._config[key].strip()
|
|
559 |
if len(value) > 0:
|
|
560 |
result.append(value)
|
|
561 |
return result
|
|
562 |
|
|
563 |
def __get_subbaselines(self):
|
|
564 |
""" Private method. """
|
|
565 |
return self.__get_array('subbaselines')
|
|
566 |
|
|
567 |
def __get_tasks(self):
|
|
568 |
""" Private method. """
|
|
569 |
return self.__get_array('tasks')
|
|
570 |
|
|
571 |
def __get_folders(self):
|
|
572 |
""" Private method. """
|
|
573 |
return self.__get_array('folders')
|
|
574 |
|
|
575 |
def _set_tasks_and_folders(self, project):
|
|
576 |
""" Private method. """
|
|
577 |
for task in self.__get_tasks():
|
|
578 |
_logger.info("Adding task %s" % task)
|
|
579 |
project.add_task(project.session.create("Task %s" % task))
|
|
580 |
for folder in self.__get_folders():
|
|
581 |
_logger.info("Adding folder %s" % folder)
|
|
582 |
project.add_folder(project.session.create("Folder %s" % folder))
|
|
583 |
|
|
584 |
class PreparationUpdate(PreparationCheckout):
|
|
585 |
""" Synergy project updater. """
|
|
586 |
|
|
587 |
def __init__(self, config, builder):
|
|
588 |
""" Initialization. """
|
|
589 |
PreparationCheckout.__init__(self, config, builder)
|
|
590 |
|
|
591 |
def check(self):
|
|
592 |
""" Checks if all synergy resources are available. """
|
|
593 |
PreparationAction.check(self)
|
|
594 |
|
|
595 |
session = self.get_session()
|
|
596 |
ccm_object = session.create(self._config.name)
|
|
597 |
role = session.role
|
|
598 |
co_role = ccm.get_role_for_status(ccm_object['status'])
|
|
599 |
_logger.info("Try to switch user to role: %s" % co_role)
|
|
600 |
session.role = co_role
|
|
601 |
session.role = role
|
|
602 |
|
|
603 |
def execute(self):
|
|
604 |
""" Updating the mentioned project. """
|
|
605 |
|
|
606 |
session = self.get_session()
|
|
607 |
ccmproject = session.create(self._config.name)
|
|
608 |
role = session.role
|
|
609 |
|
|
610 |
status = ccmproject['status']
|
|
611 |
co_role = ccm.get_role_for_status(status)
|
|
612 |
session.role = co_role
|
|
613 |
|
|
614 |
if not self._config.get_boolean('use.reconfigure.template', False):
|
|
615 |
_logger.info("Setting update properties to manual")
|
|
616 |
ccmproject.set_update_method('manual', True)
|
|
617 |
_logger.info("Cleaning up update properties")
|
|
618 |
self._clean_update_properties(ccmproject)
|
|
619 |
_logger.info("Setting update properties.")
|
|
620 |
self._set_tasks_and_folders(ccmproject)
|
|
621 |
_logger.info("Applying update properties.")
|
|
622 |
ccmproject.apply_update_properties(baseline=False)
|
|
623 |
replace_subprojects = True
|
|
624 |
if not self._config.get_boolean('replace.subprojects', True):
|
|
625 |
_logger.info("NOT replacing subprojects")
|
|
626 |
replace_subprojects = False
|
|
627 |
update_keepgoing = True
|
|
628 |
if self._config.get_boolean('update.failonerror', False):
|
|
629 |
_logger.info("The build will fail with update errors")
|
|
630 |
update_keepgoing = False
|
|
631 |
|
|
632 |
_logger.info("Updating %s..." % ccmproject.objectname)
|
|
633 |
result = ccmproject.update(True, replace_subprojects, update_keepgoing, result=ccm.UpdateResultSimple(ccmproject.session))
|
|
634 |
ccm.log_result(result, ccm.UPDATE_LOG_RULES, _logger)
|
|
635 |
|
|
636 |
self._sync(ccmproject)
|
|
637 |
|
|
638 |
self._check_conflicts(ccmproject)
|
|
639 |
|
|
640 |
session.role = role
|
|
641 |
|
588
|
642 |
def extract_release_data(self):
|
|
643 |
""" Extracting data for an updated project. """
|
|
644 |
data = None
|
|
645 |
session = self.get_session()
|
|
646 |
project = session.create(self._config.name)
|
|
647 |
|
|
648 |
session.home = self._config['dir']
|
|
649 |
|
|
650 |
if self._config.get_boolean('releasable', False):
|
|
651 |
if 'baseline.release' in self._config:
|
|
652 |
data = {}
|
|
653 |
_logger.info("Releasing: '%s'" % project)
|
|
654 |
data['name'] = project.objectname
|
|
655 |
data['database'] = session.database()
|
|
656 |
data['role'] = ccm.get_role_for_purpose(session, str(self._config['purpose']))
|
|
657 |
data['dir'] = os.path.normpath(self._config['dir'])
|
|
658 |
data['pst'] = project.name
|
|
659 |
data['release'] = self._config['baseline.release']
|
|
660 |
else:
|
|
661 |
_logger.warning("Could not release " + project + " because the 'baseline.release' property is missing.")
|
|
662 |
return data
|
|
663 |
|
587
|
664 |
class PreparationBuilder(object):
|
|
665 |
""" Creates an updated work area from a configuration. """
|
|
666 |
def __init__(self, configs, username = None, password = None, cache=None):
|
|
667 |
""" Initialization. """
|
|
668 |
self._configs = configs
|
|
669 |
self._sessions = {}
|
|
670 |
self._actions = []
|
|
671 |
self.__username = username
|
|
672 |
self.__password = password
|
|
673 |
self.__provider = ccm.extra.CachedSessionProvider(cache=cache)
|
|
674 |
for config in self._configs:
|
|
675 |
if config.type == "snapshot":
|
|
676 |
self._actions.append(PreparationSnapshot(config, self))
|
|
677 |
elif config.type == "checkout":
|
|
678 |
self._actions.append(PreparationCheckout(config, self))
|
|
679 |
elif config.type == "update":
|
|
680 |
self._actions.append(PreparationUpdate(config, self))
|
|
681 |
|
|
682 |
def check(self):
|
|
683 |
""" Check that all dependencies are there. """
|
|
684 |
for action in self._actions:
|
|
685 |
action.check()
|
|
686 |
|
|
687 |
def cleanup(self):
|
|
688 |
""" Check that all dependencies are there. """
|
|
689 |
for action in self._actions:
|
|
690 |
action.cleanup()
|
|
691 |
|
|
692 |
def get_content(self):
|
|
693 |
""" Run the each action. """
|
|
694 |
for action in self._actions:
|
|
695 |
action.execute()
|
|
696 |
|
588
|
697 |
def extract_release_data(self, filename):
|
|
698 |
""" Extract project information into an xml file. """
|
|
699 |
|
|
700 |
impl = getDOMImplementation()
|
|
701 |
|
|
702 |
doc = impl.createDocument(None, "release", None)
|
|
703 |
top_element = doc.documentElement
|
|
704 |
|
|
705 |
for action in self._actions:
|
|
706 |
data = action.extract_release_data()
|
|
707 |
if data:
|
|
708 |
project_node = doc.createElement('project')
|
|
709 |
for attr in data:
|
|
710 |
project_node.setAttribute(attr, data[attr])
|
|
711 |
top_element.appendChild(project_node)
|
|
712 |
|
|
713 |
f_file = open(filename, 'w+')
|
|
714 |
f_file.write(doc.toprettyxml(indent=" "))
|
|
715 |
f_file.close()
|
|
716 |
|
587
|
717 |
def session(self, database, size=1, engine=None, dbpath=None):
|
|
718 |
""" Handles pool rather that sessions. """
|
|
719 |
assert size > 0, "The pool must contains at least one session!"
|
|
720 |
if self.__provider is None:
|
|
721 |
raise Exception("The builder has been closed.")
|
|
722 |
if not self._sessions.has_key(database):
|
|
723 |
_logger.info("Get a session for %s" % database)
|
|
724 |
session = ccm.SessionPool(self.__username, self.__password, engine, dbpath, database, size, opener=self.__provider.get)
|
|
725 |
self._sessions[database] = session
|
|
726 |
# be developer by default
|
|
727 |
session.role = "developer"
|
|
728 |
session = self._sessions[database]
|
|
729 |
if session.size < size:
|
|
730 |
_logger.info("Resizing the pool for database %s to %d" % (database, size))
|
|
731 |
session.size = size
|
|
732 |
# be developer by default
|
|
733 |
session.role = "developer"
|
|
734 |
return session
|
|
735 |
|
|
736 |
def close(self):
|
|
737 |
""" This is the preparation cleanup method.
|
|
738 |
It closes all opened sessions.
|
|
739 |
"""
|
|
740 |
_logger.debug("Closing sessions...")
|
|
741 |
dbs = self._sessions.keys()
|
|
742 |
while len(dbs) > 0:
|
|
743 |
session = self._sessions.pop(dbs.pop())
|
|
744 |
session.close()
|
|
745 |
if self.__provider is not None:
|
|
746 |
self.__provider.close()
|
|
747 |
self.__provider = None
|
|
748 |
|
|
749 |
|
|
750 |
def __del__(self):
|
|
751 |
self.close()
|
|
752 |
|
|
753 |
|
|
754 |
|