'Convert http_archive to repository_rule

I'm trying to convert a binary fetching from http_archive:

def purescript_toolchain():
    http_archive(
        name = "purs",
        urls = ["https://github.com/purescript/purescript/releases/download/v0.14.7/linux64.tar.gz"],
        sha256 = "cae16a0017c63fd83e029ca5a01cb9fc02cacdbd805b1d2b248f9bb3c3ea926d",
        strip_prefix = strip_"purescript",
        build_file_content = """exports_files(["purs"])""",
    )

To a repository rule based approach:

def _purescript_toolchain_impl(repository_ctx):
    repository_ctx.download_and_extract(
        url = "https://github.com/purescript/purescript/releases/download/v0.14.7/linux64.tar.gz",
        sha256 = "cae16a0017c63fd83e029ca5a01cb9fc02cacdbd805b1d2b248f9bb3c3ea926d",
        stripPrefix = "purescript",
    )
    repository_ctx.file(
        "BUILD.bazel",
        content = """exports_files(["purs"])""",
    )

_purescript_toolchain = repository_rule(
    _purescript_toolchain_impl,
    configure = True,
    environ = ["PATH"],
)

def purescript_toolchain():
    _purescript_toolchain(name = "purs")

It seems to work, but when I try to call other functions:

run_template = """
#!/usr/bin/env bash
set -o errexit
node -e "require('./{target_path}/{entry_module}/index.js').{entry_function}({entry_params})"
"""

def _purescript_compile(ctx):
    srcs = ctx.files.srcs + ctx.files.deps
    target = ctx.actions.declare_file(ctx.outputs.target.basename)
    purs = ctx.executable.purs
    flags = " ".join(ctx.attr.compiler_flags)

    bazel_ps_deps = []
    for d in ctx.attr.deps:
        for f in d.files.to_list():
            if f.basename == "target_srcs":
                bazel_ps_deps = [f.path + "/**/*.purs"] + bazel_ps_deps

    compileCmd = "\n".join(
        [ "set -o errexit"
        , """mkdir "$2" """
        , """ "$1" compile """ + flags + """ --output "$2" "${@:3}" """
        ]
    )

    ctx.actions.run_shell(
        tools = srcs + [purs],
        outputs = [target],
        command = compileCmd,
        arguments = [purs.path, target.path] +
                    [src.path for src in srcs if src.extension == "purs"] +
                    bazel_ps_deps,
    )

    cpSrcsCmd = "\n".join(
        [ "set -o errexit"
        , """mkdir -p "$1" """
        , """cp "${@:2}" "$1" """
        ]
    )

    target_srcs = ctx.actions.declare_file(ctx.outputs.target_srcs.basename)

    ctx.actions.run_shell(
        inputs = ctx.files.srcs,
        outputs = [target_srcs],
        command = cpSrcsCmd,
        arguments = [target_srcs.path] + [src.path for src in ctx.files.srcs],
    )

    return target

def _purescript_tar(ctx):
    target = _purescript_compile(ctx)
    tar = ctx.actions.declare_file(ctx.outputs.tar.basename)
    ctx.actions.run_shell(
        inputs = [target],
        outputs = [tar],
        command = """
            set -o errexit
            tar --create --file "$1" --directory "$2" .
        """,
        arguments = [tar.path, target.path],
    )

def _purescript_app(ctx):
    target = _purescript_compile(ctx)

    entry_params = ",".join([
        '\\"{entry}\\"'.format(entry=e) for e in ctx.attr.entry_parameters
    ])

    script = ctx.actions.declare_file(ctx.label.name)
    script_content = run_template.format(
        target_path    = target.short_path,
        entry_module   = getattr(ctx.attr, "entry_module"),
        entry_function = getattr(ctx.attr, "entry_function"),
        entry_params   = entry_params,
    )
    ctx.actions.write(script, script_content, is_executable = True)

    runfiles = ctx.runfiles(files = [target])

    return [DefaultInfo(executable = script, runfiles = runfiles)]

purescript_app = rule(
    implementation = _purescript_app,
    attrs = {
        "srcs": attr.label_list(
            allow_files = True,
        ),
        "deps": attr.label_list(
            default = [],
        ),
        "purs": attr.label(
            allow_single_file = True,
            executable = True,
            cfg = "host",
            default = "@purs",
        ),
        "compiler_flags": attr.string_list(
            default = []
        ),
        "entry_module": attr.string(
            default = "Main",
        ),
        "entry_function": attr.string(
            default = "main",
        ),
        "entry_parameters": attr.string_list(
            default = [],
        ),
    },
    outputs = {
        "target": "target",
        "target_srcs": "target_srcs",
    },
    executable = True,
)

Called via:

purescript_app(
    name       = "ui",
    visibility = ["//visibility:public"],
    srcs       = glob(["src/**/*.purs"]),
)

However, with this new version I get this error:

DEBUG: Repository io_bazel_rules_purescript instantiated at:
  .../WORKSPACE:66:13: in <toplevel>
Repository rule http_archive defined at:
  ~/.cache/bazel/_bazel_black/b6b6a2b95964967dc5a9c8dec827e874/external/bazel_tools/tools/build_defs/repo/http.bzl:336:31: in <toplevel>
INFO: Analyzed target //webui:ui (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
ERROR: .../webui/BUILD.bazel:16:15: Action webui/target failed: (Exit 127): bash failed: error executing command /nix/store/4nmqxajzaf60yjribkgvj5j54x9yvr1r-bash-5.1-p12/bin/bash -c 'set -o errexit
mkdir "$2" 
 "$1" compile  --output "$2" "${@:3}" ' '' external/purs/purs bazel-out/k8-fastbuild/bin/webui/target ... (remaining 98 argument(s) skipped)

Use --sandbox_debug to see verbose messages from the sandbox
: line 3: external/purs/purs: No such file or directory
Target //webui:ui failed to build

Which is surprising since the file exist in the directory (external/purs/purs).

Is their anything to add in the new version?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source