diff options
Diffstat (limited to 'testing/mozbase/mozrunner/mozrunner/cli.py')
-rw-r--r-- | testing/mozbase/mozrunner/mozrunner/cli.py | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/testing/mozbase/mozrunner/mozrunner/cli.py b/testing/mozbase/mozrunner/mozrunner/cli.py new file mode 100644 index 0000000000..941734de5e --- /dev/null +++ b/testing/mozbase/mozrunner/mozrunner/cli.py @@ -0,0 +1,181 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. + +import os +import sys + +from mozprofile import MozProfileCLI + +from .application import get_app_context +from .runners import runners +from .utils import findInPath + +# Map of debugging programs to information about them +# from http://mxr.mozilla.org/mozilla-central/source/build/automationutils.py#59 +DEBUGGERS = { + "gdb": { + "interactive": True, + "args": ["-q", "--args"], + }, + "valgrind": {"interactive": False, "args": ["--leak-check=full"]}, +} + + +def debugger_arguments(debugger, arguments=None, interactive=None): + """Finds debugger arguments from debugger given and defaults + + :param debugger: name or path to debugger + :param arguments: arguments for the debugger, or None to use defaults + :param interactive: whether the debugger should run in interactive mode + + """ + # find debugger executable if not a file + executable = debugger + if not os.path.exists(executable): + executable = findInPath(debugger) + if executable is None: + raise Exception("Path to '%s' not found" % debugger) + + # if debugger not in dictionary of knowns return defaults + dirname, debugger = os.path.split(debugger) + if debugger not in DEBUGGERS: + return ([executable] + (arguments or []), bool(interactive)) + + # otherwise use the dictionary values for arguments unless specified + if arguments is None: + arguments = DEBUGGERS[debugger].get("args", []) + if interactive is None: + interactive = DEBUGGERS[debugger].get("interactive", False) + return ([executable] + arguments, interactive) + + +class CLI(MozProfileCLI): + """Command line interface""" + + module = "mozrunner" + + def __init__(self, args=sys.argv[1:]): + MozProfileCLI.__init__(self, args=args) + + # choose appropriate runner and profile classes + app = self.options.app + try: + self.runner_class = runners[app] + self.profile_class = get_app_context(app).profile_class + except KeyError: + self.parser.error( + 'Application "%s" unknown (should be one of "%s")' + % (app, ", ".join(runners.keys())) + ) + + def add_options(self, parser): + """add options to the parser""" + parser.description = ( + "Reliable start/stop/configuration of Mozilla" + " Applications (Firefox, Thunderbird, etc.)" + ) + + # add profile options + MozProfileCLI.add_options(self, parser) + + # add runner options + parser.add_option( + "-b", + "--binary", + dest="binary", + help="Binary path.", + metavar=None, + default=None, + ) + parser.add_option( + "--app", + dest="app", + default="firefox", + help="Application to use [DEFAULT: %default]", + ) + parser.add_option( + "--app-arg", + dest="appArgs", + default=[], + action="append", + help="provides an argument to the test application", + ) + parser.add_option( + "--debugger", + dest="debugger", + help="run under a debugger, e.g. gdb or valgrind", + ) + parser.add_option( + "--debugger-args", + dest="debugger_args", + action="store", + help="arguments to the debugger", + ) + parser.add_option( + "--interactive", + dest="interactive", + action="store_true", + help="run the program interactively", + ) + + # methods for running + + def command_args(self): + """additional arguments for the mozilla application""" + # pylint --py3k: W1636 + return list(map(os.path.expanduser, self.options.appArgs)) + + def runner_args(self): + """arguments to instantiate the runner class""" + return dict(cmdargs=self.command_args(), binary=self.options.binary) + + def create_runner(self): + profile = self.profile_class(**self.profile_args()) + return self.runner_class(profile=profile, **self.runner_args()) + + def run(self): + runner = self.create_runner() + self.start(runner) + runner.cleanup() + + def debugger_arguments(self): + """Get the debugger arguments + + returns a 2-tuple of debugger arguments: + (debugger_arguments, interactive) + + """ + debug_args = self.options.debugger_args + if debug_args is not None: + debug_args = debug_args.split() + interactive = self.options.interactive + if self.options.debugger: + debug_args, interactive = debugger_arguments( + self.options.debugger, debug_args, interactive + ) + return debug_args, interactive + + def start(self, runner): + """Starts the runner and waits for the application to exit + + It can also happen via a keyboard interrupt. It should be + overwritten to provide custom running of the runner instance. + + """ + # attach a debugger if specified + debug_args, interactive = self.debugger_arguments() + runner.start(debug_args=debug_args, interactive=interactive) + print("Starting: " + " ".join(runner.command)) + try: + runner.wait() + except KeyboardInterrupt: + runner.stop() + + +def cli(args=sys.argv[1:]): + CLI(args).run() + + +if __name__ == "__main__": + cli() |