"""A collection of OS-related utilities intended for use in repository rules,
i.e., rules used by WORKSPACE files, not BUILD files.

To opt-in to the "manylinux" or "macos_wheel" build variants, set the
environment variable (e.g.) `DRAKE_OS=manylinux` before running the build.  The
most precise way to do this is to add a `user.bazelrc` file to the root of the
Drake source tree with the following content:

  common --repo_env=DRAKE_OS=manylinux

Alternatively, you may pass `--repo_env=DRAKE_OS=manylinux` on the bazel
command line. (Replace "manylinux" with "macos_wheel" as appropriate.)
"""

load("//tools/workspace:execute.bzl", "which")

def exec_using_which(repository_ctx, command):
    """Run the given command (a list), using the which() function in
    execute.bzl to locate the executable named by the zeroth index of
    `command`.

    Return struct with attributes:
    - error (None when success, or else str message)
    - stdout (str command output, possibly empty)
    """

    # Find the executable.
    fullpath = which(repository_ctx, command[0])
    if fullpath == None:
        return struct(
            stdout = "",
            error = "could not find which '%s'" % command[0],
        )

    # Run the executable.
    result = repository_ctx.execute([fullpath] + command[1:])
    if result.return_code != 0:
        error = "error %d running %r (command %r, stdout %r, stderr %r)" % (
            result.return_code,
            command[0],
            command,
            result.stdout,
            result.stderr,
        )
        return struct(stdout = result.stdout, error = error)

    # Success.
    return struct(stdout = result.stdout, error = None)

def is_wheel_build(repository_ctx):
    """
    Returns true iff this build is a Python wheel flavor.
    """
    drake_os = repository_ctx.os.environ.get("DRAKE_OS", "")
    return drake_os in ["manylinux", "macos_wheel"]

def os_specific_alias(repository_ctx, mapping):
    """
    A repository_rule helper function that creates a BUILD file with alias()
    declarations based on which supported OS version we are targeting.

    Argument:
        repository_ctx: The context passed to the repository_rule calling this.
        mapping: dict(str, list(str)) where the keys match the OS (which must
            be either "linux" or "osx", and the list of values are of the form
            name=actual as in alias(name, actual).
    """

    key = repository_ctx.os.name
    if key == "mac os x":
        key = "osx"

    if key not in mapping:
        fail("Unsupported os.name " + key)
    items = mapping[key]

    # Emit the list of aliases.
    file_content = """\
# DO NOT EDIT: generated by os_specific_alias_repository()

package(default_visibility = ["//visibility:public"])
"""

    for item in items:
        name, actual = item.split("=")
        file_content += 'alias(name = "{}", actual = "{}")\n'.format(
            name,
            actual,
        )
    repository_ctx.file(
        "BUILD.bazel",
        content = file_content,
        executable = False,
    )

def _os_specific_alias_impl(repository_ctx):
    os_specific_alias(repository_ctx, repository_ctx.attr.mapping)

os_specific_alias_repository = repository_rule(
    attrs = {
        "mapping": attr.string_list_dict(mandatory = True),
    },
    implementation = _os_specific_alias_impl,
)
