blob: 37e11401ad85f7fa9c76804a8665cf22910952e4 [file] [log] [blame]
# 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"""
return 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()