예제 #1
0
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

    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:
        print >>sys.stderr, "Unknown command: %s" % command
        print >>sys.stderr, "Try using '--help' for assistance."
        sys.exit(1)

    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)
예제 #2
0
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 == "testaddons":
        test_all_testaddons(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":
        if options.filter:
            print >> sys.stderr, "The filter option is not valid with the testcfx command"
            return
        test_cfx(env_root, options.verbose)
        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)

    if options.manifest_overload:
        for k, v in packaging.load_json_file(
                options.manifest_overload).items():
            target_cfg[k] = v

    # 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', 'parseable', 'check_memory',
        'abort_on_missing'
    ]
    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, \
                                    BadChromeMarkerError
    # 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 == "addon-sdk"
    assert pkg_cfg.packages[
        "addon-sdk"].loader == "lib/sdk/loader/cuddlefish.js"
    cuddlefish_js_path = os.path.join(pkg_cfg.packages["addon-sdk"].root_dir,
                                      "lib", "sdk", "loader", "cuddlefish.js")
    loader_modules = [("addon-sdk", "lib", "sdk/loader/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,
                                  abort_on_missing=options.abort_on_missing)
    except ModuleNotFoundError, e:
        print str(e)
        sys.exit(1)
예제 #3
0
def run(arguments=sys.argv[1:],
        target_cfg=None,
        pkg_cfg=None,
        defaults=None,
        env_root=os.environ.get('CUDDLEFISH_ROOT')):
    parser_kwargs = dict(arguments=arguments,
                         parser_options=parser_options,
                         parser_groups=parser_groups,
                         usage=usage,
                         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 == "develop":
        run_development_mode(env_root, defaults=options.__dict__)
        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":
        import subprocess
        import time
        import cuddlefish.server

        print "One moment."
        popen = subprocess.Popen(
            [sys.executable, cuddlefish.server.__file__, 'daemonic'])
        # TODO: See if there's actually a way to block on
        # a particular event occurring, rather than this
        # relatively arbitrary/generous amount.
        time.sleep(cuddlefish.server.IDLE_WEBPAGE_TIMEOUT * 2)
        return
    elif command == "sdocs":
        import cuddlefish.server

        # TODO: Allow user to change this filename via cmd line.
        filename = 'jetpack-sdk-docs.tgz'
        cuddlefish.server.generate_static_docs(env_root, filename)
        print "Wrote %s." % filename
        return

    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)

    use_main = False
    if command == "xpcom":
        if 'xpcom' not in target_cfg:
            print >> sys.stderr, "package.json does not have a 'xpcom' entry."
            sys.exit(1)
        if not (options.moz_srcdir and options.moz_objdir):
            print >> sys.stderr, "srcdir and objdir not specified."
            sys.exit(1)
        options.moz_srcdir = os.path.expanduser(options.moz_srcdir)
        options.moz_objdir = os.path.expanduser(options.moz_objdir)
        xpcom = target_cfg.xpcom
        from cuddlefish.xpcom import build_xpcom_components
        if 'typelibs' in xpcom:
            xpt_output_dir = packaging.resolve_dir(target_cfg, xpcom.typelibs)
        else:
            xpt_output_dir = None
        build_xpcom_components(
            comp_src_dir=packaging.resolve_dir(target_cfg, xpcom.src),
            moz_srcdir=options.moz_srcdir,
            moz_objdir=options.moz_objdir,
            base_output_dir=packaging.resolve_dir(target_cfg, xpcom.dest),
            xpt_output_dir=xpt_output_dir,
            module_name=xpcom.module)
        sys.exit(0)
    elif command == "xpi":
        use_main = True
    elif command == "test":
        if 'tests' not in target_cfg:
            target_cfg['tests'] = []
    elif command == "run":
        use_main = True
    else:
        print >> sys.stderr, "Unknown command: %s" % command
        print >> sys.stderr, "Try using '--help' for assistance."
        sys.exit(1)

    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)

    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,
                keydir=options.keydir,
                err_if_privkey_not_found=False)
            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
        jid = target_cfg["id"]
        assert not jid.endswith("@jetpack")
        unique_prefix = '%s-' % jid  # used for resource: URLs

        # the harness_guid is used for an XPCOM class ID. We use the
        # JetpackID for the add-on ID and the XPCOM contract ID.
        import uuid
        harness_guid = str(uuid.uuid4())

    else:
        if options.use_server:
            harness_guid = '2974c5b5-b671-46f8-a4bb-63c6eca6261b'
        else:
            harness_guid = '6724fc1b-3ec4-40e2-8583-8061088b3185'
        unique_prefix = '%s-' % target
        jid = harness_guid

    assert not jid.endswith("@jetpack")
    bundle_id = jid + "@jetpack"
    # the resource: URLs prefix is treated too much like a DNS hostname
    unique_prefix = unique_prefix.lower()
    assert "@" not in unique_prefix
    assert "." not in unique_prefix

    timeout = None
    targets = [target]
    if not use_main:
        timeout = TEST_RUN_TIMEOUT
        targets.append(options.test_runner_pkg)

    if options.extra_packages:
        targets.extend(options.extra_packages.split(","))

    deps = packaging.get_deps_for_targets(pkg_cfg, targets)
    build = packaging.generate_build_for_target(
        pkg_cfg,
        target,
        deps,
        prefix=unique_prefix,  # used to create resource: URLs
        include_dep_tests=options.dep_tests)

    if 'resources' in build:
        resources = build.resources
        for name in resources:
            resources[name] = os.path.abspath(resources[name])

    dep_xpt_dirs = []
    for dep in deps:
        dep_cfg = pkg_cfg.packages[dep]
        if 'xpcom' in dep_cfg and 'typelibs' in dep_cfg.xpcom:
            abspath = packaging.resolve_dir(dep_cfg, dep_cfg.xpcom.typelibs)
            dep_xpt_dirs.append(abspath)
    xpts = get_xpts(dep_xpt_dirs)

    harness_contract_id = ('@mozilla.org/harness-service;1?id=%s' % jid)
    harness_options = {
        'bootstrap': {
            'contractID': harness_contract_id,
            'classID': '{%s}' % harness_guid
        },
        'jetpackID': jid,
        'bundleID': bundle_id,
    }

    harness_options.update(build)

    inherited_options = ['verbose']

    if use_main:
        harness_options['main'] = target_cfg.get('main')
    else:
        harness_options['main'] = "run-tests"
        inherited_options.extend(['iterations', 'filter', 'profileMemory'])

    for option in inherited_options:
        harness_options[option] = getattr(options, option)

    harness_options['metadata'] = packaging.get_metadata(pkg_cfg, deps)
    packaging.call_plugins(pkg_cfg, deps)

    retval = 0

    if options.templatedir:
        app_extension_dir = os.path.abspath(options.templatedir)
    else:
        mydir = os.path.dirname(os.path.abspath(__file__))
        if sys.platform == "darwin":
            # If we're on OS X, at least point into the XULRunner
            # app dir so we run as a proper app if using XULRunner.
            app_extension_dir = os.path.join(mydir, "Test App.app", "Contents",
                                             "Resources")
        else:
            app_extension_dir = os.path.join(mydir, "app-extension")

    if command == 'xpi':
        from cuddlefish.xpi import build_xpi
        from cuddlefish.rdf import gen_manifest, RDFUpdate

        manifest = gen_manifest(template_root_dir=app_extension_dir,
                                target_cfg=target_cfg,
                                bundle_id=bundle_id,
                                update_url=options.update_url,
                                bootstrap=True)

        if options.update_link:
            rdf_name = UPDATE_RDF_FILENAME % target_cfg.name
            print "Exporting update description to %s." % rdf_name
            update = RDFUpdate()
            update.add(manifest, options.update_link)
            open(rdf_name, "w").write(str(update))

        xpi_name = XPI_FILENAME % target_cfg.name
        print "Exporting extension to %s." % xpi_name
        build_xpi(template_root_dir=app_extension_dir,
                  manifest=manifest,
                  xpi_name=xpi_name,
                  harness_options=harness_options,
                  xpts=xpts)
    else:
        if options.use_server:
            from cuddlefish.server import run_app
        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,
                             harness_options=harness_options,
                             xpts=xpts,
                             app_type=options.app,
                             binary=options.binary,
                             profiledir=options.profiledir,
                             verbose=options.verbose,
                             timeout=timeout,
                             logfile=options.logfile,
                             addons=options.addons)
        except Exception, e:
            if e.message.startswith(MOZRUNNER_BIN_NOT_FOUND):
                print >> sys.stderr, MOZRUNNER_BIN_NOT_FOUND_HELP.strip()
                retval = -1
            else:
                raise
예제 #4
0
def run(arguments=sys.argv[1:], target_cfg=None, pkg_cfg=None,
        defaults=None, env_root=os.environ.get('CUDDLEFISH_ROOT')):
    parser_kwargs = dict(arguments=arguments,
                         global_options=global_options,
                         parser_groups=parser_groups,
                         usage=usage,
                         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 == "develop":
        run_development_mode(env_root, defaults=options.__dict__)
        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":
        import subprocess
        import time
        import cuddlefish.server

        print "One moment."
        popen = subprocess.Popen([sys.executable,
                                  cuddlefish.server.__file__,
                                  'daemonic'])
        # TODO: See if there's actually a way to block on
        # a particular event occurring, rather than this
        # relatively arbitrary/generous amount.
        time.sleep(cuddlefish.server.IDLE_WEBPAGE_TIMEOUT * 2)
        return
    elif command == "sdocs":
        import cuddlefish.server

        # TODO: Allow user to change this filename via cmd line.
        filename = 'addon-sdk-docs.tgz'
        cuddlefish.server.generate_static_docs(env_root, filename, options.baseurl)
        print "Wrote %s." % filename
        return

    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
    timeout = None
    inherited_options = ['verbose', 'enable_e10s']

    if command == "xpi":
        use_main = True
    elif command == "test":
        if 'tests' not in target_cfg:
            target_cfg['tests'] = []
        timeout = TEST_RUN_TIMEOUT
        inherited_options.extend(['iterations', 'filter', 'profileMemory'])
    elif command == "run":
        use_main = True
    else:
        print >>sys.stderr, "Unknown command: %s" % command
        print >>sys.stderr, "Try using '--help' for assistance."
        sys.exit(1)

    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

    # the harness_guid is used for an XPCOM class ID. We use the
    # JetpackID for the add-on ID and the XPCOM contract ID.
    if "harnessClassID" in target_cfg:
        # For the sake of non-bootstrapped extensions, we allow to specify the
        # classID of harness' XPCOM component in package.json. This makes it
        # possible to register the component using a static chrome.manifest file
        harness_guid = target_cfg["harnessClassID"]
    else:
        import uuid
        harness_guid = str(uuid.uuid4())

    # 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"

    if "id" in target_cfg:
        jid = target_cfg["id"]
        assert not jid.endswith("@jetpack")
        unique_prefix = '%s-' % jid # used for resource: URLs
    else:
        # The Jetpack ID is not required for cfx test, in which case we have to
        # make one up based on the GUID.
        if options.use_server:
            # The harness' contractID (hence also the jid and the harness_guid)
            # need to be static in the "development mode", so that bootstrap.js
            # can unload the previous version of the package being developed.
            harness_guid = '2974c5b5-b671-46f8-a4bb-63c6eca6261b'
        unique_prefix = '%s-' % target
        jid = harness_guid

    assert not jid.endswith("@jetpack")
    if ( jid.startswith("jid0-")
         or jid.startswith("jid1-")
         or jid.startswith("anonid0-") ):
        bundle_id = jid + "@jetpack"
    # Don't append "@jetpack" to old-style IDs, as they should be exactly
    # as specified by the addon author so AMO and Firefox continue to treat
    # their addon bundles as representing the same addon (and also because
    # they may already have an @ sign in them, and there can be only one).
    else:
        bundle_id = jid

    # the resource: URL's prefix is treated too much like a DNS hostname
    unique_prefix = unique_prefix.lower()
    unique_prefix = unique_prefix.replace("@", "-at-")
    unique_prefix = unique_prefix.replace(".", "-dot-")

    targets = [target]
    if command == "test":
        targets.append(options.test_runner_pkg)

    if options.extra_packages:
        targets.extend(options.extra_packages.split(","))

    deps = packaging.get_deps_for_targets(pkg_cfg, targets)
    build = packaging.generate_build_for_target(
        pkg_cfg, target, deps,
        prefix=unique_prefix,  # used to create resource: URLs
        include_dep_tests=options.dep_tests
        )

    if 'resources' in build:
        resources = build.resources
        for name in resources:
            resources[name] = os.path.abspath(resources[name])

    harness_contract_id = ('@mozilla.org/harness-service;1?id=%s' % jid)
    harness_options = {
        'bootstrap': {
            'contractID': harness_contract_id,
            'classID': '{%s}' % harness_guid
            },
        'jetpackID': jid,
        'bundleID': bundle_id,
        'staticArgs': options.static_args,
        'name': target,
        }

    harness_options.update(build)

    if command == "test":
        # This should be contained in the test runner package.
        harness_options['main'] = 'run-tests'
    else:
        harness_options['main'] = target_cfg.get('main')

    for option in inherited_options:
        harness_options[option] = getattr(options, option)

    harness_options['metadata'] = packaging.get_metadata(pkg_cfg, deps)

    sdk_version = get_version(env_root)
    harness_options['sdkVersion'] = sdk_version

    packaging.call_plugins(pkg_cfg, deps)

    retval = 0

    if options.templatedir:
        app_extension_dir = os.path.abspath(options.templatedir)
    else:
        mydir = os.path.dirname(os.path.abspath(__file__))
        if sys.platform == "darwin":
            # If we're on OS X, at least point into the XULRunner
            # app dir so we run as a proper app if using XULRunner.
            app_extension_dir = os.path.join(mydir, "Test App.app",
                                             "Contents", "Resources")
        else:
            app_extension_dir = os.path.join(mydir, "app-extension")

    from cuddlefish.manifest import build_manifest
    uri_prefix = "resource://%s" % unique_prefix
    include_tests = False #bool(command=="test")
    manifest = build_manifest(target_cfg, pkg_cfg, deps, uri_prefix, include_tests)
    harness_options['manifest'] = manifest.get_harness_options_manifest(uri_prefix)

    if command == 'xpi':
        from cuddlefish.xpi import build_xpi
        from cuddlefish.rdf import gen_manifest, RDFUpdate

        manifest_rdf = gen_manifest(template_root_dir=app_extension_dir,
                                    target_cfg=target_cfg,
                                    bundle_id=bundle_id,
                                    update_url=options.update_url,
                                    bootstrap=True)

        if options.update_link:
            rdf_name = UPDATE_RDF_FILENAME % target_cfg.name
            print "Exporting update description to %s." % rdf_name
            update = RDFUpdate()
            update.add(manifest_rdf, options.update_link)
            open(rdf_name, "w").write(str(update))

        xpi_name = XPI_FILENAME % target_cfg.name
        print "Exporting extension to %s." % xpi_name
        build_xpi(template_root_dir=app_extension_dir,
                  manifest=manifest_rdf,
                  xpi_name=xpi_name,
                  harness_options=harness_options)
    else:
        if options.use_server:
            from cuddlefish.server import run_app
        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,
                             harness_options=harness_options,
                             app_type=options.app,
                             binary=options.binary,
                             profiledir=options.profiledir,
                             verbose=options.verbose,
                             timeout=timeout,
                             logfile=options.logfile,
                             addons=options.addons,
                             args=options.cmdargs,
                             norun=options.no_run)
        except Exception, e:
            if str(e).startswith(MOZRUNNER_BIN_NOT_FOUND):
                print >>sys.stderr, MOZRUNNER_BIN_NOT_FOUND_HELP.strip()
                retval = -1
            else:
                raise
예제 #5
0
    def test_no_name(self):
        basedir = self.make_basedir()
        fn = os.path.join(basedir, "package.json")
        keydir = os.path.join(basedir, "keys")

        # empty config is not ok: need id (name is automatically supplied)
        config_orig = "{}"
        self.write(config_orig)
        out = StringIO()
        cfg = self.get_cfg()
        config_was_ok, modified = preflight.preflight_config(cfg, fn,
                                                             stderr=out,
                                                             keydir=keydir)
        self.failUnlessEqual(config_was_ok, False)
        self.failUnlessEqual(modified, True)
        backup_fn = os.path.join(basedir, "package.json.backup")
        config_backup = open(backup_fn,"r").read()
        self.failUnlessEqual(config_backup, config_orig)
        config = json.loads(self.read())
        self.failIf("name" in config)
        self.failUnless("id" in config)
        self.failUnlessEqual(out.getvalue().strip(),
                             "No 'id' in package.json: creating a new keypair for you.")
        jid = str(config["id"])
        keyfile = os.path.join(keydir, jid)
        fields, fieldnames = self.parse(open(keyfile).read())
        self.failUnlessEqual(fieldnames[0], "private-key")
        privkey = fields["private-key"]
        self.failUnless(privkey.startswith("private-jid0-"), privkey)
        self.failUnlessEqual(fields["jid"], jid)
        self.failUnlessEqual(fields["name"], "pretend name")
        os.unlink(backup_fn)

        # just a name? we add the id
        config_orig = '{"name": "my-awesome-package"}'
        self.write(config_orig)
        out = StringIO()
        cfg = self.get_cfg()
        config_was_ok, modified = preflight.preflight_config(cfg, fn,
                                                             stderr=out,
                                                             keydir=keydir)
        self.failUnlessEqual(config_was_ok, False)
        self.failUnlessEqual(modified, True)
        backup_fn = os.path.join(basedir, "package.json.backup")
        config_backup = open(backup_fn,"r").read()
        self.failUnlessEqual(config_backup, config_orig)
        config = json.loads(self.read())
        self.failUnlessEqual(config["name"], "my-awesome-package")
        self.failUnless("id" in config)
        self.failUnlessEqual(out.getvalue().strip(),
                             "No 'id' in package.json: creating a new keypair for you.")
        jid = str(config["id"])
        keyfile = os.path.join(keydir, jid)
        fields, fieldnames = self.parse(open(keyfile).read())
        privkey = fields["private-key"]
        self.failUnless(privkey.startswith("private-jid0-"), privkey)
        self.failUnlessEqual(fields["jid"], jid)
        self.failUnlessEqual(fields["name"], "my-awesome-package")

        # name and valid id? great! ship it!
        config2 = '{"name": "my-awesome-package", "id": "%s"}' % jid
        self.write(config2)
        out = StringIO()
        cfg = self.get_cfg()
        config_was_ok, modified = preflight.preflight_config(cfg, fn,
                                                             stderr=out,
                                                             keydir=keydir)
        self.failUnlessEqual(config_was_ok, True)
        self.failUnlessEqual(modified, False)
        config2a = self.read()
        self.failUnlessEqual(config2a, config2)
        self.failUnlessEqual(out.getvalue().strip(), "")

        # name and invalid id? tell them to get a new one
        os.unlink(keyfile)
        self.write(config2)
        out = StringIO()
        cfg = self.get_cfg()
        config_was_ok, modified = preflight.preflight_config(cfg, fn,
                                                             stderr=out,
                                                             keydir=keydir)
        self.failUnlessEqual(config_was_ok, False)
        self.failUnlessEqual(modified, False)
        out = out.getvalue().strip()
        self.failUnless("Your package.json says our ID is" in out, out)
        self.failUnless("But I don't have a corresponding private key in"
                        in out, out)
        self.failUnless("If you are the original developer" in out, out)
        self.failUnless("Otherwise, if you are a new developer" in out, out)
예제 #6
0
def run(arguments=sys.argv[1:],
        target_cfg=None,
        pkg_cfg=None,
        defaults=None,
        env_root=os.environ.get('CUDDLEFISH_ROOT')):
    parser_kwargs = dict(arguments=arguments,
                         global_options=global_options,
                         parser_groups=parser_groups,
                         usage=usage,
                         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 == "develop":
        run_development_mode(env_root, defaults=options.__dict__)
        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":
        import subprocess
        import time
        import cuddlefish.server

        print "One moment."
        popen = subprocess.Popen(
            [sys.executable, cuddlefish.server.__file__, 'daemonic'])
        # TODO: See if there's actually a way to block on
        # a particular event occurring, rather than this
        # relatively arbitrary/generous amount.
        time.sleep(cuddlefish.server.IDLE_WEBPAGE_TIMEOUT * 2)
        return
    elif command == "sdocs":
        import cuddlefish.server

        # TODO: Allow user to change this filename via cmd line.
        filename = 'addon-sdk-docs.tgz'
        cuddlefish.server.generate_static_docs(env_root, filename,
                                               options.baseurl)
        print "Wrote %s." % filename
        return

    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
    timeout = None
    inherited_options = ['verbose', 'enable_e10s']

    if command == "xpi":
        use_main = True
    elif command == "test":
        if 'tests' not in target_cfg:
            target_cfg['tests'] = []
        timeout = TEST_RUN_TIMEOUT
        inherited_options.extend(['iterations', 'filter', 'profileMemory'])
    elif command == "run":
        use_main = True
    else:
        print >> sys.stderr, "Unknown command: %s" % command
        print >> sys.stderr, "Try using '--help' for assistance."
        sys.exit(1)

    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)

    target = target_cfg.name

    # the harness_guid is used for an XPCOM class ID. We use the
    # JetpackID for the add-on ID and the XPCOM contract ID.
    if "harnessClassID" in target_cfg:
        # For the sake of non-bootstrapped extensions, we allow to specify the
        # classID of harness' XPCOM component in package.json. This makes it
        # possible to register the component using a static chrome.manifest file
        harness_guid = target_cfg["harnessClassID"]
    else:
        import uuid
        harness_guid = str(uuid.uuid4())

    # 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,
                keydir=options.keydir,
                err_if_privkey_not_found=False)
            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"

    if "id" in target_cfg:
        jid = target_cfg["id"]
        assert not jid.endswith("@jetpack")
        unique_prefix = '%s-' % jid  # used for resource: URLs
    else:
        # The Jetpack ID is not required for cfx test, in which case we have to
        # make one up based on the GUID.
        if options.use_server:
            # The harness' contractID (hence also the jid and the harness_guid)
            # need to be static in the "development mode", so that bootstrap.js
            # can unload the previous version of the package being developed.
            harness_guid = '2974c5b5-b671-46f8-a4bb-63c6eca6261b'
        unique_prefix = '%s-' % target
        jid = harness_guid

    assert not jid.endswith("@jetpack")
    if (jid.startswith("jid0-") or jid.startswith("anonid0-")):
        bundle_id = jid + "@jetpack"
    # Don't append "@jetpack" to old-style IDs, as they should be exactly
    # as specified by the addon author so AMO and Firefox continue to treat
    # their addon bundles as representing the same addon (and also because
    # they may already have an @ sign in them, and there can be only one).
    else:
        bundle_id = jid

    # the resource: URL's prefix is treated too much like a DNS hostname
    unique_prefix = unique_prefix.lower()
    unique_prefix = unique_prefix.replace("@", "-at-")
    unique_prefix = unique_prefix.replace(".", "-dot-")

    targets = [target]
    if command == "test":
        targets.append(options.test_runner_pkg)

    if options.extra_packages:
        targets.extend(options.extra_packages.split(","))

    deps = packaging.get_deps_for_targets(pkg_cfg, targets)
    build = packaging.generate_build_for_target(
        pkg_cfg,
        target,
        deps,
        prefix=unique_prefix,  # used to create resource: URLs
        include_dep_tests=options.dep_tests)

    if 'resources' in build:
        resources = build.resources
        for name in resources:
            resources[name] = os.path.abspath(resources[name])

    harness_contract_id = ('@mozilla.org/harness-service;1?id=%s' % jid)
    harness_options = {
        'bootstrap': {
            'contractID': harness_contract_id,
            'classID': '{%s}' % harness_guid
        },
        'jetpackID': jid,
        'bundleID': bundle_id,
        'staticArgs': options.static_args,
        'name': target,
    }

    harness_options.update(build)

    if command == "test":
        # This should be contained in the test runner package.
        harness_options['main'] = 'run-tests'
    else:
        harness_options['main'] = target_cfg.get('main')

    for option in inherited_options:
        harness_options[option] = getattr(options, option)

    harness_options['metadata'] = packaging.get_metadata(pkg_cfg, deps)

    sdk_version = get_version(env_root)
    harness_options['sdkVersion'] = sdk_version

    packaging.call_plugins(pkg_cfg, deps)

    retval = 0

    if options.templatedir:
        app_extension_dir = os.path.abspath(options.templatedir)
    else:
        mydir = os.path.dirname(os.path.abspath(__file__))
        if sys.platform == "darwin":
            # If we're on OS X, at least point into the XULRunner
            # app dir so we run as a proper app if using XULRunner.
            app_extension_dir = os.path.join(mydir, "Test App.app", "Contents",
                                             "Resources")
        else:
            app_extension_dir = os.path.join(mydir, "app-extension")

    if command == 'xpi':
        from cuddlefish.xpi import build_xpi
        from cuddlefish.rdf import gen_manifest, RDFUpdate

        manifest = gen_manifest(template_root_dir=app_extension_dir,
                                target_cfg=target_cfg,
                                bundle_id=bundle_id,
                                update_url=options.update_url,
                                bootstrap=True)

        if options.update_link:
            rdf_name = UPDATE_RDF_FILENAME % target_cfg.name
            print "Exporting update description to %s." % rdf_name
            update = RDFUpdate()
            update.add(manifest, options.update_link)
            open(rdf_name, "w").write(str(update))

        xpi_name = XPI_FILENAME % target_cfg.name
        print "Exporting extension to %s." % xpi_name
        build_xpi(template_root_dir=app_extension_dir,
                  manifest=manifest,
                  xpi_name=xpi_name,
                  harness_options=harness_options)
    else:
        if options.use_server:
            from cuddlefish.server import run_app
        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,
                             harness_options=harness_options,
                             app_type=options.app,
                             binary=options.binary,
                             profiledir=options.profiledir,
                             verbose=options.verbose,
                             timeout=timeout,
                             logfile=options.logfile,
                             addons=options.addons)
        except Exception, e:
            if str(e).startswith(MOZRUNNER_BIN_NOT_FOUND):
                print >> sys.stderr, MOZRUNNER_BIN_NOT_FOUND_HELP.strip()
                retval = -1
            else:
                raise
예제 #7
0
def run(arguments=sys.argv[1:],
        target_cfg=None,
        pkg_cfg=None,
        defaults=None,
        env_root=os.environ.get('CUDDLEFISH_ROOT')):
    parser_kwargs = dict(arguments=arguments,
                         parser_options=parser_options,
                         parser_groups=parser_groups,
                         usage=usage,
                         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 == "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 == "sdocs":
        import docgen
        import chromeless
        dirname = os.path.join(chromeless.Dirs().build_dir, "docs")
        docgen.generate_static_docs(env_root, dirname)
        print "Created docs in %s." % dirname
        return

    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)

    use_main = False
    if command == "xpcom":
        if 'xpcom' not in target_cfg:
            print >> sys.stderr, "package.json does not have a 'xpcom' entry."
            sys.exit(1)
        if not (options.moz_srcdir and options.moz_objdir):
            print >> sys.stderr, "srcdir and objdir not specified."
            sys.exit(1)
        options.moz_srcdir = os.path.expanduser(options.moz_srcdir)
        options.moz_objdir = os.path.expanduser(options.moz_objdir)
        xpcom = target_cfg.xpcom
        from cuddlefish.xpcom import build_xpcom_components
        if 'typelibs' in xpcom:
            xpt_output_dir = packaging.resolve_dir(target_cfg, xpcom.typelibs)
        else:
            xpt_output_dir = None
        build_xpcom_components(
            comp_src_dir=packaging.resolve_dir(target_cfg, xpcom.src),
            moz_srcdir=options.moz_srcdir,
            moz_objdir=options.moz_objdir,
            base_output_dir=packaging.resolve_dir(target_cfg, xpcom.dest),
            xpt_output_dir=xpt_output_dir,
            module_name=xpcom.module)
        sys.exit(0)
    elif command == "package":
        use_main = True
    elif command == "appify":
        use_main = True
    elif command == "test":
        if 'tests' not in target_cfg:
            target_cfg['tests'] = []
    elif command == "run":
        use_main = True
    else:
        print >> sys.stderr, "Unknown command: %s" % command
        print >> sys.stderr, "Try using '--help' for assistance."
        sys.exit(1)

    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)

    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 ('package', 'run', 'appify'):
        from cuddlefish.preflight import preflight_config
        if target_cfg_json:
            config_was_ok, modified = preflight_config(
                target_cfg,
                target_cfg_json,
                keydir=options.keydir,
                err_if_privkey_not_found=False)
            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
        jid = target_cfg["id"]
        assert not jid.endswith("@jetpack")
        unique_prefix = '%s-' % jid  # used for resource: URLs

        # the harness_guid is used for an XPCOM class ID. We use the
        # JetpackID for the add-on ID and the XPCOM contract ID.
        import uuid
        harness_guid = str(uuid.uuid4())

    else:
        if options.use_server:
            harness_guid = '2974c5b5-b671-46f8-a4bb-63c6eca6261b'
        else:
            harness_guid = '6724fc1b-3ec4-40e2-8583-8061088b3185'
        unique_prefix = '%s-' % target
        jid = harness_guid

    assert not jid.endswith("@jetpack")
    bundle_id = jid + "@jetpack"
    # the resource: URLs prefix is treated too much like a DNS hostname
    unique_prefix = unique_prefix.lower()
    assert "@" not in unique_prefix
    assert "." not in unique_prefix

    timeout = None
    targets = [target]
    if not use_main:
        timeout = TEST_RUN_TIMEOUT
        targets.append(options.test_runner_pkg)

    if options.extra_packages:
        targets.extend(options.extra_packages.split(","))

    deps = packaging.get_deps_for_targets(pkg_cfg, targets)
    build = packaging.generate_build_for_target(
        pkg_cfg,
        target,
        deps,
        prefix=unique_prefix,  # used to create resource: URLs
        include_dep_tests=options.dep_tests)

    if 'resources' in build:
        resources = build.resources
        for name in resources:
            resources[name] = os.path.abspath(resources[name])

    dep_xpt_dirs = []
    for dep in deps:
        dep_cfg = pkg_cfg.packages[dep]
        if 'xpcom' in dep_cfg and 'typelibs' in dep_cfg.xpcom:
            abspath = packaging.resolve_dir(dep_cfg, dep_cfg.xpcom.typelibs)
            dep_xpt_dirs.append(abspath)
    xpts = get_xpts(dep_xpt_dirs)

    harness_contract_id = ('@mozilla.org/harness-service;1?id=%s' % jid)
    harness_options = {
        'bootstrap': {
            'contractID': harness_contract_id,
            'classID': '{%s}' % harness_guid
        },
        'jetpackID': jid,
        'bundleID': bundle_id,
        'staticArgs': options.static_args,
    }

    harness_options.update(build)

    inherited_options = ['verbose']

    if use_main:
        harness_options['main'] = target_cfg.get('main')
    else:
        harness_options['main'] = "run-tests"
        inherited_options.extend(['iterations', 'filter', 'profileMemory'])

    for option in inherited_options:
        harness_options[option] = getattr(options, option)

    harness_options['metadata'] = packaging.get_metadata(pkg_cfg, deps)
    packaging.call_plugins(pkg_cfg, deps)

    retval = 0

    a = appifier.Appifier()

    if command == 'package':
        browser_code_path = json.loads(options.static_args)["browser"]
        a.output_xul_app(browser_code=browser_code_path,
                         harness_options=harness_options,
                         dev_mode=False)

    elif command == 'appify':
        browser_code_path = json.loads(options.static_args)["browser"]
        a.output_application(browser_code=browser_code_path,
                             harness_options=harness_options,
                             dev_mode=False)

    else:
        # on OSX we must invoke xulrunner from within a proper .app bundle,
        # otherwise many basic application features will not work.  For instance
        # keyboard focus and mouse interactions will be broken.
        # for this reason, on OSX we'll actually generate a full standalone
        # application and launch that using the open command.  On other
        # platforms we'll build a xulrunner application (directory) and
        # invoke xulrunner-bin pointing at that.

        browser_code_path = json.loads(options.static_args)["browser"]

        if options.profiledir:
            options.profiledir = os.path.expanduser(options.profiledir)
            options.profiledir = os.path.abspath(options.profiledir)

        if (platform.system() == 'Darwin'):
            # because of the manner in which we run the application, we must use a
            # temporary file to enable console output
            [fd, tmppath] = tempfile.mkstemp()
            os.close(fd)

            print "logging to '%s'" % tmppath
            harness_options['logFile'] = tmppath
            standalone_app_dir = a.output_application(
                browser_code=browser_code_path,
                harness_options=harness_options,
                dev_mode=True)
            print "opening '%s'" % standalone_app_dir

            tailProcess = None
            try:
                tailProcess = subprocess.Popen(["tail", "-f", tmppath])
                retval = subprocess.call(["open", "-W", standalone_app_dir])
            except KeyboardInterrupt:
                print "got ^C, exiting..."
                killProcessByName(standalone_app_dir)
            finally:
                tailProcess.terminate()
                os.remove(tmppath)
        else:
            xul_app_dir = a.output_xul_app(browser_code=browser_code_path,
                                           harness_options=harness_options,
                                           dev_mode=True)

            from cuddlefish.runner import run_app

            if options.addons is not None:
                options.addons = options.addons.split(",")

            try:
                retval = run_app(harness_root_dir=xul_app_dir,
                                 harness_options=harness_options,
                                 xpts=xpts,
                                 app_type=options.app,
                                 binary=options.binary,
                                 profiledir=options.profiledir,
                                 verbose=options.verbose,
                                 timeout=timeout,
                                 logfile=options.logfile,
                                 addons=options.addons)
            except Exception, e:
                if e.message.startswith(MOZRUNNER_BIN_NOT_FOUND):
                    print >> sys.stderr, MOZRUNNER_BIN_NOT_FOUND_HELP.strip()
                    retval = -1
                else:
                    raise
        sys.exit(retval)
예제 #8
0
def run(
    arguments=sys.argv[1:], target_cfg=None, pkg_cfg=None, defaults=None, env_root=os.environ.get("CUDDLEFISH_ROOT")
):
    parser_kwargs = dict(
        arguments=arguments, parser_options=parser_options, parser_groups=parser_groups, usage=usage, 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 == "develop":
        run_development_mode(env_root, defaults=options.__dict__)
        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":
        import subprocess
        import time
        import cuddlefish.server

        print "One moment."
        popen = subprocess.Popen([sys.executable, cuddlefish.server.__file__, "daemonic"])
        # TODO: See if there's actually a way to block on
        # a particular event occurring, rather than this
        # relatively arbitrary/generous amount.
        time.sleep(cuddlefish.server.IDLE_WEBPAGE_TIMEOUT * 2)
        return
    elif command == "sdocs":
        import cuddlefish.server

        # TODO: Allow user to change this filename via cmd line.
        filename = "jetpack-sdk-docs.tgz"
        cuddlefish.server.generate_static_docs(env_root, filename)
        print "Wrote %s." % filename
        return

    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)

    use_main = False
    if command == "xpcom":
        if "xpcom" not in target_cfg:
            print >> sys.stderr, "package.json does not have a 'xpcom' entry."
            sys.exit(1)
        if not (options.moz_srcdir and options.moz_objdir):
            print >> sys.stderr, "srcdir and objdir not specified."
            sys.exit(1)
        options.moz_srcdir = os.path.expanduser(options.moz_srcdir)
        options.moz_objdir = os.path.expanduser(options.moz_objdir)
        xpcom = target_cfg.xpcom
        from cuddlefish.xpcom import build_xpcom_components

        if "typelibs" in xpcom:
            xpt_output_dir = packaging.resolve_dir(target_cfg, xpcom.typelibs)
        else:
            xpt_output_dir = None
        build_xpcom_components(
            comp_src_dir=packaging.resolve_dir(target_cfg, xpcom.src),
            moz_srcdir=options.moz_srcdir,
            moz_objdir=options.moz_objdir,
            base_output_dir=packaging.resolve_dir(target_cfg, xpcom.dest),
            xpt_output_dir=xpt_output_dir,
            module_name=xpcom.module,
        )
        sys.exit(0)
    elif command == "xpi":
        use_main = True
    elif command == "test":
        if "tests" not in target_cfg:
            target_cfg["tests"] = []
    elif command == "run":
        use_main = True
    else:
        print >> sys.stderr, "Unknown command: %s" % command
        print >> sys.stderr, "Try using '--help' for assistance."
        sys.exit(1)

    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)

    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, keydir=options.keydir, err_if_privkey_not_found=False
            )
            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
        jid = target_cfg["id"]
        assert not jid.endswith("@jetpack")
        unique_prefix = "%s-" % jid  # used for resource: URLs

        # the harness_guid is used for an XPCOM class ID. We use the
        # JetpackID for the add-on ID and the XPCOM contract ID.
        import uuid

        harness_guid = str(uuid.uuid4())

    else:
        if options.use_server:
            harness_guid = "2974c5b5-b671-46f8-a4bb-63c6eca6261b"
        else:
            harness_guid = "6724fc1b-3ec4-40e2-8583-8061088b3185"
        unique_prefix = "%s-" % target
        jid = harness_guid

    assert not jid.endswith("@jetpack")
    bundle_id = jid + "@jetpack"
    # the resource: URLs prefix is treated too much like a DNS hostname
    unique_prefix = unique_prefix.lower()
    assert "@" not in unique_prefix
    assert "." not in unique_prefix

    timeout = None
    targets = [target]
    if not use_main:
        timeout = TEST_RUN_TIMEOUT
        targets.append(options.test_runner_pkg)

    if options.extra_packages:
        targets.extend(options.extra_packages.split(","))

    deps = packaging.get_deps_for_targets(pkg_cfg, targets)
    build = packaging.generate_build_for_target(
        pkg_cfg,
        target,
        deps,
        prefix=unique_prefix,  # used to create resource: URLs
        include_dep_tests=options.dep_tests,
    )

    if "resources" in build:
        resources = build.resources
        for name in resources:
            resources[name] = os.path.abspath(resources[name])

    dep_xpt_dirs = []
    for dep in deps:
        dep_cfg = pkg_cfg.packages[dep]
        if "xpcom" in dep_cfg and "typelibs" in dep_cfg.xpcom:
            abspath = packaging.resolve_dir(dep_cfg, dep_cfg.xpcom.typelibs)
            dep_xpt_dirs.append(abspath)
    xpts = get_xpts(dep_xpt_dirs)

    harness_contract_id = "@mozilla.org/harness-service;1?id=%s" % jid
    harness_options = {
        "bootstrap": {"contractID": harness_contract_id, "classID": "{%s}" % harness_guid},
        "jetpackID": jid,
        "bundleID": bundle_id,
    }

    harness_options.update(build)

    inherited_options = ["verbose"]

    if use_main:
        harness_options["main"] = target_cfg.get("main")
    else:
        harness_options["main"] = "run-tests"
        inherited_options.extend(["iterations", "filter", "profileMemory"])

    for option in inherited_options:
        harness_options[option] = getattr(options, option)

    harness_options["metadata"] = packaging.get_metadata(pkg_cfg, deps)
    packaging.call_plugins(pkg_cfg, deps)

    retval = 0

    if options.templatedir:
        app_extension_dir = os.path.abspath(options.templatedir)
    else:
        mydir = os.path.dirname(os.path.abspath(__file__))
        if sys.platform == "darwin":
            # If we're on OS X, at least point into the XULRunner
            # app dir so we run as a proper app if using XULRunner.
            app_extension_dir = os.path.join(mydir, "Test App.app", "Contents", "Resources")
        else:
            app_extension_dir = os.path.join(mydir, "app-extension")

    if command == "xpi":
        from cuddlefish.xpi import build_xpi
        from cuddlefish.rdf import gen_manifest, RDFUpdate

        manifest = gen_manifest(
            template_root_dir=app_extension_dir,
            target_cfg=target_cfg,
            bundle_id=bundle_id,
            update_url=options.update_url,
            bootstrap=True,
        )

        if options.update_link:
            rdf_name = UPDATE_RDF_FILENAME % target_cfg.name
            print "Exporting update description to %s." % rdf_name
            update = RDFUpdate()
            update.add(manifest, options.update_link)
            open(rdf_name, "w").write(str(update))

        xpi_name = XPI_FILENAME % target_cfg.name
        print "Exporting extension to %s." % xpi_name
        build_xpi(
            template_root_dir=app_extension_dir,
            manifest=manifest,
            xpi_name=xpi_name,
            harness_options=harness_options,
            xpts=xpts,
        )
    else:
        if options.use_server:
            from cuddlefish.server import run_app
        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,
                harness_options=harness_options,
                xpts=xpts,
                app_type=options.app,
                binary=options.binary,
                profiledir=options.profiledir,
                verbose=options.verbose,
                timeout=timeout,
                logfile=options.logfile,
                addons=options.addons,
            )
        except Exception, e:
            if e.message.startswith(MOZRUNNER_BIN_NOT_FOUND):
                print >> sys.stderr, MOZRUNNER_BIN_NOT_FOUND_HELP.strip()
                retval = -1
            else:
                raise
예제 #9
0
def run(
    arguments=sys.argv[1:],
    target_cfg=None,
    pkg_cfg=None,
    defaults=None,
    env_root=os.environ.get("CUDDLEFISH_ROOT"),
    stdout=sys.stdout,
):
    parser_kwargs = dict(
        arguments=arguments, global_options=global_options, parser_groups=parser_groups, usage=usage, 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 == "develop":
        run_development_mode(env_root, defaults=options.__dict__)
        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":
        import subprocess
        import time
        import cuddlefish.server

        print >> stdout, "One moment."
        popen = subprocess.Popen([sys.executable, cuddlefish.server.__file__, "daemonic"])
        # TODO: See if there's actually a way to block on
        # a particular event occurring, rather than this
        # relatively arbitrary/generous amount.
        time.sleep(cuddlefish.server.IDLE_WEBPAGE_TIMEOUT * 2)
        return
    elif command == "sdocs":
        import cuddlefish.server

        # TODO: Allow user to change this filename via cmd line.
        filename = "addon-sdk-docs.tgz"
        cuddlefish.server.generate_static_docs(env_root, filename, options.baseurl)
        print >> stdout, "Wrote %s." % filename
        return

    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
    timeout = None
    inherited_options = ["verbose", "enable_e10s"]

    if command == "xpi":
        use_main = True
    elif command == "test":
        if "tests" not in target_cfg:
            target_cfg["tests"] = []
        timeout = TEST_RUN_TIMEOUT
        inherited_options.extend(["iterations", "filter", "profileMemory"])
    elif command == "run":
        use_main = True
    else:
        print >> sys.stderr, "Unknown command: %s" % command
        print >> sys.stderr, "Try using '--help' for assistance."
        sys.exit(1)

    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

    # the harness_guid is used for an XPCOM class ID. We use the
    # JetpackID for the add-on ID and the XPCOM contract ID.
    if "harnessClassID" in target_cfg:
        # For the sake of non-bootstrapped extensions, we allow to specify the
        # classID of harness' XPCOM component in package.json. This makes it
        # possible to register the component using a static chrome.manifest file
        harness_guid = target_cfg["harnessClassID"]
    else:
        import uuid

        harness_guid = str(uuid.uuid4())

    # 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"

    if "id" in target_cfg:
        jid = target_cfg["id"]
        if not ("@" in jid or jid.startswith("{")):
            jid = jid + "@jetpack"
        unique_prefix = "%s-" % jid  # used for resource: URLs
    else:
        # The Jetpack ID is not required for cfx test, in which case we have to
        # make one up based on the GUID.
        if options.use_server:
            # The harness' contractID (hence also the jid and the harness_guid)
            # need to be static in the "development mode", so that bootstrap.js
            # can unload the previous version of the package being developed.
            harness_guid = "2974c5b5-b671-46f8-a4bb-63c6eca6261b"
        unique_prefix = "%s-" % target
        jid = harness_guid

    bundle_id = jid

    # the resource: URL's prefix is treated too much like a DNS hostname
    unique_prefix = unique_prefix.lower()
    unique_prefix = unique_prefix.replace("@", "-at-")
    unique_prefix = unique_prefix.replace(".", "-dot-")

    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

    uri_prefix = "resource://%s" % unique_prefix
    # 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 URI 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)]
    manifest = build_manifest(target_cfg, pkg_cfg, deps, uri_prefix, False, loader_modules)
    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,
        prefix=unique_prefix,  # used to create resource: URLs
        include_dep_tests=options.dep_tests,
    )

    if "resources" in build:
        resources = build.resources
        for name in resources:
            resources[name] = os.path.abspath(resources[name])

    harness_contract_id = "@mozilla.org/harness-service;1?id=%s" % jid
    harness_options = {
        "bootstrap": {"contractID": harness_contract_id, "classID": "{%s}" % harness_guid},
        "jetpackID": jid,
        "bundleID": bundle_id,
        "uriPrefix": uri_prefix,
        "staticArgs": options.static_args,
        "name": target,
    }

    harness_options.update(build)

    if command == "test":
        # This should be contained in the test runner package.
        harness_options["main"] = "run-tests"
    else:
        harness_options["main"] = target_cfg.get("main")

    for option in inherited_options:
        harness_options[option] = getattr(options, option)

    harness_options["metadata"] = packaging.get_metadata(pkg_cfg, used_deps)

    sdk_version = get_version(env_root)
    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__))
        if sys.platform == "darwin":
            # If we're on OS X, at least point into the XULRunner
            # app dir so we run as a proper app if using XULRunner.
            app_extension_dir = os.path.join(mydir, "Test App.app", "Contents", "Resources")
        else:
            app_extension_dir = os.path.join(mydir, "app-extension")

    harness_options["manifest"] = manifest.get_harness_options_manifest(uri_prefix)

    if command == "xpi":
        from cuddlefish.xpi import build_xpi
        from cuddlefish.rdf import gen_manifest, RDFUpdate

        manifest_rdf = gen_manifest(
            template_root_dir=app_extension_dir,
            target_cfg=target_cfg,
            bundle_id=bundle_id,
            update_url=options.update_url,
            bootstrap=True,
        )

        if 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 = set(manifest.get_used_files())

        if not options.strip_xpi:
            used_files = None  # disables the filter

        xpi_name = XPI_FILENAME % target_cfg.name
        print >> stdout, "Exporting extension to %s." % xpi_name
        build_xpi(
            template_root_dir=app_extension_dir,
            manifest=manifest_rdf,
            xpi_name=xpi_name,
            harness_options=harness_options,
            limit_to=used_files,
        )
    else:
        if options.use_server:
            from cuddlefish.server import run_app
        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,
                harness_options=harness_options,
                app_type=options.app,
                binary=options.binary,
                profiledir=options.profiledir,
                verbose=options.verbose,
                timeout=timeout,
                logfile=options.logfile,
                addons=options.addons,
                args=options.cmdargs,
                norun=options.no_run,
            )
        except Exception, e:
            if str(e).startswith(MOZRUNNER_BIN_NOT_FOUND):
                print >> sys.stderr, MOZRUNNER_BIN_NOT_FOUND_HELP.strip()
                retval = -1
            else:
                raise
예제 #10
0
    def test_preflight(self):
        basedir = self.make_basedir()
        fn = os.path.join(basedir, "package.json")

        # empty config is not ok: need id (name is automatically supplied)
        config_orig = "{}"
        self.write(config_orig)
        out = StringIO()
        cfg = self.get_cfg()
        config_was_ok, modified = preflight.preflight_config(cfg, fn,
                                                             stderr=out)
        self.failUnlessEqual(config_was_ok, False)
        self.failUnlessEqual(modified, True)
        backup_fn = os.path.join(basedir, "package.json.backup")
        config_backup = open(backup_fn,"r").read()
        self.failUnlessEqual(config_backup, config_orig)
        config = json.loads(self.read())
        self.failIf("name" in config)
        self.failUnless("id" in config)
        self.failUnless(config["id"].startswith("jid1-"), config["id"])
        self.failUnlessEqual(out.getvalue().strip(),
                             "No 'id' in package.json: creating a new ID for you.")
        os.unlink(backup_fn)

        # just a name? we add the id
        config_orig = '{"name": "my-awesome-package"}'
        self.write(config_orig)
        out = StringIO()
        cfg = self.get_cfg()
        config_was_ok, modified = preflight.preflight_config(cfg, fn,
                                                             stderr=out)
        self.failUnlessEqual(config_was_ok, False)
        self.failUnlessEqual(modified, True)
        backup_fn = os.path.join(basedir, "package.json.backup")
        config_backup = open(backup_fn,"r").read()
        self.failUnlessEqual(config_backup, config_orig)
        config = json.loads(self.read())
        self.failUnlessEqual(config["name"], "my-awesome-package")
        self.failUnless("id" in config)
        self.failUnless(config["id"].startswith("jid1-"), config["id"])
        jid = str(config["id"])
        self.failUnlessEqual(out.getvalue().strip(),
                             "No 'id' in package.json: creating a new ID for you.")
        os.unlink(backup_fn)

        # name and valid id? great! ship it!
        config2 = '{"name": "my-awesome-package", "id": "%s"}' % jid
        self.write(config2)
        out = StringIO()
        cfg = self.get_cfg()
        config_was_ok, modified = preflight.preflight_config(cfg, fn,
                                                             stderr=out)
        self.failUnlessEqual(config_was_ok, True)
        self.failUnlessEqual(modified, False)
        config2a = self.read()
        self.failUnlessEqual(config2a, config2)
        self.failUnlessEqual(out.getvalue().strip(), "")

        # name and anonymous ID? without asking to see its papers, ship it
        config3 = '{"name": "my-old-skool-package", "id": "anonid0-deadbeef"}'
        self.write(config3)
        out = StringIO()
        cfg = self.get_cfg()
        config_was_ok, modified = preflight.preflight_config(cfg, fn,
                                                             stderr=out)
        self.failUnlessEqual(config_was_ok, True)
        self.failUnlessEqual(modified, False)
        config3a = self.read()
        self.failUnlessEqual(config3a, config3)
        self.failUnlessEqual(out.getvalue().strip(), "")

        # name and old-style ID? with nostalgic trepidation, ship it
        config4 = '{"name": "my-old-skool-package", "id": "*****@*****.**"}'
        self.write(config4)
        out = StringIO()
        cfg = self.get_cfg()
        config_was_ok, modified = preflight.preflight_config(cfg, fn,
                                                             stderr=out)
        self.failUnlessEqual(config_was_ok, True)
        self.failUnlessEqual(modified, False)
        config4a = self.read()
        self.failUnlessEqual(config4a, config4)
        self.failUnlessEqual(out.getvalue().strip(), "")
예제 #11
0
def run(arguments=sys.argv[1:], target_cfg=None, pkg_cfg=None,
        defaults=None, env_root=os.environ.get('CUDDLEFISH_ROOT'),
        stdout=sys.stdout):
    parser_kwargs = dict(arguments=arguments,
                         global_options=global_options,
                         parser_groups=parser_groups,
                         usage=usage,
                         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_docs(env_root, filename=args[1])
        else:
            docs_home = generate.generate_docs(env_root)
        webbrowser.open(docs_home)
        return
    elif command == "sdocs":
        from cuddlefish.docs import generate

        # TODO: Allow user to change this filename via cmd line.
        filename = generate.generate_static_docs(env_root, base_url=options.baseurl)
        print >>stdout, "Wrote %s." % filename
        return

    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'])
        enforce_timeouts = True
    elif command == "run":
        use_main = True
    else:
        print >>sys.stderr, "Unknown command: %s" % command
        print >>sys.stderr, "Try using '--help' for assistance."
        sys.exit(1)

    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

    # the harness_guid is used for an XPCOM class ID. We use the
    # JetpackID for the add-on ID and the XPCOM contract ID.
    if "harnessClassID" in target_cfg:
        # For the sake of non-bootstrapped extensions, we allow to specify the
        # classID of harness' XPCOM component in package.json. This makes it
        # possible to register the component using a static chrome.manifest file
        harness_guid = target_cfg["harnessClassID"]
    else:
        import uuid
        harness_guid = str(uuid.uuid4())

    # 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"

    if "id" in target_cfg:
        jid = target_cfg["id"]
    else:
        jid = harness_guid
    if not ("@" in jid or jid.startswith("{")):
        jid = jid + "@jetpack"
    unique_prefix = '%s-' % jid # used for resource: URLs
    bundle_id = jid

    # the resource: URL's prefix is treated too much like a DNS hostname
    unique_prefix = unique_prefix.lower()
    unique_prefix = unique_prefix.replace("@", "-at-")
    unique_prefix = unique_prefix.replace(".", "-dot-")

    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
    uri_prefix = "resource://%s" % unique_prefix
    # 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 URI 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"
    try:
        manifest = build_manifest(target_cfg, pkg_cfg, deps, uri_prefix, scan_tests,
                                  loader_modules)
    except ModuleNotFoundError, e:
        print str(e)
        sys.exit(1)
예제 #12
0
    def test_preflight(self):
        basedir = self.make_basedir()
        fn = os.path.join(basedir, "package.json")
        keydir = os.path.join(basedir, "keys")

        # empty config is not ok: need id (name is automatically supplied)
        config_orig = "{}"
        self.write(config_orig)
        out = StringIO()
        cfg = self.get_cfg()
        config_was_ok, modified = preflight.preflight_config(cfg, fn,
                                                             stderr=out,
                                                             keydir=keydir)
        self.failUnlessEqual(config_was_ok, False)
        self.failUnlessEqual(modified, True)
        backup_fn = os.path.join(basedir, "package.json.backup")
        config_backup = open(backup_fn,"r").read()
        self.failUnlessEqual(config_backup, config_orig)
        config = json.loads(self.read())
        self.failIf("name" in config)
        self.failUnless("id" in config)
        self.failUnlessEqual(out.getvalue().strip(),
                             "No 'id' in package.json: creating a new keypair for you.")
        jid = str(config["id"])
        keyfile = os.path.join(keydir, jid)
        fields, fieldnames = self.parse(open(keyfile).read())
        self.failUnlessEqual(fieldnames[0], "private-key")
        privkey = fields["private-key"]
        self.failUnless(privkey.startswith("private-jid0-"), privkey)
        self.failUnlessEqual(fields["jid"], jid)
        self.failUnlessEqual(fields["name"], "pretend name")
        os.unlink(backup_fn)

        # just a name? we add the id
        config_orig = '{"name": "my-awesome-package"}'
        self.write(config_orig)
        out = StringIO()
        cfg = self.get_cfg()
        config_was_ok, modified = preflight.preflight_config(cfg, fn,
                                                             stderr=out,
                                                             keydir=keydir)
        self.failUnlessEqual(config_was_ok, False)
        self.failUnlessEqual(modified, True)
        backup_fn = os.path.join(basedir, "package.json.backup")
        config_backup = open(backup_fn,"r").read()
        self.failUnlessEqual(config_backup, config_orig)
        config = json.loads(self.read())
        self.failUnlessEqual(config["name"], "my-awesome-package")
        self.failUnless("id" in config)
        self.failUnlessEqual(out.getvalue().strip(),
                             "No 'id' in package.json: creating a new keypair for you.")
        jid = str(config["id"])
        keyfile = os.path.join(keydir, jid)
        fields, fieldnames = self.parse(open(keyfile).read())
        privkey = fields["private-key"]
        self.failUnless(privkey.startswith("private-jid0-"), privkey)
        self.failUnlessEqual(fields["jid"], jid)
        self.failUnlessEqual(fields["name"], "my-awesome-package")

        # name and valid id? great! ship it!
        config2 = '{"name": "my-awesome-package", "id": "%s"}' % jid
        self.write(config2)
        out = StringIO()
        cfg = self.get_cfg()
        config_was_ok, modified = preflight.preflight_config(cfg, fn,
                                                             stderr=out,
                                                             keydir=keydir)
        self.failUnlessEqual(config_was_ok, True)
        self.failUnlessEqual(modified, False)
        config2a = self.read()
        self.failUnlessEqual(config2a, config2)
        self.failUnlessEqual(out.getvalue().strip(), "")

        # name and invalid id? tell them to get a new one
        os.unlink(keyfile)
        self.write(config2)
        out = StringIO()
        cfg = self.get_cfg()
        config_was_ok, modified = preflight.preflight_config(cfg, fn,
                                                             stderr=out,
                                                             keydir=keydir)
        self.failUnlessEqual(config_was_ok, False)
        self.failUnlessEqual(modified, False)
        out = out.getvalue().strip()
        self.failUnless("Your package.json says our ID is" in out, out)
        self.failUnless("But I don't have a corresponding private key in"
                        in out, out)
        self.failUnless("If you are the original developer" in out, out)
        self.failUnless("Otherwise, if you are a new developer" in out, out)

        # name and anonymous ID? without asking to see its papers, ship it
        config3 = '{"name": "my-old-skool-package", "id": "anonid0-deadbeef"}'
        self.write(config3)
        out = StringIO()
        cfg = self.get_cfg()
        config_was_ok, modified = preflight.preflight_config(cfg, fn,
                                                             stderr=out,
                                                             keydir=keydir,
                                                             err_if_privkey_not_found=False)
        self.failUnlessEqual(config_was_ok, True)
        self.failUnlessEqual(modified, False)
        config3a = self.read()
        self.failUnlessEqual(config3a, config3)
        self.failUnlessEqual(out.getvalue().strip(), "")

        # name and old-style ID? with nostalgic trepidation, ship it
        config4 = '{"name": "my-old-skool-package", "id": "*****@*****.**"}'
        self.write(config4)
        out = StringIO()
        cfg = self.get_cfg()
        config_was_ok, modified = preflight.preflight_config(cfg, fn,
                                                             stderr=out,
                                                             keydir=keydir,
                                                             err_if_privkey_not_found=False)
        self.failUnlessEqual(config_was_ok, True)
        self.failUnlessEqual(modified, False)
        config4a = self.read()
        self.failUnlessEqual(config4a, config4)
        self.failUnlessEqual(out.getvalue().strip(), "")
예제 #13
0
def run(arguments=sys.argv[1:], target_cfg=None, pkg_cfg=None,
        defaults=None, env_root=os.environ.get('CUDDLEFISH_ROOT')):
    parser_kwargs = dict(arguments=arguments,
                         parser_options=parser_options,
                         parser_groups=parser_groups,
                         usage=usage,
                         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 == "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 == "sdocs":
        import docgen
        import chromeless
        dirname = os.path.join(chromeless.Dirs().build_dir, "docs")
        docgen.generate_static_docs(env_root, dirname)
        print "Created docs in %s." % dirname
        return

    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)

    use_main = False
    if command == "xpcom":
        if 'xpcom' not in target_cfg:
            print >>sys.stderr, "package.json does not have a 'xpcom' entry."
            sys.exit(1)
        if not (options.moz_srcdir and options.moz_objdir):
            print >>sys.stderr, "srcdir and objdir not specified."
            sys.exit(1)
        options.moz_srcdir = os.path.expanduser(options.moz_srcdir)
        options.moz_objdir = os.path.expanduser(options.moz_objdir)
        xpcom = target_cfg.xpcom
        from cuddlefish.xpcom import build_xpcom_components
        if 'typelibs' in xpcom:
            xpt_output_dir = packaging.resolve_dir(target_cfg,
                                                   xpcom.typelibs)
        else:
            xpt_output_dir = None
        build_xpcom_components(
            comp_src_dir=packaging.resolve_dir(target_cfg, xpcom.src),
            moz_srcdir=options.moz_srcdir,
            moz_objdir=options.moz_objdir,
            base_output_dir=packaging.resolve_dir(target_cfg, xpcom.dest),
            xpt_output_dir=xpt_output_dir,
            module_name=xpcom.module
            )
        sys.exit(0)
    elif command == "package":
        use_main = True
    elif command == "appify":
        use_main = True
    elif command == "test":
        if 'tests' not in target_cfg:
            target_cfg['tests'] = []
    elif command == "run":
        use_main = True
    else:
        print >>sys.stderr, "Unknown command: %s" % command
        print >>sys.stderr, "Try using '--help' for assistance."
        sys.exit(1)

    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)

    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 ('package', 'run', 'appify'):
        from cuddlefish.preflight import preflight_config
        if target_cfg_json:
            config_was_ok, modified = preflight_config(
                target_cfg,
                target_cfg_json,
                keydir=options.keydir,
                err_if_privkey_not_found=False
                )
            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
        jid = target_cfg["id"]
        assert not jid.endswith("@jetpack")
        unique_prefix = '%s-' % jid # used for resource: URLs

        # the harness_guid is used for an XPCOM class ID. We use the
        # JetpackID for the add-on ID and the XPCOM contract ID.
        import uuid
        harness_guid = str(uuid.uuid4())

    else:
        if options.use_server:
            harness_guid = '2974c5b5-b671-46f8-a4bb-63c6eca6261b'
        else:
            harness_guid = '6724fc1b-3ec4-40e2-8583-8061088b3185'
        unique_prefix = '%s-' % target
        jid = harness_guid

    assert not jid.endswith("@jetpack")
    bundle_id = jid + "@jetpack"
    # the resource: URLs prefix is treated too much like a DNS hostname
    unique_prefix = unique_prefix.lower()
    assert "@" not in unique_prefix
    assert "." not in unique_prefix

    timeout = None
    targets = [target]
    if not use_main:
        timeout = TEST_RUN_TIMEOUT
        targets.append(options.test_runner_pkg)

    if options.extra_packages:
        targets.extend(options.extra_packages.split(","))

    deps = packaging.get_deps_for_targets(pkg_cfg, targets)
    build = packaging.generate_build_for_target(
        pkg_cfg, target, deps,
        prefix=unique_prefix,  # used to create resource: URLs
        include_dep_tests=options.dep_tests
        )

    if 'resources' in build:
        resources = build.resources
        for name in resources:
            resources[name] = os.path.abspath(resources[name])

    dep_xpt_dirs = []
    for dep in deps:
        dep_cfg = pkg_cfg.packages[dep]
        if 'xpcom' in dep_cfg and 'typelibs' in dep_cfg.xpcom:
            abspath = packaging.resolve_dir(dep_cfg,
                                            dep_cfg.xpcom.typelibs)
            dep_xpt_dirs.append(abspath)
    xpts = get_xpts(dep_xpt_dirs)

    harness_contract_id = ('@mozilla.org/harness-service;1?id=%s' % jid)
    harness_options = {
        'bootstrap': {
            'contractID': harness_contract_id,
            'classID': '{%s}' % harness_guid
            },
        'jetpackID': jid,
        'bundleID': bundle_id,
        'staticArgs': options.static_args,
        }

    harness_options.update(build)

    inherited_options = ['verbose']

    if use_main:
        harness_options['main'] = target_cfg.get('main')
    else:
        harness_options['main'] = "run-tests"
        inherited_options.extend(['iterations', 'filter', 'profileMemory'])

    for option in inherited_options:
        harness_options[option] = getattr(options, option)

    harness_options['metadata'] = packaging.get_metadata(pkg_cfg, deps)
    packaging.call_plugins(pkg_cfg, deps)

    retval = 0

    a = appifier.Appifier()

    if command == 'package':
        browser_code_path = json.loads(options.static_args)["browser"]
        a.output_xul_app(browser_code=browser_code_path,
                         harness_options=harness_options,
                         dev_mode=False)

    elif command == 'appify':
        browser_code_path = json.loads(options.static_args)["browser"]
        a.output_application(browser_code=browser_code_path,
                             harness_options=harness_options,
                             dev_mode=False)
      
    else:
        # on OSX we must invoke xulrunner from within a proper .app bundle,
        # otherwise many basic application features will not work.  For instance
        # keyboard focus and mouse interactions will be broken.
        # for this reason, on OSX we'll actually generate a full standalone
        # application and launch that using the open command.  On other
        # platforms we'll build a xulrunner application (directory) and
        # invoke xulrunner-bin pointing at that. 

        browser_code_path = json.loads(options.static_args)["browser"]

        if options.profiledir:
            options.profiledir = os.path.expanduser(options.profiledir)
            options.profiledir = os.path.abspath(options.profiledir)

        if (platform.system() == 'Darwin'): 
            # because of the manner in which we run the application, we must use a
            # temporary file to enable console output
            [fd, tmppath] = tempfile.mkstemp()
            os.close(fd)

            print "logging to '%s'" % tmppath
            harness_options['logFile'] = tmppath
            standalone_app_dir = a.output_application(browser_code=browser_code_path,
                                                      harness_options=harness_options,
                                                      dev_mode=True)
            print "opening '%s'" % standalone_app_dir

            tailProcess = None
            try:
                tailProcess = subprocess.Popen(["tail", "-f", tmppath])
                retval = subprocess.call(["open", "-W", standalone_app_dir])
            except KeyboardInterrupt:
                print "got ^C, exiting..."
                killProcessByName(standalone_app_dir)
            finally:
                tailProcess.terminate()
                os.remove(tmppath)
        else:
            xul_app_dir = a.output_xul_app(browser_code=browser_code_path,
                                           harness_options=harness_options,
                                           dev_mode=True)

            from cuddlefish.runner import run_app

            if options.addons is not None:
                options.addons = options.addons.split(",")

            try:
                retval = run_app(harness_root_dir=xul_app_dir,
                                 harness_options=harness_options,
                                 xpts=xpts,
                                 app_type=options.app,
                                 binary=options.binary,
                                 profiledir=options.profiledir,
                                 verbose=options.verbose,
                                 timeout=timeout,
                                 logfile=options.logfile,
                                 addons=options.addons)
            except Exception, e:
                if e.message.startswith(MOZRUNNER_BIN_NOT_FOUND):
                    print >>sys.stderr, MOZRUNNER_BIN_NOT_FOUND_HELP.strip()
                    retval = -1
                else:
                    raise
        sys.exit(retval)
예제 #14
0
def run(arguments=sys.argv[1:],
        target_cfg=None,
        pkg_cfg=None,
        defaults=None,
        env_root=os.environ.get('CUDDLEFISH_ROOT')):
    parser_kwargs = dict(arguments=arguments,
                         global_options=global_options,
                         parser_groups=parser_groups,
                         usage=usage,
                         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 == "sdocs":
        import docgen
        import chromeless
        dirname = os.path.join(chromeless.Dirs().build_dir, "docs")
        docgen.generate_static_docs(env_root, dirname)
        print "Created docs in %s." % dirname
        return

    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
    timeout = None
    inherited_options = ['verbose', 'enable_e10s']

    if command == "xpi":
        use_main = True
    if command == "appify":
        use_main = True
    elif command == "test":
        if 'tests' not in target_cfg:
            target_cfg['tests'] = []
        timeout = TEST_RUN_TIMEOUT
        inherited_options.extend(['iterations', 'filter', 'profileMemory'])
    elif command == "run":
        use_main = True
    else:
        print >> sys.stderr, "Unknown command: %s" % command
        print >> sys.stderr, "Try using '--help' for assistance."
        sys.exit(1)

    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)

    target = target_cfg.name

    # the harness_guid is used for an XPCOM class ID. We use the
    # JetpackID for the add-on ID and the XPCOM contract ID.
    if "harnessClassID" in target_cfg:
        # For the sake of non-bootstrapped extensions, we allow to specify the
        # classID of harness' XPCOM component in package.json. This makes it
        # possible to register the component using a static chrome.manifest file
        harness_guid = target_cfg["harnessClassID"]
    else:
        import uuid
        harness_guid = str(uuid.uuid4())

    # TODO: Consider keeping a cache of dynamic UUIDs, based
    # on absolute filesystem pathname, in the root directory
    # or something.
    if command in ('xpi', 'run', 'appify'):
        from cuddlefish.preflight import preflight_config
        if target_cfg_json:
            config_was_ok, modified = preflight_config(
                target_cfg,
                target_cfg_json,
                keydir=options.keydir,
                err_if_privkey_not_found=False)
            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"

    if "id" in target_cfg:
        jid = target_cfg["id"]
        assert not jid.endswith("@jetpack")
        unique_prefix = '%s-' % jid  # used for resource: URLs
    else:
        unique_prefix = '%s-' % target
        jid = harness_guid

    assert not jid.endswith("@jetpack")
    if (jid.startswith("jid0-") or jid.startswith("anonid0-")):
        bundle_id = jid + "@jetpack"
    # Don't append "@jetpack" to old-style IDs, as they should be exactly
    # as specified by the addon author so AMO and Firefox continue to treat
    # their addon bundles as representing the same addon (and also because
    # they may already have an @ sign in them, and there can be only one).
    else:
        bundle_id = jid

    # the resource: URL's prefix is treated too much like a DNS hostname
    unique_prefix = unique_prefix.lower()
    unique_prefix = unique_prefix.replace("@", "-at-")
    unique_prefix = unique_prefix.replace(".", "-dot-")

    targets = [target]
    if command == "test":
        targets.append(options.test_runner_pkg)

    if options.extra_packages:
        targets.extend(options.extra_packages.split(","))

    deps = packaging.get_deps_for_targets(pkg_cfg, targets)
    build = packaging.generate_build_for_target(
        pkg_cfg,
        target,
        deps,
        prefix=unique_prefix,  # used to create resource: URLs
        include_dep_tests=options.dep_tests)

    if 'resources' in build:
        resources = build.resources
        for name in resources:
            resources[name] = os.path.abspath(resources[name])

    harness_contract_id = ('@mozilla.org/harness-service;1?id=%s' % jid)
    harness_options = {
        'bootstrap': {
            'contractID': harness_contract_id,
            'classID': '{%s}' % harness_guid
        },
        'jetpackID': jid,
        'bundleID': bundle_id,
        'staticArgs': options.static_args,
    }

    harness_options.update(build)

    if command == "test":
        # This should be contained in the test runner package.
        harness_options['main'] = 'run-tests'
    else:
        harness_options['main'] = target_cfg.get('main')

    for option in inherited_options:
        harness_options[option] = getattr(options, option)

    harness_options['metadata'] = packaging.get_metadata(pkg_cfg, deps)

    #sdk_version = get_version(env_root)
    #harness_options['sdkVersion'] = sdk_version

    packaging.call_plugins(pkg_cfg, deps)

    retval = 0

    a = appifier.Appifier()

    if command == 'package':
        browser_code_path = options.static_args["browser"]
        a.output_xul_app(browser_code=browser_code_path,
                         harness_options=harness_options,
                         dev_mode=False)
    elif command == 'appify':
        browser_code_path = options.static_args["browser"]
        a.output_application(browser_code=browser_code_path,
                             harness_options=harness_options,
                             dev_mode=False)

    if command == 'run':
        browser_code_path = options.static_args["browser"]

        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(",")

        if (platform.system() == 'Darwin'):
            # because of the manner in which we run the application, we mus t use a
            # temporary file to enable console output
            [fd, tmppath] = tempfile.mkstemp()
            os.close(fd)

            print "__init__: tmppath" + tmppath
            print "__init__: browser code path: " + browser_code_path
            print "And logging to '%s'" % tmppath

            harness_options['logFile'] = tmppath

            standalone_app_dir = a.output_application(
                browser_code=browser_code_path,
                harness_options=harness_options,
                dev_mode=True)
            print "opening '%s'" % standalone_app_dir

            tailProcess = None
            try:
                import subprocess
                tailProcess = subprocess.Popen(["tail", "-f", tmppath])
                retval = subprocess.call(["open", "-W", standalone_app_dir])
            except KeyboardInterrupt:
                print "got ^C, exiting..."
                killProcessByName(standalone_app_dir)
            finally:
                tailProcess.terminate()
                os.remove(tmppath)
    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(",")

        app_extension_dir = os.path.join(env_root, "impl", "appifier",
                                         "resources", "xulrunner.template")
        try:
            retval = run_app(harness_root_dir=app_extension_dir,
                             harness_options=harness_options,
                             app_type=options.app,
                             binary=options.binary,
                             profiledir=options.profiledir,
                             verbose=options.verbose,
                             timeout=timeout,
                             logfile=options.logfile,
                             addons=options.addons)
        except Exception, e:
            if str(e).startswith(MOZRUNNER_BIN_NOT_FOUND):
                print >> sys.stderr, MOZRUNNER_BIN_NOT_FOUND_HELP.strip()
                retval = -1
            else:
                raise
예제 #15
0
def run(arguments=sys.argv[1:], target_cfg=None, pkg_cfg=None,
        defaults=None, env_root=os.environ.get('CUDDLEFISH_ROOT')):
    parser_kwargs = dict(arguments=arguments,
                         global_options=global_options,
                         parser_groups=parser_groups,
                         usage=usage,
                         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 == "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 == "sdocs":
        import docgen
        import chromeless
        dirname = os.path.join(chromeless.Dirs().build_dir, "docs")
        docgen.generate_static_docs(env_root, dirname)
        print "Created docs in %s." % dirname
        return

    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
    timeout = None
    inherited_options = ['verbose', 'enable_e10s']

    if command in ("run", "package", "appify"):
        use_main = True
    elif command == "test":
        if 'tests' not in target_cfg:
            target_cfg['tests'] = []
        timeout = TEST_RUN_TIMEOUT
        inherited_options.extend(['iterations', 'filter', 'profileMemory'])
    else:
        print >>sys.stderr, "Unknown command: %s" % command
        print >>sys.stderr, "Try using '--help' for assistance."
        sys.exit(1)

    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)

    target = target_cfg.name

    # the harness_guid is used for an XPCOM class ID. We use the
    # JetpackID for the add-on ID and the XPCOM contract ID.
    if "harnessClassID" in target_cfg:
        # For the sake of non-bootstrapped extensions, we allow to specify the
        # classID of harness' XPCOM component in package.json. This makes it
        # possible to register the component using a static chrome.manifest file
        harness_guid = target_cfg["harnessClassID"]
    else:
        import uuid
        harness_guid = str(uuid.uuid4())

    # TODO: Consider keeping a cache of dynamic UUIDs, based
    # on absolute filesystem pathname, in the root directory
    # or something.
    if command in ('package', 'run', 'appify'):
        from cuddlefish.preflight import preflight_config
        if target_cfg_json:
            config_was_ok, modified = preflight_config(
                target_cfg,
                target_cfg_json,
                keydir=options.keydir,
                err_if_privkey_not_found=False
                )
            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"

    if "id" in target_cfg:
        jid = target_cfg["id"]
        assert not jid.endswith("@jetpack")
        unique_prefix = '%s-' % jid # used for resource: URLs
    else:
        unique_prefix = '%s-' % target
        jid = harness_guid

    assert not jid.endswith("@jetpack")
    if (jid.startswith("jid0-") or jid.startswith("anonid0-")):
        bundle_id = jid + "@jetpack"
    # Don't append "@jetpack" to old-style IDs, as they should be exactly
    # as specified by the addon author so AMO and Firefox continue to treat
    # their addon bundles as representing the same addon (and also because
    # they may already have an @ sign in them, and there can be only one).
    else:
        bundle_id = jid

    # the resource: URL's prefix is treated too much like a DNS hostname
    unique_prefix = unique_prefix.lower()
    unique_prefix = unique_prefix.replace("@", "-at-")
    unique_prefix = unique_prefix.replace(".", "-dot-")

    targets = [target]
    if command == "test":
        targets.append(options.test_runner_pkg)

    if options.extra_packages:
        targets.extend(options.extra_packages.split(","))

    deps = packaging.get_deps_for_targets(pkg_cfg, targets)
    build = packaging.generate_build_for_target(
        pkg_cfg, target, deps,
        prefix=unique_prefix,  # used to create resource: URLs
        include_dep_tests=options.dep_tests
        )

    if 'resources' in build:
        resources = build.resources
        for name in resources:
            resources[name] = os.path.abspath(resources[name])

    harness_contract_id = ('@mozilla.org/harness-service;1?id=%s' % jid)
    harness_options = {
        'bootstrap': {
            'contractID': harness_contract_id,
            'classID': '{%s}' % harness_guid
            },
        'jetpackID': jid,
        'bundleID': bundle_id,
        'staticArgs': options.static_args,
        }

    harness_options.update(build)

    if command == "test":
        # This should be contained in the test runner package.
        harness_options['main'] = 'run-tests'
    else:
        harness_options['main'] = target_cfg.get('main')

    for option in inherited_options:
        harness_options[option] = getattr(options, option)

    harness_options['metadata'] = packaging.get_metadata(pkg_cfg, deps)

    #sdk_version = get_version(env_root)
    #harness_options['sdkVersion'] = sdk_version

    packaging.call_plugins(pkg_cfg, deps)

    retval = 0

    a = appifier.Appifier()

    if command == 'package':
       browser_code_path = options.static_args["browser"]
       a.output_xul_app(browser_code=browser_code_path,
                        harness_options=harness_options,
                        dev_mode=False)
    elif command == 'appify':
        browser_code_path = options.static_args["browser"]
        a.output_application(browser_code=browser_code_path,
                             harness_options=harness_options,
                             dev_mode=False)

    else: 
        browser_code_path = options.static_args["browser"]

        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(",")

        if (platform.system() == 'Darwin'):
            # because of the manner in which we run the application, we mus t use a
            # temporary file to enable console output
            [fd, tmppath] = tempfile.mkstemp()
            os.close(fd)

            print "__init__: tmppath" + tmppath;
            print "__init__: browser code path: " + browser_code_path
            print "And logging to '%s'" % tmppath

            harness_options['logFile'] = tmppath

            standalone_app_dir = a.output_application(browser_code=browser_code_path, harness_options=harness_options, dev_mode=True, verbose=False)
            print "opening '%s'" % standalone_app_dir

            tailProcess = None
            try:
		import subprocess
                tailProcess = subprocess.Popen(["tail", "-f", tmppath])
                retval = subprocess.call(["open", "-W", standalone_app_dir])
            except KeyboardInterrupt:
                print "got ^C, exiting..."
                killProcessByName(standalone_app_dir)
            finally:
                tailProcess.terminate()
                os.remove(tmppath)
        else:
            xul_app_dir = a.output_xul_app(browser_code=browser_code_path,
                                           harness_options=harness_options,
                                           dev_mode=True, verbose=False)
            from cuddlefish.runner import run_app

            try:
                retval = run_app(harness_root_dir=xul_app_dir,
                             harness_options=harness_options,
                             app_type=options.app,
                             binary=options.binary,
                             profiledir=options.profiledir,
                             verbose=options.verbose,
                             timeout=timeout,
                             logfile=options.logfile,
                             addons=options.addons)
            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)