Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(12)

Side by Side Diff: buildbot/manifest_version.py

Issue 6691047: Merge MVP script into cbuildbot. (Closed) Base URL: http://git.chromium.org/git/chromite.git@master
Patch Set: Implement Debug option for manifest_version Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 #!/usr/bin/python
2 # Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """
7 A script to generate and store the manifests for the canary builders to use.
sosa 2011/04/11 19:03:54 Change docstring to reflect change to library
8 """
9
10 import fnmatch
11 import logging
12 import logging.handlers
13 import optparse
14 import os
15 import re
16 import shutil
17 import sys
18 import tempfile
19
20 import chromite.lib.cros_build_lib as cros_lib
21
22 logging_format = '%(asctime)s - %(filename)s - %(levelname)-8s: %(message)s'
23 date_format = '%Y/%m/%d %H:%M:%S'
24 logging.basicConfig(level=logging.INFO, format=logging_format,
25 datefmt=date_format)
26
27 # Pattern for matching build name format. E.g, 12.3.4.5,1.0.25.3
28 VER_PATTERN = '(\d+).(\d+).(\d+).(\d+)'
29
30 class VersionUpdateException(Exception):
31 """Exception gets thrown for failing to update the version file"""
32 pass
33
34
35 class InvalidOptionException(Exception):
36 """Exception gets thrown for invalid options"""
37 pass
38
39
40 class GitCommandException(Exception):
41 """Exception gets thrown for a git command that fails to execute."""
42 pass
43
44 class SrcCheckOutException(Exception):
45 """Exception gets thrown for failure to sync sources"""
46 pass
47
48 class StatusUpdateException(Exception):
49 """Exception gets thrown for failure to update the status"""
50 pass
51
52 class GenerateBuildSpecException(Exception):
53 """Exception gets thrown for failure to Generate a buildspec for the build"""
54 pass
55
56
57 class GitMirror(object):
58 """ A Class to deal with the source tree/mirror setup and sync repos
59 Args:
60 mirror_dir: location for setting up git mirror
61 git_server: gitserver URI information
62 manifest_repo: repo to fetch the manifests from
63 manifest_file: manifest_file to use for syncing
64 """
65 def __init__(self, mirror_dir, repo_url, manifest_file='full.xml'):
66 self.mirror_dir = mirror_dir
67 self.repo_url = repo_url
68 self.manifest_file = manifest_file
69 self.InitMirrorRepos()
70
71 def InitMirrorRepos(self):
72 """Initialize the git mirroring"""
73 if not os.path.exists(self.mirror_dir):
74 os.makedirs(self.mirror_dir)
75 logging.debug('git mirror does not exist. Creating it for the first time')
76
77 if not os.path.exists(os.path.join(self.mirror_dir, '.repo')):
78 cros_lib.RunCommand(['repo', 'init', '-u', self.repo_url, '-m',
79 self.manifest_file, '--mirror'], cwd=self.mirror_dir,
80 input='\n\ny\n')
81
82 def SyncMirror(self):
83 """Sync/update the git mirror location"""
84 cros_lib.RunCommand(['repo', 'sync'], cwd=self.mirror_dir)
85
86
87 class VersionInfo(object):
88 """Class to encapsualte the chrome os version info
89 You can instantiate this class in two ways.
90 1)using a version file, specifically chromeos_version.sh,
91 which contains the version information.
92 2) just passing in the 4 version components (major, minor, sp and patch)
93 Args:
94 ver_maj: major version
95 ver_min: minor version
96 ver_sp: sp version
97 ver_patch: patch version
98 version_file: version file location.
99 """
100 def __init__(self, ver_maj=0, ver_min=0, ver_sp=0, ver_patch=0,
101 incr_type=None, version_file=None):
102 self.ver_maj = ver_maj
103 self.ver_min = ver_min
104 self.ver_sp = ver_sp
105 self.ver_patch = ver_patch
106 self.incr_type = incr_type
107 if version_file:
108 self.version_file = version_file
109 self.load()
110
111 def FindValue(self, key, line):
112 """Given the key find the value from the line, if it finds key = value
113 Args:
114 key: key to look for
115 line: string to search
116 returns:
117 None: on a non match
118 value: for a matching key
119 """
120 regex = '.*(%s)\s*=\s*(\d+)$' % key
121
122 match = re.match(regex, line)
123 if match:
124 return match.group(2)
125 return None
126
127 def load(self):
128 """Read the version file and set the version components"""
129 with open(self.version_file, 'r') as version_fh:
130 for line in version_fh:
131 if not line.strip():
132 continue
133
134 match = self.FindValue('CHROMEOS_VERSION_MAJOR', line)
135 if match:
136 self.ver_maj = match
137 logging.debug('Set the major version to:%s', self.ver_maj)
138 continue
139
140 match = self.FindValue('CHROMEOS_VERSION_MINOR', line)
141 if match:
142 self.ver_min = match
143 logging.debug('Set the minor version to:%s', self.ver_min)
144 continue
145
146 match = self.FindValue('CHROMEOS_VERSION_BRANCH', line)
147 if match:
148 self.ver_sp = match
149 logging.debug('Set the sp version to:%s', self.ver_sp)
150 continue
151
152 match = self.FindValue('CHROMEOS_VERSION_PATCH', line)
153 if match:
154 self.ver_patch = match
155 logging.debug('Set the patch version to:%s', self.ver_patch)
156 continue
157 logging.debug(self.VersionString())
158
159 def IncrementVersion(self):
160 """Updates the version file by incrementing the patch component"""
161 if not self.version_file:
162 raise VersionUpdateException('Cannot call IncrementVersion without '
163 'an associated version_file')
164 if not self.incr_type:
165 raise VersionUpdateException('Need to specify the part of the version to'
166 'increment')
167
168 if self.incr_type == 'branch':
169 self.ver_sp = str(int(self.ver_sp) + 1)
170 self.ver_patch = '0'
171 if self.incr_type == 'patch':
172 self.ver_patch = str(int(self.ver_patch) + 1)
173 temp_file = tempfile.mkstemp(suffix='mvp', prefix='tmp', dir=None,
174 text=True)[1]
175 with open(self.version_file, 'r') as source_version_fh:
176 with open(temp_file, 'w') as temp_fh:
177 for line in source_version_fh:
178 old_patch = self.FindValue('CHROMEOS_VERSION_PATCH', line)
179 if old_patch:
180 temp_fh.write(line.replace(old_patch, self.ver_patch, 1))
181 continue
182
183 old_sp = self.FindValue('CHROMEOS_VERSION_BRANCH', line)
184 if old_sp:
185 temp_fh.write(line.replace(old_sp, self.ver_sp, 1))
186 continue
187
188 temp_fh.write(line)
189 temp_fh.close()
190 source_version_fh.close()
191 shutil.copyfile(temp_file, self.version_file)
192 os.unlink(temp_file)
193 return self.VersionString()
194
195 def VersionString(self):
196 """returns the version string"""
197 return '%s.%s.%s.%s' % (self.ver_maj, self.ver_min, self.ver_sp,
198 self.ver_patch)
199 def DirPrefix(self):
200 """returns the sub directory suffix in manifest-versions"""
201 return '%s.%s' % (self.ver_maj, self.ver_min)
202
203 def BuildPrefix(self):
204 """returns the build prefix to match the buildspecs in manifest-versions"""
205 if self.incr_type == 'patch':
206 return '%s.%s.%s' % (self.ver_maj, self.ver_min, self.ver_sp)
207
208 if self.incr_type == 'branch':
209 return '%s.%s' % (self.ver_maj, self.ver_min)
210
211 return None
212
213
214 class SpecsInfo(object):
215 """Class that contains information about the buildspecs
216 Args:
217 working_dir: location of the buildspecs location
218 build_name: name of the build that we will be dealing with
219 dir_prefix: prefix of the version for sub-directory location
220 build_prefix: prefix of the build version for build specs matching
221 """
222 def __init__(self, working_dir, ver_manifests, build_name, dir_prefix,
223 build_prefix):
224 self.working_dir = working_dir
225 self.ver_manifests = ver_manifests
226 self.build_name = build_name
227 self.dir_prefix = dir_prefix
228 self.build_prefix = build_prefix
229 self.root_dir = os.path.join(self.working_dir, self.ver_manifests)
230 self.all_specs_dir = os.path.join(self.root_dir, 'buildspecs',
231 self.dir_prefix)
232 self.pass_dir = os.path.join(self.root_dir, 'build-name', self.build_name,
233 'pass', self.dir_prefix)
234 self.fail_dir = os.path.join(self.root_dir, 'build-name', self.build_name,
235 'fail', self.dir_prefix)
236 self.inflight_dir = os.path.join(self.root_dir, 'build-name',
237 self.build_name, 'inflight',
238 self.dir_prefix)
239 logging.debug('Build Specs Dir = %s', self.all_specs_dir)
240
241
242 class BuildSpecs(object):
243 """ Class to manage buildspecs
244 Args:
245 working_dir:location where the ver_manifests repo is synced to
246 ver_manifests: Name of the ver_manifests repo. Default: manifest-versions
247 build_name: Name of the build that we are interested in. E.g., x86-alex
248 dir_prefix: prefix of the version numbers for sub directory look up
249 build_prefix: prefix of the build version for build specs matching
250 incr_type: part of the version to increment. 'patch or branch'
251 """
252 def __init__(self, working_dir, ver_manifests, build_name, dir_prefix,
253 build_prefix, incr_type):
254 self.specs_info = SpecsInfo(working_dir, ver_manifests, build_name,
255 dir_prefix, build_prefix)
256 self.all = self.GetMatchingSpecs(self.specs_info.all_specs_dir, incr_type)
257 self.latest = '0.0.0.0'
258 self.incr_type = incr_type
259
260 if self.all:
261 self.latest = self.all[-1]
262 self.all = set(self.GetMatchingSpecs(self.specs_info.all_specs_dir,
263 self.incr_type))
264 self.passed = self.GetMatchingSpecs(self.specs_info.pass_dir,
265 self.incr_type)
266 self.failed = self.GetMatchingSpecs(self.specs_info.fail_dir,
267 self.incr_type)
268 self.inflight = self.GetMatchingSpecs(self.specs_info.inflight_dir,
269 self.incr_type)
270 self.processed = sorted((self.passed + self.failed + self.inflight),
271 key=lambda s: map(int, s.split('.')))
272 self.last_processed = '0.0.0.0'
273 if self.processed:
274 self.last_processed = self.processed[-1]
275 logging.debug('Last processed build for %s is %s' %
276 (build_name, self.last_processed))
277
278 difference = list(self.all.difference(set(self.processed)))
279
280 for build in difference[:]:
281 build1 = map(int, build.split("."))
282 build2 = map(int, self.last_processed.split("."))
283
284 if cmp(build1 , build2) == 1:
285 logging.debug('Still need to build %s' % build)
286 else:
287 logging.debug('Ignoring build %s less than %s' %
288 (build, self.last_processed))
289 difference.remove(build)
290
291 self.unprocessed = sorted(difference, key=lambda s: map(int, s.split('.')))
292
293 def GetMatchingSpecs(self, specs_info, incr_type):
294 """Returns the sorted list of buildspecs that match '*.xml'
295 Args:
296 specs_info: SpecsInfo object for the buildspecs location information.
297 """
298 matched_manifests = []
299 if os.path.exists(specs_info):
300 all_manifests = os.listdir(specs_info)
301 match_string = self.specs_info.build_prefix + '.*.xml'
302
303 if incr_type == 'branch':
304 match_string = self.specs_info.build_prefix + '.*.0.xml'
305
306 matched_manifests = fnmatch.filter(
307 all_manifests, match_string)
308 matched_manifests = [os.path.splitext(m)[0] for m in matched_manifests]
309
310 return matched_manifests
311
312 def FindNextBuild(self, latest=False):
313 """"Find the next build to build from unprocessed buildspecs
314 Args:
315 latest: True of False. (Returns the last known build on latest =True
316 Returns:
317 Returns the next build to be built or None
318 """
319 if not self.unprocessed:
320 return None
321
322 if latest:
323 return self.unprocessed[-1]
324
325 return self.unprocessed[0]
326
327 def ExistsBuildSpec(self, build_number):
328 """"Find out if the build_number exists in existing buildspecs
329 Args:
330 build_number: build number to check for existence of build spec
331 Returns:
332 True if the buildspec exists, False if it doesn't
333 """
334 return build_number in self.all
335
336
337 class BuildSpecsManager(object):
338 """A Class to manage buildspecs and their states
339 Args:
340 working_dir: location of the buildspecs repo
341 build_name: build_name e.g., x86-mario, x86-mario-factory
342 dir_prefix: version prefix to match for the sub directories
343 build_prefix: prefix of the build version for build specs matching
344 """
345
346 def __init__(self, working_dir, ver_manifests, build_name, dir_prefix,
347 build_prefix):
348 self.specs_info = SpecsInfo(working_dir, ver_manifests, build_name,
349 dir_prefix, build_prefix)
350
351 def SetUpSymLinks(self, src_file, dest_file, remove_file=None):
352 """Setting up symlinks for various statuses in the git repo
353 Args:
354 status: status type to set to, (one of inflight, pass, fail)
355 src_file: source for the symlink
356 dest_file: destination for the symlink
357 remove_file: symlink that needs to be deleted for clearing the old state
358 """
359 dest_dir = os.path.dirname(dest_file)
360 if os.path.lexists(dest_file):
361 os.unlink(dest_file)
362
363 if not os.path.exists(dest_dir):
364 os.makedirs(dest_dir)
365 rel_src_file = os.path.relpath(src_file, dest_dir)
366 logging.debug('Linking %s to %s', rel_src_file, dest_file)
367 os.symlink(rel_src_file, dest_file)
368
369 if remove_file and os.path.lexists(remove_file):
370 logging.debug('REMOVE: Removing %s', remove_file)
371 os.unlink(remove_file)
372
373
374 def SetInFlight(self, version):
375 """Marks a buildspec as inflight by creating a symlink in 'inflight' dir
376 Args:
377 version: version of the buildspec to mark as inflight
378 """
379 dest_file = '%s.xml' % os.path.join(self.specs_info.inflight_dir, version)
380 src_file = '%s.xml' % os.path.join(self.specs_info.all_specs_dir, version)
381 logging.debug('Setting build in flight %s: %s', src_file, dest_file)
382 self.SetUpSymLinks(src_file, dest_file)
383
384 def SetFailed(self, version):
385 """Marks a buildspec as failed by creating a symlink in 'fail' dir
386 Args:
387 version: version of the buildspec to mark as failed
388 """
389 dest_file = '%s.xml' % os.path.join(self.specs_info.fail_dir, version)
390 src_file = '%s.xml' % os.path.join(self.specs_info.all_specs_dir, version)
391 remove_file = '%s.xml' % os.path.join(self.specs_info.inflight_dir, version)
392 logging.debug('Setting build to failed %s: %s', src_file, dest_file)
393 self.SetUpSymLinks(src_file, dest_file, remove_file)
394
395 def SetPassed(self, version):
396 """Marks a buildspec as failed by creating a symlink in 'pass' dir
397 Args:
398 version: version of the buildspec to mark as passed
399 """
400 dest_file = '%s.xml' % os.path.join(self.specs_info.pass_dir, version)
401 src_file = '%s.xml' % os.path.join(self.specs_info.all_specs_dir, version)
402 remove_file = '%s.xml' % os.path.join(self.specs_info.inflight_dir, version)
403 logging.debug('Setting build to passed %s: %s', src_file, dest_file)
404 self.SetUpSymLinks(src_file, dest_file, remove_file)
405
406
407 def CloneGitRepo(working_dir, repo_url):
408 """"Clone Given git repo
409 Args:
410 repo: git repo to clione
411 git_server: git server URL
412 repo_dir: location where it should be cloned to
413 """
414 if not os.path.exists(working_dir):
415 os.makedirs(working_dir)
416 cros_lib.RunCommand(['git', 'clone', repo_url], cwd=working_dir)
417
418 def PushChanges(git_repo, message, use_repo=False, dry_run=True):
419 """Do the final commit into the git repo
420 Args:
421 git_repo: git repo to push
422 message: Commit message
423 use_repo: use repo tool for pushing changes. Default: False
424 raises: GitCommandException
425 """
426 branch = 'temp_auto_checkin_branch'
427 try:
428 if use_repo:
429 cros_lib.RunCommand(['repo', 'start', branch, '.'], cwd=git_repo)
430 cros_lib.RunCommand(['repo', 'sync', '.'], cwd=git_repo)
431 cros_lib.RunCommand(['git', 'config', 'push.default', 'tracking'],
432 cwd=git_repo)
433 else:
434 cros_lib.RunCommand(['git', 'pull', '--force'], cwd=git_repo)
435 cros_lib.RunCommand(['git', 'add', '-A'], cwd=git_repo)
436 cros_lib.RunCommand(['git', 'commit', '-am', message], cwd=git_repo)
437
438 push_cmd = ['git', 'push', '--verbose']
439 if dry_run: push_cmd.append('--dry-run')
440 cros_lib.RunCommand(push_cmd, cwd=git_repo)
441 except cros_lib.RunCommandError, e:
442 err_msg = 'Failed to commit to %s' % e.message
443 logging.error(err_msg)
444 git_status = cros_lib.RunCommand(['git', 'status'], cwd=git_repo)
445 logging.error('Current repo %s status: %s', git_repo, git_status)
446 CleanGitChanges(git_repo)
447 raise GitCommandException(err_msg)
448 finally:
449 if use_repo:
450 cros_lib.RunCommand(['repo', 'abandon', branch], cwd=git_repo)
451
sosa 2011/04/11 19:03:54 two lines
452 def CleanGitChanges(git_repo):
453 """"Clean git repo chanages
454 Args:
455 git_repo: location of the git repo to clean
456 raises: GitCommandException: when fails to clean
457 """
458 try:
459 cros_lib.RunCommand(['git', 'clean', '-d', '-f'], cwd=git_repo)
460 cros_lib.RunCommand(['git', 'reset', '--hard', 'HEAD'], cwd=git_repo)
461 except cros_lib.RunCommandError, e:
462 err_msg = 'Failed to clean git repo %s' % e.message
463 logging.error(err_msg)
464 raise GitCommandException(err_msg)
465
466
467 def SetLogFileHandler(logfile):
468 """This sets the logging handler to a file.
469 define a Handler which writes INFO messages or higher to the sys.stderr
470 Add the log message handler to the logger
471 Args:
472 logfile: name of the logfile to open
473 """
474 logfile_handler = logging.handlers.RotatingFileHandler(logfile, backupCount=5)
475 logfile_handler.setLevel(logging.DEBUG)
476 logfile_handler.setFormatter(logging.Formatter(logging_format))
477 logging.getLogger().addHandler(logfile_handler)
478
479
480 def CheckOutSources(cros_source, repo_url, source_dir, branch,
481 manifest_file='full.xml', retries=0):
482 """"Fetches the sources from the git server using repo tool
483 Args:
484 cros_source: GitMirror Object
485 source_dir: Location to sync the sources to
486 branch: branch to use for the manifest.xml for repo tool
487 manifest_repo: repo to use for manifest files
488 manifest_file: manifest file to use for the file definition
489 retries: Number of times to try to fetch sources
490 """
491 while True:
492 if not os.path.exists(source_dir):
493 os.makedirs(source_dir)
494 try:
495 cros_source.SyncMirror()
496 cros_lib.RunCommand(['repo', 'init', '-u', repo_url, '-b', branch, '-m',
497 manifest_file, '--reference',
498 cros_source.mirror_dir], cwd=source_dir,
499 input='\n\ny\n')
500 cros_lib.RunCommand(['repo', 'sync'], cwd=source_dir)
501 break
502 except cros_lib.RunCommandError, e:
503 if retries < 1:
504 err_msg = 'Failed to sync sources %s' % e.message
505 logging.error(err_msg)
506 raise SrcCheckOutException(err_msg)
507 logging.info('Failed to sync sources %s', e.message)
508 logging.info('But will try %d times', retries)
509 CleanUP(source_dir)
510 retries = retries - 1
511
512 def ExportManifest(source_dir, output_file):
513 """Exports manifests file
514 Args:
515 source_dir: repo root
516 output_file: output_file to out put the manifest to
517 """
518 cros_lib.RunCommand(['repo', 'manifest', '-r', '-o', output_file],
519 cwd=source_dir)
520
521
522 def SetupExistingBuildSpec(build_specs_manager, next_build, debug):
523 build_specs_manager.SetInFlight(next_build)
524 commit_message = 'Automatic: Start %s %s' % (
525 build_specs_manager.specs_info.build_name, next_build)
526 PushChanges(build_specs_manager.specs_info.root_dir, commit_message, debug)
527
528
529 def GenerateNewBuildSpec(source_dir, branch, latest_build, build_specs_root,
530 build_specs_manager, cros_source, version_info,
531 increment_version,
532 debug):
533 """Generates a new buildspec for the builders to consume
534 Checks to see, if there are new changes that need to be built from the last
535 time another buildspec was created. Updates the version number in version
536 number file. Generates the manifest as the next buildspecs. pushes it to git
537 and returns the next build spec number
538 If there are no new changes returns None
539 Args:
540 source_dir: location of the source tree root
541 branch: branch to sync the sources to
542 latest_build: latest known build to match the latest sources against
543 build_specs_root: location of the build specs root
544 build_specs_manager: BuildSpecsManager object
545 cros_source: GitMirror object
546 version_info: VersionInfo Object
547 increment_version: True or False for incrementing the chromeos_version.sh
548 debug: if True don't push changes externally
549 Returns:
550 next build number: on new changes or
551 None: on no new changes
552 """
553 temp_manifest_file = tempfile.mkstemp(suffix='mvp', text=True)[1]
554
555 ExportManifest(source_dir, temp_manifest_file)
556
557 latest_spec_file = '%s.xml' % os.path.join(
558 build_specs_manager.specs_info.all_specs_dir, latest_build)
559
560 logging.debug('Calling DiffManifests with %s, %s', latest_spec_file,
561 temp_manifest_file)
562 if not (latest_build == '0.0.0.0' or
563 DiffManifests(temp_manifest_file, latest_spec_file)):
564 return None
565
566 next_version = version_info.VersionString()
567
568 if increment_version:
569 next_version = version_info.IncrementVersion()
570 logging.debug('Incremented version number to %s', next_version)
571 message = 'Automatic: Updating the new version number %s' % next_version
572 PushChanges(os.path.dirname(version_info.version_file), message,
573 True, debug)
574 CheckOutSources(cros_source, source_dir, branch)
575
576 next_spec_file = '%s.xml' % os.path.join(
577 build_specs_manager.specs_info.all_specs_dir, next_version)
578 if not os.path.exists(os.path.dirname(next_spec_file)):
579 os.makedirs(os.path.dirname(next_spec_file))
580 ExportManifest(source_dir, next_spec_file)
581 message = 'Automatic: Buildspec %s. Created by %s' % (
582 next_version, build_specs_manager.specs_info.build_name)
583 logging.debug('Created New Build Spec %s', message)
584
585 build_specs_manager.SetInFlight(next_version)
586 PushChanges(build_specs_root, message, debug)
587 return next_version
588
589
590 def DiffManifests(manifest1, manifest2):
591 """Diff two manifest files. excluding the revisions to manifest-verisons.git
592 Args:
593 manifest1: First manifest file to compare
594 manifest2: Second manifest file to compare
595 Returns:
596 True: If the manifests are different
597 False: If the manifests are same
598 """
599 black_list = ['manifest-versions']
600 blacklist_pattern = re.compile(r'|'.join(black_list))
601 with open(manifest1, 'r') as manifest1_fh:
602 with open(manifest2, 'r') as manifest2_fh:
603 for (line1, line2) in zip(manifest1_fh, manifest2_fh):
604 if blacklist_pattern.search(line1):
605 logging.debug('%s ignored %s', line1, line2)
606 continue
607
608 if line1 != line2:
609 return True
610 return False
611
612
613 def SetStatus(build_version, status, working_dir, ver_manifests, build_name,
614 debug):
615 """Set the status of a particular build by moving the build_spec files around
616 Args:
617 build_version: version of the build that we should set the status for
618 status: status to set. One of 'pass|fail'
619 working_dir: working dir where our version-manifests repos are synced
620 ver_manifests: name of the version manifests repo
621 build_name: Name of the build that we are settting the status for
622 debug: if True don't push changes externally
623 """
624 logging.info('Setting Status for %s as %s', build_version, status)
625 match = re.search(VER_PATTERN, build_version)
626 logging.debug('Matched %s - %s - %s - %s', match.group(1), match.group(2),
627 match.group(3), match.group(4))
628 version_info = VersionInfo(ver_maj=match.group(1), ver_min=match.group(2),
629 ver_sp=match.group(3), ver_patch=match.group(4))
630 logging.debug('Using Version: %s', version_info.VersionString())
631 logging.debug('Using Directory Prefix: %s', version_info.DirPrefix())
632 logging.debug('Using Build Prefix: %s', version_info.BuildPrefix())
633
634 build_specs_manager = BuildSpecsManager(working_dir, ver_manifests,
635 build_name, version_info.DirPrefix(),
636 version_info.BuildPrefix())
637 if status == 'pass':
638 build_specs_manager.SetPassed(build_version)
639 if status == 'fail':
640 build_specs_manager.SetFailed(build_version)
641
642 commit_message = 'Automatic checkin: status = %s build_version %s for %s' % (
643 status, build_version, build_name)
644 PushChanges(build_specs_manager.specs_info.root_dir, commit_message,
645 dry_run=debug)
646
647
648 def RemoveDirs(dir_name):
649 """Remove directories recursively, if they exist"""
650 if os.path.exists(dir_name):
651 shutil.rmtree(dir_name)
652
653 def CleanUP(source_dir=None, working_dir=None, git_mirror_dir=None):
654 """Clean up of all the directories that are created by this script
655 Args:
656 source_dir: directory where the sources are. Default: None
657 working_dir: directory where manifest-versions is. Default: None
658 git_mirror_dir: directory where git mirror is setup. Default: None
659 """
660 if source_dir:
661 logging.debug('Cleaning source dir = %s', source_dir)
662 RemoveDirs(source_dir)
663
664 if working_dir:
665 logging.debug('Cleaning working dir = %s', working_dir)
666 RemoveDirs(working_dir)
667
668 if git_mirror_dir:
669 logging.debug('Cleaning git mirror dir = %s', git_mirror_dir)
670 RemoveDirs(git_mirror_dir)
671
sosa 2011/04/11 19:03:54 two lines
672 def GenerateWorkload(tmp_dir, source_repo, manifest_repo,
673 branch, version_file,
674 board, incr_type, latest=False,
675 debug=False,
676 retries=0):
677 """Function to see, if there are any new builds that need to be built.
678 Args:
679 tmp_dir: Temporary working directory, best shared with GenerateWorkload
680 source_repo: git URL to repo with source code
681 manifest_repo: git URL to repo with manifests/status values
682 branch: Which branch to build ('master' or mainline)
683 version_file: location of chromeos_version.sh
684 board: name of the board
685 incr_type: part of the version number to increment 'patch or branch'
686 latest: Whether we need to handout the latest build. Default: False
687 debug: if True don't push changes externally
688 retries: Number of retries for updating the status
689 Returns:
690 next_build: a string of the next build number for the builder to consume
691 or None in case of no need to build.
692 Raises:
693 GenerateBuildSpecException in case of failure to generate a buildspec
694 """
695
696 ver_manifests=os.path.basename(manifest_repo)
697
698 git_mirror_dir = os.path.join(tmp_dir, 'mirror')
699 source_dir = os.path.join(tmp_dir, 'source')
700 working_dir = os.path.join(tmp_dir, 'working')
701
702 while True:
703 try:
704 cros_source = GitMirror(git_mirror_dir, source_repo)
705 CheckOutSources(cros_source, source_repo, source_dir, branch)
706
707 # Let's be conservative and remove the version_manifests directory.
708 RemoveDirs(working_dir)
709 CloneGitRepo(working_dir, manifest_repo)
710
711 version_file = os.path.join(source_dir, version_file)
712 logging.debug('Using VERSION _FILE = %s', version_file)
713 version_info = VersionInfo(version_file=version_file, incr_type=incr_type)
714 build_specs = BuildSpecs(working_dir, ver_manifests, board,
715 version_info.DirPrefix(),
716 version_info.BuildPrefix(),
717 version_info.incr_type)
718 current_build = version_info.VersionString()
719 logging.debug('Current build in %s: %s', version_file, current_build)
720
721 build_specs_manager = BuildSpecsManager(
722 working_dir, ver_manifests, board, version_info.DirPrefix(),
723 version_info.BuildPrefix())
724
725 next_build = build_specs.FindNextBuild(latest)
726 if next_build:
727 logging.debug('Using an existing build spec: %s', next_build)
728 SetupExistingBuildSpec(build_specs_manager, next_build, debug)
729 return next_build
730
731 # If the build spec doesn't exist for the current version in chromeos_
732 # version.sh. we should just create the build_spec for that version,
733 # instead of incrementing chromeos_version.sh
734
735 increment_version = build_specs.ExistsBuildSpec(current_build)
736 return GenerateNewBuildSpec(source_dir, branch, build_specs.latest,
737 build_specs.specs_info.root_dir,
738 build_specs_manager, cros_source,
739 version_info, increment_version,
740 debug)
741
742 except (cros_lib.RunCommandError, GitCommandException), e:
743 if retries < 1:
744 err_msg = 'Failed to generate buildspec. error: %s' % e
745 logging.error(err_msg)
746 raise GenerateBuildSpecException(err_msg)
747
748 logging.info('Failed to generate a buildspec for consumption: %s',
749 e.message)
750 logging.info('But will try %d times', retries)
751 CleanUP(source_dir, working_dir)
752 retries = retries - 1
753
sosa 2011/04/11 19:03:54 two lines
754 def UpdateStatus(tmp_dir, manifest_repo, board,
755 build_version, success, debug=False, retries=0):
756 """Updates the status of the build
757 Args:
758 tmp_dir: Temporary working directory, best shared with GenerateWorkload
759 manifest_repo: git URL to repo with manifests/status values
760 board: name of the board
761 build_version: value returned by GenerateWorkload for this build
762 success: True for success, False for failure
763 debug: if True don't push changes externally
764 retries: Number of retries for updating the status
765 Raises:
766 GenerateBuildSpecExtension in case of failure to generate a buildspec
767 """
768
769 working_dir = os.path.join(tmp_dir, 'working')
770 ver_manifests=os.path.basename(manifest_repo)
771 ver_manifests_dir = os.path.join(working_dir, ver_manifests)
772
773 if success:
774 status = 'pass'
775 else:
776 status = 'fail'
777
778 while True:
779 try:
780 if not os.path.exists(ver_manifests_dir):
781 CloneGitRepo(ver_manifests, git_server, working_dir)
782 cros_lib.RunCommand(['git', 'checkout', 'master'], cwd=ver_manifests_dir)
783 logging.debug('Updating the status info for %s to %s', board,
784 status)
785 SetStatus(build_version, status, working_dir, ver_manifests, board, debug)
786 logging.debug('Updated the status info for %s to %s', board,
787 status)
788 break
789 except (GitCommandException, cros_lib.RunCommandError), e:
790 if retries <= 0:
791 logging.error('Failed to update the status for %s to %s', board,
792 status)
793 err_msg = 'with the following error: %s' % e.message
794 logging.error(err_msg)
795 raise StatusUpdateException(err_msg)
796
797 logging.info('Failed to update the status for %s to %s', board,
798 status)
799 logging.info('But will try %d times', retries)
800 RemoveDirs(ver_manifests_dir)
801 retries = retries - 1
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698