#!/usr/bin/env python3

# This differs from matrix-check in the following ways:
#   - it only tests one combination of features, as specified on the command line
#   - it doesn't have crate-specific hacks (or any knowledge of our workspace contents)
#     (but it does read some ad-hoc parseable comments from Cargo.toml's).
#   - it runs `cargo test`

import argparse
import subprocess
import sys
import list_crates


def test_crate(args, c):
    conditional_options = []

    for line in open(c.subdir + "/Cargo.toml"):

        # TODO do something more formal here
        #
        # We need this because some crates don't compile without a runtime selected.
        #
        # Ideally, if the crate doesn't compile without any features selected,
        # the manifest should have a `minimal` feature we can use, or something.
        if line.startswith("# @@ test-all-crates ignore"):
            print(
                """(
(((((((((( skipping %s ))))))))))
)"""
                % c.name,
                file=sys.stderr,
            )
            return

        conditional_option_directive = "# @@ test-all-crates conditional-option "
        # One option per line, so it can contain spaces
        if line.startswith(conditional_option_directive):
            (key, option) = (
                line[len(conditional_option_directive) :].rstrip().split(maxsplit=1)
            )
            if key in args.enable_conditional_options:
                conditional_options.append(option)
            continue

    command_sh = 'p=$1; shift; set -x; $CARGO test -p $p "$@"'

    print(
        """:
:::::::::: %s ::::::::::
:"""
        % c.name,
        file=sys.stderr,
    )

    # We run a separate build command for each one, to defeat cargo feature unification.

    command_l = (
        [
            "sh",
            "-ec",
            ': "${CARGO:=cargo --locked}"; ' + command_sh,
            "x",
            c.name,
        ]
        + args.cargo_option
        + conditional_options
    )

    child = subprocess.run(command_l)

    if child.returncode != 0:
        print(
            """failed command %s
"return code" %s
failed to test crate %s"""
            % (repr(command_l), child.returncode, c.name),
            file=sys.stderr,
        )
        sys.exit(1)


def main():
    parser = argparse.ArgumentParser(prog="test-all-crates")
    parser.add_argument("cargo_option", nargs="*")
    parser.add_argument("--enable-conditional-options", action="append", default=[])
    parser.add_argument("--skip-until", action="store", default=None)
    args = parser.parse_args()

    skip_until = args.skip_until

    for crate in list_crates.list_crates():
        if skip_until is not None:
            if skip_until == crate.name:
                skip_until = None
            else:
                print(
                    "skipping due to --skip-until %s: %s" % (skip_until, crate.name),
                    file=sys.stderr,
                )
                continue

        test_crate(args, crate)


main()
