Example #1
0
def load_rules(
    flags: Dict[str, object],
    *,
    skip_version_check: bool,
    workspace: bool = False,
):
    flags = Struct(flags, default=True)
    repo_root = find_root()
    src_files = get_repo_files()
    build_files = (["WORKSPACE"] if workspace else [
        file for file in src_files if file.split("/")[-1] == "BUILD"
    ])
    target_rule_lookup = TargetLookup()
    sys.path.insert(0, repo_root)
    callback, find, resolve = make_callback(repo_root, None, set(src_files),
                                            target_rule_lookup)
    config.skip_version_check = skip_version_check
    for build_file in build_files:
        make_callback.build_root = os.path.dirname(build_file)

        with open(build_file) as f:
            frame = {}
            load = make_load_rules(repo_root, build_file)

            __builtins__["callback"] = callback
            __builtins__["find"] = find
            __builtins__["resolve"] = resolve
            __builtins__["load"] = load
            __builtins__["flags"] = flags

            frame = {
                **frame,
                "__builtins__": __builtins__,
            }

            reset_mock_imports(
                frame, ["callback", "find", "load", "flags", "resolve"])

            if workspace:
                __builtins__["config"] = config
                config.active = True
                reset_mock_imports(frame, ["config"])

            start_time_stack.append(time.time())
            try:
                exec(f.read(), frame)
                config.active = False
            except Exception:
                raise BuildException(
                    f"Error while processing BUILD file {build_file}:\n" +
                    f"\n{Style.RESET_ALL}" + traceback.format_exc())
            TIMINGS[build_file] = time.time() - start_time_stack.pop()

        make_callback.build_root = None

    return target_rule_lookup
Example #2
0
def load_rules(
    flags: Dict[str, object],
    *,
    skip_version_check: bool,
    workspace: bool = False,
):
    flags = Struct(flags, default=True)
    src_files = get_repo_files()
    build_files = (
        ["WORKSPACE"]
        if workspace
        else [file for file in src_files if file.split("/")[-1] == "BUILD"]
    )
    target_rule_lookup = TargetLookup()
    macros = {}
    callback, find, resolve, macro, make_depset = make_callback(
        None,
        set(src_files),
        target_rule_lookup,
        macros,
    )
    config.skip_version_check = skip_version_check
    for build_file in build_files:
        make_callback.build_root = os.path.dirname(build_file)

        with open(build_file) as f:
            frame = {}
            load = make_load_rules(build_file)

            __builtins__["callback"] = __builtins__["rule"] = callback
            __builtins__["find"] = find
            __builtins__["resolve"] = resolve
            __builtins__["load"] = load
            __builtins__["flags"] = flags
            __builtins__["macro"] = macro
            __builtins__["provider"] = provider
            __builtins__["depset"] = make_depset
            __builtins__["DepsProvider"] = DepsProvider
            __builtins__["OutputProvider"] = OutputProvider
            __builtins__["TransitiveDepsProvider"] = TransitiveDepsProvider
            __builtins__["TransitiveOutputProvider"] = TransitiveOutputProvider

            frame = {
                **frame,
                "__builtins__": __builtins__,
            }

            if workspace:
                __builtins__["config"] = config
                config.active = True

            start_time_stack.append(time.time())
            try:
                exec(compile(f.read(), build_file, "exec"), frame)
                config.active = False
            except Exception:
                raise BuildException(
                    f"Error while processing BUILD file {build_file}:\n"
                    + f"\n{Style.RESET_ALL}"
                    + traceback.format_exc()
                )
            TIMINGS[build_file] = time.time() - start_time_stack.pop()

        make_callback.build_root = None

    return target_rule_lookup, macros
Example #3
0
def cli(
    targets: Tuple[str],
    profile: bool,
    shell_log: bool,
    locate: bool,
    verbose: bool,
    quiet: bool,
    skip_version_check: bool,
    skip_setup: bool,
    skip_build: bool,
    clean: bool,
    num_threads: int,
    state_directory: str,
    cache_directory: str,
    flags: List[str],
):
    """
    This is a `make` alternative with a simpler syntax and some useful features.
    """
    try:
        repo_root = find_root()
        os.chdir(repo_root)

        if verbose:
            enable_logging()

        if profile or shell_log:
            enable_profiling()

        flags = [flag.split("=", 1) + ["true"] for flag in flags]
        flags = {flag[0].lower(): loads(flag[1]) for flag in flags}

        if not skip_setup:
            setup_rule_lookup, macros = load_rules(
                flags, workspace=True, skip_version_check=skip_version_check)

            if macros:
                raise BuildException(
                    "Macros are not supported in setup rules.")

            setup_targets = [
                target[5:] for target in targets if target.startswith("setup:")
            ]

            if locate and setup_targets:
                raise BuildException(
                    "--locate cannot be used with setup rules - they are declared in WORKSPACE"
                )

            setup_targets = setup_targets or ([
                config.default_setup_rule
            ] if config.default_setup_rule else [])

            initialize_workspace(
                setup_rule_lookup,
                setup_targets,
                state_directory,
                quiet,
            )

        target_rule_lookup, macros = load_rules(
            flags, skip_version_check=skip_version_check)
        target_rule_lookup.verify()

        all_files = get_repo_files()
        source_files = target_rule_lookup.find_source_files(all_files)

        if profile:
            print("Slow Build / Rules Files (Loading Phase):")
            slowest = sorted(LOAD_TIMINGS,
                             key=lambda x: LOAD_TIMINGS[x],
                             reverse=True)[:20]
            for key in slowest:
                print(key, LOAD_TIMINGS[key])

            print()

        need_target = locate or not skip_build

        if not targets and need_target:
            if config.default_build_rule is None:
                raise BuildException(
                    "No target provided, and no default target set.")
            targets = [config.default_build_rule]

        if locate:
            for target in targets:
                if target in source_files:
                    raise BuildException(
                        f"Target {target} is a source file, not a build target."
                    )
                rule = target_rule_lookup.try_lookup(target)
                if rule is None and not target.startswith(":"):
                    rule = target_rule_lookup.try_lookup(f":{target}")
                if rule is None:
                    raise BuildException(f"Target {target} was not found.")
                print(
                    f"Target {target} is declared by {rule} in {rule.location}/BUILD."
                )
            exit(0)

        if not skip_build:
            for _ in range(2 if clean else 1):
                if clean:
                    for out_dir in config.output_directories:
                        rmtree(out_dir, ignore_errors=True)
                    for rule in set(
                            target_rule_lookup.direct_lookup.values()) | set(
                                target_rule_lookup.direct_lookup.values()):
                        rule.pending_rule_dependencies = set()
                        rule.runtime_dependents = set()
                run_build(
                    BuildState(
                        target_rule_lookup=target_rule_lookup,
                        source_files=source_files,
                        cache_directory=cache_directory,
                        macros=macros,
                    ),
                    [
                        target for target in targets
                        if not target.startswith("setup:")
                    ],
                    num_threads,
                    quiet,
                )

        if profile:
            print("Slow Rules (Execution Phase):")
            slowest = sorted(BUILD_TIMINGS,
                             key=lambda x: BUILD_TIMINGS[x],
                             reverse=True)[:20]
            for key in slowest:
                print(key, BUILD_TIMINGS[key])
            print("Cache Statistics")
            print(
                f"{STATS['hits']} cache hits, {STATS['misses']} cache misses, {STATS['inserts']} cache inserts (approx)"
            )

    except BuildException as e:
        display_error(e)
        exit(1)
    except Exception as e:
        display_error(BuildException("Internal error: " + repr(e)))
        print(f"\n{Style.RESET_ALL}" + traceback.format_exc())
        exit(1)