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

Side by Side Diff: drover.py

Issue 8498038: Drover: Add --milestone option to merge to a specific milestone. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools/
Patch Set: '' Created 9 years, 1 month 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 import optparse 6 import optparse
7 import os 7 import os
8 import re 8 import re
9 import string
9 import sys 10 import sys
11 import urllib2
10 12
11 import breakpad # pylint: disable=W0611 13 import breakpad # pylint: disable=W0611
12 14
13 import gclient_utils 15 import gclient_utils
14 import subprocess2 16 import subprocess2
15 17
16 USAGE = """ 18 USAGE = """
17 WARNING: Please use this tool in an empty directory 19 WARNING: Please use this tool in an empty directory
18 (or at least one that you don't mind clobbering.) 20 (or at least one that you don't mind clobbering.)
19 21
20 REQUIRES: SVN 1.5+ 22 REQUIRES: SVN 1.5+
21 NOTE: NO NEED TO CHECKOUT ANYTHING IN ADVANCE OF USING THIS TOOL. 23 NOTE: NO NEED TO CHECKOUT ANYTHING IN ADVANCE OF USING THIS TOOL.
22 Valid parameters: 24 Valid parameters:
23 25
24 [Merge from trunk to branch] 26 [Merge from trunk to branch]
25 --merge <revision> --branch <branch_num> 27 --merge <revision> --branch <branch_num>
26 Example: %(app)s --merge 12345 --branch 187 28 Example: %(app)s --merge 12345 --branch 187
27 29
30 [Merge from trunk to milestone]
31 --merge <revision> --milestone <milestone_num>
32 Example: %(app)s -- merge 12345 --milestone 16
33
28 [Merge from trunk to local copy] 34 [Merge from trunk to local copy]
29 --merge <revision> --local 35 --merge <revision> --local
30 Example: %(app)s --merge 12345 --local 36 Example: %(app)s --merge 12345 --local
31 37
32 [Merge from branch to branch] 38 [Merge from branch to branch]
33 --merge <revision> --sbranch <branch_num> --branch <branch_num> 39 --merge <revision> --sbranch <branch_num> --branch <branch_num>
34 Example: %(app)s --merge 12345 --sbranch 248 --branch 249 40 Example: %(app)s --merge 12345 --sbranch 248 --branch 249
35 41
36 [Revert from trunk] 42 [Revert from trunk]
37 --revert <revision> 43 --revert <revision>
(...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after
350 356
351 357
352 def getAllFilesInRevision(files_info): 358 def getAllFilesInRevision(files_info):
353 """Checks for existing files in the revision. 359 """Checks for existing files in the revision.
354 360
355 Anything that's A will require special treatment (either a merge or an 361 Anything that's A will require special treatment (either a merge or an
356 export + add) 362 export + add)
357 """ 363 """
358 return ['%s/%s' % (f[2], f[3]) for f in files_info] 364 return ['%s/%s' % (f[2], f[3]) for f in files_info]
359 365
366
367 def getBranchForMilestone(milestone):
368 """Queries omahaproxy.appspot.com for the branch number given |milestone|.
369 """
370 OMAHA_PROXY_URL = "http://omahaproxy.appspot.com"
371 request = urllib2.Request(OMAHA_PROXY_URL)
372 try:
373 response = urllib2.urlopen(request)
374 except urllib2.HTTPError, e:
375 print "Failed to query %s: %d" % (OMAHA_PROXY_URL, e.code)
376 return None
377
378 # Dictionary of [branch: major]. When searching for the appropriate branch
379 # matching |milestone|, all major versions that match are added to the
380 # dictionary. If all of the branches are the same, this branch value is
381 # returned; otherwise, the user is prompted to accept the largest branch
382 # value.
383 branch_dict = {}
384
385 # Slice the first line since it's column information text.
386 for line in response.readlines()[1:]:
387 # Version data is CSV.
388 parameters = string.split(line, ',')
389
390 # Version is the third parameter and consists of a quad of numbers separated
391 # by periods.
392 version = string.split(parameters[2], '.')
393 major = int(version[0], 10)
394 if major != milestone:
395 continue
396
397 # Branch number is the third value in the quad.
398 branch_dict[version[2]] = major
399
400 if not branch_dict:
401 # |milestone| not found.
402 print "Milestone provided is invalid"
403 return None
404
405 # The following returns a sorted list of the keys of |branch_dict|.
406 sorted_branches = sorted(branch_dict)
407 branch = sorted_branches[0]
408
409 # If all keys match, the branch is the same for all platforms given
410 # |milestone|. This is the safe case, so return the branch.
411 if len(sorted_branches) == 1:
412 return branch
413
414 # Not all of the platforms have the same branch. Prompt the user and return
415 # the greatest (by value) branch on success.
416 if prompt("Not all platforms have the same branch number, "
417 "continue with branch %s?" % branch):
418 return branch
419
420 # User cancelled.
421 return None
422
423
360 def prompt(question): 424 def prompt(question):
361 while True: 425 while True:
362 print question + " [y|n]:", 426 print question + " [y|n]:",
363 answer = sys.stdin.readline() 427 answer = sys.stdin.readline()
364 if answer.lower().startswith('n'): 428 if answer.lower().startswith('n'):
365 return False 429 return False
366 elif answer.lower().startswith('y'): 430 elif answer.lower().startswith('y'):
367 return True 431 return True
368 432
369 433
370 def text_prompt(question, default): 434 def text_prompt(question, default):
371 print question + " [" + default + "]:" 435 print question + " [" + default + "]:"
372 answer = sys.stdin.readline() 436 answer = sys.stdin.readline()
373 if answer.strip() == "": 437 if answer.strip() == "":
374 return default 438 return default
375 return answer 439 return answer
376 440
377 441
378 def drover(options, args): 442 def drover(options, args):
379 revision = options.revert or options.merge 443 revision = options.revert or options.merge
380 444
381 # Initialize some variables used below. They can be overwritten by 445 # Initialize some variables used below. They can be overwritten by
382 # the drover.properties file. 446 # the drover.properties file.
383 BASE_URL = "svn://svn.chromium.org/chrome" 447 BASE_URL = "svn://svn.chromium.org/chrome"
384 TRUNK_URL = BASE_URL + "/trunk/src" 448 TRUNK_URL = BASE_URL + "/trunk/src"
385 BRANCH_URL = BASE_URL + "/branches/$branch/src" 449 BRANCH_URL = BASE_URL + "/branches/$branch/src"
386 SKIP_CHECK_WORKING = True 450 SKIP_CHECK_WORKING = True
387 PROMPT_FOR_AUTHOR = False 451 PROMPT_FOR_AUTHOR = False
388 452
453 # Translate a given milestone to the appropriate branch number.
454 if options.milestone:
455 options.branch = getBranchForMilestone(options.milestone)
456 if not options.branch:
457 return 1
458
389 DEFAULT_WORKING = "drover_" + str(revision) 459 DEFAULT_WORKING = "drover_" + str(revision)
390 if options.branch: 460 if options.branch:
391 DEFAULT_WORKING += ("_" + options.branch) 461 DEFAULT_WORKING += ("_" + options.branch)
392 462
393 if not isMinimumSVNVersion(1, 5): 463 if not isMinimumSVNVersion(1, 5):
394 print "You need to use at least SVN version 1.5.x" 464 print "You need to use at least SVN version 1.5.x"
395 return 1 465 return 1
396 466
397 # Override the default properties if there is a drover.properties file. 467 # Override the default properties if there is a drover.properties file.
398 global file_pattern_ 468 global file_pattern_
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
515 else: 585 else:
516 return 0 586 return 0
517 587
518 588
519 def main(): 589 def main():
520 option_parser = optparse.OptionParser(usage=USAGE % {"app": sys.argv[0]}) 590 option_parser = optparse.OptionParser(usage=USAGE % {"app": sys.argv[0]})
521 option_parser.add_option('-m', '--merge', type="int", 591 option_parser.add_option('-m', '--merge', type="int",
522 help='Revision to merge from trunk to branch') 592 help='Revision to merge from trunk to branch')
523 option_parser.add_option('-b', '--branch', 593 option_parser.add_option('-b', '--branch',
524 help='Branch to revert or merge from') 594 help='Branch to revert or merge from')
595 option_parser.add_option('-M', '--milestone', type="int",
596 help='Milestone to revert or merge from')
525 option_parser.add_option('-l', '--local', action='store_true', 597 option_parser.add_option('-l', '--local', action='store_true',
526 help='Local working copy to merge to') 598 help='Local working copy to merge to')
527 option_parser.add_option('-s', '--sbranch', 599 option_parser.add_option('-s', '--sbranch',
528 help='Source branch for merge') 600 help='Source branch for merge')
529 option_parser.add_option('-r', '--revert', type="int", 601 option_parser.add_option('-r', '--revert', type="int",
530 help='Revision to revert') 602 help='Revision to revert')
531 option_parser.add_option('-w', '--workdir', 603 option_parser.add_option('-w', '--workdir',
532 help='subdir to use for the revert') 604 help='subdir to use for the revert')
533 option_parser.add_option('-a', '--auditor', 605 option_parser.add_option('-a', '--auditor',
534 help='overrides the author for reviewer') 606 help='overrides the author for reviewer')
535 option_parser.add_option('', '--revertbot', action='store_true', 607 option_parser.add_option('', '--revertbot', action='store_true',
536 default=False) 608 default=False)
537 option_parser.add_option('', '--revertbot-commit', action='store_true', 609 option_parser.add_option('', '--revertbot-commit', action='store_true',
538 default=False) 610 default=False)
539 option_parser.add_option('', '--revertbot-reviewers') 611 option_parser.add_option('', '--revertbot-reviewers')
540 options, args = option_parser.parse_args() 612 options, args = option_parser.parse_args()
541 613
542 if not options.merge and not options.revert: 614 if not options.merge and not options.revert:
543 option_parser.error("You need at least --merge or --revert") 615 option_parser.error("You need at least --merge or --revert")
544 return 1 616 return 1
545 617
546 if options.merge and not options.branch and not options.local: 618 if options.merge and not (options.branch or options.milestone or
547 option_parser.error("--merge requires either --branch or --local") 619 options.local):
620 option_parser.error("--merge requires either --branch "
621 "or --milestone or --local")
548 return 1 622 return 1
549 623
550 if options.local and (options.revert or options.branch): 624 if options.local and (options.revert or options.branch or options.milestone):
551 option_parser.error("--local cannot be used with --revert or --branch") 625 option_parser.error("--local cannot be used with --revert "
626 "or --branch or --milestone")
627 return 1
628
629 if options.branch and options.milestone:
630 option_parser.error("--branch cannot be used with --milestone")
552 return 1 631 return 1
553 632
554 return drover(options, args) 633 return drover(options, args)
555 634
556 635
557 if __name__ == "__main__": 636 if __name__ == "__main__":
558 sys.exit(main()) 637 sys.exit(main())
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698