| OLD | NEW |
| (Empty) |
| 1 #!/usr/bin/python | |
| 2 | |
| 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 | |
| 5 # found in the LICENSE file. | |
| 6 | |
| 7 """This module uprevs a given package's ebuild to the next revision.""" | |
| 8 | |
| 9 | |
| 10 import fileinput | |
| 11 import gflags | |
| 12 import os | |
| 13 import re | |
| 14 import shutil | |
| 15 import subprocess | |
| 16 import sys | |
| 17 | |
| 18 sys.path.append(os.path.join(os.path.dirname(__file__), 'lib')) | |
| 19 from cros_build_lib import Info, RunCommand, Warning, Die | |
| 20 | |
| 21 gflags.DEFINE_boolean('all', False, | |
| 22 'Mark all packages as stable.') | |
| 23 gflags.DEFINE_string('board', '', | |
| 24 'Board for which the package belongs.', short_name='b') | |
| 25 gflags.DEFINE_string('drop_file', None, | |
| 26 'File to list packages that were revved.') | |
| 27 gflags.DEFINE_boolean('dryrun', False, | |
| 28 'Passes dry-run to git push if pushing a change.') | |
| 29 gflags.DEFINE_string('overlays', '', | |
| 30 'Colon-separated list of overlays to modify.', | |
| 31 short_name='o') | |
| 32 gflags.DEFINE_string('packages', '', | |
| 33 'Colon-separated list of packages to mark as stable.', | |
| 34 short_name='p') | |
| 35 gflags.DEFINE_string('srcroot', '%s/trunk/src' % os.environ['HOME'], | |
| 36 'Path to root src directory.', | |
| 37 short_name='r') | |
| 38 gflags.DEFINE_string('tracking_branch', 'cros/master', | |
| 39 'Used with commit to specify branch to track against.', | |
| 40 short_name='t') | |
| 41 gflags.DEFINE_boolean('verbose', False, | |
| 42 'Prints out verbose information about what is going on.', | |
| 43 short_name='v') | |
| 44 | |
| 45 | |
| 46 # Takes two strings, package_name and commit_id. | |
| 47 _GIT_COMMIT_MESSAGE = 'Marking 9999 ebuild for %s with commit %s as stable.' | |
| 48 | |
| 49 # Dictionary of valid commands with usage information. | |
| 50 COMMAND_DICTIONARY = { | |
| 51 'clean': | |
| 52 'Cleans up previous calls to either commit or push', | |
| 53 'commit': | |
| 54 'Marks given ebuilds as stable locally', | |
| 55 'push': | |
| 56 'Pushes previous marking of ebuilds to remote repo', | |
| 57 } | |
| 58 | |
| 59 # Name used for stabilizing branch. | |
| 60 STABLE_BRANCH_NAME = 'stabilizing_branch' | |
| 61 | |
| 62 | |
| 63 def BestEBuild(ebuilds): | |
| 64 """Returns the newest EBuild from a list of EBuild objects.""" | |
| 65 from portage.versions import vercmp | |
| 66 winner = ebuilds[0] | |
| 67 for ebuild in ebuilds[1:]: | |
| 68 if vercmp(winner.version, ebuild.version) < 0: | |
| 69 winner = ebuild | |
| 70 return winner | |
| 71 | |
| 72 # ======================= Global Helper Functions ======================== | |
| 73 | |
| 74 | |
| 75 def _Print(message): | |
| 76 """Verbose print function.""" | |
| 77 if gflags.FLAGS.verbose: | |
| 78 Info(message) | |
| 79 | |
| 80 | |
| 81 def _CleanStalePackages(board, package_atoms): | |
| 82 """Cleans up stale package info from a previous build.""" | |
| 83 Info('Cleaning up stale packages %s.' % package_atoms) | |
| 84 unmerge_board_cmd = ['emerge-%s' % board, '--unmerge'] | |
| 85 unmerge_board_cmd.extend(package_atoms) | |
| 86 RunCommand(unmerge_board_cmd) | |
| 87 | |
| 88 unmerge_host_cmd = ['sudo', 'emerge', '--unmerge'] | |
| 89 unmerge_host_cmd.extend(package_atoms) | |
| 90 RunCommand(unmerge_host_cmd) | |
| 91 | |
| 92 RunCommand(['eclean-%s' % board, '-d', 'packages'], redirect_stderr=True) | |
| 93 RunCommand(['sudo', 'eclean', '-d', 'packages'], redirect_stderr=True) | |
| 94 | |
| 95 | |
| 96 def _FindUprevCandidates(files): | |
| 97 """Return a list of uprev candidates from specified list of files. | |
| 98 | |
| 99 Usually an uprev candidate is a the stable ebuild in a cros_workon directory. | |
| 100 However, if no such stable ebuild exists (someone just checked in the 9999 | |
| 101 ebuild), this is the unstable ebuild. | |
| 102 | |
| 103 Args: | |
| 104 files: List of files. | |
| 105 """ | |
| 106 workon_dir = False | |
| 107 stable_ebuilds = [] | |
| 108 unstable_ebuilds = [] | |
| 109 for path in files: | |
| 110 if path.endswith('.ebuild') and not os.path.islink(path): | |
| 111 ebuild = EBuild(path) | |
| 112 if ebuild.is_workon: | |
| 113 workon_dir = True | |
| 114 if ebuild.is_stable: | |
| 115 stable_ebuilds.append(ebuild) | |
| 116 else: | |
| 117 unstable_ebuilds.append(ebuild) | |
| 118 | |
| 119 # If we found a workon ebuild in this directory, apply some sanity checks. | |
| 120 if workon_dir: | |
| 121 if len(unstable_ebuilds) > 1: | |
| 122 Die('Found multiple unstable ebuilds in %s' % os.path.dirname(path)) | |
| 123 if len(stable_ebuilds) > 1: | |
| 124 stable_ebuilds = [BestEBuild(stable_ebuilds)] | |
| 125 | |
| 126 # Print a warning if multiple stable ebuilds are found in the same | |
| 127 # directory. Storing multiple stable ebuilds is error-prone because | |
| 128 # the older ebuilds will not get rev'd. | |
| 129 # | |
| 130 # We make a special exception for x11-drivers/xf86-video-msm for legacy | |
| 131 # reasons. | |
| 132 if stable_ebuilds[0].package != 'x11-drivers/xf86-video-msm': | |
| 133 Warning('Found multiple stable ebuilds in %s' % os.path.dirname(path)) | |
| 134 | |
| 135 if not unstable_ebuilds: | |
| 136 Die('Missing 9999 ebuild in %s' % os.path.dirname(path)) | |
| 137 if not stable_ebuilds: | |
| 138 Warning('Missing stable ebuild in %s' % os.path.dirname(path)) | |
| 139 return unstable_ebuilds[0] | |
| 140 | |
| 141 if stable_ebuilds: | |
| 142 return stable_ebuilds[0] | |
| 143 else: | |
| 144 return None | |
| 145 | |
| 146 | |
| 147 def _BuildEBuildDictionary(overlays, all, packages): | |
| 148 """Build a dictionary of the ebuilds in the specified overlays. | |
| 149 | |
| 150 overlays: A map which maps overlay directories to arrays of stable EBuilds | |
| 151 inside said directories. | |
| 152 all: Whether to include all ebuilds in the specified directories. If true, | |
| 153 then we gather all packages in the directories regardless of whether | |
| 154 they are in our set of packages. | |
| 155 packages: A set of the packages we want to gather. | |
| 156 """ | |
| 157 for overlay in overlays: | |
| 158 for package_dir, dirs, files in os.walk(overlay): | |
| 159 # Add stable ebuilds to overlays[overlay]. | |
| 160 paths = [os.path.join(package_dir, path) for path in files] | |
| 161 ebuild = _FindUprevCandidates(paths) | |
| 162 | |
| 163 # If the --all option isn't used, we only want to update packages that | |
| 164 # are in packages. | |
| 165 if ebuild and (all or ebuild.package in packages): | |
| 166 overlays[overlay].append(ebuild) | |
| 167 | |
| 168 | |
| 169 def _DoWeHaveLocalCommits(stable_branch, tracking_branch): | |
| 170 """Returns true if there are local commits.""" | |
| 171 current_branch = _SimpleRunCommand('git branch | grep \*').split()[1] | |
| 172 if current_branch == stable_branch: | |
| 173 current_commit_id = _SimpleRunCommand('git rev-parse HEAD') | |
| 174 tracking_commit_id = _SimpleRunCommand('git rev-parse %s' % tracking_branch) | |
| 175 return current_commit_id != tracking_commit_id | |
| 176 else: | |
| 177 return False | |
| 178 | |
| 179 | |
| 180 def _CheckSaneArguments(package_list, command): | |
| 181 """Checks to make sure the flags are sane. Dies if arguments are not sane.""" | |
| 182 if not command in COMMAND_DICTIONARY.keys(): | |
| 183 _PrintUsageAndDie('%s is not a valid command' % command) | |
| 184 if not gflags.FLAGS.packages and command == 'commit' and not gflags.FLAGS.all: | |
| 185 _PrintUsageAndDie('Please specify at least one package') | |
| 186 if not gflags.FLAGS.board and command == 'commit': | |
| 187 _PrintUsageAndDie('Please specify a board') | |
| 188 if not os.path.isdir(gflags.FLAGS.srcroot): | |
| 189 _PrintUsageAndDie('srcroot is not a valid path') | |
| 190 gflags.FLAGS.srcroot = os.path.abspath(gflags.FLAGS.srcroot) | |
| 191 | |
| 192 | |
| 193 def _PrintUsageAndDie(error_message=''): | |
| 194 """Prints optional error_message the usage and returns an error exit code.""" | |
| 195 command_usage = 'Commands: \n' | |
| 196 # Add keys and usage information from dictionary. | |
| 197 commands = sorted(COMMAND_DICTIONARY.keys()) | |
| 198 for command in commands: | |
| 199 command_usage += ' %s: %s\n' % (command, COMMAND_DICTIONARY[command]) | |
| 200 commands_str = '|'.join(commands) | |
| 201 Warning('Usage: %s FLAGS [%s]\n\n%s\nFlags:%s' % (sys.argv[0], commands_str, | |
| 202 command_usage, gflags.FLAGS)) | |
| 203 if error_message: | |
| 204 Die(error_message) | |
| 205 else: | |
| 206 sys.exit(1) | |
| 207 | |
| 208 | |
| 209 def _SimpleRunCommand(command): | |
| 210 """Runs a shell command and returns stdout back to caller.""" | |
| 211 _Print(' + %s' % command) | |
| 212 proc_handle = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True) | |
| 213 stdout = proc_handle.communicate()[0] | |
| 214 retcode = proc_handle.wait() | |
| 215 if retcode != 0: | |
| 216 _Print(stdout) | |
| 217 raise subprocess.CalledProcessError(retcode, command) | |
| 218 return stdout | |
| 219 | |
| 220 | |
| 221 # ======================= End Global Helper Functions ======================== | |
| 222 | |
| 223 | |
| 224 def Clean(tracking_branch): | |
| 225 """Cleans up uncommitted changes. | |
| 226 | |
| 227 Args: | |
| 228 tracking_branch: The tracking branch we want to return to after the call. | |
| 229 """ | |
| 230 # Safety case in case we got into a bad state with a previous build. | |
| 231 try: | |
| 232 _SimpleRunCommand('git rebase --abort') | |
| 233 except: | |
| 234 pass | |
| 235 | |
| 236 _SimpleRunCommand('git reset HEAD --hard') | |
| 237 branch = GitBranch(STABLE_BRANCH_NAME, tracking_branch) | |
| 238 if branch.Exists(): | |
| 239 GitBranch.Checkout(branch) | |
| 240 branch.Delete() | |
| 241 | |
| 242 | |
| 243 def PushChange(stable_branch, tracking_branch): | |
| 244 """Pushes commits in the stable_branch to the remote git repository. | |
| 245 | |
| 246 Pushes locals commits from calls to CommitChange to the remote git | |
| 247 repository specified by current working directory. | |
| 248 | |
| 249 Args: | |
| 250 stable_branch: The local branch with commits we want to push. | |
| 251 tracking_branch: The tracking branch of the local branch. | |
| 252 Raises: | |
| 253 OSError: Error occurred while pushing. | |
| 254 """ | |
| 255 num_retries = 5 | |
| 256 | |
| 257 # Sanity check to make sure we're on a stabilizing branch before pushing. | |
| 258 if not _DoWeHaveLocalCommits(stable_branch, tracking_branch): | |
| 259 Info('Not work found to push. Exiting') | |
| 260 return | |
| 261 | |
| 262 description = _SimpleRunCommand('git log --format=format:%s%n%n%b ' + | |
| 263 tracking_branch + '..') | |
| 264 description = 'Marking set of ebuilds as stable\n\n%s' % description | |
| 265 Info('Using description %s' % description) | |
| 266 merge_branch_name = 'merge_branch' | |
| 267 for push_try in range(num_retries + 1): | |
| 268 try: | |
| 269 merge_branch = GitBranch(merge_branch_name, tracking_branch) | |
| 270 if merge_branch.Exists(): | |
| 271 merge_branch.Delete() | |
| 272 _SimpleRunCommand('repo sync .') | |
| 273 merge_branch.CreateBranch() | |
| 274 if not merge_branch.Exists(): | |
| 275 Die('Unable to create merge branch.') | |
| 276 _SimpleRunCommand('git merge --squash %s' % stable_branch) | |
| 277 _SimpleRunCommand('git commit -m "%s"' % description) | |
| 278 _SimpleRunCommand('git config push.default tracking') | |
| 279 if gflags.FLAGS.dryrun: | |
| 280 _SimpleRunCommand('git push --dry-run') | |
| 281 else: | |
| 282 _SimpleRunCommand('git push') | |
| 283 | |
| 284 break | |
| 285 except: | |
| 286 if push_try < num_retries: | |
| 287 Warning('Failed to push change, performing retry (%s/%s)' % ( | |
| 288 push_try + 1, num_retries)) | |
| 289 else: | |
| 290 raise | |
| 291 | |
| 292 | |
| 293 class GitBranch(object): | |
| 294 """Wrapper class for a git branch.""" | |
| 295 | |
| 296 def __init__(self, branch_name, tracking_branch): | |
| 297 """Sets up variables but does not create the branch.""" | |
| 298 self.branch_name = branch_name | |
| 299 self.tracking_branch = tracking_branch | |
| 300 | |
| 301 def CreateBranch(self): | |
| 302 GitBranch.Checkout(self) | |
| 303 | |
| 304 @classmethod | |
| 305 def Checkout(cls, target): | |
| 306 """Function used to check out to another GitBranch.""" | |
| 307 if target.branch_name == target.tracking_branch or target.Exists(): | |
| 308 git_cmd = 'git checkout %s -f' % target.branch_name | |
| 309 else: | |
| 310 git_cmd = 'git checkout -b %s %s -f' % (target.branch_name, | |
| 311 target.tracking_branch) | |
| 312 _SimpleRunCommand(git_cmd) | |
| 313 | |
| 314 def Exists(self): | |
| 315 """Returns True if the branch exists.""" | |
| 316 branch_cmd = 'git branch' | |
| 317 branches = _SimpleRunCommand(branch_cmd) | |
| 318 return self.branch_name in branches.split() | |
| 319 | |
| 320 def Delete(self): | |
| 321 """Deletes the branch and returns the user to the master branch. | |
| 322 | |
| 323 Returns True on success. | |
| 324 """ | |
| 325 tracking_branch = GitBranch(self.tracking_branch, self.tracking_branch) | |
| 326 GitBranch.Checkout(tracking_branch) | |
| 327 delete_cmd = 'git branch -D %s' % self.branch_name | |
| 328 _SimpleRunCommand(delete_cmd) | |
| 329 | |
| 330 | |
| 331 class EBuild(object): | |
| 332 """Wrapper class for information about an ebuild.""" | |
| 333 | |
| 334 def __init__(self, path): | |
| 335 """Sets up data about an ebuild from its path.""" | |
| 336 from portage.versions import pkgsplit | |
| 337 unused_path, self.category, self.pkgname, filename = path.rsplit('/', 3) | |
| 338 unused_pkgname, self.version_no_rev, rev = pkgsplit( | |
| 339 filename.replace('.ebuild', '')) | |
| 340 | |
| 341 self.ebuild_path_no_version = os.path.join( | |
| 342 os.path.dirname(path), self.pkgname) | |
| 343 self.ebuild_path_no_revision = '%s-%s' % (self.ebuild_path_no_version, | |
| 344 self.version_no_rev) | |
| 345 self.current_revision = int(rev.replace('r', '')) | |
| 346 self.version = '%s-%s' % (self.version_no_rev, rev) | |
| 347 self.package = '%s/%s' % (self.category, self.pkgname) | |
| 348 self.ebuild_path = path | |
| 349 | |
| 350 self.is_workon = False | |
| 351 self.is_stable = False | |
| 352 | |
| 353 for line in fileinput.input(path): | |
| 354 if line.startswith('inherit ') and 'cros-workon' in line: | |
| 355 self.is_workon = True | |
| 356 elif (line.startswith('KEYWORDS=') and '~' not in line and | |
| 357 ('amd64' in line or 'x86' in line or 'arm' in line)): | |
| 358 self.is_stable = True | |
| 359 fileinput.close() | |
| 360 | |
| 361 def GetCommitId(self): | |
| 362 """Get the commit id for this ebuild.""" | |
| 363 # Grab and evaluate CROS_WORKON variables from this ebuild. | |
| 364 unstable_ebuild = '%s-9999.ebuild' % self.ebuild_path_no_version | |
| 365 cmd = ('export CROS_WORKON_LOCALNAME="%s" CROS_WORKON_PROJECT="%s"; ' | |
| 366 'eval $(grep -E "^CROS_WORKON" %s) && ' | |
| 367 'echo $CROS_WORKON_PROJECT ' | |
| 368 '$CROS_WORKON_LOCALNAME/$CROS_WORKON_SUBDIR' | |
| 369 % (self.pkgname, self.pkgname, unstable_ebuild)) | |
| 370 project, subdir = _SimpleRunCommand(cmd).split() | |
| 371 | |
| 372 # Calculate srcdir. | |
| 373 srcroot = gflags.FLAGS.srcroot | |
| 374 if self.category == 'chromeos-base': | |
| 375 dir = 'platform' | |
| 376 else: | |
| 377 dir = 'third_party' | |
| 378 srcdir = os.path.join(srcroot, dir, subdir) | |
| 379 | |
| 380 if not os.path.isdir(srcdir): | |
| 381 Die('Cannot find commit id for %s' % self.ebuild_path) | |
| 382 | |
| 383 # Verify that we're grabbing the commit id from the right project name. | |
| 384 # NOTE: chromeos-kernel has the wrong project name, so it fails this | |
| 385 # check. | |
| 386 # TODO(davidjames): Fix the project name in the chromeos-kernel ebuild. | |
| 387 cmd = 'cd %s && git config --get remote.cros.projectname' % srcdir | |
| 388 actual_project = _SimpleRunCommand(cmd).rstrip() | |
| 389 if project not in (actual_project, 'chromeos-kernel'): | |
| 390 Die('Project name mismatch for %s (%s != %s)' % (unstable_ebuild, project, | |
| 391 actual_project)) | |
| 392 | |
| 393 # Get commit id. | |
| 394 output = _SimpleRunCommand('cd %s && git rev-parse HEAD' % srcdir) | |
| 395 if not output: | |
| 396 Die('Missing commit id for %s' % self.ebuild_path) | |
| 397 return output.rstrip() | |
| 398 | |
| 399 | |
| 400 class EBuildStableMarker(object): | |
| 401 """Class that revs the ebuild and commits locally or pushes the change.""" | |
| 402 | |
| 403 def __init__(self, ebuild): | |
| 404 assert ebuild | |
| 405 self._ebuild = ebuild | |
| 406 | |
| 407 @classmethod | |
| 408 def MarkAsStable(cls, unstable_ebuild_path, new_stable_ebuild_path, | |
| 409 commit_keyword, commit_value, redirect_file=None, | |
| 410 make_stable=True): | |
| 411 """Static function that creates a revved stable ebuild. | |
| 412 | |
| 413 This function assumes you have already figured out the name of the new | |
| 414 stable ebuild path and then creates that file from the given unstable | |
| 415 ebuild and marks it as stable. If the commit_value is set, it also | |
| 416 set the commit_keyword=commit_value pair in the ebuild. | |
| 417 | |
| 418 Args: | |
| 419 unstable_ebuild_path: The path to the unstable ebuild. | |
| 420 new_stable_ebuild_path: The path you want to use for the new stable | |
| 421 ebuild. | |
| 422 commit_keyword: Optional keyword to set in the ebuild to mark it as | |
| 423 stable. | |
| 424 commit_value: Value to set the above keyword to. | |
| 425 redirect_file: Optionally redirect output of new ebuild somewhere else. | |
| 426 make_stable: Actually make the ebuild stable. | |
| 427 """ | |
| 428 shutil.copyfile(unstable_ebuild_path, new_stable_ebuild_path) | |
| 429 for line in fileinput.input(new_stable_ebuild_path, inplace=1): | |
| 430 # Has to be done here to get changes to sys.stdout from fileinput.input. | |
| 431 if not redirect_file: | |
| 432 redirect_file = sys.stdout | |
| 433 if line.startswith('KEYWORDS'): | |
| 434 # Actually mark this file as stable by removing ~'s. | |
| 435 if make_stable: | |
| 436 redirect_file.write(line.replace('~', '')) | |
| 437 else: | |
| 438 redirect_file.write(line) | |
| 439 elif line.startswith('EAPI'): | |
| 440 # Always add new commit_id after EAPI definition. | |
| 441 redirect_file.write(line) | |
| 442 if commit_keyword and commit_value: | |
| 443 redirect_file.write('%s="%s"\n' % (commit_keyword, commit_value)) | |
| 444 elif not line.startswith(commit_keyword): | |
| 445 # Skip old commit_keyword definition. | |
| 446 redirect_file.write(line) | |
| 447 fileinput.close() | |
| 448 | |
| 449 def RevWorkOnEBuild(self, commit_id, redirect_file=None): | |
| 450 """Revs a workon ebuild given the git commit hash. | |
| 451 | |
| 452 By default this class overwrites a new ebuild given the normal | |
| 453 ebuild rev'ing logic. However, a user can specify a redirect_file | |
| 454 to redirect the new stable ebuild to another file. | |
| 455 | |
| 456 Args: | |
| 457 commit_id: String corresponding to the commit hash of the developer | |
| 458 package to rev. | |
| 459 redirect_file: Optional file to write the new ebuild. By default | |
| 460 it is written using the standard rev'ing logic. This file must be | |
| 461 opened and closed by the caller. | |
| 462 | |
| 463 Raises: | |
| 464 OSError: Error occurred while creating a new ebuild. | |
| 465 IOError: Error occurred while writing to the new revved ebuild file. | |
| 466 Returns: | |
| 467 If the revved package is different than the old ebuild, return the full | |
| 468 revved package name, including the version number. Otherwise, return None. | |
| 469 """ | |
| 470 if self._ebuild.is_stable: | |
| 471 stable_version_no_rev = self._ebuild.version_no_rev | |
| 472 else: | |
| 473 # If given unstable ebuild, use 0.0.1 rather than 9999. | |
| 474 stable_version_no_rev = '0.0.1' | |
| 475 | |
| 476 new_version = '%s-r%d' % (stable_version_no_rev, | |
| 477 self._ebuild.current_revision + 1) | |
| 478 new_stable_ebuild_path = '%s-%s.ebuild' % ( | |
| 479 self._ebuild.ebuild_path_no_version, new_version) | |
| 480 | |
| 481 _Print('Creating new stable ebuild %s' % new_stable_ebuild_path) | |
| 482 unstable_ebuild_path = ('%s-9999.ebuild' % | |
| 483 self._ebuild.ebuild_path_no_version) | |
| 484 if not os.path.exists(unstable_ebuild_path): | |
| 485 Die('Missing unstable ebuild: %s' % unstable_ebuild_path) | |
| 486 | |
| 487 self.MarkAsStable(unstable_ebuild_path, new_stable_ebuild_path, | |
| 488 'CROS_WORKON_COMMIT', commit_id, redirect_file) | |
| 489 | |
| 490 old_ebuild_path = self._ebuild.ebuild_path | |
| 491 diff_cmd = ['diff', '-Bu', old_ebuild_path, new_stable_ebuild_path] | |
| 492 if 0 == RunCommand(diff_cmd, exit_code=True, redirect_stdout=True, | |
| 493 redirect_stderr=True, print_cmd=gflags.FLAGS.verbose): | |
| 494 os.unlink(new_stable_ebuild_path) | |
| 495 return None | |
| 496 else: | |
| 497 _Print('Adding new stable ebuild to git') | |
| 498 _SimpleRunCommand('git add %s' % new_stable_ebuild_path) | |
| 499 | |
| 500 if self._ebuild.is_stable: | |
| 501 _Print('Removing old ebuild from git') | |
| 502 _SimpleRunCommand('git rm %s' % old_ebuild_path) | |
| 503 | |
| 504 return '%s-%s' % (self._ebuild.package, new_version) | |
| 505 | |
| 506 @classmethod | |
| 507 def CommitChange(cls, message): | |
| 508 """Commits current changes in git locally with given commit message. | |
| 509 | |
| 510 Args: | |
| 511 message: the commit string to write when committing to git. | |
| 512 | |
| 513 Raises: | |
| 514 OSError: Error occurred while committing. | |
| 515 """ | |
| 516 Info('Committing changes with commit message: %s' % message) | |
| 517 git_commit_cmd = 'git commit -am "%s"' % message | |
| 518 _SimpleRunCommand(git_commit_cmd) | |
| 519 | |
| 520 | |
| 521 def main(argv): | |
| 522 try: | |
| 523 argv = gflags.FLAGS(argv) | |
| 524 if len(argv) != 2: | |
| 525 _PrintUsageAndDie('Must specify a valid command') | |
| 526 else: | |
| 527 command = argv[1] | |
| 528 except gflags.FlagsError, e : | |
| 529 _PrintUsageAndDie(str(e)) | |
| 530 | |
| 531 package_list = gflags.FLAGS.packages.split(':') | |
| 532 _CheckSaneArguments(package_list, command) | |
| 533 if gflags.FLAGS.overlays: | |
| 534 overlays = {} | |
| 535 for path in gflags.FLAGS.overlays.split(':'): | |
| 536 if command != 'clean' and not os.path.isdir(path): | |
| 537 Die('Cannot find overlay: %s' % path) | |
| 538 overlays[path] = [] | |
| 539 else: | |
| 540 Warning('Missing --overlays argument') | |
| 541 overlays = { | |
| 542 '%s/private-overlays/chromeos-overlay' % gflags.FLAGS.srcroot: [], | |
| 543 '%s/third_party/chromiumos-overlay' % gflags.FLAGS.srcroot: [] | |
| 544 } | |
| 545 | |
| 546 if command == 'commit': | |
| 547 _BuildEBuildDictionary(overlays, gflags.FLAGS.all, package_list) | |
| 548 | |
| 549 for overlay, ebuilds in overlays.items(): | |
| 550 if not os.path.isdir(overlay): | |
| 551 Warning("Skipping %s" % overlay) | |
| 552 continue | |
| 553 | |
| 554 # TODO(davidjames): Currently, all code that interacts with git depends on | |
| 555 # the cwd being set to the overlay directory. We should instead pass in | |
| 556 # this parameter so that we don't need to modify the cwd globally. | |
| 557 os.chdir(overlay) | |
| 558 | |
| 559 if command == 'clean': | |
| 560 Clean(gflags.FLAGS.tracking_branch) | |
| 561 elif command == 'push': | |
| 562 PushChange(STABLE_BRANCH_NAME, gflags.FLAGS.tracking_branch) | |
| 563 elif command == 'commit' and ebuilds: | |
| 564 work_branch = GitBranch(STABLE_BRANCH_NAME, gflags.FLAGS.tracking_branch) | |
| 565 work_branch.CreateBranch() | |
| 566 if not work_branch.Exists(): | |
| 567 Die('Unable to create stabilizing branch in %s' % overlay) | |
| 568 | |
| 569 # Contains the array of packages we actually revved. | |
| 570 revved_packages = [] | |
| 571 new_package_atoms = [] | |
| 572 for ebuild in ebuilds: | |
| 573 try: | |
| 574 _Print('Working on %s' % ebuild.package) | |
| 575 worker = EBuildStableMarker(ebuild) | |
| 576 commit_id = ebuild.GetCommitId() | |
| 577 new_package = worker.RevWorkOnEBuild(commit_id) | |
| 578 if new_package: | |
| 579 message = _GIT_COMMIT_MESSAGE % (ebuild.package, commit_id) | |
| 580 worker.CommitChange(message) | |
| 581 revved_packages.append(ebuild.package) | |
| 582 new_package_atoms.append('=%s' % new_package) | |
| 583 except (OSError, IOError): | |
| 584 Warning('Cannot rev %s\n' % ebuild.package, | |
| 585 'Note you will have to go into %s ' | |
| 586 'and reset the git repo yourself.' % overlay) | |
| 587 raise | |
| 588 | |
| 589 _CleanStalePackages(gflags.FLAGS.board, new_package_atoms) | |
| 590 if gflags.FLAGS.drop_file: | |
| 591 fh = open(gflags.FLAGS.drop_file, 'w') | |
| 592 fh.write(' '.join(revved_packages)) | |
| 593 fh.close() | |
| 594 | |
| 595 | |
| 596 if __name__ == '__main__': | |
| 597 main(sys.argv) | |
| OLD | NEW |