| Index: drover.py
|
| diff --git a/drover.py b/drover.py
|
| index 9db4e91c8087bbec9efdb047b2577d330934e091..6d2fb7d700a64985c0915865c9c9174e9eb142ed 100755
|
| --- a/drover.py
|
| +++ b/drover.py
|
| @@ -29,7 +29,7 @@ Example: %(app)s --merge 12345 --branch 187
|
| Example: %(app)s --merge 12345 --local
|
|
|
| [Merge from branch to branch]
|
| ---merge <revision> --sbranch <branch_num> --branch <branch_num>
|
| +--merge <revision> --sbranch <branch_num> --branch <branch_num>
|
| Example: %(app)s --merge 12345 --sbranch 248 --branch 249
|
|
|
| [Revert from trunk]
|
| @@ -62,15 +62,15 @@ def deltree(root):
|
| os.unlink(path)
|
| os.rmdir(root)
|
|
|
| -def clobberDir(dir):
|
| +def clobberDir(dirname):
|
| """Removes a given directory"""
|
|
|
| - if (os.path.exists(dir)):
|
| + if (os.path.exists(dirname)):
|
| 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)
|
| + deltree(dirname)
|
|
|
| def runGcl(subcommand):
|
| gcl_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "gcl")
|
| @@ -96,7 +96,7 @@ def getSVNInfo(url, revision):
|
| for line in svn_info:
|
| match = re.search(r"(.*?):(.*)", line)
|
| if match:
|
| - info[match.group(1).strip()]=match.group(2).strip()
|
| + info[match.group(1).strip()]=match.group(2).strip()
|
|
|
| return info
|
|
|
| @@ -137,7 +137,7 @@ def inCheckoutRoot(path):
|
| info = getSVNInfo(path, "HEAD")
|
| if (not info.has_key("Repository Root")):
|
| return False
|
| - repo_root = info["Repository Root"];
|
| + repo_root = info["Repository Root"]
|
| info = getSVNInfo(os.path.dirname(os.path.abspath(path)), "HEAD")
|
| if (info.get("Repository Root", None) != repo_root):
|
| return True
|
| @@ -146,9 +146,9 @@ def inCheckoutRoot(path):
|
| def getRevisionLog(url, revision):
|
| """Takes an svn url and gets the associated revision."""
|
| command = 'svn log ' + url + " -r"+str(revision)
|
| - svn_log = subprocess.Popen(command,
|
| - shell=True,
|
| - stdout=subprocess.PIPE,
|
| + svn_log = subprocess.Popen(command,
|
| + shell=True,
|
| + stdout=subprocess.PIPE,
|
| stderr=subprocess.PIPE).stdout.readlines()
|
| # Don't include the header lines and the trailing "---..." line and eliminate
|
| # any '\r's.
|
| @@ -165,12 +165,12 @@ def getSVNVersionInfo():
|
| for line in svn_info:
|
| match = re.search(r"svn, version ((\d+)\.(\d+)\.(\d+)) \(r(\d+)\)", line)
|
| if match:
|
| - info['version']=match.group(1)
|
| - info['major']=int(match.group(2))
|
| - info['minor']=int(match.group(3))
|
| - info['patch']=int(match.group(4))
|
| - info['revision']=match.group(5)
|
| - return info
|
| + info['version'] = match.group(1)
|
| + info['major'] = int(match.group(2))
|
| + info['minor'] = int(match.group(3))
|
| + info['patch'] = int(match.group(4))
|
| + info['revision'] = match.group(5)
|
| + return info
|
|
|
| return None
|
|
|
| @@ -217,32 +217,32 @@ def checkoutRevision(url, revision, branch_url, revert=False):
|
| # 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
|
| - continue
|
| - subpaths = path.split('/')
|
| - subpaths.pop(0)
|
| - base = ''
|
| - for subpath in subpaths:
|
| - base += '/' + subpath
|
| - # This logic ensures that you don't empty out any directories
|
| - if not os.path.exists("." + base):
|
| - command = ('svn update --depth empty ' + "." + base)
|
| - print command
|
| - os.system(command)
|
| + if (export_map.has_key(path) and not revert):
|
| + print "Exclude new directory " + path
|
| + continue
|
| + subpaths = path.split('/')
|
| + subpaths.pop(0)
|
| + base = ''
|
| + for subpath in subpaths:
|
| + base += '/' + subpath
|
| + # This logic ensures that you don't empty out any directories
|
| + if not os.path.exists("." + 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
|
| - if (file == ""):
|
| +
|
| + for f in files:
|
| + # Prevent the tool from clobbering the src directory
|
| + if (f == ""):
|
| continue
|
| - command = ('svn up ".' + file + '"')
|
| + command = ('svn up ".' + f + '"')
|
| print command
|
| os.system(command)
|
|
|
| @@ -272,7 +272,7 @@ def exportRevision(url, revision):
|
| os.system(command)
|
|
|
| command = 'svn add .' + path
|
| - print command
|
| + print command
|
| os.system(command)
|
|
|
| def deleteRevision(url, revision):
|
| @@ -298,7 +298,7 @@ def revertExportRevision(url, revision):
|
| def revertRevision(url, revision):
|
| paths = getBestMergePaths(url, revision)
|
| for path in paths:
|
| - command = ('svn merge -N -r ' + str(revision) + ":" + str(revision-1) +
|
| + command = ('svn merge -N -r ' + str(revision) + ":" + str(revision-1) +
|
| " " + url + path + " ." + path)
|
| print command
|
| os.system(command)
|
| @@ -336,12 +336,7 @@ def getBestMergePaths(url, revision):
|
|
|
| def getBestMergePaths2(files_info, revision):
|
| """Takes an svn url and gets the associated revision."""
|
| -
|
| - map = dict()
|
| - for file_info in files_info:
|
| - map[file_info[2]] = file_info[2]
|
| -
|
| - return map.keys()
|
| + return list(set([f[2] for f in files_info]))
|
|
|
| def getBestExportPathsMap(url, revision):
|
| return getBestExportPathsMap2(getFileInfo(url, revision), revision)
|
| @@ -353,15 +348,15 @@ def getBestExportPathsMap2(files_info, revision):
|
| if export_map_:
|
| return export_map_
|
|
|
| - map = dict()
|
| + result = {}
|
| for file_info in files_info:
|
| if (file_info[0] == "A"):
|
| if(isSVNDirectory("svn://svn.chromium.org/chrome/" + file_info[1],
|
| revision)):
|
| - map[file_info[2] + "/" + file_info[3]] = ""
|
| + result[file_info[2] + "/" + file_info[3]] = ""
|
|
|
| - export_map_ = map
|
| - return map
|
| + export_map_ = result
|
| + return result
|
|
|
| def getBestDeletePathsMap(url, revision):
|
| return getBestDeletePathsMap2(getFileInfo(url, revision), revision)
|
| @@ -373,28 +368,25 @@ def getBestDeletePathsMap2(files_info, revision):
|
| if delete_map_:
|
| return delete_map_
|
|
|
| - map = dict()
|
| + result = {}
|
| for file_info in files_info:
|
| if (file_info[0] == "D"):
|
| if(isSVNDirectory("svn://svn.chromium.org/chrome/" + file_info[1],
|
| revision)):
|
| - map[file_info[2] + "/" + file_info[3]] = ""
|
| + result[file_info[2] + "/" + file_info[3]] = ""
|
| +
|
| + delete_map_ = result
|
| + return result
|
|
|
| - 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)
|
| """
|
| - map = []
|
| - for file_info in files_info:
|
| - if file_info[0] != "A":
|
| - map.append(file_info[2] + "/" + file_info[3])
|
| + return ['%s/%s' % (f[2], f[3]) for f in files_info if f[0] != 'A']
|
|
|
| - return map
|
|
|
| def getAllFilesInRevision(files_info):
|
| """Checks for existing files in the revision.
|
| @@ -402,23 +394,17 @@ def getAllFilesInRevision(files_info):
|
| 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
|
| + return ['%s/%s' % (f[2], f[3]) for f in files_info]
|
|
|
| def prompt(question):
|
| - answer = None
|
| -
|
| - while not answer:
|
| + while True:
|
| print question + " [y|n]:",
|
| answer = sys.stdin.readline()
|
| if answer.lower().startswith('n'):
|
| return False
|
| elif answer.lower().startswith('y'):
|
| return True
|
| - else:
|
| - answer = None
|
| +
|
|
|
| def text_prompt(question, default):
|
| print question + " [" + default + "]:"
|
| @@ -427,7 +413,8 @@ def text_prompt(question, default):
|
| return default
|
| return answer
|
|
|
| -def main(options, args):
|
| +
|
| +def drover(options, args):
|
| revision = options.revert or options.merge
|
|
|
| # Initialize some variables used below. They can be overwritten by
|
| @@ -442,18 +429,18 @@ def main(options, args):
|
| if options.branch:
|
| DEFAULT_WORKING += ("_" + options.branch)
|
|
|
| - if not isMinimumSVNVersion(1,5):
|
| + if not isMinimumSVNVersion(1, 5):
|
| print "You need to use at least SVN version 1.5.x"
|
| - sys.exit(1)
|
| + return 1
|
|
|
| # Override the default properties if there is a drover.properties file.
|
| global file_pattern_
|
| if os.path.exists("drover.properties"):
|
| - file = open("drover.properties")
|
| - exec(file)
|
| - file.close()
|
| + f = open("drover.properties")
|
| + exec(f)
|
| + f.close()
|
| if FILE_PATTERN:
|
| - file_pattern_ = FILE_PATTERN
|
| + file_pattern_ = FILE_PATTERN
|
|
|
| if options.revert and options.branch:
|
| url = BRANCH_URL.replace("$branch", options.branch)
|
| @@ -468,21 +455,21 @@ def main(options, args):
|
| working = os.getcwd()
|
| if not inCheckoutRoot(working):
|
| print "'%s' appears not to be the root of a working copy" % working
|
| - sys.exit(1)
|
| + return 1
|
| if isSVNDirty():
|
| print "Working copy contains uncommitted files"
|
| - sys.exit(1)
|
| + return 1
|
|
|
| command = 'svn log ' + url + " -r "+str(revision) + " -v"
|
| os.system(command)
|
|
|
| if not (options.revertbot or prompt("Is this the correct revision?")):
|
| - sys.exit(0)
|
| + return 0
|
|
|
| if (os.path.exists(working)) and not options.local:
|
| if not (options.revertbot or SKIP_CHECK_WORKING or
|
| prompt("Working directory: '%s' already exists, clobber?" % working)):
|
| - sys.exit(0)
|
| + return 0
|
| deltree(working)
|
|
|
| if not options.local:
|
| @@ -533,7 +520,7 @@ def main(options, args):
|
| os.unlink(filename)
|
|
|
| if options.local:
|
| - sys.exit(0)
|
| + return 0
|
|
|
| print author
|
| print revision
|
| @@ -552,18 +539,19 @@ def main(options, args):
|
| print "Deleting the changelist."
|
| print "gcl delete " + str(revision)
|
| runGcl("delete " + str(revision))
|
| - sys.exit(0)
|
| + return 0
|
|
|
| # We commit if the reverbot is set to commit automatically, or if this is
|
| # not the revertbot and the user agrees.
|
| if options.revertbot_commit or (not options.revertbot and
|
| prompt("Would you like to commit?")):
|
| print "gcl commit " + str(revision) + " --no_presubmit --force"
|
| - runGcl("commit " + str(revision) + " --no_presubmit --force")
|
| + return runGcl("commit " + str(revision) + " --no_presubmit --force")
|
| else:
|
| - sys.exit(0)
|
| + return 0
|
|
|
| -if __name__ == "__main__":
|
| +
|
| +def main():
|
| option_parser = optparse.OptionParser(usage=USAGE % {"app": sys.argv[0]})
|
| option_parser.add_option('-m', '--merge', type="int",
|
| help='Revision to merge from trunk to branch')
|
| @@ -578,7 +566,7 @@ if __name__ == "__main__":
|
| option_parser.add_option('-w', '--workdir',
|
| help='subdir to use for the revert')
|
| option_parser.add_option('-a', '--auditor',
|
| - help='overrides the author for reviewer')
|
| + help='overrides the author for reviewer')
|
| option_parser.add_option('', '--revertbot', action='store_true',
|
| default=False)
|
| option_parser.add_option('', '--revertbot-commit', action='store_true',
|
| @@ -588,14 +576,18 @@ if __name__ == "__main__":
|
|
|
| if not options.merge and not options.revert:
|
| option_parser.error("You need at least --merge or --revert")
|
| - sys.exit(1)
|
| + return 1
|
|
|
| if options.merge and not options.branch and not options.local:
|
| option_parser.error("--merge requires either --branch or --local")
|
| - sys.exit(1)
|
| + return 1
|
|
|
| if options.local and (options.revert or options.branch):
|
| option_parser.error("--local cannot be used with --revert or --branch")
|
| - sys.exit(1)
|
| + return 1
|
| +
|
| + return drover(options, args)
|
|
|
| - sys.exit(main(options, args))
|
| +
|
| +if __name__ == "__main__":
|
| + sys.exit(main())
|
|
|