Source code

Revision control

Copy as Markdown

Other Tools

# 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
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()