Merge pull request #1376 from NoRedInk/wat-590-build-the-project-javascript-code-with

build project JavaScript with Buck
This commit is contained in:
Brian Hicks 2023-05-02 11:42:18 -05:00 committed by GitHub
commit 1155f43d49
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 321 additions and 0 deletions

13
BUCK
View File

@ -1,5 +1,6 @@
# A list of available rules and their signatures can be found here: https://buck2.build/docs/api/rules/
load("@prelude-nri//:elm.bzl", "elm_docs")
load("@prelude-nri//:node.bzl", "node_modules", "npm_bin")
elm_docs(
name = "docs.json",
@ -12,3 +13,15 @@ filegroup(
srcs = glob(["src/**/*.elm"]),
visibility = ["//component-catalog:app"]
)
node_modules(
name = "node_modules",
package = "package.json",
package_lock = "package-lock.json",
)
npm_bin(
name = "browserify",
node_modules = ":node_modules",
visibility = ["//lib:lib.js"],
)

6
lib/BUCK Normal file
View File

@ -0,0 +1,6 @@
genrule(
name = "lib.js",
out = "lib.js",
srcs = glob(["**/*.js"]),
cmd = "$(exe //:browserify) index.js --outfile $OUT",
)

77
prelude-nri/node.bzl Normal file
View File

@ -0,0 +1,77 @@
load("//node:toolchain.bzl", "NodeToolchainInfo")
load("@prelude//python:toolchain.bzl", "PythonToolchainInfo")
def _node_modules_impl(ctx: "context") -> [DefaultInfo.type]:
out = ctx.actions.declare_output("node_modules")
node_toolchain = ctx.attrs._node_toolchain[NodeToolchainInfo]
ctx.actions.run(
[
ctx.attrs._python_toolchain[PythonToolchainInfo].interpreter,
node_toolchain.build_node_modules[DefaultInfo].default_outputs,
out.as_output(),
"--package", ctx.attrs.package,
"--package-lock", ctx.attrs.package_lock,
"--bin-dir", node_toolchain.bin_dir[DefaultInfo].default_outputs,
],
category = "npm",
)
return [DefaultInfo(default_output = out)]
node_modules = rule(
impl = _node_modules_impl,
attrs = {
"package": attrs.source(),
"package_lock": attrs.source(),
"_node_toolchain": attrs.toolchain_dep(
default="toolchains//:node",
providers=[NodeToolchainInfo]
),
"_python_toolchain": attrs.toolchain_dep(
default="toolchains//:python",
providers=[PythonToolchainInfo]
),
}
)
def _npm_bin_impl(ctx: "context") -> [[DefaultInfo.type, RunInfo.type]]:
bin_name = ctx.attrs.bin_name or ctx.attrs.name
out = ctx.actions.declare_output(bin_name)
node_toolchain = ctx.attrs._node_toolchain[NodeToolchainInfo]
ctx.actions.run(
[
ctx.attrs._python_toolchain[PythonToolchainInfo].interpreter,
node_toolchain.build_npm_bin[DefaultInfo].default_outputs,
ctx.attrs.node_modules,
bin_name,
out.as_output(),
"--bin-dir", node_toolchain.bin_dir[DefaultInfo].default_outputs,
],
category = "build_npm_bin",
)
return [
DefaultInfo(default_output = out),
RunInfo(out),
]
npm_bin = rule(
impl = _npm_bin_impl,
attrs = {
"bin_name": attrs.option(attrs.string(), default=None),
"node_modules": attrs.source(),
"_node_toolchain": attrs.toolchain_dep(
default="toolchains//:node",
providers=[NodeToolchainInfo]
),
"_python_toolchain": attrs.toolchain_dep(
default="toolchains//:python",
providers=[PythonToolchainInfo]
),
}
)

55
prelude-nri/node/BUCK Normal file
View File

@ -0,0 +1,55 @@
_NODE_URL = select({
"config//os:linux": "https://nodejs.org/dist/v20.0.0/node-v20.0.0-linux-x64.tar.xz",
"config//os:macos": select({
"config//cpu:arm64": "https://nodejs.org/dist/v20.0.0/node-v20.0.0-darwin-arm64.tar.gz",
"config//cpu:x86_64": "https://nodejs.org/dist/v20.0.0/node-v20.0.0-darwin-x64.tar.gz",
}),
})
_NODE_SHA256 = select({
"config//os:linux": "9e512f1f1cadb3a5e37a10aa2d5e632f93aaf9f37165803e2ed981009970a3d7",
"config//os:macos": select({
"config//cpu:arm64": "ee27eea6694a5d8c834b11a12fb85a5dae01a91178be12920a6da12d8c299c43",
"config//cpu:x86_64": "a26019f8dc6f0b261b1eebabeedb00f478460c36950a99b5c7e161af005e400e",
}),
})
_NODE_PREFIX = select({
"config//os:linux": "node-v20.0.0-linux-x64",
"config//os:macos": select({
"config//cpu:arm64": "node-v20.0.0-darwin-arm64",
"config//cpu:x86_64": "node-v20.0.0-darwin-x64",
}),
})
http_archive(
name = "node_binaries",
urls = [_NODE_URL],
sha256 = _NODE_SHA256,
strip_prefix = _NODE_PREFIX,
)
genrule(
name = "bin",
out = "bin",
cmd = "ln -s $(location :node_binaries)/bin $OUT",
visibility = ["PUBLIC"],
)
genrule(
name = "node",
out = "node",
cmd = "ln -s $(location :node_binaries)/bin/node $OUT",
visibility = ["PUBLIC"],
executable = True,
)
export_file(
name = "build_node_modules.py",
visibility = ["PUBLIC"],
)
export_file(
name = "build_npm_bin.py",
visibility = ["PUBLIC"],
)

View File

@ -0,0 +1,61 @@
#!/usr/bin/env python3
"""
Make a fresh `node_modules` directory in an isolated directory.
"""
import argparse
import os
import subprocess
import sys
import shutil
import tempfile
if __name__ == "__main__":
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("out", help="Where you want node_modules to end up")
parser.add_argument(
"--package",
help="The package.json to install dependencies from",
default="package.json",
)
parser.add_argument(
"--package-lock",
help="The package-lock.json corresponding to package.json",
default="package-lock.json",
)
parser.add_argument(
"--no-ignore-scripts",
action="store_true",
help="Don't run package post-install scripts",
)
parser.add_argument(
"--bin-dir",
help="Path to a node installation's binary directory. If present, will be treated as an extra entry in PATH for the duration of this command.",
)
args = parser.parse_args()
if args.bin_dir:
os.environ["PATH"] = "{}:{}".format(
os.path.abspath(args.bin_dir), os.environ["PATH"]
)
with tempfile.TemporaryDirectory() as tempdir:
# npm wants these to be real files for whatever reason, and will throw
# errors if they're symlinks.
shutil.copy(args.package, os.path.join(tempdir, "package.json"))
shutil.copy(args.package_lock, os.path.join(tempdir, "package-lock.json"))
cmd = ["npm", "clean-install"]
if not args.no_ignore_scripts:
cmd.append("--ignore-scripts")
proc = subprocess.Popen(cmd, cwd=tempdir)
proc.communicate()
if proc.returncode == 0:
os.rename(
os.path.join(tempdir, "node_modules"),
args.out,
)
sys.exit(proc.returncode)

View File

@ -0,0 +1,62 @@
#!/usr/bin/env python3
"""
Make a independently-runnable npm binary.
"""
import argparse
import os
import stat
import sys
if __name__ == "__main__":
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
"node_modules",
help="The path to the node_modules you want to get binaries from.",
)
parser.add_argument(
"bin",
help="The binary to pull from node_modules",
)
parser.add_argument("out", help="Where you want the resulting binary.")
parser.add_argument(
"--bin-dir",
help="Path to a node installation's binary directory. If present, will be treated as an extra entry in PATH for the duration of this command.",
)
args = parser.parse_args()
if not os.path.exists(args.node_modules):
print("The given node_modules does not exist!")
sys.exit(1)
lines = [
"#!/usr/bin/env bash",
"set -e",
]
bins = os.path.join(os.path.abspath(args.node_modules), ".bin")
path = [bins]
if args.bin_dir:
path.append(os.path.abspath(args.bin_dir))
lines.append("export PATH={}:$PATH".format(":".join(path)))
bin = os.path.join(bins, args.bin)
if not os.path.exists(bin):
print("The given binary does not exist!")
sys.exit(1)
lines.append(f"exec {bin} $@")
with open(args.out, "w") as fh:
fh.write("\n".join(lines))
os.chmod(
args.out,
stat.S_IRUSR
| stat.S_IXUSR
| stat.S_IRGRP
| stat.S_IXGRP
| stat.S_IROTH
| stat.S_IXOTH,
)

View File

@ -0,0 +1,41 @@
NodeToolchainInfo = provider(fields=[
"bin_dir",
"node",
"build_node_modules",
"build_npm_bin",
])
def _node_toolchain_impl(ctx) -> [[DefaultInfo.type, NodeToolchainInfo.type]]:
"""
A Node toolchain which you can source binaries from wherever it makes sense
to you.
"""
return [
DefaultInfo(),
NodeToolchainInfo(
bin_dir = ctx.attrs.bin_dir,
node = ctx.attrs.node[RunInfo],
build_node_modules = ctx.attrs._build_node_modules,
build_npm_bin = ctx.attrs._build_npm_bin,
),
]
node_toolchain = rule(
impl = _node_toolchain_impl,
attrs = {
"bin_dir": attrs.dep(
default="prelude-nri//node:bin"
),
"node": attrs.dep(
providers = [RunInfo],
default="prelude-nri//node:node"
),
"_build_node_modules": attrs.dep(
default="prelude-nri//node:build_node_modules.py",
),
"_build_npm_bin": attrs.dep(
default="prelude-nri//node:build_npm_bin.py",
),
},
is_toolchain_rule = True,
)

View File

@ -1,6 +1,7 @@
load("@prelude//toolchains:genrule.bzl", "system_genrule_toolchain")
load("@prelude//toolchains:python.bzl", "system_python_bootstrap_toolchain", "system_python_toolchain")
load("@prelude-nri//elm:toolchain.bzl", "elm_toolchain")
load("@prelude-nri//node:toolchain.bzl", "node_toolchain")
system_genrule_toolchain(
name = "genrule",
@ -45,3 +46,8 @@ genrule(
out = "elm",
executable = True,
)
node_toolchain(
name = "node",
visibility = ["PUBLIC"],
)