Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 | 2 |
| 3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
| 6 | 6 |
| 7 """This module uprevs a given package's ebuild to the next revision.""" | 7 """This module uprevs a given package's ebuild to the next revision.""" |
| 8 | 8 |
| 9 | 9 |
| 10 import fileinput | 10 import fileinput |
| 11 import gflags | 11 import gflags |
| 12 import os | 12 import os |
| 13 import re | 13 import re |
| 14 import shutil | 14 import shutil |
| 15 import subprocess | 15 import subprocess |
| 16 import sys | 16 import sys |
| 17 | 17 |
| 18 sys.path.append(os.path.join(os.path.dirname(__file__), 'lib')) | 18 sys.path.append(os.path.join(os.path.dirname(__file__), 'lib')) |
| 19 from cros_build_lib import Info, RunCommand, Warning, Die | 19 from cros_build_lib import Info, RunCommand, Warning, Die |
| 20 | 20 |
| 21 | 21 |
| 22 gflags.DEFINE_string('board', '', | 22 gflags.DEFINE_string('board', '', |
| 23 'Board for which the package belongs.', short_name='b') | 23 'Board for which the package belongs.', short_name='b') |
| 24 gflags.DEFINE_string('overlays', '', | 24 gflags.DEFINE_string('overlays', '', |
| 25 'Space separated list of overlays to modify.', | 25 'Colon-separated list of overlays to modify.', |
| 26 short_name='o') | 26 short_name='o') |
| 27 gflags.DEFINE_string('packages', '', | 27 gflags.DEFINE_string('packages', '', |
| 28 'Space separated list of packages to mark as stable.', | 28 'Colon-separated list of packages to mark as stable.', |
|
diandersAtChromium
2010/11/12 19:25:30
Any easy way to detect other places that might hav
sosa
2010/11/12 19:38:09
CBuildbot is the only caller as this manages the p
| |
| 29 short_name='p') | 29 short_name='p') |
| 30 gflags.DEFINE_string('push_options', '', | 30 gflags.DEFINE_string('push_options', '', |
| 31 'Options to use with git-cl push using push command.') | 31 'Options to use with git-cl push using push command.') |
| 32 gflags.DEFINE_string('srcroot', '%s/trunk/src' % os.environ['HOME'], | 32 gflags.DEFINE_string('srcroot', '%s/trunk/src' % os.environ['HOME'], |
| 33 'Path to root src directory.', | 33 'Path to root src directory.', |
| 34 short_name='r') | 34 short_name='r') |
| 35 gflags.DEFINE_string('tracking_branch', 'cros/master', | 35 gflags.DEFINE_string('tracking_branch', 'cros/master', |
| 36 'Used with commit to specify branch to track against.', | 36 'Used with commit to specify branch to track against.', |
| 37 short_name='t') | 37 short_name='t') |
| 38 gflags.DEFINE_boolean('all', False, | 38 gflags.DEFINE_boolean('all', False, |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 61 | 61 |
| 62 # ======================= Global Helper Functions ======================== | 62 # ======================= Global Helper Functions ======================== |
| 63 | 63 |
| 64 | 64 |
| 65 def _Print(message): | 65 def _Print(message): |
| 66 """Verbose print function.""" | 66 """Verbose print function.""" |
| 67 if gflags.FLAGS.verbose: | 67 if gflags.FLAGS.verbose: |
| 68 Info(message) | 68 Info(message) |
| 69 | 69 |
| 70 | 70 |
| 71 def _CleanStalePackages(board, package_array): | 71 def _CleanStalePackages(board, package_array): |
|
diandersAtChromium
2010/11/12 19:25:30
Downside of all the enter_chroot here: it will be
sosa
2010/11/12 19:38:09
This is a really good point I didn't think about.
davidjames
2010/11/12 21:18:05
Done.
| |
| 72 """Cleans up stale package info from a previous build.""" | 72 """Cleans up stale package info from a previous build.""" |
| 73 Info('Cleaning up stale packages %s.' % package_array) | 73 Info('Cleaning up stale packages %s.' % package_array) |
| 74 unmerge_board_cmd = ['emerge-%s' % board, '--unmerge'] | 74 unmerge_board_cmd = ['emerge-%s' % board, '--unmerge'] |
| 75 unmerge_board_cmd.extend(package_array) | 75 unmerge_board_cmd.extend(package_array) |
| 76 RunCommand(unmerge_board_cmd) | 76 RunCommand(unmerge_board_cmd, enter_chroot=True) |
| 77 | 77 |
| 78 unmerge_host_cmd = ['sudo', 'emerge', '--unmerge'] | 78 unmerge_host_cmd = ['sudo', 'emerge', '--unmerge'] |
| 79 unmerge_host_cmd.extend(package_array) | 79 unmerge_host_cmd.extend(package_array) |
| 80 RunCommand(unmerge_host_cmd) | 80 RunCommand(unmerge_host_cmd, enter_chroot=True) |
| 81 | 81 |
| 82 RunCommand(['eclean-%s' % board, '-d', 'packages'], redirect_stderr=True) | 82 RunCommand(['eclean-%s' % board, '-d', 'packages'], redirect_stderr=True, |
| 83 RunCommand(['sudo', 'eclean', '-d', 'packages'], redirect_stderr=True) | 83 enter_chroot=True) |
| 84 RunCommand(['sudo', 'eclean', '-d', 'packages'], redirect_stderr=True, | |
| 85 enter_chroot=True) | |
| 84 | 86 |
| 85 | 87 |
| 86 def _BestEBuild(ebuilds): | 88 def _BestEBuild(ebuilds): |
| 87 """Returns the newest EBuild from a list of EBuild objects.""" | 89 """Returns the newest EBuild from a list of EBuild objects.""" |
| 88 from portage.versions import vercmp | 90 from cros_portage_versions import vercmp |
| 89 winner = ebuilds[0] | 91 winner = ebuilds[0] |
| 90 for ebuild in ebuilds[1:]: | 92 for ebuild in ebuilds[1:]: |
| 91 if vercmp(winner.version, ebuild.version) < 0: | 93 if vercmp(winner.version, ebuild.version) < 0: |
| 92 winner = ebuild | 94 winner = ebuild |
| 93 return winner | 95 return winner |
| 94 | 96 |
| 95 | 97 |
| 96 def _FindUprevCandidates(files): | 98 def _FindUprevCandidates(files): |
| 97 """Return a list of uprev candidates from specified list of files. | 99 """Return a list of uprev candidates from specified list of files. |
| 98 | 100 |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 238 _SimpleRunCommand('git commit -m "%s"' % description) | 240 _SimpleRunCommand('git commit -m "%s"' % description) |
| 239 # Ugh. There has got to be an easier way to push to a tracking branch | 241 # Ugh. There has got to be an easier way to push to a tracking branch |
| 240 _SimpleRunCommand('git config push.default tracking') | 242 _SimpleRunCommand('git config push.default tracking') |
| 241 _SimpleRunCommand('git push') | 243 _SimpleRunCommand('git push') |
| 242 | 244 |
| 243 | 245 |
| 244 def _SimpleRunCommand(command): | 246 def _SimpleRunCommand(command): |
| 245 """Runs a shell command and returns stdout back to caller.""" | 247 """Runs a shell command and returns stdout back to caller.""" |
| 246 _Print(' + %s' % command) | 248 _Print(' + %s' % command) |
| 247 proc_handle = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True) | 249 proc_handle = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True) |
| 248 return proc_handle.communicate()[0] | 250 stdout = proc_handle.communicate()[0] |
| 251 retcode = proc_handle.wait() | |
| 252 assert retcode == 0, "Return code %s for command: %s" % (retcode, command) | |
|
diandersAtChromium
2010/11/12 19:25:30
Not convinced that assert should be used here unle
sosa
2010/11/12 19:38:09
Throw an exception.
On 2010/11/12 19:25:30, diand
davidjames
2010/11/12 21:18:05
Done.
| |
| 253 return stdout | |
| 249 | 254 |
| 250 | 255 |
| 251 # ======================= End Global Helper Functions ======================== | 256 # ======================= End Global Helper Functions ======================== |
| 252 | 257 |
| 253 | 258 |
| 254 class _GitBranch(object): | 259 class _GitBranch(object): |
| 255 """Wrapper class for a git branch.""" | 260 """Wrapper class for a git branch.""" |
| 256 | 261 |
| 257 def __init__(self, branch_name): | 262 def __init__(self, branch_name): |
| 258 """Sets up variables but does not create the branch.""" | 263 """Sets up variables but does not create the branch.""" |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 290 | 295 |
| 291 class _EBuild(object): | 296 class _EBuild(object): |
| 292 """Wrapper class for an ebuild.""" | 297 """Wrapper class for an ebuild.""" |
| 293 | 298 |
| 294 def __init__(self, path): | 299 def __init__(self, path): |
| 295 """Initializes all data about an ebuild. | 300 """Initializes all data about an ebuild. |
| 296 | 301 |
| 297 Uses equery to find the ebuild path and sets data about an ebuild for | 302 Uses equery to find the ebuild path and sets data about an ebuild for |
| 298 easy reference. | 303 easy reference. |
| 299 """ | 304 """ |
| 300 from portage.versions import pkgsplit | 305 from cros_portage_versions import pkgsplit |
| 301 self.ebuild_path = path | 306 self.ebuild_path = path |
| 302 (self.ebuild_path_no_revision, | 307 (self.ebuild_path_no_revision, |
| 303 self.ebuild_path_no_version, | 308 self.ebuild_path_no_version, |
| 304 self.current_revision) = self._ParseEBuildPath(self.ebuild_path) | 309 self.current_revision) = self._ParseEBuildPath(self.ebuild_path) |
| 305 _, self.category, pkgpath, filename = path.rsplit('/', 3) | 310 _, self.category, pkgpath, filename = path.rsplit('/', 3) |
| 306 filename_no_suffix = os.path.join(filename.replace('.ebuild', '')) | 311 filename_no_suffix = os.path.join(filename.replace('.ebuild', '')) |
| 307 self.pkgname, version_no_rev, rev = pkgsplit(filename_no_suffix) | 312 self.pkgname, version_no_rev, rev = pkgsplit(filename_no_suffix) |
| 308 self.version = '%s-%s' % (version_no_rev, rev) | 313 self.version = '%s-%s' % (version_no_rev, rev) |
| 309 self.package = '%s/%s' % (self.category, self.pkgname) | 314 self.package = '%s/%s' % (self.category, self.pkgname) |
| 310 self.is_workon = False | 315 self.is_workon = False |
| 311 self.is_stable = False | 316 self.is_stable = False |
| 312 | 317 |
| 313 for line in fileinput.input(path): | 318 for line in fileinput.input(path): |
| 314 if line.startswith('inherit ') and 'cros-workon' in line: | 319 if line.startswith('inherit ') and 'cros-workon' in line: |
| 315 self.is_workon = True | 320 self.is_workon = True |
| 316 elif (line.startswith('KEYWORDS=') and '~' not in line and | 321 elif (line.startswith('KEYWORDS=') and '~' not in line and |
| 317 ('amd64' in line or 'x86' in line or 'arm' in line)): | 322 ('amd64' in line or 'x86' in line or 'arm' in line)): |
| 318 self.is_stable = True | 323 self.is_stable = True |
| 319 fileinput.close() | 324 fileinput.close() |
| 320 | 325 |
| 321 def GetCommitId(self): | 326 def GetCommitId(self): |
| 322 """Get the commit id for this ebuild.""" | 327 """Get the commit id for this ebuild.""" |
| 323 | 328 |
| 324 # Grab and evaluate CROS_WORKON variables from this ebuild. | 329 # Grab and evaluate CROS_WORKON variables from this ebuild. |
| 325 unstable_ebuild = '%s-9999.ebuild' % self.ebuild_path_no_version | 330 unstable_ebuild = '%s-9999.ebuild' % self.ebuild_path_no_version |
| 326 cmd = ('CROS_WORKON_LOCALNAME="%s" CROS_WORKON_PROJECT="%s" ' | 331 cmd = ('export CROS_WORKON_LOCALNAME="%s" CROS_WORKON_PROJECT="%s"; ' |
| 327 'eval $(grep -E "^CROS_WORKON" %s) && ' | 332 'eval $(grep -E "^CROS_WORKON" %s) && ' |
| 328 'echo $CROS_WORKON_PROJECT ' | 333 'echo $CROS_WORKON_PROJECT ' |
| 329 '$CROS_WORKON_LOCALNAME/$CROS_WORKON_SUBDIR' | 334 '$CROS_WORKON_LOCALNAME/$CROS_WORKON_SUBDIR' |
| 330 % (self.pkgname, self.pkgname, unstable_ebuild)) | 335 % (self.pkgname, self.pkgname, unstable_ebuild)) |
| 331 project, subdir = _SimpleRunCommand(cmd).split() | 336 project, subdir = _SimpleRunCommand(cmd).split() |
| 332 | 337 |
| 333 # Calculate srcdir. | 338 # Calculate srcdir. |
| 334 srcroot = gflags.FLAGS.srcroot | 339 srcroot = gflags.FLAGS.srcroot |
| 335 if self.category == 'chromeos-base': | 340 if self.category == 'chromeos-base': |
| 336 dir = 'platform' | 341 dir = 'platform' |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 365 | 370 |
| 366 @classmethod | 371 @classmethod |
| 367 def _ParseEBuildPath(cls, ebuild_path): | 372 def _ParseEBuildPath(cls, ebuild_path): |
| 368 """Static method that parses the path of an ebuild | 373 """Static method that parses the path of an ebuild |
| 369 | 374 |
| 370 Returns a tuple containing the (ebuild path without the revision | 375 Returns a tuple containing the (ebuild path without the revision |
| 371 string, without the version string, and the current revision number for | 376 string, without the version string, and the current revision number for |
| 372 the ebuild). | 377 the ebuild). |
| 373 """ | 378 """ |
| 374 # Get the ebuild name without the revision string. | 379 # Get the ebuild name without the revision string. |
| 375 (ebuild_no_rev, _, rev_string) = ebuild_path.rpartition('-') | 380 (ebuild_no_rev, _, rev_string) = ebuild_path.rpartition('-') |
|
diandersAtChromium
2010/11/12 19:25:30
It looks like you're sorta getting "lucky" that th
davidjames
2010/11/12 21:18:05
Just tested this. Looks like it works, and does no
| |
| 376 | 381 |
| 377 # Verify the revision string starts with the revision character. | 382 # Verify the revision string starts with the revision character. |
| 378 if rev_string.startswith('r'): | 383 if rev_string.startswith('r'): |
| 379 # Get the ebuild name without the revision and version strings. | 384 # Get the ebuild name without the revision and version strings. |
| 380 ebuild_no_version = ebuild_no_rev.rpartition('-')[0] | 385 ebuild_no_version = ebuild_no_rev.rpartition('-')[0] |
| 381 rev_string = rev_string[1:].rpartition('.ebuild')[0] | 386 rev_string = rev_string[1:].rpartition('.ebuild')[0] |
| 382 else: | 387 else: |
| 383 # Has no revision so we stripped the version number instead. | 388 # Has no revision so we stripped the version number instead. |
|
diandersAtChromium
2010/11/12 19:25:30
Old case of having no revision number at all is no
sosa
2010/11/12 19:38:09
This handles the 9999 case for the above comment.
| |
| 384 ebuild_no_version = ebuild_no_rev | 389 ebuild_no_version = ebuild_no_rev |
| 385 ebuild_no_rev = ebuild_path.rpartition('9999.ebuild')[0] + '0.0.1' | 390 ebuild_no_rev = ebuild_path.rpartition('9999.ebuild')[0] + '0.0.1' |
| 386 rev_string = '0' | 391 rev_string = '0' |
| 387 revision = int(rev_string) | 392 revision = int(rev_string) |
| 388 return (ebuild_no_rev, ebuild_no_version, revision) | 393 return (ebuild_no_rev, ebuild_no_version, revision) |
| 389 | 394 |
| 390 | 395 |
| 391 class EBuildStableMarker(object): | 396 class EBuildStableMarker(object): |
| 392 """Class that revs the ebuild and commits locally or pushes the change.""" | 397 """Class that revs the ebuild and commits locally or pushes the change.""" |
| 393 | 398 |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 480 def main(argv): | 485 def main(argv): |
| 481 try: | 486 try: |
| 482 argv = gflags.FLAGS(argv) | 487 argv = gflags.FLAGS(argv) |
| 483 if len(argv) != 2: | 488 if len(argv) != 2: |
| 484 _PrintUsageAndDie('Must specify a valid command') | 489 _PrintUsageAndDie('Must specify a valid command') |
| 485 else: | 490 else: |
| 486 command = argv[1] | 491 command = argv[1] |
| 487 except gflags.FlagsError, e : | 492 except gflags.FlagsError, e : |
| 488 _PrintUsageAndDie(str(e)) | 493 _PrintUsageAndDie(str(e)) |
| 489 | 494 |
| 490 package_list = gflags.FLAGS.packages.split() | 495 package_list = gflags.FLAGS.packages.split(':') |
| 491 _CheckSaneArguments(package_list, command) | 496 _CheckSaneArguments(package_list, command) |
| 492 if gflags.FLAGS.overlays: | 497 if gflags.FLAGS.overlays: |
| 493 overlays = dict((path, []) for path in gflags.FLAGS.overlays.split()) | 498 overlays = {} |
| 499 for path in gflags.FLAGS.overlays.split(':'): | |
| 500 if not os.path.exists(path): | |
| 501 Die('Cannot find overlay: %s' % path) | |
| 502 overlays[path] = [] | |
| 494 else: | 503 else: |
| 504 Warning('Missing --overlays argument') | |
| 495 overlays = { | 505 overlays = { |
| 496 '%s/private-overlays/chromeos-overlay' % gflags.FLAGS.srcroot: [], | 506 '%s/private-overlays/chromeos-overlay' % gflags.FLAGS.srcroot: [], |
| 497 '%s/third_party/chromiumos-overlay' % gflags.FLAGS.srcroot: [] | 507 '%s/third_party/chromiumos-overlay' % gflags.FLAGS.srcroot: [] |
| 498 } | 508 } |
| 499 | 509 |
| 500 if command == 'commit': | 510 if command == 'commit': |
| 501 _BuildEBuildDictionary(overlays, gflags.FLAGS.all, package_list) | 511 _BuildEBuildDictionary(overlays, gflags.FLAGS.all, package_list) |
| 502 | 512 |
| 513 cwd = os.getcwd() | |
| 503 for overlay, ebuilds in overlays.items(): | 514 for overlay, ebuilds in overlays.items(): |
| 504 if not os.path.exists(overlay): | 515 if not os.path.exists(overlay): |
| 505 Warning("Skipping %s" % overlay) | 516 Warning("Skipping %s" % overlay) |
| 506 continue | 517 continue |
| 507 os.chdir(overlay) | 518 os.chdir(overlay) |
|
diandersAtChromium
2010/11/12 19:25:30
Why is chdir here? What actually needs it? ...an
sosa
2010/11/12 19:38:09
For local git commits.
On 2010/11/12 19:25:30, di
davidjames
2010/11/12 21:18:05
Added a comment.
| |
| 508 | 519 |
| 509 if command == 'clean': | 520 if command == 'clean': |
| 510 _Clean() | 521 _Clean() |
| 511 elif command == 'push': | 522 elif command == 'push': |
| 512 _PushChange() | 523 _PushChange() |
| 513 elif command == 'commit' and ebuilds: | 524 elif command == 'commit' and ebuilds: |
| 514 work_branch = _GitBranch(_STABLE_BRANCH_NAME) | 525 work_branch = _GitBranch(_STABLE_BRANCH_NAME) |
| 515 work_branch.CreateBranch() | 526 work_branch.CreateBranch() |
| 516 if not work_branch.Exists(): | 527 if not work_branch.Exists(): |
| 517 Die('Unable to create stabilizing branch in %s' % overlay) | 528 Die('Unable to create stabilizing branch in %s' % overlay) |
| 518 | 529 |
| 519 # Contains the array of packages we actually revved. | 530 # Contains the array of packages we actually revved. |
| 520 revved_packages = [] | 531 revved_packages = [] |
| 521 for ebuild in ebuilds: | 532 for ebuild in ebuilds: |
| 522 try: | 533 try: |
| 523 _Print('Working on %s' % ebuild.package) | 534 _Print('Working on %s' % ebuild.package) |
| 524 worker = EBuildStableMarker(ebuild) | 535 worker = EBuildStableMarker(ebuild) |
| 525 commit_id = ebuild.GetCommitId() | 536 commit_id = ebuild.GetCommitId() |
| 526 if worker.RevEBuild(commit_id): | 537 if worker.RevEBuild(commit_id): |
| 527 message = _GIT_COMMIT_MESSAGE % (ebuild.package, commit_id) | 538 message = _GIT_COMMIT_MESSAGE % (ebuild.package, commit_id) |
| 528 worker.CommitChange(message) | 539 worker.CommitChange(message) |
| 529 revved_packages.append(ebuild.package) | 540 revved_packages.append(ebuild.package) |
| 530 | 541 |
| 531 except (OSError, IOError): | 542 except (OSError, IOError): |
| 532 Warning('Cannot rev %s\n' % ebuild.package, | 543 Warning('Cannot rev %s\n' % ebuild.package, |
| 533 'Note you will have to go into %s ' | 544 'Note you will have to go into %s ' |
| 534 'and reset the git repo yourself.' % overlay) | 545 'and reset the git repo yourself.' % overlay) |
| 535 raise | 546 raise |
| 536 | 547 |
| 548 os.chdir(cwd) | |
|
sosa
2010/11/12 19:38:09
Why do you chdir back before work_branch.Delete???
davidjames
2010/11/12 21:18:05
Removed.
This was necessary for entering the chro
| |
| 537 if revved_packages: | 549 if revved_packages: |
| 538 _CleanStalePackages(gflags.FLAGS.board, revved_packages) | 550 _CleanStalePackages(gflags.FLAGS.board, revved_packages) |
| 539 else: | 551 else: |
| 540 work_branch.Delete() | 552 work_branch.Delete() |
| 541 | 553 |
| 542 | 554 |
| 543 if __name__ == '__main__': | 555 if __name__ == '__main__': |
| 544 main(sys.argv) | 556 main(sys.argv) |
| OLD | NEW |