| 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', 'x86-generic', | 22 gflags.DEFINE_string('board', 'x86-generic', |
| 23 'Board for which the package belongs.', short_name='b') | 23 'Board for which the package belongs.', short_name='b') |
| 24 gflags.DEFINE_string('commit_ids', '', | |
| 25 """Optional list of commit ids for each package. | |
| 26 This list must either be empty or have the same length as | |
| 27 the packages list. If not set all rev'd ebuilds will have | |
| 28 empty commit id's.""", | |
| 29 short_name='i') | |
| 30 gflags.DEFINE_string('packages', '', | 24 gflags.DEFINE_string('packages', '', |
| 31 'Space separated list of packages to mark as stable.', | 25 'Space separated list of packages to mark as stable.', |
| 32 short_name='p') | 26 short_name='p') |
| 33 gflags.DEFINE_string('push_options', '', | 27 gflags.DEFINE_string('push_options', '', |
| 34 'Options to use with git-cl push using push command.') | 28 'Options to use with git-cl push using push command.') |
| 35 gflags.DEFINE_string('srcroot', '%s/trunk/src' % os.environ['HOME'], | 29 gflags.DEFINE_string('srcroot', '%s/trunk/src' % os.environ['HOME'], |
| 36 'Path to root src directory.', | 30 'Path to root src directory.', |
| 37 short_name='r') | 31 short_name='r') |
| 38 gflags.DEFINE_string('tracking_branch', 'cros/master', | 32 gflags.DEFINE_string('tracking_branch', 'cros/master', |
| 39 'Used with commit to specify branch to track against.', | 33 'Used with commit to specify branch to track against.', |
| (...skipping 24 matching lines...) Expand all Loading... |
| 64 | 58 |
| 65 # ======================= Global Helper Functions ======================== | 59 # ======================= Global Helper Functions ======================== |
| 66 | 60 |
| 67 | 61 |
| 68 def _Print(message): | 62 def _Print(message): |
| 69 """Verbose print function.""" | 63 """Verbose print function.""" |
| 70 if gflags.FLAGS.verbose: | 64 if gflags.FLAGS.verbose: |
| 71 Info(message) | 65 Info(message) |
| 72 | 66 |
| 73 | 67 |
| 68 def _CleanStalePackages(board, package_array): |
| 69 """Cleans up stale package info from a previous build.""" |
| 70 Info('Cleaning up stale packages %s.' % package_array) |
| 71 unmerge_board_cmd = ['emerge-%s' % board, '--unmerge'] |
| 72 unmerge_board_cmd.extend(package_array) |
| 73 RunCommand(unmerge_board_cmd, env=env) |
| 74 |
| 75 unmerge_host_cmd = ['sudo', 'emerge', '--unmerge'] |
| 76 unmerge_host_cmd.extend(package_array) |
| 77 RunCommand(unmerge_host_cmd, env=env) |
| 78 |
| 79 RunCommand(['eclean-%s' % board, '-d', 'packages'], redirect_stderr=True) |
| 80 RunCommand(['sudo', 'eclean', '-d', 'packages'], redirect_stderr=True) |
| 81 |
| 82 |
| 74 def _BestEBuild(ebuilds): | 83 def _BestEBuild(ebuilds): |
| 75 """Returns the newest EBuild from a list of EBuild objects.""" | 84 """Returns the newest EBuild from a list of EBuild objects.""" |
| 76 from portage.versions import vercmp | 85 from portage.versions import vercmp |
| 77 winner = ebuilds[0] | 86 winner = ebuilds[0] |
| 78 for ebuild in ebuilds[1:]: | 87 for ebuild in ebuilds[1:]: |
| 79 if vercmp(winner.version, ebuild.version) < 0: | 88 if vercmp(winner.version, ebuild.version) < 0: |
| 80 winner = ebuild | 89 winner = ebuild |
| 81 return winner | 90 return winner |
| 82 | 91 |
| 83 | 92 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 96 if ebuild.is_workon: | 105 if ebuild.is_workon: |
| 97 workon_dir = True | 106 workon_dir = True |
| 98 if ebuild.is_stable: | 107 if ebuild.is_stable: |
| 99 stable_ebuilds.append(ebuild) | 108 stable_ebuilds.append(ebuild) |
| 100 else: | 109 else: |
| 101 unstable_ebuilds.append(ebuild) | 110 unstable_ebuilds.append(ebuild) |
| 102 | 111 |
| 103 # If we found a workon ebuild in this directory, apply some sanity checks. | 112 # If we found a workon ebuild in this directory, apply some sanity checks. |
| 104 if workon_dir: | 113 if workon_dir: |
| 105 if len(unstable_ebuilds) > 1: | 114 if len(unstable_ebuilds) > 1: |
| 106 Die('Found multiple unstable ebuilds in %s' % root) | 115 Die('Found multiple unstable ebuilds in %s' % os.path.dirname(path)) |
| 107 if len(stable_ebuilds) > 1: | 116 if len(stable_ebuilds) > 1: |
| 108 stable_ebuilds = [_BestEBuild(stable_ebuilds)] | 117 stable_ebuilds = [_BestEBuild(stable_ebuilds)] |
| 109 | 118 |
| 110 # Print a warning if multiple stable ebuilds are found in the same | 119 # Print a warning if multiple stable ebuilds are found in the same |
| 111 # directory. Storing multiple stable ebuilds is error-prone because | 120 # directory. Storing multiple stable ebuilds is error-prone because |
| 112 # the older ebuilds will not get rev'd. | 121 # the older ebuilds will not get rev'd. |
| 113 # | 122 # |
| 114 # We make a special exception for x11-drivers/xf86-video-msm for legacy | 123 # We make a special exception for x11-drivers/xf86-video-msm for legacy |
| 115 # reasons. | 124 # reasons. |
| 116 if stable_ebuilds[0].package != 'x11-drivers/xf86-video-msm': | 125 if stable_ebuilds[0].package != 'x11-drivers/xf86-video-msm': |
| 117 Warning('Found multiple stable ebuilds in %s' % root) | 126 Warning('Found multiple stable ebuilds in %s' % os.path.dirname(path)) |
| 118 | 127 |
| 119 if not unstable_ebuilds: | 128 if not unstable_ebuilds: |
| 120 Die('Missing 9999 ebuild in %s' % root) | 129 Die('Missing 9999 ebuild in %s' % os.path.dirname(path)) |
| 121 if not stable_ebuilds: | 130 if not stable_ebuilds: |
| 122 Die('Missing stable ebuild in %s' % root) | 131 Die('Missing stable ebuild in %s' % os.path.dirname(path)) |
| 123 | 132 |
| 124 if stable_ebuilds: | 133 if stable_ebuilds: |
| 125 return stable_ebuilds[0] | 134 return stable_ebuilds[0] |
| 126 else: | 135 else: |
| 127 return None | 136 return None |
| 128 | 137 |
| 129 | 138 |
| 130 def _BuildEBuildDictionary(overlays, all, packages): | 139 def _BuildEBuildDictionary(overlays, all, packages): |
| 131 """Build a dictionary of the ebuilds in the specified overlays. | 140 """Build a dictionary of the ebuilds in the specified overlays. |
| 132 | 141 |
| 133 overlays: A map which maps overlay directories to arrays of stable EBuilds | 142 overlays: A map which maps overlay directories to arrays of stable EBuilds |
| 134 inside said directories. | 143 inside said directories. |
| 135 all: Whether to include all ebuilds in the specified directories. If true, | 144 all: Whether to include all ebuilds in the specified directories. If true, |
| 136 then we gather all packages in the directories regardless of whether | 145 then we gather all packages in the directories regardless of whether |
| 137 they are in our set of packages. | 146 they are in our set of packages. |
| 138 packages: A set of the packages we want to gather. | 147 packages: A set of the packages we want to gather. |
| 139 """ | 148 """ |
| 140 for overlay in overlays: | 149 for overlay in overlays: |
| 141 for root_dir, dirs, files in os.walk(overlay): | 150 for package_dir, dirs, files in os.walk(overlay): |
| 142 # Add stable ebuilds to overlays[overlay]. | 151 # Add stable ebuilds to overlays[overlay]. |
| 143 paths = [os.path.join(root_dir, path) for path in files] | 152 paths = [os.path.join(package_dir, path) for path in files] |
| 144 ebuild = _FindStableEBuilds(paths) | 153 ebuild = _FindStableEBuilds(paths) |
| 145 | 154 |
| 146 # If the --all option isn't used, we only want to update packages that | 155 # If the --all option isn't used, we only want to update packages that |
| 147 # are in packages. | 156 # are in packages. |
| 148 if ebuild and (all or ebuild.package in packages): | 157 if ebuild and (all or ebuild.package in packages): |
| 149 overlays[overlay].append(ebuild) | 158 overlays[overlay].append(ebuild) |
| 150 | 159 |
| 151 | 160 |
| 152 def _CheckOnStabilizingBranch(): | 161 def _CheckOnStabilizingBranch(): |
| 153 """Returns true if the git branch is on the stabilizing branch.""" | 162 """Returns true if the git branch is on the stabilizing branch.""" |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 327 srcdir = os.path.join(srcroot, 'third_party/kernel/files') | 336 srcdir = os.path.join(srcroot, 'third_party/kernel/files') |
| 328 | 337 |
| 329 if not os.path.exists(srcdir): | 338 if not os.path.exists(srcdir): |
| 330 Die('Cannot find commit id for %s' % self.ebuild_path) | 339 Die('Cannot find commit id for %s' % self.ebuild_path) |
| 331 | 340 |
| 332 # Verify that we're grabbing the commit id from the right project name. | 341 # Verify that we're grabbing the commit id from the right project name. |
| 333 # NOTE: chromeos-kernel has the wrong project name, so it fails this | 342 # NOTE: chromeos-kernel has the wrong project name, so it fails this |
| 334 # check. | 343 # check. |
| 335 # TODO(davidjames): Fix the project name in the chromeos-kernel ebuild. | 344 # TODO(davidjames): Fix the project name in the chromeos-kernel ebuild. |
| 336 cmd = 'cd %s && git config --get remote.cros.projectname' % srcdir | 345 cmd = 'cd %s && git config --get remote.cros.projectname' % srcdir |
| 337 actual_project =_SimpleRunCommand(cmd).rstrip() | 346 actual_project = _SimpleRunCommand(cmd).rstrip() |
| 338 if project not in (actual_project, 'chromeos-kernel'): | 347 if project not in (actual_project, 'chromeos-kernel'): |
| 339 Die('Project name mismatch for %s (%s != %s)' % (unstable_ebuild, project, | 348 Die('Project name mismatch for %s (%s != %s)' % (unstable_ebuild, project, |
| 340 actual_project)) | 349 actual_project)) |
| 341 | 350 |
| 342 # Get commit id. | 351 # Get commit id. |
| 343 output = _SimpleRunCommand('cd %s && git rev-parse HEAD' % srcdir) | 352 output = _SimpleRunCommand('cd %s && git rev-parse HEAD' % srcdir) |
| 344 if not output: | 353 if not output: |
| 345 Die('Missing commit id for %s' % self.ebuild_path) | 354 Die('Missing commit id for %s' % self.ebuild_path) |
| 346 return output.rstrip() | 355 return output.rstrip() |
| 347 | 356 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 369 revision = int(rev_string) | 378 revision = int(rev_string) |
| 370 return (ebuild_no_rev, ebuild_no_version, revision) | 379 return (ebuild_no_rev, ebuild_no_version, revision) |
| 371 | 380 |
| 372 | 381 |
| 373 class EBuildStableMarker(object): | 382 class EBuildStableMarker(object): |
| 374 """Class that revs the ebuild and commits locally or pushes the change.""" | 383 """Class that revs the ebuild and commits locally or pushes the change.""" |
| 375 | 384 |
| 376 def __init__(self, ebuild): | 385 def __init__(self, ebuild): |
| 377 self._ebuild = ebuild | 386 self._ebuild = ebuild |
| 378 | 387 |
| 379 def RevEBuild(self, commit_id="", redirect_file=None): | 388 def RevEBuild(self, commit_id='', redirect_file=None): |
| 380 """Revs an ebuild given the git commit id. | 389 """Revs an ebuild given the git commit id. |
| 381 | 390 |
| 382 By default this class overwrites a new ebuild given the normal | 391 By default this class overwrites a new ebuild given the normal |
| 383 ebuild rev'ing logic. However, a user can specify a redirect_file | 392 ebuild rev'ing logic. However, a user can specify a redirect_file |
| 384 to redirect the new stable ebuild to another file. | 393 to redirect the new stable ebuild to another file. |
| 385 | 394 |
| 386 Args: | 395 Args: |
| 387 commit_id: String corresponding to the commit hash of the developer | 396 commit_id: String corresponding to the commit hash of the developer |
| 388 package to rev. | 397 package to rev. |
| 389 redirect_file: Optional file to write the new ebuild. By default | 398 redirect_file: Optional file to write the new ebuild. By default |
| 390 it is written using the standard rev'ing logic. This file must be | 399 it is written using the standard rev'ing logic. This file must be |
| 391 opened and closed by the caller. | 400 opened and closed by the caller. |
| 392 | 401 |
| 393 Raises: | 402 Raises: |
| 394 OSError: Error occurred while creating a new ebuild. | 403 OSError: Error occurred while creating a new ebuild. |
| 395 IOError: Error occurred while writing to the new revved ebuild file. | 404 IOError: Error occurred while writing to the new revved ebuild file. |
| 405 Returns: |
| 406 True if the revved package is different than the old ebuild. |
| 396 """ | 407 """ |
| 397 # TODO(sosa): Change to a check. | 408 # TODO(sosa): Change to a check. |
| 398 if not self._ebuild: | 409 if not self._ebuild: |
| 399 Die('Invalid ebuild given to EBuildStableMarker') | 410 Die('Invalid ebuild given to EBuildStableMarker') |
| 400 | 411 |
| 401 new_ebuild_path = '%s-r%d.ebuild' % (self._ebuild.ebuild_path_no_revision, | 412 new_ebuild_path = '%s-r%d.ebuild' % (self._ebuild.ebuild_path_no_revision, |
| 402 self._ebuild.current_revision + 1) | 413 self._ebuild.current_revision + 1) |
| 403 | 414 |
| 404 _Print('Creating new stable ebuild %s' % new_ebuild_path) | 415 _Print('Creating new stable ebuild %s' % new_ebuild_path) |
| 405 workon_ebuild = '%s-9999.ebuild' % self._ebuild.ebuild_path_no_version | 416 workon_ebuild = '%s-9999.ebuild' % self._ebuild.ebuild_path_no_version |
| 406 if not os.path.exists(workon_ebuild): | 417 if not os.path.exists(workon_ebuild): |
| 407 Die('Missing 9999 ebuild: %s' % workon_ebuild) | 418 Die('Missing 9999 ebuild: %s' % workon_ebuild) |
| 408 shutil.copyfile(workon_ebuild, new_ebuild_path) | 419 shutil.copyfile(workon_ebuild, new_ebuild_path) |
| 409 | 420 |
| 410 for line in fileinput.input(new_ebuild_path, inplace=1): | 421 for line in fileinput.input(new_ebuild_path, inplace=1): |
| 411 # Has to be done here to get changes to sys.stdout from fileinput.input. | 422 # Has to be done here to get changes to sys.stdout from fileinput.input. |
| 412 if not redirect_file: | 423 if not redirect_file: |
| 413 redirect_file = sys.stdout | 424 redirect_file = sys.stdout |
| 414 if line.startswith('KEYWORDS'): | 425 if line.startswith('KEYWORDS'): |
| 415 # Actually mark this file as stable by removing ~'s. | 426 # Actually mark this file as stable by removing ~'s. |
| 416 redirect_file.write(line.replace("~", "")) | 427 redirect_file.write(line.replace('~', '')) |
| 417 elif line.startswith('EAPI'): | 428 elif line.startswith('EAPI'): |
| 418 # Always add new commit_id after EAPI definition. | 429 # Always add new commit_id after EAPI definition. |
| 419 redirect_file.write(line) | 430 redirect_file.write(line) |
| 420 redirect_file.write('CROS_WORKON_COMMIT="%s"\n' % commit_id) | 431 redirect_file.write('CROS_WORKON_COMMIT="%s"\n' % commit_id) |
| 421 elif not line.startswith('CROS_WORKON_COMMIT'): | 432 elif not line.startswith('CROS_WORKON_COMMIT'): |
| 422 # Skip old CROS_WORKON_COMMIT definition. | 433 # Skip old CROS_WORKON_COMMIT definition. |
| 423 redirect_file.write(line) | 434 redirect_file.write(line) |
| 424 fileinput.close() | 435 fileinput.close() |
| 425 | 436 |
| 426 # If the new ebuild is identical to the old ebuild, return False and | |
| 427 # delete our changes. | |
| 428 old_ebuild_path = self._ebuild.ebuild_path | 437 old_ebuild_path = self._ebuild.ebuild_path |
| 429 diff_cmd = ['diff', '-Bu', old_ebuild_path, new_ebuild_path] | 438 diff_cmd = ['diff', '-Bu', old_ebuild_path, new_ebuild_path] |
| 430 if 0 == RunCommand(diff_cmd, exit_code=True, | 439 if 0 == RunCommand(diff_cmd, exit_code=True, redirect_stdout=True, |
| 431 print_cmd=gflags.FLAGS.verbose): | 440 redirect_stderr=True, print_cmd=gflags.FLAGS.verbose): |
| 432 os.unlink(new_ebuild_path) | 441 os.unlink(new_ebuild_path) |
| 433 return False | 442 return False |
| 434 else: | 443 else: |
| 435 _Print('Adding new stable ebuild to git') | 444 _Print('Adding new stable ebuild to git') |
| 436 _SimpleRunCommand('git add %s' % new_ebuild_path) | 445 _SimpleRunCommand('git add %s' % new_ebuild_path) |
| 437 | 446 |
| 438 _Print('Removing old ebuild from git') | 447 _Print('Removing old ebuild from git') |
| 439 _SimpleRunCommand('git rm %s' % old_ebuild_path) | 448 _SimpleRunCommand('git rm %s' % old_ebuild_path) |
| 440 return True | 449 return True |
| 441 | 450 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 467 except gflags.FlagsError, e : | 476 except gflags.FlagsError, e : |
| 468 _PrintUsageAndDie(str(e)) | 477 _PrintUsageAndDie(str(e)) |
| 469 | 478 |
| 470 package_list = gflags.FLAGS.packages.split() | 479 package_list = gflags.FLAGS.packages.split() |
| 471 _CheckSaneArguments(package_list, command) | 480 _CheckSaneArguments(package_list, command) |
| 472 | 481 |
| 473 overlays = { | 482 overlays = { |
| 474 '%s/private-overlays/chromeos-overlay' % gflags.FLAGS.srcroot: [], | 483 '%s/private-overlays/chromeos-overlay' % gflags.FLAGS.srcroot: [], |
| 475 '%s/third_party/chromiumos-overlay' % gflags.FLAGS.srcroot: [] | 484 '%s/third_party/chromiumos-overlay' % gflags.FLAGS.srcroot: [] |
| 476 } | 485 } |
| 477 all = gflags.FLAGS.all | |
| 478 | 486 |
| 479 if command == 'commit': | 487 if command == 'commit': |
| 480 _BuildEBuildDictionary(overlays, all, package_list) | 488 _BuildEBuildDictionary(overlays, gflags.FLAGS.all, package_list) |
| 481 | 489 |
| 482 for overlay, ebuilds in overlays.items(): | 490 for overlay, ebuilds in overlays.items(): |
| 483 if not os.path.exists(overlay): | 491 if not os.path.exists(overlay): continue |
| 484 continue | |
| 485 os.chdir(overlay) | 492 os.chdir(overlay) |
| 486 | 493 |
| 487 if command == 'clean': | 494 if command == 'clean': |
| 488 _Clean() | 495 _Clean() |
| 489 elif command == 'push': | 496 elif command == 'push': |
| 490 _PushChange() | 497 _PushChange() |
| 491 elif command == 'commit' and ebuilds: | 498 elif command == 'commit' and ebuilds: |
| 499 work_branch = _GitBranch(_STABLE_BRANCH_NAME) |
| 500 work_branch.CreateBranch() |
| 501 if not work_branch.Exists(): |
| 502 Die('Unable to create stabilizing branch in %s' % overlay) |
| 503 |
| 504 # Contains the array of packages we actually revved. |
| 505 revved_packages = [] |
| 492 for ebuild in ebuilds: | 506 for ebuild in ebuilds: |
| 493 try: | 507 try: |
| 494 _Print('Working on %s' % ebuild.package) | 508 _Print('Working on %s' % ebuild.package) |
| 495 worker = EBuildStableMarker(ebuild) | 509 worker = EBuildStableMarker(ebuild) |
| 496 commit_id = ebuild.GetCommitId() | 510 commit_id = ebuild.GetCommitId() |
| 497 if worker.RevEBuild(commit_id): | 511 if worker.RevEBuild(commit_id): |
| 498 if not _CheckOnStabilizingBranch(): | |
| 499 work_branch = _GitBranch(_STABLE_BRANCH_NAME) | |
| 500 work_branch.CreateBranch() | |
| 501 if not work_branch.Exists(): | |
| 502 Die('Unable to create stabilizing branch in %s' % overlay) | |
| 503 message = _GIT_COMMIT_MESSAGE % (ebuild.package, commit_id) | 512 message = _GIT_COMMIT_MESSAGE % (ebuild.package, commit_id) |
| 504 worker.CommitChange(message) | 513 worker.CommitChange(message) |
| 514 revved_packages.append(ebuild.package) |
| 515 |
| 505 except (OSError, IOError): | 516 except (OSError, IOError): |
| 506 Warning('Cannot rev %s\n' % ebuild.package, | 517 Warning('Cannot rev %s\n' % ebuild.package, |
| 507 'Note you will have to go into %s ' | 518 'Note you will have to go into %s ' |
| 508 'and reset the git repo yourself.' % overlay) | 519 'and reset the git repo yourself.' % overlay) |
| 509 raise | 520 raise |
| 510 | 521 |
| 522 if revved_packages: |
| 523 _CleanStalePackages(gflags.FLAGS.board, revved_packages) |
| 524 else: |
| 525 work_branch.Delete() |
| 526 |
| 511 | 527 |
| 512 if __name__ == '__main__': | 528 if __name__ == '__main__': |
| 513 main(sys.argv) | 529 main(sys.argv) |
| 514 | |
| OLD | NEW |