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

Unified Diff: drover.py

Issue 282014: Make drover look a little bit more like the rest of... (Closed) Base URL: svn://chrome-svn.corp.google.com/chrome/trunk/tools/depot_tools/
Patch Set: Created 11 years, 2 months 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: drover.py
===================================================================
--- drover.py (revision 29214)
+++ drover.py (working copy)
@@ -2,129 +2,145 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import optparse
+import os
+import re
import subprocess
import sys
-import re
-import os
import webbrowser
+USAGE = """
+WARNING: Please use this tool in an empty directory
+(or at least one that you don't mind clobbering.)
+
+REQUIRES: SVN 1.5+
+NOTE: NO NEED TO CHECKOUT ANYTHING IN ADVANCE OF USING THIS TOOL."
+Valid parameters:
+
+[Merge from trunk to branch]
+<revision> --merge <branch_num>
+Example: %(app)s 12345 --merge 187
+
+[Merge from trunk to branch, ignoring revision history]
+<revision> --mplus <branch_num>
+Example: %(app)s 12345 --mplus 187
+
+[Revert from trunk]
+<revision> --revert
+Example: %(app)s 12345 --revert
+
+
+[Revert from branch]
+<revision> --revert <branch_num>
+Example: %(app)s 12345 --revert 187
+"""
+
export_map_ = None
files_info_ = None
delete_map_ = None
file_pattern_ = r"[ ]+([MADUC])[ ]+/((?:trunk|branches/\d+)/src(.*)/(.*))"
def deltree(root):
- """
- Removes a given directory
- """
+ """Removes a given directory"""
if (not os.path.exists(root)):
return
-
+
if sys.platform == 'win32':
os.system('rmdir /S /Q ' + root.replace('/','\\'))
else:
for name in os.listdir(root):
- path = os.path.join(root, name)
- if os.path.isdir(path):
- deltree(path)
- else:
- os.unlink(path)
+ path = os.path.join(root, name)
+ if os.path.isdir(path):
+ deltree(path)
+ else:
+ os.unlink(path)
os.rmdir(root)
def clobberDir(dir):
- """
- Removes a given directory
- """
-
+ """Removes a given directory"""
+
if (os.path.exists(dir)):
- print dir + " directory found, deleting"
- #The following line was removed due to access controls in Windows
- #which make os.unlink(path) calls impossible.
- #deltree(dir)
- os.system('rmdir /S /Q ' + dir.replace('/','\\'))
+ print dir + " directory found, deleting"
+ # The following line was removed due to access controls in Windows
+ # which make os.unlink(path) calls impossible.
+ #TODO(laforge) : Is this correct?
laforge 2009/10/16 14:57:25 That's correct
+ deltree(dir)
def gclUpload(revision, author):
- command = ("gcl upload " + str(revision) +
+ command = ("gcl upload " + str(revision) +
" --send_mail --no_try --no_presubmit --reviewers=" + author)
os.system(command)
def getSVNInfo(url, revision):
command = 'svn info ' + url + "@"+str(revision)
- svn_info = subprocess.Popen(command,
- shell=True,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE).stdout.readlines()
- rtn = {}
+ svn_info = subprocess.Popen(command,
+ shell=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE).stdout.readlines()
+ info = {}
for line in svn_info:
match = re.search(r"(.*?):(.*)", line)
if match:
- rtn[match.group(1).strip()]=match.group(2).strip()
-
- return rtn
+ info[match.group(1).strip()]=match.group(2).strip()
+ return info
+
def getAuthor(url, revision):
info = getSVNInfo(url, revision)
-
if (info.has_key("Last Changed Author")):
return info["Last Changed Author"]
-
return None
def isSVNFile(url, revision):
info = getSVNInfo(url, revision)
-
if (info.has_key("Node Kind")):
- if (info["Node Kind"] == "file"): return True
-
- return False
+ if (info["Node Kind"] == "file"):
+ return True
+ return False
def isSVNDirectory(url, revision):
info = getSVNInfo(url, revision)
-
if (info.has_key("Node Kind")):
- if (info["Node Kind"] == "directory"): return True
-
- return False
-
+ if (info["Node Kind"] == "directory"):
+ return True
+ return False
+
def getRevisionLog(url, revision):
- """
- Takes an svn url and gets the associated revision.
- """
+ """Takes an svn url and gets the associated revision."""
command = 'svn log ' + url + " -r"+str(revision)
- svn_info = subprocess.Popen(command,
- shell=True,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE).stdout.readlines()
- rtn= ""
+ svn_log = subprocess.Popen(command,
+ shell=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE).stdout.readlines()
+ log = ""
pos = 0
- for line in svn_info:
+ for line in svn_log:
if (pos > 2):
- rtn += line.replace('-','').replace('\r','')
+ log += line.replace('-','').replace('\r','')
else:
pos = pos + 1
+ return log
- return rtn
-
def checkoutRevision(url, revision, branch_url, revert=False):
- files_info = getFileInfo(url, revision)
+ files_info = getFileInfo(url, revision)
paths = getBestMergePaths2(files_info, revision)
export_map = getBestExportPathsMap2(files_info, revision)
-
+
command = 'svn checkout -N ' + branch_url
print command
os.system(command)
match = re.search(r"svn://.*/(.*)", branch_url)
-
+
if match:
os.chdir(match.group(1))
- #This line is extremely important due to the way svn behaves in the set-depths
- #action. If parents aren't handled before children, the child directories get
- #clobbered and the merge step fails.
+ # This line is extremely important due to the way svn behaves in the
+ # set-depths action. If parents aren't handled before children, the child
+ # directories get clobbered and the merge step fails.
paths.sort()
- #Checkout the directories that already exist
+ # Checkout the directories that already exist
for path in paths:
if (export_map.has_key(path) and not revert):
print "Exclude new directory " + path
@@ -134,50 +150,49 @@
base = ''
for subpath in subpaths:
base += '/' + subpath
- #This logic ensures that you don't empty out any directories
+ # This logic ensures that you don't empty out any directories
if not os.path.exists("." + base):
- command = ('svn update --depth empty ' + "." + base)
+ command = ('svn update --depth empty ' + "." + base)
print command
os.system(command)
-
+
if (revert):
files = getAllFilesInRevision(files_info)
else:
files = getExistingFilesInRevision(files_info)
for file in files:
- #Prevent the tool from clobbering the src directory
+ # Prevent the tool from clobbering the src directory
if (file == ""):
continue
command = ('svn up ".' + file + '"')
print command
os.system(command)
-
+
def mergeRevision(url, revision):
paths = getBestMergePaths(url, revision)
export_map = getBestExportPathsMap(url, revision)
-
+
for path in paths:
if export_map.has_key(path):
continue
command = ('svn merge -N -r ' + str(revision-1) + ":" + str(revision) + " ")
command = command + url + path + "@" + str(revision) + " ." + path
-
+
print command
os.system(command)
def exportRevision(url, revision):
paths = getBestExportPathsMap(url, revision).keys()
-
paths.sort()
-
+
for path in paths:
- command = ('svn export -N ' + url + path + "@" + str(revision) + " ."
- + path)
+ command = ('svn export -N ' + url + path + "@" + str(revision) + " ." +
+ path)
print command
os.system(command)
-
- command = ('svn add .' + path)
+
+ command = 'svn add .' + path
print command
os.system(command)
@@ -185,20 +200,19 @@
paths = getBestDeletePathsMap(url, revision).keys()
paths.sort()
paths.reverse()
-
+
for path in paths:
- command = ("svn delete ." + path)
+ command = "svn delete ." + path
print command
os.system(command)
-
def revertExportRevision(url, revision):
paths = getBestExportPathsMap(url, revision).keys()
paths.sort()
paths.reverse()
-
+
for path in paths:
- command = ("svn delete ." + path)
+ command = "svn delete ." + path
print command
os.system(command)
@@ -206,47 +220,43 @@
paths = getBestMergePaths(url, revision)
for path in paths:
command = ('svn merge -N -r ' + str(revision) + ":" + str(revision-1) +
- " " + url + path + " ." + path)
+ " " + url + path + " ." + path)
print command
os.system(command)
-
+
def getFileInfo(url, revision):
global files_info_, file_pattern_
-
+
if (files_info_ != None):
return files_info_
command = 'svn log ' + url + " -r " + str(revision) + " -v"
- svn_log = subprocess.Popen(command,
- shell=True,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE).stdout.readlines()
-
- rtn = []
+ svn_log = subprocess.Popen(command,
+ shell=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE).stdout.readlines()
+
+ info = []
for line in svn_log:
- #A workaround to dump the (from .*) stuff, regex not so friendly in the 2nd
- #pass...
+ # A workaround to dump the (from .*) stuff, regex not so friendly in the 2nd
+ # pass...
match = re.search(r"(.*) \(from.*\)", line)
if match:
line = match.group(1)
match = re.search(file_pattern_, line)
if match:
- rtn.append([match.group(1).strip(), match.group(2).strip(),
- match.group(3).strip(),match.group(4).strip()])
+ info.append([match.group(1).strip(), match.group(2).strip(),
+ match.group(3).strip(),match.group(4).strip()])
- files_info_ = rtn
+ files_info_ = info
return rtn
def getBestMergePaths(url, revision):
- """
- Takes an svn url and gets the associated revision.
- """
+ """Takes an svn url and gets the associated revision."""
return getBestMergePaths2(getFileInfo(url, revision), revision)
def getBestMergePaths2(files_info, revision):
- """
- Takes an svn url and gets the associated revision.
- """
+ """Takes an svn url and gets the associated revision."""
map = dict()
for file_info in files_info:
@@ -256,13 +266,11 @@
def getBestExportPathsMap(url, revision):
return getBestExportPathsMap2(getFileInfo(url, revision), revision)
-
+
def getBestExportPathsMap2(files_info, revision):
- """
- Takes an svn url and gets the associated revision.
- """
+ """Takes an svn url and gets the associated revision."""
global export_map_
-
+
if export_map_:
return export_map_
@@ -273,18 +281,15 @@
map[file_info[2] + "/" + file_info[3]] = ""
export_map_ = map
-
return map
def getBestDeletePathsMap(url, revision):
- return getBestDeletePathsMap2(getFileInfo(url, revision), revision)
+ return getBestDeletePathsMap2(getFileInfo(url, revision), revision)
def getBestDeletePathsMap2(files_info, revision):
- """
- Takes an svn url and gets the associated revision.
- """
+ """Takes an svn url and gets the associated revision."""
global delete_map_
-
+
if delete_map_:
return delete_map_
@@ -295,14 +300,14 @@
map[file_info[2] + "/" + file_info[3]] = ""
delete_map_ = map
-
return map
-
+
def getExistingFilesInRevision(files_info):
+ """Checks for existing files in the revision.
+
+ Anything that's A will require special treatment (either a merge or an
+ export + add)
"""
- Checks for existing files in the revision, anything that's A will require
- special treatment (either a merge or an export + add)
- """
map = []
for file_info in files_info:
if file_info[0] != "A":
@@ -311,36 +316,36 @@
return map
def getAllFilesInRevision(files_info):
+ """Checks for existing files in the revision.
+
+ Anything that's A will require special treatment (either a merge or an
+ export + add)
"""
- Checks for existing files in the revision, anything that's A will require
- special treatment (either a merge or an export + add)
- """
map = []
for file_info in files_info:
map.append(file_info[2] + "/" + file_info[3])
-
return map
def prompt(question):
- p = None
-
+ answer = None
+
while not p:
print question + " [y|n]:"
- p = sys.stdin.readline()
- if p.lower().startswith('n'):
+ answer = sys.stdin.readline()
+ if answer.lower().startswith('n'):
return False
- elif p.lower().startswith('y'):
+ elif answer.lower().startswith('y'):
return True
else:
- p = None
+ answer = None
def text_prompt(question, default):
print question + " [" + default + "]:"
- p = sys.stdin.readline()
- if p.strip() == "":
+ answer = sys.stdin.readline()
+ if answer.strip() == "":
return default
- return p
-
+ return answer
+
def main(argv=None):
BASE_URL = "svn://chrome-svn/chrome"
TRUNK_URL = BASE_URL + "/trunk/src"
@@ -348,7 +353,8 @@
DEFAULT_WORKING = "working"
SKIP_CHECK_WORKING = True
PROMPT_FOR_AUTHOR = False
-
+
+ # Override the default properties if there is a drover.properties file.
global file_pattern_
if os.path.exists("drover.properties"):
file = open("drover.properties")
@@ -358,23 +364,7 @@
file_pattern_ = FILE_PATTERN
if (len(sys.argv) == 1):
- print "WARNING: Please use this tool in an empty directory (or at least one"
- print "that you don't mind clobbering."
- print "REQUIRES: SVN 1.5+"
- print "NOTE: NO NEED TO CHECKOUT ANYTHING IN ADVANCE OF USING THIS TOOL."
- print "\nValid parameters:"
- print "\n[Merge from trunk to branch]"
- print "<revision> --merge <branch_num>"
- print "Example " + sys.argv[0] + " 12345 --merge 187"
- print "\n[Merge from trunk to branch, ignoring revision history]"
- print "<revision> --mplus <branch_num>"
- print "Example " + sys.argv[0] + " 12345 --mplus 187"
- print "\n[Revert from trunk]"
- print " <revision> --revert"
- print "Example " + sys.argv[0] + " 12345 --revert"
- print "\n[Revert from branch]"
- print " <revision> --revert <branch_num>"
- print "Example " + sys.argv[0] + " 12345 --revert 187"
+ print USAGE % {"app": sys.argv[0]}
sys.exit(0)
revision = int(sys.argv[1])
@@ -383,39 +373,39 @@
else:
url = TRUNK_URL
action = "Merge"
-
+
working = DEFAULT_WORKING
-
+
command = 'svn log ' + url + " -r "+str(revision) + " -v"
os.system(command)
-
+
if not prompt("Is this the correct revision?"):
sys.exit(0)
-
+
if (os.path.exists(working)):
if not (SKIP_CHECK_WORKING or prompt("Working directory: '" + working + "' already exists, clobber?")):
sys.exit(0)
deltree(working)
-
- os.makedirs(working)
+
+ os.makedirs(working)
os.chdir(working)
-
+
if (len(sys.argv) > 1):
if sys.argv[2] in ['--merge','-m']:
if (len(sys.argv) != 4):
print "Please specify the branch # you want (i.e. 182) after --merge"
sys.exit(0)
-
+
branch_url = BRANCH_URL.replace("$branch", sys.argv[3])
- #Checkout everything but stuff that got added into a new dir
+ # Checkout everything but stuff that got added into a new dir
checkoutRevision(url, revision, branch_url)
- #Merge everything that changed
+ # Merge everything that changed
mergeRevision(url, revision)
- #"Export" files that were added from the source and add them to branch
+ # "Export" files that were added from the source and add them to branch
exportRevision(url, revision)
- #Delete directories that were deleted (file deletes are handled in the
- #merge).
- deleteRevision(url, revision)
+ # Delete directories that were deleted (file deletes are handled in the
+ # merge).
+ deleteRevision(url, revision)
elif sys.argv[2] in ['--revert','-r']:
if (len(sys.argv) == 4):
url = BRANCH_URL.replace("$branch", sys.argv[3])
@@ -426,10 +416,10 @@
else:
print "Unknown parameter " + sys.argv[2]
sys.exit(0)
-
- #Check the base url so we actually find the author who made the change
+
+ # Check the base url so we actually find the author who made the change
author = getAuthor(TRUNK_URL, revision)
-
+
filename = str(revision)+".txt"
out = open(filename,"w")
out.write(action +" " + str(revision) + " - ")
@@ -437,12 +427,12 @@
if (author):
out.write("TBR=" + author)
out.close()
-
+
os.system('gcl change ' + str(revision) + " " + filename)
os.unlink(filename)
print author
print revision
- print ("gcl upload " + str(revision) +
+ print ("gcl upload " + str(revision) +
" --send_mail --no_try --no_presubmit --reviewers=" + author)
print "gcl commit " + str(revision) + " --no_presubmit --force"
print "gcl delete " + str(revision)
@@ -460,6 +450,6 @@
os.system("gcl commit " + str(revision) + " --no_presubmit --force")
else:
sys.exit(0)
-
+
if __name__ == "__main__":
sys.exit(main())
« 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