diff options
Diffstat (limited to 'tools/addon-sdk-1.7/python-lib/cuddlefish/__init__.py')
-rw-r--r-- | tools/addon-sdk-1.7/python-lib/cuddlefish/__init__.py | 797 |
1 files changed, 797 insertions, 0 deletions
diff --git a/tools/addon-sdk-1.7/python-lib/cuddlefish/__init__.py b/tools/addon-sdk-1.7/python-lib/cuddlefish/__init__.py new file mode 100644 index 0000000..9792eb9 --- /dev/null +++ b/tools/addon-sdk-1.7/python-lib/cuddlefish/__init__.py @@ -0,0 +1,797 @@ +# 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 sys +import os +import optparse +import webbrowser + +from copy import copy +import simplejson as json +from cuddlefish import packaging +from cuddlefish._version import get_versions + +MOZRUNNER_BIN_NOT_FOUND = 'Mozrunner could not locate your binary' +MOZRUNNER_BIN_NOT_FOUND_HELP = """ +I can't find the application binary in any of its default locations +on your system. Please specify one using the -b/--binary option. +""" + +UPDATE_RDF_FILENAME = "%s.update.rdf" +XPI_FILENAME = "%s.xpi" + +usage = """ +%prog [options] command [command-specific options] + +Supported Commands: + docs - view web-based documentation + init - create a sample addon in an empty directory + test - run tests + run - run program + xpi - generate an xpi + +Internal Commands: + sdocs - export static documentation + testcfx - test the cfx tool + testex - test all example code + testpkgs - test all installed packages + testall - test whole environment + +Experimental and internal commands and options are not supported and may be +changed or removed in the future. +""" + +global_options = [ + (("-v", "--verbose",), dict(dest="verbose", + help="enable lots of output", + action="store_true", + default=False)), + ] + +parser_groups = ( + ("Supported Command-Specific Options", [ + (("", "--update-url",), dict(dest="update_url", + help="update URL in install.rdf", + metavar=None, + default=None, + cmds=['xpi'])), + (("", "--update-link",), dict(dest="update_link", + help="generate update.rdf", + metavar=None, + default=None, + cmds=['xpi'])), + (("-p", "--profiledir",), dict(dest="profiledir", + help=("profile directory to pass to " + "app"), + metavar=None, + default=None, + cmds=['test', 'run', 'testex', + 'testpkgs', 'testall'])), + (("-b", "--binary",), dict(dest="binary", + help="path to app binary", + metavar=None, + default=None, + cmds=['test', 'run', 'testex', 'testpkgs', + 'testall'])), + (("", "--binary-args",), dict(dest="cmdargs", + help=("additional arguments passed to the " + "binary"), + metavar=None, + default=None, + cmds=['run', 'test'])), + (("", "--dependencies",), dict(dest="dep_tests", + help="include tests for all deps", + action="store_true", + default=False, + cmds=['test', 'testex', 'testpkgs', + 'testall'])), + (("", "--times",), dict(dest="iterations", + type="int", + help="number of times to run tests", + default=1, + cmds=['test', 'testex', 'testpkgs', + 'testall'])), + (("-f", "--filter",), dict(dest="filter", + help=("only run tests whose filenames " + "match FILENAME and optionally " + "match TESTNAME, both regexps"), + metavar="FILENAME[:TESTNAME]", + default=None, + cmds=['test', 'testex', 'testpkgs', + 'testall'])), + (("-g", "--use-config",), dict(dest="config", + help="use named config from local.json", + metavar=None, + default="default", + cmds=['test', 'run', 'xpi', 'testex', + 'testpkgs', 'testall'])), + (("", "--templatedir",), dict(dest="templatedir", + help="XULRunner app/ext. template", + metavar=None, + default=None, + cmds=['run', 'xpi'])), + (("", "--package-path",), dict(dest="packagepath", action="append", + help="extra directories for package search", + metavar=None, + default=[], + cmds=['run', 'xpi', 'test'])), + (("", "--extra-packages",), dict(dest="extra_packages", + help=("extra packages to include, " + "comma-separated. Default is " + "'addon-kit'."), + metavar=None, + default="addon-kit", + cmds=['run', 'xpi', 'test', 'testex', + 'testpkgs', 'testall', + 'testcfx'])), + (("", "--pkgdir",), dict(dest="pkgdir", + help=("package dir containing " + "package.json; default is " + "current directory"), + metavar=None, + default=None, + cmds=['run', 'xpi', 'test'])), + (("", "--static-args",), dict(dest="static_args", + help="extra harness options as JSON", + type="json", + metavar=None, + default="{}", + cmds=['run', 'xpi'])), + ] + ), + + ("Experimental Command-Specific Options", [ + (("-a", "--app",), dict(dest="app", + help=("app to run: firefox (default), fennec, " + "fennec-on-device, xulrunner or " + "thunderbird"), + metavar=None, + type="choice", + choices=["firefox", "fennec", + "fennec-on-device", "thunderbird", + "xulrunner"], + default="firefox", + cmds=['test', 'run', 'testex', 'testpkgs', + 'testall'])), + (("", "--no-run",), dict(dest="no_run", + help=("Instead of launching the " + "application, just show the command " + "for doing so. Use this to launch " + "the application in a debugger like " + "gdb."), + action="store_true", + default=False, + cmds=['run', 'test'])), + (("", "--no-strip-xpi",), dict(dest="no_strip_xpi", + help="retain unused modules in XPI", + action="store_true", + default=False, + cmds=['xpi'])), + (("", "--force-mobile",), dict(dest="enable_mobile", + help="Force compatibility with Firefox Mobile", + action="store_true", + default=False, + cmds=['run', 'test', 'xpi', 'testall'])), + (("", "--mobile-app",), dict(dest="mobile_app_name", + help=("Name of your Android application to " + "use. Possible values: 'firefox', " + "'firefox_beta', 'fennec_aurora', " + "'fennec' (for nightly)."), + metavar=None, + default=None, + cmds=['run', 'test', 'testall'])), + (("", "--harness-option",), dict(dest="extra_harness_option_args", + help=("Extra properties added to " + "harness-options.json"), + action="append", + metavar="KEY=VALUE", + default=[], + cmds=['xpi'])), + (("", "--stop-on-error",), dict(dest="stopOnError", + help="Stop running tests after the first failure", + action="store_true", + metavar=None, + default=False, + cmds=['test', 'testex', 'testpkgs'])), + ] + ), + + ("Internal Command-Specific Options", [ + (("", "--addons",), dict(dest="addons", + help=("paths of addons to install, " + "comma-separated"), + metavar=None, + default=None, + cmds=['test', 'run', 'testex', 'testpkgs', + 'testall'])), + (("", "--baseurl",), dict(dest="baseurl", + help=("root of static docs tree: " + "for example: 'http://me.com/the_docs/'"), + metavar=None, + default='', + cmds=['sdocs'])), + (("", "--test-runner-pkg",), dict(dest="test_runner_pkg", + help=("name of package " + "containing test runner " + "program (default is " + "test-harness)"), + default="test-harness", + cmds=['test', 'testex', 'testpkgs', + 'testall'])), + # --keydir was removed in 1.0b5, but we keep it around in the options + # parser to make life easier for frontends like FlightDeck which + # might still pass it. It can go away once the frontends are updated. + (("", "--keydir",), dict(dest="keydir", + help=("obsolete, ignored"), + metavar=None, + default=None, + cmds=['test', 'run', 'xpi', 'testex', + 'testpkgs', 'testall'])), + (("", "--e10s",), dict(dest="enable_e10s", + help="enable out-of-process Jetpacks", + action="store_true", + default=False, + cmds=['test', 'run', 'testex', 'testpkgs'])), + (("", "--logfile",), dict(dest="logfile", + help="log console output to file", + metavar=None, + default=None, + cmds=['run', 'test', 'testex', 'testpkgs'])), + # TODO: This should default to true once our memory debugging + # issues are resolved; see bug 592774. + (("", "--profile-memory",), dict(dest="profileMemory", + help=("profile memory usage " + "(default is false)"), + type="int", + action="store", + default=0, + cmds=['test', 'testex', 'testpkgs', + 'testall'])), + ] + ), + ) + +def find_parent_package(cur_dir): + tail = True + while tail: + if os.path.exists(os.path.join(cur_dir, 'package.json')): + return cur_dir + cur_dir, tail = os.path.split(cur_dir) + return None + +def check_json(option, opt, value): + # We return the parsed JSON here; see bug 610816 for background on why. + try: + return json.loads(value) + except ValueError: + raise optparse.OptionValueError("Option %s must be JSON." % opt) + +class CfxOption(optparse.Option): + TYPES = optparse.Option.TYPES + ('json',) + TYPE_CHECKER = copy(optparse.Option.TYPE_CHECKER) + TYPE_CHECKER['json'] = check_json + +def parse_args(arguments, global_options, usage, version, parser_groups, + defaults=None): + parser = optparse.OptionParser(usage=usage.strip(), option_class=CfxOption, + version=version) + + def name_cmp(a, b): + # a[0] = name sequence + # a[0][0] = short name (possibly empty string) + # a[0][1] = long name + names = [] + for seq in (a, b): + names.append(seq[0][0][1:] if seq[0][0] else seq[0][1][2:]) + return cmp(*names) + + global_options.sort(name_cmp) + for names, opts in global_options: + parser.add_option(*names, **opts) + + for group_name, options in parser_groups: + group = optparse.OptionGroup(parser, group_name) + options.sort(name_cmp) + for names, opts in options: + if 'cmds' in opts: + cmds = opts['cmds'] + del opts['cmds'] + cmds.sort() + if not 'help' in opts: + opts['help'] = "" + opts['help'] += " (%s)" % ", ".join(cmds) + group.add_option(*names, **opts) + parser.add_option_group(group) + + if defaults: + parser.set_defaults(**defaults) + + (options, args) = parser.parse_args(args=arguments) + + if not args: + parser.print_help() + parser.exit() + + return (options, args) + +# all tests emit progress messages to stderr, not stdout. (the mozrunner +# console output goes to stderr and is hard to change, and +# unittest.TextTestRunner prefers stderr, so we send everything else there +# too, to keep all the messages in order) + +def test_all(env_root, defaults): + fail = False + + print >>sys.stderr, "Testing cfx..." + sys.stderr.flush() + result = test_cfx(env_root, defaults['verbose']) + if result.failures or result.errors: + fail = True + + if not fail or not defaults.get("stopOnError"): + print >>sys.stderr, "Testing all examples..." + sys.stderr.flush() + + try: + test_all_examples(env_root, defaults) + except SystemExit, e: + fail = (e.code != 0) or fail + + if not fail or not defaults.get("stopOnError"): + print >>sys.stderr, "Testing all packages..." + sys.stderr.flush() + try: + test_all_packages(env_root, defaults) + except SystemExit, e: + fail = (e.code != 0) or fail + + if fail: + print >>sys.stderr, "Some tests were unsuccessful." + sys.exit(1) + print >>sys.stderr, "All tests were successful. Ship it!" + sys.exit(0) + +def test_cfx(env_root, verbose): + import cuddlefish.tests + + # tests write to stderr. flush everything before and after to avoid + # confusion later. + sys.stdout.flush(); sys.stderr.flush() + olddir = os.getcwd() + os.chdir(env_root) + retval = cuddlefish.tests.run(verbose) + os.chdir(olddir) + sys.stdout.flush(); sys.stderr.flush() + return retval + +def test_all_examples(env_root, defaults): + examples_dir = os.path.join(env_root, "examples") + examples = [dirname for dirname in os.listdir(examples_dir) + if os.path.isdir(os.path.join(examples_dir, dirname))] + examples.sort() + fail = False + for dirname in examples: + print >>sys.stderr, "Testing %s..." % dirname + sys.stderr.flush() + try: + run(arguments=["test", + "--pkgdir", + os.path.join(examples_dir, dirname)], + defaults=defaults, + env_root=env_root) + except SystemExit, e: + fail = (e.code != 0) or fail + if fail and defaults.get("stopOnError"): + break + + if fail: + print >>sys.stderr, "Some examples tests were unsuccessful." + sys.exit(-1) + +def test_all_packages(env_root, defaults): + packages_dir = os.path.join(env_root, "packages") + packages = [dirname for dirname in os.listdir(packages_dir) + if os.path.isdir(os.path.join(packages_dir, dirname))] + packages.sort() + print >>sys.stderr, "Testing all available packages: %s." % (", ".join(packages)) + sys.stderr.flush() + fail = False + for dirname in packages: + print >>sys.stderr, "Testing %s..." % dirname + sys.stderr.flush() + try: + run(arguments=["test", + "--pkgdir", + os.path.join(packages_dir, dirname)], + defaults=defaults, + env_root=env_root) + except SystemExit, e: + fail = (e.code != 0) or fail + if fail and defaults.get('stopOnError'): + break + if fail: + print >>sys.stderr, "Some package tests were unsuccessful." + sys.exit(-1) + +def get_config_args(name, env_root): + local_json = os.path.join(env_root, "local.json") + if not (os.path.exists(local_json) and + os.path.isfile(local_json)): + if name == "default": + return [] + else: + print >>sys.stderr, "File does not exist: %s" % local_json + sys.exit(1) + local_json = packaging.load_json_file(local_json) + if 'configs' not in local_json: + print >>sys.stderr, "'configs' key not found in local.json." + sys.exit(1) + if name not in local_json.configs: + if name == "default": + return [] + else: + print >>sys.stderr, "No config found for '%s'." % name + sys.exit(1) + config = local_json.configs[name] + if type(config) != list: + print >>sys.stderr, "Config for '%s' must be a list of strings." % name + sys.exit(1) + return config + +def initializer(env_root, args, out=sys.stdout, err=sys.stderr): + from templates import MAIN_JS, PACKAGE_JSON, README_DOC, MAIN_JS_DOC, TEST_MAIN_JS + path = os.getcwd() + addon = os.path.basename(path) + # if more than one argument + if len(args) > 1: + print >>err, 'Too many arguments.' + return 1 + # avoid clobbering existing files, but we tolerate things like .git + existing = [fn for fn in os.listdir(path) if not fn.startswith(".")] + if existing: + print >>err, 'This command must be run in an empty directory.' + return 1 + for d in ['lib','data','test','doc']: + os.mkdir(os.path.join(path,d)) + print >>out, '*', d, 'directory created' + open('README.md','w').write(README_DOC % {'name':addon}) + print >>out, '* README.md written' + open('package.json','w').write(PACKAGE_JSON % {'name':addon.lower(), + 'fullName':addon }) + print >>out, '* package.json written' + open(os.path.join(path,'test','test-main.js'),'w').write(TEST_MAIN_JS) + print >>out, '* test/test-main.js written' + open(os.path.join(path,'lib','main.js'),'w').write(MAIN_JS) + print >>out, '* lib/main.js written' + open(os.path.join(path,'doc','main.md'),'w').write(MAIN_JS_DOC) + print >>out, '* doc/main.md written' + print >>out, '\nYour sample add-on is now ready.' + print >>out, 'Do "cfx test" to test it and "cfx run" to try it. Have fun!' + return 0 + +def buildJID(target_cfg): + if "id" in target_cfg: + jid = target_cfg["id"] + else: + import uuid + jid = str(uuid.uuid4()) + if not ("@" in jid or jid.startswith("{")): + jid = jid + "@jetpack" + return jid + +def run(arguments=sys.argv[1:], target_cfg=None, pkg_cfg=None, + defaults=None, env_root=os.environ.get('CUDDLEFISH_ROOT'), + stdout=sys.stdout): + versions = get_versions() + sdk_version = versions["version"] + display_version = "Add-on SDK %s (%s)" % (sdk_version, versions["full"]) + parser_kwargs = dict(arguments=arguments, + global_options=global_options, + parser_groups=parser_groups, + usage=usage, + version=display_version, + defaults=defaults) + + (options, args) = parse_args(**parser_kwargs) + + config_args = get_config_args(options.config, env_root); + + # reparse configs with arguments from local.json + if config_args: + parser_kwargs['arguments'] += config_args + (options, args) = parse_args(**parser_kwargs) + + command = args[0] + + if command == "init": + initializer(env_root, args) + return + if command == "testpkgs": + test_all_packages(env_root, defaults=options.__dict__) + return + elif command == "testex": + test_all_examples(env_root, defaults=options.__dict__) + return + elif command == "testall": + test_all(env_root, defaults=options.__dict__) + return + elif command == "testcfx": + test_cfx(env_root, options.verbose) + return + elif command == "docs": + from cuddlefish.docs import generate + if len(args) > 1: + docs_home = generate.generate_named_file(env_root, filename=args[1]) + else: + docs_home = generate.generate_local_docs(env_root) + webbrowser.open(docs_home) + return + elif command == "sdocs": + from cuddlefish.docs import generate + filename = generate.generate_static_docs(env_root) + print >>stdout, "Wrote %s." % filename + return + elif command not in ["xpi", "test", "run"]: + print >>sys.stderr, "Unknown command: %s" % command + print >>sys.stderr, "Try using '--help' for assistance." + sys.exit(1) + + target_cfg_json = None + if not target_cfg: + if not options.pkgdir: + options.pkgdir = find_parent_package(os.getcwd()) + if not options.pkgdir: + print >>sys.stderr, ("cannot find 'package.json' in the" + " current directory or any parent.") + sys.exit(1) + else: + options.pkgdir = os.path.abspath(options.pkgdir) + if not os.path.exists(os.path.join(options.pkgdir, 'package.json')): + print >>sys.stderr, ("cannot find 'package.json' in" + " %s." % options.pkgdir) + sys.exit(1) + + target_cfg_json = os.path.join(options.pkgdir, 'package.json') + target_cfg = packaging.get_config_in_dir(options.pkgdir) + + # At this point, we're either building an XPI or running Jetpack code in + # a Mozilla application (which includes running tests). + + use_main = False + inherited_options = ['verbose', 'enable_e10s'] + enforce_timeouts = False + + if command == "xpi": + use_main = True + elif command == "test": + if 'tests' not in target_cfg: + target_cfg['tests'] = [] + inherited_options.extend(['iterations', 'filter', 'profileMemory', + 'stopOnError']) + enforce_timeouts = True + elif command == "run": + use_main = True + else: + assert 0, "shouldn't get here" + + if use_main and 'main' not in target_cfg: + # If the user supplies a template dir, then the main + # program may be contained in the template. + if not options.templatedir: + print >>sys.stderr, "package.json does not have a 'main' entry." + sys.exit(1) + + if not pkg_cfg: + pkg_cfg = packaging.build_config(env_root, target_cfg, options.packagepath) + + target = target_cfg.name + + # TODO: Consider keeping a cache of dynamic UUIDs, based + # on absolute filesystem pathname, in the root directory + # or something. + if command in ('xpi', 'run'): + from cuddlefish.preflight import preflight_config + if target_cfg_json: + config_was_ok, modified = preflight_config(target_cfg, + target_cfg_json) + if not config_was_ok: + if modified: + # we need to re-read package.json . The safest approach + # is to re-run the "cfx xpi"/"cfx run" command. + print >>sys.stderr, ("package.json modified: please re-run" + " 'cfx %s'" % command) + else: + print >>sys.stderr, ("package.json needs modification:" + " please update it and then re-run" + " 'cfx %s'" % command) + sys.exit(1) + # if we make it this far, we have a JID + else: + assert command == "test" + + jid = buildJID(target_cfg) + + targets = [target] + if command == "test": + targets.append(options.test_runner_pkg) + + extra_packages = [] + if options.extra_packages: + extra_packages = options.extra_packages.split(",") + if extra_packages: + targets.extend(extra_packages) + target_cfg.extra_dependencies = extra_packages + + deps = packaging.get_deps_for_targets(pkg_cfg, targets) + + from cuddlefish.manifest import build_manifest, ModuleNotFoundError + # Figure out what loader files should be scanned. This is normally + # computed inside packaging.generate_build_for_target(), by the first + # dependent package that defines a "loader" property in its package.json. + # This property is interpreted as a filename relative to the top of that + # file, and stored as a path in build.loader . generate_build_for_target() + # cannot be called yet (it needs the list of used_deps that + # build_manifest() computes, but build_manifest() needs the list of + # loader files that it computes). We could duplicate or factor out this + # build.loader logic, but that would be messy, so instead we hard-code + # the choice of loader for manifest-generation purposes. In practice, + # this means that alternative loaders probably won't work with + # --strip-xpi. + assert packaging.DEFAULT_LOADER == "api-utils" + assert pkg_cfg.packages["api-utils"].loader == "lib/cuddlefish.js" + cuddlefish_js_path = os.path.join(pkg_cfg.packages["api-utils"].root_dir, + "lib", "cuddlefish.js") + loader_modules = [("api-utils", "lib", "cuddlefish", cuddlefish_js_path)] + scan_tests = command == "test" + test_filter_re = None + if scan_tests and options.filter: + test_filter_re = options.filter + if ":" in options.filter: + test_filter_re = options.filter.split(":")[0] + try: + manifest = build_manifest(target_cfg, pkg_cfg, deps, + scan_tests, test_filter_re, + loader_modules) + except ModuleNotFoundError, e: + print str(e) + sys.exit(1) + used_deps = manifest.get_used_packages() + if command == "test": + # The test runner doesn't appear to link against any actual packages, + # because it loads everything at runtime (invisible to the linker). + # If we believe that, we won't set up URI mappings for anything, and + # tests won't be able to run. + used_deps = deps + for xp in extra_packages: + if xp not in used_deps: + used_deps.append(xp) + + build = packaging.generate_build_for_target( + pkg_cfg, target, used_deps, + include_dep_tests=options.dep_tests + ) + + harness_options = { + 'jetpackID': jid, + 'staticArgs': options.static_args, + 'name': target, + } + + harness_options.update(build) + + extra_environment = {} + if command == "test": + # This should be contained in the test runner package. + # maybe just do: target_cfg.main = 'test-harness/run-tests' + harness_options['main'] = 'test-harness/run-tests' + harness_options['mainPath'] = manifest.get_manifest_entry("test-harness", "lib", "run-tests").get_path() + else: + harness_options['main'] = target_cfg.get('main') + harness_options['mainPath'] = manifest.top_path + extra_environment["CFX_COMMAND"] = command + + for option in inherited_options: + harness_options[option] = getattr(options, option) + + harness_options['metadata'] = packaging.get_metadata(pkg_cfg, used_deps) + + harness_options['sdkVersion'] = sdk_version + + packaging.call_plugins(pkg_cfg, used_deps) + + retval = 0 + + if options.templatedir: + app_extension_dir = os.path.abspath(options.templatedir) + else: + mydir = os.path.dirname(os.path.abspath(__file__)) + app_extension_dir = os.path.join(mydir, "app-extension") + + + if target_cfg.get('preferences'): + harness_options['preferences'] = target_cfg.get('preferences') + + harness_options['manifest'] = manifest.get_harness_options_manifest() + harness_options['allTestModules'] = manifest.get_all_test_modules() + + from cuddlefish.rdf import gen_manifest, RDFUpdate + + manifest_rdf = gen_manifest(template_root_dir=app_extension_dir, + target_cfg=target_cfg, + jid=jid, + update_url=options.update_url, + bootstrap=True, + enable_mobile=options.enable_mobile) + + if command == "xpi" and options.update_link: + rdf_name = UPDATE_RDF_FILENAME % target_cfg.name + print >>stdout, "Exporting update description to %s." % rdf_name + update = RDFUpdate() + update.add(manifest_rdf, options.update_link) + open(rdf_name, "w").write(str(update)) + + # ask the manifest what files were used, so we can construct an XPI + # without the rest. This will include the loader (and everything it + # uses) because of the "loader_modules" starting points we passed to + # build_manifest earlier + used_files = None + if command == "xpi": + used_files = set(manifest.get_used_files()) + + if options.no_strip_xpi: + used_files = None # disables the filter, includes all files + + if command == 'xpi': + from cuddlefish.xpi import build_xpi + extra_harness_options = {} + for kv in options.extra_harness_option_args: + key,value = kv.split("=", 1) + extra_harness_options[key] = value + xpi_path = XPI_FILENAME % target_cfg.name + print >>stdout, "Exporting extension to %s." % xpi_path + build_xpi(template_root_dir=app_extension_dir, + manifest=manifest_rdf, + xpi_path=xpi_path, + harness_options=harness_options, + limit_to=used_files, + extra_harness_options=extra_harness_options) + else: + from cuddlefish.runner import run_app + + if options.profiledir: + options.profiledir = os.path.expanduser(options.profiledir) + options.profiledir = os.path.abspath(options.profiledir) + + if options.addons is not None: + options.addons = options.addons.split(",") + + try: + retval = run_app(harness_root_dir=app_extension_dir, + manifest_rdf=manifest_rdf, + harness_options=harness_options, + app_type=options.app, + binary=options.binary, + profiledir=options.profiledir, + verbose=options.verbose, + enforce_timeouts=enforce_timeouts, + logfile=options.logfile, + addons=options.addons, + args=options.cmdargs, + extra_environment=extra_environment, + norun=options.no_run, + used_files=used_files, + enable_mobile=options.enable_mobile, + mobile_app_name=options.mobile_app_name) + except ValueError, e: + print "" + print "A given cfx option has an inappropriate value:" + print >>sys.stderr, " " + " \n ".join(str(e).split("\n")) + retval = -1 + except Exception, e: + if str(e).startswith(MOZRUNNER_BIN_NOT_FOUND): + print >>sys.stderr, MOZRUNNER_BIN_NOT_FOUND_HELP.strip() + retval = -1 + else: + raise + sys.exit(retval) |