153 lines
5.4 KiB
Python
153 lines
5.4 KiB
Python
# 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()
|