From a489904204fb9a331db7d25af2c751ef28fae0f0 Mon Sep 17 00:00:00 2001 From: "nsylvain@chromium.org" Date: Fri, 16 Oct 2009 19:42:41 +0000 Subject: [PATCH] Make drover look a little bit more like the rest of the python code we have. 90% of the changes are removing trailing spaces. Review URL: http://codereview.chromium.org/282014 git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@29312 0039d316-1c4b-4281-b951-d872f2087c98 --- drover.py | 320 ++++++++++++++++++++++++++---------------------------- 1 file changed, 155 insertions(+), 165 deletions(-) diff --git a/drover.py b/drover.py index 9f81287eb..2c3d73faf 100644 --- a/drover.py +++ b/drover.py @@ -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] + --merge +Example: %(app)s 12345 --merge 187 + +[Merge from trunk to branch, ignoring revision history] + --mplus +Example: %(app)s 12345 --mplus 187 + +[Revert from trunk] + --revert +Example: %(app)s 12345 --revert + + +[Revert from branch] + --revert +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? + 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 rtn + return log 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 @@ def checkoutRevision(url, revision, branch_url, revert=False): 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 @@ def deleteRevision(url, revision): 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 @@ def revertRevision(url, revision): 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 getBestMergePaths2(files_info, revision): 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 @@ def getBestExportPathsMap2(files_info, revision): 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,13 +300,13 @@ def getBestDeletePathsMap2(files_info, revision): 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: @@ -311,36 +316,36 @@ def getExistingFilesInRevision(files_info): 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 @@ def main(argv=None): 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 @@ def main(argv=None): 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 " --merge " - print "Example " + sys.argv[0] + " 12345 --merge 187" - print "\n[Merge from trunk to branch, ignoring revision history]" - print " --mplus " - print "Example " + sys.argv[0] + " 12345 --mplus 187" - print "\n[Revert from trunk]" - print " --revert" - print "Example " + sys.argv[0] + " 12345 --revert" - print "\n[Revert from branch]" - print " --revert " - 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 @@ def main(argv=None): 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 @@ def main(argv=None): 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 @@ def main(argv=None): 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 @@ def main(argv=None): os.system("gcl commit " + str(revision) + " --no_presubmit --force") else: sys.exit(0) - + if __name__ == "__main__": sys.exit(main()) \ No newline at end of file