Skip to content

Commit

Permalink
WIP: run bare rust binary, no node
Browse files Browse the repository at this point in the history
  • Loading branch information
alexeagle committed Jul 1, 2022
1 parent 87a087b commit cd4fe82
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 75 deletions.
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,6 @@ You'll basically follow the example of /swc/private/swc.bzl in this repo, by usi
the `ctx.actions.run` Starlark API.

- Use `@aspect_rules_swc//swc:cli` as the binary tool to execute
- To get the swc nodejs bindings for Rust, `env` should include
`"SWC_BINARY_PATH": ctx.toolchains["@aspect_rules_swc//swc:toolchain_type"].swcinfo.binding`
- To pass the relevant files to the action, `inputs` should include
`ctx.toolchains["@aspect_rules_swc//swc:toolchain_type"].swcinfo.tool_files`

Expand Down
8 changes: 6 additions & 2 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@ load("//swc:repositories.bzl", "swc_register_toolchains")

swc_register_toolchains(
name = "default_swc",
node_repository = "node16",
swc_version = "v1.2.168",
integrity_hashes = {
"darwin-arm64": "sha512-DuBBKIyk0iUGPmq6RQc7/uOCkGnvB0JDWQbWxA2NGAEcK0ZtI9J0efG9M1/gLIb0QD+d2DVS5Lx7VRIUFTx9lA==",
"darwin-x64": "sha512-WvDN6tRjQ/p+4gNvT4UVU4VyJLXy6hT4nT6mGgrtftG/9pP5dDPwwtTm86ISfqGUs8/LuZvrr4Nhwdr3j+0uAA==",
"linux-x64-gnu": "sha512-6eco63idgYWPYrSpDeSE3tgh/4CC0hJz8cAO/M/f3azmCXvI+11isC60ic3UKeZ2QNXz3YbsX6CKAgBPSkkaVA==",
},
swc_version = "v1.2.204",
)

load("@rules_nodejs//nodejs:repositories.bzl", "nodejs_register_toolchains")
Expand Down
22 changes: 9 additions & 13 deletions e2e/workspace/WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,18 @@ load("@aspect_rules_swc//swc:dependencies.bzl", "rules_swc_dependencies")

rules_swc_dependencies()

# Fetches a pre-built Rust-node binding from
# https://github.com/swc-project/swc/releases.
# Fetches a pre-built Rust-node binary from
# https://registry.npmjs.org/@swc/core-[platform]
# If you'd rather compile it from source, you can use rules_rust, fetch the project,
# then register the toolchain yourself. (Note, this is not yet documented)
load("@aspect_rules_swc//swc:repositories.bzl", "LATEST_VERSION", "swc_register_toolchains")
load("@aspect_rules_swc//swc:repositories.bzl", "swc_register_toolchains")

swc_register_toolchains(
name = "swc",
swc_version = LATEST_VERSION,
)

# Fetches a NodeJS interpreter, needed to run the swc CLI.
# You can skip this if you already register a nodejs toolchain.
load("@rules_nodejs//nodejs:repositories.bzl", "DEFAULT_NODE_VERSION", "nodejs_register_toolchains")

nodejs_register_toolchains(
name = "nodejs",
node_version = DEFAULT_NODE_VERSION,
integrity_hashes = {
"darwin-arm64": "sha512-DuBBKIyk0iUGPmq6RQc7/uOCkGnvB0JDWQbWxA2NGAEcK0ZtI9J0efG9M1/gLIb0QD+d2DVS5Lx7VRIUFTx9lA==",
"darwin-x64": "sha512-WvDN6tRjQ/p+4gNvT4UVU4VyJLXy6hT4nT6mGgrtftG/9pP5dDPwwtTm86ISfqGUs8/LuZvrr4Nhwdr3j+0uAA==",
"linux-x64-gnu": "sha512-6eco63idgYWPYrSpDeSE3tgh/4CC0hJz8cAO/M/f3azmCXvI+11isC60ic3UKeZ2QNXz3YbsX6CKAgBPSkkaVA==",
},
swc_version = "v1.2.204",
)
2 changes: 1 addition & 1 deletion swc/extensions.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ load(":repositories.bzl", "swc_register_toolchains")

swc_toolchain = tag_class(attrs = {
"name": attr.string(doc = "Base name for generated repositories"),
"swc_version": attr.string(doc = "Version of the swc rust binding"),
"swc_version": attr.string(doc = "Version of the swc core package"),
})

def _toolchain_extension(module_ctx):
Expand Down
71 changes: 35 additions & 36 deletions swc/private/swc.bzl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"Internal implementation details"

load("@bazel_skylib//lib:paths.bzl", "paths")
load("@aspect_bazel_lib//lib:copy_to_bin.bzl", "copy_file_to_bin_action", "copy_files_to_bin_actions")
load("@aspect_bazel_lib//lib:copy_to_bin.bzl", "copy_file_to_bin_action")

_attrs = {
"srcs": attr.label_list(
Expand All @@ -28,12 +28,6 @@ _attrs = {
doc = "label of a configuration file for swc, see https://swc.rs/docs/configuration/swcrc",
allow_single_file = True,
),
"swc_cli": attr.label(
doc = "binary that executes the swc CLI",
default = "@aspect_rules_swc//swc:cli",
executable = True,
cfg = "exec",
),
"out_dir": attr.string(
doc = "base directory for output files",
),
Expand Down Expand Up @@ -72,7 +66,7 @@ def _calculate_js_outs(srcs, out_dir = None):
if paths.split_extension(src)[-1] == ".js":
js_srcs.append(src)
if len(js_srcs) > 0:
fail("Detected swc rule with srcs=[{}, ...] and out_dir=None. Please set out_dir when compiling .js files.".format(', '.join(js_srcs[:3])))
fail("Detected swc rule with srcs=[{}, ...] and out_dir=None. Please set out_dir when compiling .js files.".format(", ".join(js_srcs[:3])))

js_outs = [paths.replace_extension(f, ".js") for f in srcs if _is_supported_src(f)]
if out_dir != None:
Expand All @@ -87,12 +81,13 @@ def _calculate_map_outs(srcs, source_maps):

def _impl(ctx):
outputs = []
binding = ctx.toolchains["@aspect_rules_swc//swc:toolchain_type"].swcinfo.binding
binary = ctx.toolchains["@aspect_rules_swc//swc:toolchain_type"].swcinfo.swc_binary
args = ctx.actions.args()
args.add("compile")

# Add user specified arguments *before* rule supplied arguments
args.add_all(ctx.attr.args)
args.add_all(["--source-maps", ctx.attr.source_maps])
#args.add_all(["--source-maps", ctx.attr.source_maps])

if ctx.attr.output_dir:
if len(ctx.attr.srcs) != 1:
Expand All @@ -102,24 +97,21 @@ def _impl(ctx):
out = ctx.actions.declare_directory(ctx.label.name)
outputs.append(out)
args.add_all([
ctx.files.srcs[0].short_path,
ctx.files.srcs[0].path,
"--out-dir",
out.short_path,
"--no-swcrc",
"-q",
out.path,
#"--no-swcrc",
#"-q",
])

ctx.actions.run(
inputs = copy_files_to_bin_actions(ctx, ctx.files.srcs) + ctx.toolchains["@aspect_rules_swc//swc:toolchain_type"].swcinfo.tool_files,
inputs = ctx.files.srcs + ctx.toolchains["@aspect_rules_swc//swc:toolchain_type"].swcinfo.tool_files,
arguments = [args],
outputs = [out],
env = {
# Our patch for @swc/core uses this environment variable to locate the rust binding
"SWC_BINARY_PATH": "../../../" + binding,
"BAZEL_BINDIR": ctx.bin_dir.path,
},
executable = ctx.executable.swc_cli,
executable = binary,
progress_message = "Transpiling with swc %s" % ctx.label,
# sandboxing is unnecessary with swc which takes an explilit list of srcs via args
execution_requirements = {"no-sandbox": "1"},
)

else:
Expand All @@ -139,45 +131,52 @@ def _impl(ctx):
src_args = ctx.actions.args()

js_out = js_outs[i]
inputs = [copy_file_to_bin_action(ctx, src)] + ctx.toolchains["@aspect_rules_swc//swc:toolchain_type"].swcinfo.tool_files
inputs = [src] + ctx.toolchains["@aspect_rules_swc//swc:toolchain_type"].swcinfo.tool_files
outs = [js_out]
if ctx.attr.source_maps in ["true", "both"]:
outs.append(map_outs[i])

# Pass in the swcrc config if it is set
if ctx.file.swcrc:
swcrc_path = ctx.file.swcrc.short_path
swcrc_path = ctx.file.swcrc.path
swcrc_directory = paths.dirname(swcrc_path)
src_args.add_all([
"--config-file",
swcrc_path,
])
inputs.append(copy_file_to_bin_action(ctx, ctx.file.swcrc))
else:
src_args.add("--no-swcrc")
pass
#src_args.add("--no-swcrc")

src_args.add_all([
src.short_path,
# src.path,
"--out-file",
js_out.short_path,
"-q",
js_out.path,
#"-q",
])

ctx.actions.run(
ctx.actions.run_shell(
inputs = inputs,
arguments = [args, src_args],
arguments = [
args,
src_args,
"-f ",
src.path,
],
outputs = outs,
env = {
# Our patch for @swc/core uses this environment variable to locate the rust binding
"SWC_BINARY_PATH": "../../../" + binding,
"BAZEL_BINDIR": ctx.bin_dir.path,
},
executable = ctx.executable.swc_cli,
# Workaround swc cli bug:
# https://github.com/swc-project/swc/blob/main/crates/swc_cli/src/commands/compile.rs#L241-L254
# under Bazel it will think there's no tty and so it always errors here
# https://github.com/swc-project/swc/blob/main/crates/swc_cli/src/commands/compile.rs#L301
command = binary + " $@ < " + src.path,
mnemonic = "SWCTranspile",
progress_message = "Transpiling with swc %s [swc %s]" % (
ctx.label,
src.short_path,
src.path,
),
# sandboxing is unnecessary with swc which takes an explilit list of srcs via args
execution_requirements = {"no-sandbox": "1"},
)

# See https://docs.bazel.build/versions/main/skylark/rules.html#runfiles
Expand Down
39 changes: 27 additions & 12 deletions swc/repositories.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,37 @@ LATEST_VERSION = TOOL_VERSIONS.keys()[0]

_DOC = "Fetch external tools needed for swc toolchain"
_ATTRS = {
"swc_version": attr.string(mandatory = True, values = TOOL_VERSIONS.keys()),
"swc_version": attr.string(mandatory = True),
"platform": attr.string(mandatory = True, values = PLATFORMS.keys()),
"integrity_hashes": attr.string_dict(),
}

def _swc_repo_impl(repository_ctx):
filename = "swc.%s.node" % repository_ctx.attr.platform
url = "https://github.com/swc-project/swc/releases/download/{0}/{1}".format(
repository_ctx.attr.swc_version,
filename,
url = "https://registry.npmjs.org/@swc/core-{0}/-/core-{0}-{1}.tgz".format(
repository_ctx.attr.platform,
repository_ctx.attr.swc_version.lstrip("v"),
)
repository_ctx.download(
output = filename,
integrity = repository_ctx.attr.integrity_hashes.get(
repository_ctx.attr.platform,
None,
)
if not integrity:
integrity = TOOL_VERSIONS[repository_ctx.attr.swc_version][repository_ctx.attr.platform]
bin = "package/swc{ext}".format(ext = ".exe" if False else "") # FIXME: check for windows

repository_ctx.download_and_extract(
#output = filename,
url = url,
integrity = TOOL_VERSIONS[repository_ctx.attr.swc_version][repository_ctx.attr.platform],
integrity = integrity,
)
result = repository_ctx.execute(["chmod", "u+x", "package/swc"])
if result.return_code:
msg = "chmod failed: \nSTDOUT:\n%s\nSTDERR:\n%s" % (result.stdout, result.stderr)
fail(msg)
build_content = """#Generated by swc/repositories.bzl
load("@aspect_rules_swc//swc:toolchain.bzl", "swc_toolchain")
swc_toolchain(name = "swc_toolchain", node_binding = "%s")
""" % filename
swc_toolchain(name = "swc_toolchain", swc_binary = "{bin}")
""".format(bin = bin)

# Base BUILD file for this repository
repository_ctx.file("BUILD.bazel", build_content)
Expand All @@ -43,7 +55,7 @@ swc_repositories = repository_rule(
)

# Wrapper macro around everything above, this is the primary API
def swc_register_toolchains(name, node_repository = "nodejs", register = True, **kwargs):
def swc_register_toolchains(name, register = True, **kwargs):
"""Convenience macro for users which does typical setup.
- create a repository for each built-in platform like "swc_linux_amd64" -
Expand All @@ -54,11 +66,13 @@ def swc_register_toolchains(name, node_repository = "nodejs", register = True, *
Users can avoid this macro and do these steps themselves, if they want more control.
Args:
name: base name for all created repos, like "swc"
node_repository: what name was given to register_nodejs_toolchains.
register: whether to call through to native.register_toolchains.
Should be True for WORKSPACE users, but false when used under bzlmod extension
**kwargs: passed to each node_repositories call
"""

# FIXME: validate the swc_version is either in TOOL_VERSIONS.keys()
# or you gave us integrity_hashes and it includes the current platform
for platform in PLATFORMS.keys():
swc_repositories(
name = name + "_" + platform,
Expand All @@ -73,6 +87,7 @@ def swc_register_toolchains(name, node_repository = "nodejs", register = True, *
user_repository_name = name,
)

# FIXME
npm_import(
name = "npm__at_swc_core__1.2.185",
integrity = "sha512-dDNzDrJ4bzMVWeFWqLJojjv5XZJZ84Zia7kQdJjp+kfOMdEhS+onrAwrk5Q88PlAvbrhY6kQbWD2LZ8JdyEaSQ==",
Expand Down
18 changes: 9 additions & 9 deletions swc/toolchain.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
SwcInfo = provider(
doc = "Information about how to invoke the tool executable.",
fields = {
"binding": "Path to the node binding for the target platform.",
"swc_binary": "Path to the native swc cli binary for the target platform.",
"tool_files": """Files required in runfiles to make the tool executable available.
May be empty if the target_tool_path points to a locally installed tool binary.""",
Expand All @@ -19,16 +19,16 @@ def _to_manifest_path(ctx, file):
return ctx.workspace_name + "/" + file.short_path

def _swc_toolchain_impl(ctx):
if ctx.attr.node_binding and ctx.attr.target_tool_path:
fail("Can only set one of node_binding or target_tool_path but both were set.")
if not ctx.attr.node_binding and not ctx.attr.target_tool_path:
fail("Must set one of node_binding or target_tool_path.")
if ctx.attr.swc_binary and ctx.attr.target_tool_path:
fail("Can only set one of swc_binary or target_tool_path but both were set.")
if not ctx.attr.swc_binary and not ctx.attr.target_tool_path:
fail("Must set one of swc_binary or target_tool_path.")

tool_files = []
target_tool_path = ctx.attr.target_tool_path

if ctx.attr.node_binding:
tool_files = ctx.attr.node_binding.files.to_list()
if ctx.attr.swc_binary:
tool_files = ctx.attr.swc_binary.files.to_list()
target_tool_path = _to_manifest_path(ctx, tool_files[0])

# Make the $(tool_BIN) variable available in places like genrules.
Expand All @@ -41,7 +41,7 @@ def _swc_toolchain_impl(ctx):
runfiles = ctx.runfiles(files = tool_files),
)
swcinfo = SwcInfo(
binding = target_tool_path,
swc_binary = target_tool_path,
tool_files = tool_files,
)

Expand All @@ -61,7 +61,7 @@ def _swc_toolchain_impl(ctx):
swc_toolchain = rule(
implementation = _swc_toolchain_impl,
attrs = {
"node_binding": attr.label(
"swc_binary": attr.label(
doc = "A hermetically downloaded executable target for the target platform.",
mandatory = False,
allow_single_file = True,
Expand Down

0 comments on commit cd4fe82

Please sign in to comment.