Refactoring: Deprecate optparse in push and merge scripts.

- Deprecate optparse with argparse
- The tests include now options parsing by default: each test specifies the command-line args to parse rather than the options directly

This CL is split off from https://codereview.chromium.org/173983002/

TBR=ulan@chromium.org

Review URL: https://codereview.chromium.org/181583002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19565 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 201436d4
...@@ -26,8 +26,8 @@ ...@@ -26,8 +26,8 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import argparse
import json import json
import optparse
import os import os
import re import re
import sys import sys
...@@ -180,28 +180,28 @@ def RunAutoRoll(config, ...@@ -180,28 +180,28 @@ def RunAutoRoll(config,
def BuildOptions(): def BuildOptions():
result = optparse.OptionParser() parser = argparse.ArgumentParser()
result.add_option("-a", "--author", dest="a", parser.add_argument("-a", "--author", dest="a",
help=("Specify the author email used for rietveld.")) help="The author email used for rietveld.")
result.add_option("-c", "--chromium", dest="c", parser.add_argument("-c", "--chromium", dest="c",
help=("Specify the path to your Chromium src/ " help=("The path to your Chromium src/ directory to "
"directory to automate the V8 roll.")) "automate the V8 roll."))
result.add_option("-p", "--push", parser.add_argument("-p", "--push",
help="Push to trunk if possible. Dry run if unspecified.", help="Push to trunk if possible. Dry run if unspecified.",
default=False, action="store_true") default=False, action="store_true")
result.add_option("-r", "--reviewer", parser.add_argument("-r", "--reviewer",
help=("Specify the account name to be used for reviews.")) help="The account name to be used for reviews.")
result.add_option("-s", "--step", dest="s", parser.add_argument("-s", "--step", dest="s",
help="Specify the step where to start work. Default: 0.", help="Specify the step where to start work. Default: 0.",
default=0, type="int") default=0, type=int)
result.add_option("--status-password", parser.add_argument("--status-password",
help="A file with the password to the status app.") help="A file with the password to the status app.")
return result return parser
def Main(): def Main():
parser = BuildOptions() parser = BuildOptions()
(options, args) = parser.parse_args() options = parser.parse_args()
if not options.a or not options.c or not options.reviewer: if not options.a or not options.c or not options.reviewer:
print "You need to specify author, chromium src location and reviewer." print "You need to specify author, chromium src location and reviewer."
parser.print_help() parser.print_help()
......
...@@ -26,8 +26,8 @@ ...@@ -26,8 +26,8 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import argparse
from collections import OrderedDict from collections import OrderedDict
import optparse
import sys import sys
from common_includes import * from common_includes import *
...@@ -51,7 +51,7 @@ CONFIG = { ...@@ -51,7 +51,7 @@ CONFIG = {
class MergeToBranchOptions(CommonOptions): class MergeToBranchOptions(CommonOptions):
def __init__(self, options, args): def __init__(self, options):
super(MergeToBranchOptions, self).__init__(options, True) super(MergeToBranchOptions, self).__init__(options, True)
self.requires_editor = True self.requires_editor = True
self.wait_for_lgtm = True self.wait_for_lgtm = True
...@@ -60,7 +60,8 @@ class MergeToBranchOptions(CommonOptions): ...@@ -60,7 +60,8 @@ class MergeToBranchOptions(CommonOptions):
self.revert = getattr(options, "r", False) self.revert = getattr(options, "r", False)
self.revert_bleeding_edge = getattr(options, "revert_bleeding_edge", False) self.revert_bleeding_edge = getattr(options, "revert_bleeding_edge", False)
self.patch = getattr(options, "p", "") self.patch = getattr(options, "p", "")
self.args = args self.branch = options.branch
self.revisions = options.revisions
class Preparation(Step): class Preparation(Step):
...@@ -77,9 +78,8 @@ class Preparation(Step): ...@@ -77,9 +78,8 @@ class Preparation(Step):
self.InitialEnvironmentChecks() self.InitialEnvironmentChecks()
if self._options.revert_bleeding_edge: if self._options.revert_bleeding_edge:
self["merge_to_branch"] = "bleeding_edge" self["merge_to_branch"] = "bleeding_edge"
elif self._options.args[0]: elif self._options.branch:
self["merge_to_branch"] = self._options.args[0] self["merge_to_branch"] = self._options.branch
self._options.args = self._options.args[1:]
else: else:
self.Die("Please specify a branch to merge to") self.Die("Please specify a branch to merge to")
...@@ -99,7 +99,8 @@ class SearchArchitecturePorts(Step): ...@@ -99,7 +99,8 @@ class SearchArchitecturePorts(Step):
MESSAGE = "Search for corresponding architecture ports." MESSAGE = "Search for corresponding architecture ports."
def RunStep(self): def RunStep(self):
self["full_revision_list"] = list(OrderedDict.fromkeys(self._options.args)) self["full_revision_list"] = list(OrderedDict.fromkeys(
self._options.revisions))
port_revision_list = [] port_revision_list = []
for revision in self["full_revision_list"]: for revision in self["full_revision_list"]:
# Search for commits which matches the "Port rXXX" pattern. # Search for commits which matches the "Port rXXX" pattern.
...@@ -310,53 +311,53 @@ def RunMergeToBranch(config, ...@@ -310,53 +311,53 @@ def RunMergeToBranch(config,
def BuildOptions(): def BuildOptions():
result = optparse.OptionParser() parser = argparse.ArgumentParser(
result.set_usage("""%prog [OPTIONS]... [BRANCH] [REVISION]... description=("Performs the necessary steps to merge revisions from "
"bleeding_edge to other branches, including trunk."))
Performs the necessary steps to merge revisions from bleeding_edge group = parser.add_mutually_exclusive_group(required=True)
to other branches, including trunk.""") group.add_argument("--branch", help="The branch to merge to.")
result.add_option("-f", group.add_argument("-R", "--revert-bleeding-edge",
help="Revert specified patches from bleeding edge.",
default=False, action="store_true")
parser.add_argument("revisions", nargs="*",
help="The revisions to merge.")
parser.add_argument("-a", "--author", default="",
help="The author email used for rietveld.")
parser.add_argument("-f",
help="Delete sentinel file.", help="Delete sentinel file.",
default=False, action="store_true") default=False, action="store_true")
result.add_option("-m", "--message", parser.add_argument("-m", "--message",
help="Specify a commit message for the patch.") help="A commit message for the patch.")
result.add_option("-r", "--revert", parser.add_argument("-r", "--revert",
help="Revert specified patches.", help="Revert specified patches.",
default=False, action="store_true") default=False, action="store_true")
result.add_option("-R", "--revert-bleeding-edge", parser.add_argument("-p", "--patch", dest="p",
help="Revert specified patches from bleeding edge.", help="A patch file to apply as part of the merge.")
default=False, action="store_true") parser.add_argument("-s", "--step", dest="s",
result.add_option("-p", "--patch", dest="p", help="The step where to start work. Default: 0.",
help="Specify a patch file to apply as part of the merge.") default=0, type=int)
result.add_option("-s", "--step", dest="s", return parser
help="Specify the step where to start work. Default: 0.",
default=0, type="int")
return result def ProcessOptions(options):
# TODO(machenbach): Add a test that covers revert from bleeding_edge
if len(options.revisions) < 1:
def ProcessOptions(options, args): if not options.patch:
revert_from_bleeding_edge = 1 if options.revert_bleeding_edge else 0
min_exp_args = 2 - revert_from_bleeding_edge
if len(args) < min_exp_args:
if not options.p:
print "Either a patch file or revision numbers must be specified" print "Either a patch file or revision numbers must be specified"
return False return False
if not options.message: if not options.message:
print "You must specify a merge comment if no patches are specified" print "You must specify a merge comment if no patches are specified"
return False return False
if options.s < 0:
print "Bad step number %d" % options.s
return False
return True return True
def Main(): def Main():
parser = BuildOptions() parser = BuildOptions()
(options, args) = parser.parse_args() options = parser.parse_args()
if not ProcessOptions(options, args): if not ProcessOptions(options):
parser.print_help() parser.print_help()
return 1 return 1
RunMergeToBranch(CONFIG, MergeToBranchOptions(options, args)) RunMergeToBranch(CONFIG, MergeToBranchOptions(options))
if __name__ == "__main__": if __name__ == "__main__":
sys.exit(Main()) sys.exit(Main())
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import optparse import argparse
import sys import sys
import tempfile import tempfile
import urllib2 import urllib2
...@@ -545,32 +545,31 @@ def RunPushToTrunk(config, ...@@ -545,32 +545,31 @@ def RunPushToTrunk(config,
def BuildOptions(): def BuildOptions():
result = optparse.OptionParser() parser = argparse.ArgumentParser()
result.add_option("-a", "--author", dest="a", group = parser.add_mutually_exclusive_group()
help=("Specify the author email used for rietveld.")) group.add_argument("-f", "--force", dest="f",
result.add_option("-b", "--last-bleeding-edge", dest="b",
help=("Manually specify the git commit ID of the last "
"bleeding edge revision that was pushed to trunk. "
"This is used for the auto-generated ChangeLog "
"entry."))
result.add_option("-c", "--chromium", dest="c",
help=("Specify the path to your Chromium src/ "
"directory to automate the V8 roll."))
result.add_option("-f", "--force", dest="f",
help="Don't prompt the user.", help="Don't prompt the user.",
default=False, action="store_true") default=False, action="store_true")
result.add_option("-l", "--last-push", dest="l", group.add_argument("-m", "--manual", dest="m",
help=("Manually specify the git commit ID "
"of the last push to trunk."))
result.add_option("-m", "--manual", dest="m",
help="Prompt the user at every important step.", help="Prompt the user at every important step.",
default=False, action="store_true") default=False, action="store_true")
result.add_option("-r", "--reviewer", parser.add_argument("-a", "--author", dest="a",
help=("Specify the account name to be used for reviews.")) help="The author email used for rietveld.")
result.add_option("-s", "--step", dest="s", parser.add_argument("-b", "--last-bleeding-edge", dest="b",
help="Specify the step where to start work. Default: 0.", help=("The git commit ID of the last bleeding edge "
default=0, type="int") "revision that was pushed to trunk. This is used "
return result "for the auto-generated ChangeLog entry."))
parser.add_argument("-c", "--chromium", dest="c",
help=("The path to your Chromium src/ directory to "
"automate the V8 roll."))
parser.add_argument("-l", "--last-push", dest="l",
help="The git commit ID of the last push to trunk.")
parser.add_argument("-r", "--reviewer",
help="The account name to be used for reviews.")
parser.add_argument("-s", "--step", dest="s",
help="The step where to start work. Default: 0.",
default=0, type=int)
return parser
def ProcessOptions(options): def ProcessOptions(options):
...@@ -580,9 +579,6 @@ def ProcessOptions(options): ...@@ -580,9 +579,6 @@ def ProcessOptions(options):
if not options.m and not options.reviewer: if not options.m and not options.reviewer:
print "A reviewer (-r) is required in (semi-)automatic mode." print "A reviewer (-r) is required in (semi-)automatic mode."
return False return False
if options.f and options.m:
print "Manual and forced mode cannot be combined."
return False
if not options.m and not options.c: if not options.m and not options.c:
print "A chromium checkout (-c) is required in (semi-)automatic mode." print "A chromium checkout (-c) is required in (semi-)automatic mode."
return False return False
...@@ -594,7 +590,7 @@ def ProcessOptions(options): ...@@ -594,7 +590,7 @@ def ProcessOptions(options):
def Main(): def Main():
parser = BuildOptions() parser = BuildOptions()
(options, args) = parser.parse_args() options = parser.parse_args()
if not ProcessOptions(options): if not ProcessOptions(options):
parser.print_help() parser.print_help()
return 1 return 1
......
...@@ -64,6 +64,12 @@ TEST_CONFIG = { ...@@ -64,6 +64,12 @@ TEST_CONFIG = {
TEMPORARY_PATCH_FILE: "/tmp/test-merge-to-branch-tempfile-temporary-patch", TEMPORARY_PATCH_FILE: "/tmp/test-merge-to-branch-tempfile-temporary-patch",
} }
AUTO_ROLL_ARGS = [
"-a", "author@chromium.org",
"-c", TEST_CONFIG[CHROMIUM],
"-r", "reviewer@chromium.org",
]
def MakeOptions(s=0, l=None, f=False, m=True, r=None, c=None, a=None, def MakeOptions(s=0, l=None, f=False, m=True, r=None, c=None, a=None,
status_password=None, revert_bleeding_edge=None, p=None): status_password=None, revert_bleeding_edge=None, p=None):
...@@ -740,9 +746,11 @@ Performance and stability improvements on all platforms.""", commit) ...@@ -740,9 +746,11 @@ Performance and stability improvements on all platforms.""", commit)
if force: if force:
self.ExpectReadline([]) self.ExpectReadline([])
options = MakeOptions(f=force, m=manual, a="author@chromium.org", args = ["-a", "author@chromium.org", "-c", TEST_CONFIG[CHROMIUM]]
r="reviewer@chromium.org" if not manual else None, if force: args.append("-f")
c = TEST_CONFIG[CHROMIUM]) if manual: args.append("-m")
else: args += ["-r", "reviewer@chromium.org"]
options = push_to_trunk.BuildOptions().parse_args(args)
RunPushToTrunk(TEST_CONFIG, PushToTrunkOptions(options), self) RunPushToTrunk(TEST_CONFIG, PushToTrunkOptions(options), self)
deps = FileToText(TEST_CONFIG[DEPS_FILE]) deps = FileToText(TEST_CONFIG[DEPS_FILE])
...@@ -777,8 +785,8 @@ Performance and stability improvements on all platforms.""", commit) ...@@ -777,8 +785,8 @@ Performance and stability improvements on all platforms.""", commit)
self.assertRaises(Exception, self.MakeStep(CheckLastPush, state=state).Run) self.assertRaises(Exception, self.MakeStep(CheckLastPush, state=state).Run)
def testAutoRoll(self): def testAutoRoll(self):
status_password = self.MakeEmptyTempFile() password = self.MakeEmptyTempFile()
TextToFile("PW", status_password) TextToFile("PW", password)
TEST_CONFIG[DOT_GIT_LOCATION] = self.MakeEmptyTempFile() TEST_CONFIG[DOT_GIT_LOCATION] = self.MakeEmptyTempFile()
TEST_CONFIG[SETTINGS_LOCATION] = "~/.doesnotexist" TEST_CONFIG[SETTINGS_LOCATION] = "~/.doesnotexist"
...@@ -807,8 +815,9 @@ Performance and stability improvements on all platforms.""", commit) ...@@ -807,8 +815,9 @@ Performance and stability improvements on all platforms.""", commit)
["svn find-rev push_hash", "65"], ["svn find-rev push_hash", "65"],
]) ])
auto_roll.RunAutoRoll(TEST_CONFIG, AutoRollOptions( options = auto_roll.BuildOptions().parse_args(
MakeOptions(status_password=status_password)), self) AUTO_ROLL_ARGS + ["--status-password", password])
auto_roll.RunAutoRoll(TEST_CONFIG, AutoRollOptions(options), self)
state = json.loads(FileToText("%s-state.json" state = json.loads(FileToText("%s-state.json"
% TEST_CONFIG[PERSISTFILE_BASENAME])) % TEST_CONFIG[PERSISTFILE_BASENAME]))
...@@ -829,8 +838,9 @@ Performance and stability improvements on all platforms.""", commit) ...@@ -829,8 +838,9 @@ Performance and stability improvements on all platforms.""", commit)
["svn fetch", ""], ["svn fetch", ""],
]) ])
options = auto_roll.BuildOptions().parse_args(AUTO_ROLL_ARGS)
def RunAutoRoll(): def RunAutoRoll():
auto_roll.RunAutoRoll(TEST_CONFIG, AutoRollOptions(MakeOptions()), self) auto_roll.RunAutoRoll(TEST_CONFIG, AutoRollOptions(options), self)
self.assertRaises(Exception, RunAutoRoll) self.assertRaises(Exception, RunAutoRoll)
def testAutoRollStoppedByTreeStatus(self): def testAutoRollStoppedByTreeStatus(self):
...@@ -848,8 +858,9 @@ Performance and stability improvements on all platforms.""", commit) ...@@ -848,8 +858,9 @@ Performance and stability improvements on all platforms.""", commit)
["svn fetch", ""], ["svn fetch", ""],
]) ])
options = auto_roll.BuildOptions().parse_args(AUTO_ROLL_ARGS)
def RunAutoRoll(): def RunAutoRoll():
auto_roll.RunAutoRoll(TEST_CONFIG, AutoRollOptions(MakeOptions()), self) auto_roll.RunAutoRoll(TEST_CONFIG, AutoRollOptions(options), self)
self.assertRaises(Exception, RunAutoRoll) self.assertRaises(Exception, RunAutoRoll)
def testMergeToBranch(self): def testMergeToBranch(self):
...@@ -966,21 +977,22 @@ LOG=N ...@@ -966,21 +977,22 @@ LOG=N
"LGTM", # Enter LGTM for V8 CL. "LGTM", # Enter LGTM for V8 CL.
]) ])
options = MakeOptions(p=extra_patch, f=True)
# r12345 and r34567 are patches. r23456 (included) and r45678 are the MIPS # r12345 and r34567 are patches. r23456 (included) and r45678 are the MIPS
# ports of r12345. r56789 is the MIPS port of r34567. # ports of r12345. r56789 is the MIPS port of r34567.
args = ["trunk", "12345", "23456", "34567"] args = ["-f", "-p", extra_patch, "--branch", "trunk", "12345", "23456",
self.assertTrue(merge_to_branch.ProcessOptions(options, args)) "34567"]
options = merge_to_branch.BuildOptions().parse_args(args)
self.assertTrue(merge_to_branch.ProcessOptions(options))
# The first run of the script stops because of the svn being down. # The first run of the script stops because of the svn being down.
self.assertRaises(GitFailedException, self.assertRaises(GitFailedException,
lambda: RunMergeToBranch(TEST_CONFIG, lambda: RunMergeToBranch(TEST_CONFIG,
MergeToBranchOptions(options, args), MergeToBranchOptions(options),
self)) self))
# Test that state recovery after restarting the script works. # Test that state recovery after restarting the script works.
options.s = 3 options.s = 3
RunMergeToBranch(TEST_CONFIG, MergeToBranchOptions(options, args), self) RunMergeToBranch(TEST_CONFIG, MergeToBranchOptions(options), self)
class SystemTest(unittest.TestCase): class SystemTest(unittest.TestCase):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment