| OLD | NEW |
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # Copyright (c) 2010 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2010 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 subprocess | 9 import subprocess |
| 10 import sys | 10 import sys |
| 11 import webbrowser | |
| 12 | 11 |
| 13 import breakpad | 12 import breakpad |
| 14 | 13 |
| 14 import gclient_utils |
| 15 |
| 15 USAGE = """ | 16 USAGE = """ |
| 16 WARNING: Please use this tool in an empty directory | 17 WARNING: Please use this tool in an empty directory |
| 17 (or at least one that you don't mind clobbering.) | 18 (or at least one that you don't mind clobbering.) |
| 18 | 19 |
| 19 REQUIRES: SVN 1.5+ | 20 REQUIRES: SVN 1.5+ |
| 20 NOTE: NO NEED TO CHECKOUT ANYTHING IN ADVANCE OF USING THIS TOOL." | 21 NOTE: NO NEED TO CHECKOUT ANYTHING IN ADVANCE OF USING THIS TOOL." |
| 21 Valid parameters: | 22 Valid parameters: |
| 22 | 23 |
| 23 [Merge from trunk to branch] | 24 [Merge from trunk to branch] |
| 24 --merge <revision> --branch <branch_num> | 25 --merge <revision> --branch <branch_num> |
| (...skipping 14 matching lines...) Expand all Loading... |
| 39 [Revert from branch] | 40 [Revert from branch] |
| 40 --revert <revision> --branch <branch_num> | 41 --revert <revision> --branch <branch_num> |
| 41 Example: %(app)s --revert 12345 --branch 187 | 42 Example: %(app)s --revert 12345 --branch 187 |
| 42 """ | 43 """ |
| 43 | 44 |
| 44 export_map_ = None | 45 export_map_ = None |
| 45 files_info_ = None | 46 files_info_ = None |
| 46 delete_map_ = None | 47 delete_map_ = None |
| 47 file_pattern_ = r"[ ]+([MADUC])[ ]+/((?:trunk|branches/.*?)/src(.*)/(.*))" | 48 file_pattern_ = r"[ ]+([MADUC])[ ]+/((?:trunk|branches/.*?)/src(.*)/(.*))" |
| 48 | 49 |
| 49 def deltree(root): | |
| 50 """Removes a given directory""" | |
| 51 if (not os.path.exists(root)): | |
| 52 return | |
| 53 | |
| 54 if sys.platform == 'win32': | |
| 55 os.system('rmdir /S /Q ' + root.replace('/','\\')) | |
| 56 else: | |
| 57 for name in os.listdir(root): | |
| 58 path = os.path.join(root, name) | |
| 59 if os.path.isdir(path): | |
| 60 deltree(path) | |
| 61 else: | |
| 62 os.unlink(path) | |
| 63 os.rmdir(root) | |
| 64 | |
| 65 def clobberDir(dirname): | |
| 66 """Removes a given directory""" | |
| 67 | |
| 68 if (os.path.exists(dirname)): | |
| 69 print dir + " directory found, deleting" | |
| 70 # The following line was removed due to access controls in Windows | |
| 71 # which make os.unlink(path) calls impossible. | |
| 72 #TODO(laforge) : Is this correct? | |
| 73 deltree(dirname) | |
| 74 | 50 |
| 75 def runGcl(subcommand): | 51 def runGcl(subcommand): |
| 76 gcl_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "gcl") | 52 gcl_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "gcl") |
| 77 if not os.path.exists(gcl_path): | 53 if not os.path.exists(gcl_path): |
| 78 print "WARNING: gcl not found beside drover.py. Using system gcl instead..." | 54 print "WARNING: gcl not found beside drover.py. Using system gcl instead..." |
| 79 gcl_path = 'gcl' | 55 gcl_path = 'gcl' |
| 80 | 56 |
| 81 command = "%s %s" % (gcl_path, subcommand) | 57 command = "%s %s" % (gcl_path, subcommand) |
| 82 return os.system(command) | 58 return os.system(command) |
| 83 | 59 |
| 84 def gclUpload(revision, author): | 60 def gclUpload(revision, author): |
| 85 command = ("upload " + str(revision) + | 61 command = ("upload " + str(revision) + |
| 86 " --send_mail --no_presubmit --reviewers=" + author) | 62 " --send_mail --no_presubmit --reviewers=" + author) |
| 87 return runGcl(command) | 63 return runGcl(command) |
| 88 | 64 |
| 89 def getSVNInfo(url, revision): | 65 def getSVNInfo(url, revision): |
| 90 command = 'svn info ' + url + "@"+str(revision) | 66 svn_info = gclient_utils.Popen(['svn', 'info', '%s@%s' % (url, revision)], |
| 91 svn_info = subprocess.Popen(command, | 67 stdout=subprocess.PIPE, |
| 92 shell=True, | 68 stderr=subprocess.PIPE).stdout.readlines() |
| 93 stdout=subprocess.PIPE, | |
| 94 stderr=subprocess.PIPE).stdout.readlines() | |
| 95 info = {} | 69 info = {} |
| 96 for line in svn_info: | 70 for line in svn_info: |
| 97 match = re.search(r"(.*?):(.*)", line) | 71 match = re.search(r"(.*?):(.*)", line) |
| 98 if match: | 72 if match: |
| 99 info[match.group(1).strip()]=match.group(2).strip() | 73 info[match.group(1).strip()]=match.group(2).strip() |
| 100 | 74 |
| 101 return info | 75 return info |
| 102 | 76 |
| 103 def isSVNDirty(): | 77 def isSVNDirty(): |
| 104 command = 'svn status' | 78 svn_status = gclient_utils.Popen(['svn', 'status'], |
| 105 svn_status = subprocess.Popen(command, | 79 stdout=subprocess.PIPE, |
| 106 shell=True, | 80 stderr=subprocess.PIPE).stdout.readlines() |
| 107 stdout=subprocess.PIPE, | |
| 108 stderr=subprocess.PIPE).stdout.readlines() | |
| 109 for line in svn_status: | 81 for line in svn_status: |
| 110 match = re.search(r"^[^X?]", line) | 82 match = re.search(r"^[^X?]", line) |
| 111 if match: | 83 if match: |
| 112 return True | 84 return True |
| 113 | 85 |
| 114 return False | 86 return False |
| 115 | 87 |
| 116 def getAuthor(url, revision): | 88 def getAuthor(url, revision): |
| 117 info = getSVNInfo(url, revision) | 89 info = getSVNInfo(url, revision) |
| 118 if (info.has_key("Last Changed Author")): | 90 if (info.has_key("Last Changed Author")): |
| (...skipping 19 matching lines...) Expand all Loading... |
| 138 if (not info.has_key("Repository Root")): | 110 if (not info.has_key("Repository Root")): |
| 139 return False | 111 return False |
| 140 repo_root = info["Repository Root"] | 112 repo_root = info["Repository Root"] |
| 141 info = getSVNInfo(os.path.dirname(os.path.abspath(path)), "HEAD") | 113 info = getSVNInfo(os.path.dirname(os.path.abspath(path)), "HEAD") |
| 142 if (info.get("Repository Root", None) != repo_root): | 114 if (info.get("Repository Root", None) != repo_root): |
| 143 return True | 115 return True |
| 144 return False | 116 return False |
| 145 | 117 |
| 146 def getRevisionLog(url, revision): | 118 def getRevisionLog(url, revision): |
| 147 """Takes an svn url and gets the associated revision.""" | 119 """Takes an svn url and gets the associated revision.""" |
| 148 command = 'svn log ' + url + " -r"+str(revision) | 120 svn_log = gclient_utils.Popen(['svn', 'log', url, '-r', str(revision)], |
| 149 svn_log = subprocess.Popen(command, | 121 stdout=subprocess.PIPE, |
| 150 shell=True, | 122 stderr=subprocess.PIPE).stdout.readlines() |
| 151 stdout=subprocess.PIPE, | |
| 152 stderr=subprocess.PIPE).stdout.readlines() | |
| 153 # Don't include the header lines and the trailing "---..." line and eliminate | 123 # Don't include the header lines and the trailing "---..." line and eliminate |
| 154 # any '\r's. | 124 # any '\r's. |
| 155 return ''.join([l.replace('\r','') for l in svn_log[3:-1]]) | 125 return ''.join([l.replace('\r','') for l in svn_log[3:-1]]) |
| 156 | 126 |
| 157 def getSVNVersionInfo(): | 127 def getSVNVersionInfo(): |
| 158 """Extract version information from SVN""" | 128 """Extract version information from SVN""" |
| 159 command = 'svn --version' | 129 svn_info = gclient_utils.Popen(['svn', '--version'], |
| 160 svn_info = subprocess.Popen(command, | 130 stdout=subprocess.PIPE, |
| 161 shell=True, | 131 stderr=subprocess.PIPE).stdout.readlines() |
| 162 stdout=subprocess.PIPE, | |
| 163 stderr=subprocess.PIPE).stdout.readlines() | |
| 164 info = {} | 132 info = {} |
| 165 for line in svn_info: | 133 for line in svn_info: |
| 166 match = re.search(r"svn, version ((\d+)\.(\d+)\.(\d+)) \(r(\d+)\)", line) | 134 match = re.search(r"svn, version ((\d+)\.(\d+)\.(\d+)) \(r(\d+)\)", line) |
| 167 if match: | 135 if match: |
| 168 info['version'] = match.group(1) | 136 info['version'] = match.group(1) |
| 169 info['major'] = int(match.group(2)) | 137 info['major'] = int(match.group(2)) |
| 170 info['minor'] = int(match.group(3)) | 138 info['minor'] = int(match.group(3)) |
| 171 info['patch'] = int(match.group(4)) | 139 info['patch'] = int(match.group(4)) |
| 172 info['revision'] = match.group(5) | 140 info['revision'] = match.group(5) |
| 173 return info | 141 return info |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 297 | 265 |
| 298 def revertRevision(url, revision): | 266 def revertRevision(url, revision): |
| 299 paths = getBestMergePaths(url, revision) | 267 paths = getBestMergePaths(url, revision) |
| 300 for path in paths: | 268 for path in paths: |
| 301 command = ('svn merge -N -r ' + str(revision) + ":" + str(revision-1) + | 269 command = ('svn merge -N -r ' + str(revision) + ":" + str(revision-1) + |
| 302 " " + url + path + " ." + path) | 270 " " + url + path + " ." + path) |
| 303 print command | 271 print command |
| 304 os.system(command) | 272 os.system(command) |
| 305 | 273 |
| 306 def getFileInfo(url, revision): | 274 def getFileInfo(url, revision): |
| 307 global files_info_, file_pattern_ | 275 global files_info_ |
| 308 | 276 |
| 309 if (files_info_ != None): | 277 if (files_info_ != None): |
| 310 return files_info_ | 278 return files_info_ |
| 311 | 279 |
| 312 command = 'svn log ' + url + " -r " + str(revision) + " -v" | 280 svn_log = gclient_utils.Popen(['svn', 'log', url, '-r', str(revision), '-v'], |
| 313 svn_log = subprocess.Popen(command, | 281 stdout=subprocess.PIPE, |
| 314 shell=True, | 282 stderr=subprocess.PIPE).stdout.readlines() |
| 315 stdout=subprocess.PIPE, | |
| 316 stderr=subprocess.PIPE).stdout.readlines() | |
| 317 | 283 |
| 318 info = [] | 284 info = [] |
| 319 for line in svn_log: | 285 for line in svn_log: |
| 320 # A workaround to dump the (from .*) stuff, regex not so friendly in the 2nd | 286 # A workaround to dump the (from .*) stuff, regex not so friendly in the 2nd |
| 321 # pass... | 287 # pass... |
| 322 match = re.search(r"(.*) \(from.*\)", line) | 288 match = re.search(r"(.*) \(from.*\)", line) |
| 323 if match: | 289 if match: |
| 324 line = match.group(1) | 290 line = match.group(1) |
| 325 match = re.search(file_pattern_, line) | 291 match = re.search(file_pattern_, line) |
| 326 if match: | 292 if match: |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 463 command = 'svn log ' + url + " -r "+str(revision) + " -v" | 429 command = 'svn log ' + url + " -r "+str(revision) + " -v" |
| 464 os.system(command) | 430 os.system(command) |
| 465 | 431 |
| 466 if not (options.revertbot or prompt("Is this the correct revision?")): | 432 if not (options.revertbot or prompt("Is this the correct revision?")): |
| 467 return 0 | 433 return 0 |
| 468 | 434 |
| 469 if (os.path.exists(working)) and not options.local: | 435 if (os.path.exists(working)) and not options.local: |
| 470 if not (options.revertbot or SKIP_CHECK_WORKING or | 436 if not (options.revertbot or SKIP_CHECK_WORKING or |
| 471 prompt("Working directory: '%s' already exists, clobber?" % working)): | 437 prompt("Working directory: '%s' already exists, clobber?" % working)): |
| 472 return 0 | 438 return 0 |
| 473 deltree(working) | 439 gclient_utils.RemoveDirectory(working) |
| 474 | 440 |
| 475 if not options.local: | 441 if not options.local: |
| 476 os.makedirs(working) | 442 os.makedirs(working) |
| 477 os.chdir(working) | 443 os.chdir(working) |
| 478 | 444 |
| 479 if options.merge: | 445 if options.merge: |
| 480 action = "Merge" | 446 action = "Merge" |
| 481 if not options.local: | 447 if not options.local: |
| 482 branch_url = BRANCH_URL.replace("$branch", options.branch) | 448 branch_url = BRANCH_URL.replace("$branch", options.branch) |
| 483 # Checkout everything but stuff that got added into a new dir | 449 # Checkout everything but stuff that got added into a new dir |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 584 | 550 |
| 585 if options.local and (options.revert or options.branch): | 551 if options.local and (options.revert or options.branch): |
| 586 option_parser.error("--local cannot be used with --revert or --branch") | 552 option_parser.error("--local cannot be used with --revert or --branch") |
| 587 return 1 | 553 return 1 |
| 588 | 554 |
| 589 return drover(options, args) | 555 return drover(options, args) |
| 590 | 556 |
| 591 | 557 |
| 592 if __name__ == "__main__": | 558 if __name__ == "__main__": |
| 593 sys.exit(main()) | 559 sys.exit(main()) |
| OLD | NEW |