Skip to main content
Glama
pnpm.bzl35.2 kB
load( "@prelude//:artifacts.bzl", "ArtifactGroupInfo", ) load( "@prelude//:paths.bzl", "paths", ) load( "@prelude//decls/re_test_common.bzl", "re_test_common", ) load( "@prelude//python:toolchain.bzl", "PythonToolchainInfo", ) load( "@prelude//test/inject_test_run_info.bzl", "inject_test_run_info", ) load( "@prelude-si//:test.bzl", "inject_test_env", ) load( "//pnpm:toolchain.bzl", "PnpmToolchainInfo", ) TypescriptDistInfo = provider(fields = { "index_file": provider_field(str, default = "index.js"), # [str] }) TypescriptRunnableDistInfo = provider(fields = { "runnable_dist": provider_field(typing.Any, default = None), # [Artifact] "bin": provider_field(typing.Any, default = None), # [str] }) def _npm_test_impl( ctx: AnalysisContext, program_run_info: RunInfo, program_args: cmd_args, test_info_type: str) -> list[[ DefaultInfo, RunInfo, ExternalRunnerTestInfo, ]]: pnpm_toolchain = ctx.attrs._pnpm_toolchain[PnpmToolchainInfo] package_build_ctx = package_build_context(ctx) if ctx.attrs.pnpm_exec_cmd_override: exec_cmd = cmd_args( "pnpm", "exec", ctx.attrs.pnpm_exec_cmd_override, ) else: exec_cmd = cmd_args(program_run_info, format = "{}::abspath") run_cmd_args = cmd_args([ ctx.attrs._python_toolchain[PythonToolchainInfo].interpreter, pnpm_toolchain.exec_cmd[DefaultInfo].default_outputs, "--cwd", cmd_args([package_build_ctx.srcs_tree, ctx.label.package], delimiter = "/"), "--", exec_cmd, ]) run_cmd_args.add(program_args) args_file = ctx.actions.write("args.txt", run_cmd_args) # We implicitly make the target run from the project root if remote # excution options were specified run_from_project_root = "buck2_run_from_project_root" in ( ctx.attrs.labels or [] ) return inject_test_run_info( ctx, ExternalRunnerTestInfo( type = test_info_type, command = [run_cmd_args], env = ctx.attrs.env, labels = ctx.attrs.labels, contacts = ctx.attrs.contacts, run_from_project_root = run_from_project_root, use_project_relative_paths = run_from_project_root, ), ) + [ DefaultInfo(default_output = args_file), ] def eslint_impl(ctx: AnalysisContext) -> list[[ DefaultInfo, RunInfo, ExternalRunnerTestInfo, ]]: args = cmd_args() args.add(ctx.attrs.directories) args.add("--ext") args.add(",".join(ctx.attrs.extensions)) if ctx.attrs.warnings == False: args.add("--max-warnings=0") args.add(ctx.attrs.args) return _npm_test_impl( ctx, ctx.attrs.eslint[RunInfo], args, "eslint", ) eslint = rule( impl = eslint_impl, attrs = { "srcs": attrs.list( attrs.source(), default = [], doc = """List of package source files to track.""", ), "prod_deps_srcs": attrs.dict( attrs.string(), attrs.source(allow_directory = True), default = {}, doc = """Mapping of dependent prod package paths to source files to track.""", ), "dev_deps_srcs": attrs.dict( attrs.string(), attrs.source(allow_directory = True), default = {}, doc = """Mapping of dependent dev package paths to source files from to track.""", ), "eslint": attrs.dep( providers = [RunInfo], doc = """eslint dependency.""", ), "directories": attrs.list( attrs.string(), default = ["src", "test"], doc = """Directories under which to check.""", ), "extensions": attrs.list( attrs.string(), default = [".ts", ".js", ".cjs", ".vue"], doc = """File extensions to search for.""", ), "args": attrs.list( attrs.string(), default = [], doc = """Extra arguments passed to eslint.""", ), "warnings": attrs.bool( default = False, doc = """If `False`, then exit non-zero (treat warnings as errors).""", ), "package_node_modules": attrs.source( doc = """Target which builds package `node_modules`.""", ), "pnpm_exec_cmd_override": attrs.option( attrs.string(), default = None, doc = """Invoke a command via 'pnpm exec' rather than npm_bin script.""", ), "_python_toolchain": attrs.toolchain_dep( default = "toolchains//:python", providers = [PythonToolchainInfo], ), "_pnpm_toolchain": attrs.toolchain_dep( default = "toolchains//:pnpm", providers = [PnpmToolchainInfo], ), } | re_test_common.test_args() | inject_test_env.args(), ) def ts_test_impl(ctx: AnalysisContext) -> list[[ DefaultInfo, RunInfo, ExternalRunnerTestInfo, ]]: args = cmd_args() args.add(ctx.attrs.args) return _npm_test_impl( ctx, ctx.attrs.program[RunInfo], args, "ts_test", ) ts_test = rule( impl = ts_test_impl, attrs = { "srcs": attrs.list( attrs.source(), default = [], doc = """List of package source files to track.""", ), "prod_deps_srcs": attrs.dict( attrs.string(), attrs.source(allow_directory = True), default = {}, doc = """Mapping of dependent prod package paths to source files to track.""", ), "dev_deps_srcs": attrs.dict( attrs.string(), attrs.source(allow_directory = True), default = {}, doc = """Mapping of dependent dev package paths to source files from to track.""", ), "program": attrs.dep( providers = [RunInfo], doc = """test program to run.""", ), "args": attrs.list( attrs.string(), default = [], doc = """Extra arguments passed to test program.""", ), "package_node_modules": attrs.source( doc = """Target which builds package `node_modules`.""", ), "pnpm_exec_cmd_override": attrs.option( attrs.string(), default = None, doc = """Invoke a command via 'pnpm exec' rather than npm_bin script.""", ), "_python_toolchain": attrs.toolchain_dep( default = "toolchains//:python", providers = [PythonToolchainInfo], ), "_pnpm_toolchain": attrs.toolchain_dep( default = "toolchains//:pnpm", providers = [PnpmToolchainInfo], ), } | re_test_common.test_args() | inject_test_env.args(), ) def typescript_check_impl(ctx: AnalysisContext) -> list[[ DefaultInfo, RunInfo, ExternalRunnerTestInfo, ]]: args = cmd_args() args.add("--noEmit") args.add(ctx.attrs.args) return _npm_test_impl( ctx, ctx.attrs.tsc[RunInfo], args, "tsc", ) typescript_check = rule( impl = typescript_check_impl, attrs = { "srcs": attrs.list( attrs.source(), default = [], doc = """List of package source files to track.""", ), "prod_deps_srcs": attrs.dict( attrs.string(), attrs.source(allow_directory = True), default = {}, doc = """Mapping of dependent prod package paths to source files to track.""", ), "dev_deps_srcs": attrs.dict( attrs.string(), attrs.source(allow_directory = True), default = {}, doc = """Mapping of dependent dev package paths to source files from to track.""", ), "tsc": attrs.dep( providers = [RunInfo], doc = """tsc dependency.""", ), "args": attrs.list( attrs.string(), default = [], doc = """Extra arguments passed to tsc.""", ), "package_node_modules": attrs.source( doc = """Target which builds package `node_modules`.""", ), "pnpm_exec_cmd_override": attrs.option( attrs.string(), default = None, doc = """Invoke a command via 'pnpm exec' rather than npm_bin script.""", ), "_python_toolchain": attrs.toolchain_dep( default = "toolchains//:python", providers = [PythonToolchainInfo], ), "_pnpm_toolchain": attrs.toolchain_dep( default = "toolchains//:pnpm", providers = [PnpmToolchainInfo], ), } | re_test_common.test_args() | inject_test_env.args(), ) def prettier_check_impl(ctx: AnalysisContext) -> list[[ DefaultInfo, RunInfo, ExternalRunnerTestInfo, ]]: args = cmd_args() args.add("--check") args.add(ctx.attrs.args) args.add(".") return _npm_test_impl( ctx, ctx.attrs.prettier[RunInfo], args, "prettier", ) prettier_check = rule( impl = prettier_check_impl, attrs = { "srcs": attrs.list( attrs.source(), default = [], doc = """List of package source files to track.""", ), "prod_deps_srcs": attrs.dict( attrs.string(), attrs.source(allow_directory = True), default = {}, doc = """Mapping of dependent prod package paths to source files to track.""", ), "dev_deps_srcs": attrs.dict( attrs.string(), attrs.source(allow_directory = True), default = {}, doc = """Mapping of dependent dev package paths to source files from to track.""", ), "prettier": attrs.dep( providers = [RunInfo], doc = """prettier dependency.""", ), "args": attrs.list( attrs.string(), default = [], doc = """Extra arguments passed to prettier.""", ), "package_node_modules": attrs.source( doc = """Target which builds package `node_modules`.""", ), "pnpm_exec_cmd_override": attrs.option( attrs.string(), default = None, doc = """Invoke a command via 'pnpm exec' rather than npm_bin script.""", ), "_python_toolchain": attrs.toolchain_dep( default = "toolchains//:python", providers = [PythonToolchainInfo], ), "_pnpm_toolchain": attrs.toolchain_dep( default = "toolchains//:pnpm", providers = [PnpmToolchainInfo], ), } | re_test_common.test_args() | inject_test_env.args(), ) def node_pkg_bin_impl(ctx: AnalysisContext) -> list[[DefaultInfo, RunInfo]]: bin_name = ctx.attrs.bin_name or ctx.attrs.name out = ctx.actions.declare_output(bin_name) pnpm_toolchain = ctx.attrs._pnpm_toolchain[PnpmToolchainInfo] package_dir = cmd_args(ctx.label.package).relative_to(ctx.label.cell_root) cmd = cmd_args( ctx.attrs._python_toolchain[PythonToolchainInfo].interpreter, pnpm_toolchain.build_pkg_bin[DefaultInfo].default_outputs, "--pkg-bin", ctx.attrs.pkg[RunInfo], "--package-dir", package_dir, "--package-node-modules-path", ctx.attrs.package_node_modules, "--dist-path", ctx.attrs.dist, ) for src in ctx.attrs.extra_srcs: cmd.add(["--extra-src", src]) cmd.add(out.as_output()) ctx.actions.run(cmd, category = "pkg", local_only = True) return [ DefaultInfo(default_output = out), RunInfo(out), ] node_pkg_bin = rule( impl = node_pkg_bin_impl, attrs = { "pkg": attrs.dep( providers = [RunInfo], doc = """pkg dependency.""", ), "bin_name": attrs.option( attrs.string(), default = None, doc = """Output bin name (default: attrs.name).""", ), "dist": attrs.source( doc = """Target which which builds a `dist`.""", ), "package_node_modules": attrs.source( doc = """Target which builds package `node_modules`.""", ), "extra_srcs": attrs.list( attrs.source(), default = [], doc = "Additional file(s) needed to produce the binary", ), "_python_toolchain": attrs.toolchain_dep( default = "toolchains//:python", providers = [PythonToolchainInfo], ), "_pnpm_toolchain": attrs.toolchain_dep( default = "toolchains//:pnpm", providers = [PnpmToolchainInfo], ), }, ) def npm_bin_impl(ctx: AnalysisContext) -> list[[DefaultInfo, RunInfo, TemplatePlaceholderInfo]]: bin_name = ctx.attrs.bin_name or ctx.attrs.name exe = ctx.actions.declare_output(bin_name) pnpm_toolchain = ctx.attrs._pnpm_toolchain[PnpmToolchainInfo] cmd = cmd_args( ctx.attrs._python_toolchain[PythonToolchainInfo].interpreter, pnpm_toolchain.build_npm_bin[DefaultInfo].default_outputs, "--bin-out-path", exe.as_output(), ) if not ctx.attrs.workspace: cmd.add("--package-dir") cmd.add(ctx.label.package) cmd.add([ ctx.attrs.node_modules, bin_name, ]) ctx.actions.run(cmd, category = "build_npm_bin", identifier = bin_name, local_only = True) return [ DefaultInfo(default_output = exe), RunInfo(exe), TemplatePlaceholderInfo( keyed_variables = { "exe": exe, }, ), ] npm_bin = rule( impl = npm_bin_impl, attrs = { "bin_name": attrs.option( attrs.string(), default = None, doc = """Node module bin name (default: attrs.name).""", ), "workspace": attrs.bool( default = False, doc = """Whether the binary script is in the workspace root.""", ), "node_modules": attrs.source( doc = """Target which builds `node_modules`.""", ), "_python_toolchain": attrs.toolchain_dep( default = "toolchains//:python", providers = [PythonToolchainInfo], ), "_pnpm_toolchain": attrs.toolchain_dep( default = "toolchains//:pnpm", providers = [PnpmToolchainInfo], ), }, ) def package_node_modules_impl(ctx: AnalysisContext) -> list[DefaultInfo]: node_modules_ctx = node_modules_context(ctx, ctx.attrs.prod_only) return [DefaultInfo(default_output = node_modules_ctx.root)] package_node_modules = rule( impl = package_node_modules_impl, attrs = { "turbo": attrs.dep( providers = [RunInfo], default = "root//third-party/node/turbo:turbo", doc = """Turbo dependency.""", ), "pnpm_lock": attrs.source( default = "root//:pnpm-lock.yaml", doc = """Workspace Pnpm lock file""", ), "package_name": attrs.option( attrs.string(), default = None, doc = "Explicitly set the npm package name if it differs from directory name", ), "root_workspace": attrs.bool( default = True, ), "prod_only": attrs.bool( default = False, doc = "Only install production dependencies", ), "_python_toolchain": attrs.toolchain_dep( default = "toolchains//:python", providers = [PythonToolchainInfo], ), "_pnpm_toolchain": attrs.toolchain_dep( default = "toolchains//:pnpm", providers = [PnpmToolchainInfo], ), }, ) def pnpm_lock_impl(ctx: AnalysisContext) -> list[DefaultInfo]: out = ctx.actions.declare_output("pnpm-lock.yaml") output = ctx.actions.copy_file(out, ctx.attrs.src) return [DefaultInfo(default_output = out)] pnpm_lock = rule( impl = pnpm_lock_impl, attrs = { "src": attrs.source( doc = """pnpm-lock.yaml source.""", ), "pnpm_workspace": attrs.dep( default = "root//:pnpm-workspace.yaml", doc = """Pnpm Workspace dependency.""", ), }, ) def pnpm_workspace_impl(ctx: AnalysisContext) -> list[[DefaultInfo, ArtifactGroupInfo]]: out = ctx.actions.declare_output("pnpm-workspace.yaml") output = ctx.actions.copy_file(out, ctx.attrs.src) ctx.actions.write_json("member-packages.json", ctx.attrs.packages) return [ DefaultInfo(default_output = output), ArtifactGroupInfo(artifacts = [ctx.attrs.workspace_package] + ctx.attrs.packages), ] pnpm_workspace = rule( impl = pnpm_workspace_impl, attrs = { "src": attrs.source( doc = """pnpm-workspace.yaml source.""", ), "workspace_package": attrs.source( doc = """Workspace root package.json source.""", ), "packages": attrs.list( attrs.source(), default = [], doc = """List of package.json files to track.""", ), }, ) def typescript_dist_impl(ctx: AnalysisContext) -> list[[DefaultInfo, TypescriptDistInfo]]: out = ctx.actions.declare_output("dist", dir = True) if ctx.attrs.tsc and ctx.attrs.tsup: fail("Only one of `tsc` or `tsup` must be set") elif ctx.attrs.tsc: ts_compiler = ctx.attrs.tsc[RunInfo] index_file = "index.js" elif ctx.attrs.tsup: ts_compiler = ctx.attrs.tsup[RunInfo] index_file = "index.cjs" else: fail("Either `tsc` or `tsup` attribute is required") pnpm_toolchain = ctx.attrs._pnpm_toolchain[PnpmToolchainInfo] package_build_ctx = package_build_context(ctx) cmd = cmd_args( ctx.attrs._python_toolchain[PythonToolchainInfo].interpreter, pnpm_toolchain.exec_cmd[DefaultInfo].default_outputs, "--cwd", cmd_args([package_build_ctx.srcs_tree, ctx.label.package], delimiter = "/"), "--", cmd_args(ts_compiler, format = "{}::abspath"), ) if ctx.attrs.tsup: cmd.add("--out-dir") else: cmd.add("--outDir") cmd.add(cmd_args(out.as_output(), format = "{}::relpath")) if ctx.attrs.args: cmd.append(ctx.attrs.args) ctx.actions.run(cmd, category = "tsc", local_only = True) return [ DefaultInfo(default_output = out), TypescriptDistInfo(index_file = index_file), ] typescript_dist = rule( impl = typescript_dist_impl, attrs = { "tsc": attrs.option( attrs.dep(providers = [RunInfo]), default = None, doc = """TypeScript compiler dependency.""", ), "tsup": attrs.option( attrs.dep(providers = [RunInfo]), default = None, doc = """tsup compiler dependency.""", ), "srcs": attrs.list( attrs.source(), default = [], doc = """List of package source files to track.""", ), "prod_deps_srcs": attrs.dict( attrs.string(), attrs.source(allow_directory = True), default = {}, doc = """Mapping of dependent prod package paths to source files to track.""", ), "dev_deps_srcs": attrs.dict( attrs.string(), attrs.source(allow_directory = True), default = {}, doc = """Mapping of dependent dev package paths to source files from to track.""", ), "args": attrs.option( attrs.list(attrs.arg()), default = None, doc = """Extra script arguments.""", ), "dist_dir": attrs.string( default = "dist", doc = """Output directory from the compilation.""", ), "package_node_modules": attrs.source( doc = """Target which builds package `node_modules`.""", ), "_python_toolchain": attrs.toolchain_dep( default = "toolchains//:python", providers = [PythonToolchainInfo], ), "_pnpm_toolchain": attrs.toolchain_dep( default = "toolchains//:pnpm", providers = [PnpmToolchainInfo], ), }, ) def typescript_runnable_dist_impl(ctx: AnalysisContext) -> list[[ DefaultInfo, RunInfo, TypescriptRunnableDistInfo, ]]: runnable_dist_ctx = package_runnable_dist_context(ctx) out = runnable_dist_ctx.tree pnpm_toolchain = ctx.attrs._pnpm_toolchain[PnpmToolchainInfo] package_dir = cmd_args(ctx.label.package).relative_to(ctx.label.cell_root) bin = paths.join("bin", paths.basename(ctx.label.package)) run_cmd = cmd_args( cmd_args([out, bin], delimiter = "/"), ) return [ DefaultInfo(default_output = out), RunInfo(run_cmd), TypescriptRunnableDistInfo( runnable_dist = out, bin = bin, ), ] typescript_runnable_dist = rule( impl = typescript_runnable_dist_impl, attrs = { "typescript_dist": attrs.dep( providers = [TypescriptDistInfo], doc = """Target which builds the Typescript dist artifact.""", ), "package_node_modules_prod": attrs.dep( doc = """Target which builds package `node_modules` with prod-only modules.""", ), "_python_toolchain": attrs.toolchain_dep( default = "toolchains//:python", providers = [PythonToolchainInfo], ), "_pnpm_toolchain": attrs.toolchain_dep( default = "toolchains//:pnpm", providers = [PnpmToolchainInfo], ), }, ) def typescript_runnable_dist_bin_impl(ctx: AnalysisContext) -> list[[DefaultInfo, RunInfo]]: base_path = ctx.attrs.typescript_runnable_dist[DefaultInfo].default_outputs[0] bin = ctx.attrs.typescript_runnable_dist[TypescriptRunnableDistInfo].bin cd_path = cmd_args([base_path, paths.dirname(bin)], delimiter = "/") out = ctx.actions.declare_output(paths.basename(bin)) pnpm_toolchain = ctx.attrs._pnpm_toolchain[PnpmToolchainInfo] cmd = cmd_args( ctx.attrs._python_toolchain[PythonToolchainInfo].interpreter, pnpm_toolchain.build_typescript_runnable_dist_bin[DefaultInfo].default_outputs, "--cd-path", cd_path, "--rel-path", paths.basename(bin), out.as_output(), hidden = [base_path], ) ctx.actions.run(cmd, category = "pnpm", identifier = "typescript_runnable_dist_bin", local_only = True) return [ DefaultInfo(default_output = out), RunInfo(out), ] typescript_runnable_dist_bin = rule( impl = typescript_runnable_dist_bin_impl, attrs = { "typescript_runnable_dist": attrs.dep( doc = """Target which builds the runnable Typescript dist artifact.""", ), "_python_toolchain": attrs.toolchain_dep( default = "toolchains//:python", providers = [PythonToolchainInfo], ), "_pnpm_toolchain": attrs.toolchain_dep( default = "toolchains//:pnpm", providers = [PnpmToolchainInfo], ), }, ) def vite_app_impl(ctx: AnalysisContext) -> list[[DefaultInfo, RunInfo]]: out = ctx.actions.declare_output("dist", dir = True) pnpm_toolchain = ctx.attrs._pnpm_toolchain[PnpmToolchainInfo] package_build_ctx = package_build_context(ctx) if ctx.attrs.pnpm_exec_cmd_override: exec_cmd = cmd_args( "pnpm", "exec", ctx.attrs.pnpm_exec_cmd_override, ) else: exec_cmd = cmd_args(ctx.attrs.vite[RunInfo], format = "{}::abspath") cmd = cmd_args( ctx.attrs._python_toolchain[PythonToolchainInfo].interpreter, pnpm_toolchain.exec_cmd[DefaultInfo].default_outputs, "--cwd", cmd_args([package_build_ctx.srcs_tree, ctx.label.package], delimiter = "/"), "--copy-tree", cmd_args(["dist", cmd_args(out.as_output(), format = "{}::abspath")], delimiter = "="), "--", exec_cmd, "build", ) ctx.actions.run(cmd, category = "vite", identifier = "build", local_only = True) run_cmd = cmd_args( ctx.attrs._python_toolchain[PythonToolchainInfo].interpreter, pnpm_toolchain.exec_cmd[DefaultInfo].default_outputs, "--cwd", cmd_args([out, ".."], delimiter = "/"), "--", ctx.attrs.vite[RunInfo], "preview", ) return [ DefaultInfo(default_output = out), RunInfo(run_cmd), ] vite_app = rule( impl = vite_app_impl, attrs = { "vite": attrs.dep( providers = [RunInfo], doc = """vite dependency.""", ), "srcs": attrs.list( attrs.source(), default = [], doc = """List of package source files to track.""", ), "prod_deps_srcs": attrs.dict( attrs.string(), attrs.source(allow_directory = True), default = {}, doc = """Mapping of dependent prod package paths to source files to track.""", ), "dev_deps_srcs": attrs.dict( attrs.string(), attrs.source(allow_directory = True), default = {}, doc = """Mapping of dependent dev package paths to source files from to track.""", ), "package_node_modules": attrs.source( doc = """Target which builds package `node_modules`.""", ), "pnpm_exec_cmd_override": attrs.option( attrs.string(), default = None, doc = """Invoke a command via 'pnpm exec' rather than npm_bin script.""", ), "_python_toolchain": attrs.toolchain_dep( default = "toolchains//:python", providers = [PythonToolchainInfo], ), "_pnpm_toolchain": attrs.toolchain_dep( default = "toolchains//:pnpm", providers = [PnpmToolchainInfo], ), }, ) def workspace_node_modules_impl(ctx: AnalysisContext) -> list[DefaultInfo]: out = ctx.actions.declare_output("root", dir = True) pnpm_toolchain = ctx.attrs._pnpm_toolchain[PnpmToolchainInfo] package_dir = cmd_args(ctx.label.package).relative_to(ctx.label.cell_root) cmd = cmd_args( ctx.attrs._python_toolchain[PythonToolchainInfo].interpreter, pnpm_toolchain.build_workspace_node_modules[DefaultInfo].default_outputs, hidden = [ctx.attrs.pnpm_lock], ) if ctx.attrs.root_workspace: cmd.add("--package-dir") cmd.add(package_dir) else: cmd.add("--root-dir") cmd.add(package_dir) cmd.add(out.as_output()) ctx.actions.run(cmd, category = "pnpm", identifier = "install", local_only = True) return [DefaultInfo(default_output = out)] workspace_node_modules = rule( impl = workspace_node_modules_impl, attrs = { "pnpm_lock": attrs.source( default = "root//:pnpm-lock.yaml", doc = """Workspace Pnpm lock file""", ), "root_workspace": attrs.bool( default = True, ), "_python_toolchain": attrs.toolchain_dep( default = "toolchains//:python", providers = [PythonToolchainInfo], ), "_pnpm_toolchain": attrs.toolchain_dep( default = "toolchains//:pnpm", providers = [PnpmToolchainInfo], ), }, ) NodeModulesContext = record( root = field(Artifact), ) def node_modules_context( ctx: AnalysisContext, prod_only: bool = False, out_dir: str = "root") -> NodeModulesContext: out = ctx.actions.declare_output(out_dir, dir = True) pnpm_toolchain = ctx.attrs._pnpm_toolchain[PnpmToolchainInfo] package_dir = cmd_args(ctx.label.package).relative_to(ctx.label.cell_root) cmd = cmd_args( ctx.attrs._python_toolchain[PythonToolchainInfo].interpreter, pnpm_toolchain.build_package_node_modules[DefaultInfo].default_outputs, "--turbo-bin", ctx.attrs.turbo[RunInfo], hidden = [ctx.attrs.pnpm_lock], ) if ctx.attrs.package_name: cmd.add("--package-name") cmd.add(ctx.attrs.package_name) if ctx.attrs.root_workspace: cmd.add("--package-dir") cmd.add(package_dir) else: cmd.add("--root-dir") cmd.add(package_dir) if prod_only: cmd.add("--prod-only") cmd.add(out.as_output()) ctx.actions.run(cmd, category = "pnpm", identifier = "install " + ctx.label.package, local_only = True) return NodeModulesContext(root = out) PackageBuildContext = record( # Root of a workspace source tree containing a pruned sub-package and all node_modules srcs_tree = field(Artifact), ) def package_build_context(ctx: AnalysisContext) -> PackageBuildContext: srcs_tree = ctx.actions.declare_output("__src") pnpm_toolchain = ctx.attrs._pnpm_toolchain[PnpmToolchainInfo] package_dir = cmd_args(ctx.label.package).relative_to(ctx.label.cell_root) cmd = cmd_args( ctx.attrs._python_toolchain[PythonToolchainInfo].interpreter, pnpm_toolchain.package_build_context[DefaultInfo].default_outputs, "--package-dir", package_dir, "--package-node-modules-path", ctx.attrs.package_node_modules, ) for src in ctx.attrs.srcs: cmd.add("--src") cmd.add(cmd_args(src, format = ctx.label.package + "={}")) for (name, src) in ctx.attrs.prod_deps_srcs.items(): cmd.add("--src") cmd.add(cmd_args(src, format = name + "={}")) for (name, src) in ctx.attrs.dev_deps_srcs.items(): cmd.add("--src") cmd.add(cmd_args(src, format = name + "={}")) if pnpm_toolchain.editorconfig: cmd.add("--editorconfig") cmd.add(pnpm_toolchain.editorconfig) cmd.add(srcs_tree.as_output()) ctx.actions.run(cmd, category = "package_build_context", local_only = True) return PackageBuildContext( srcs_tree = srcs_tree, ) PackageDistContext = record( tree = field(Artifact), ) def package_runnable_dist_context( ctx: AnalysisContext, dist_path: [Artifact, None] = None) -> PackageDistContext: out = ctx.actions.declare_output("runnable_dist", dir = True) pnpm_toolchain = ctx.attrs._pnpm_toolchain[PnpmToolchainInfo] package_dir = cmd_args(ctx.label.package).relative_to(ctx.label.cell_root) if not dist_path: dist_path = ctx.attrs.typescript_dist[DefaultInfo].default_outputs[0] cmd = cmd_args( ctx.attrs._python_toolchain[PythonToolchainInfo].interpreter, pnpm_toolchain.package_dist_context[DefaultInfo].default_outputs, "--package-dir", package_dir, "--package-node-modules-path", ctx.attrs.package_node_modules_prod[DefaultInfo].default_outputs[0], "--dist-path", dist_path, "--index-file", ctx.attrs.typescript_dist[TypescriptDistInfo].index_file, ) cmd.add(out.as_output()) ctx.actions.run(cmd, category = "package_runnable_dist_context", local_only = True) return PackageDistContext( tree = out, ) def pnpm_task_library_impl(ctx: AnalysisContext) -> list[DefaultInfo]: script = ctx.actions.write("pnpm-run.sh", """\ #!/usr/bin/env bash set -euo pipefail rootpath="$(git rev-parse --show-toplevel)" npm_package_path="$1" npm_run_command="$2" buck_out_directory="$3" output_paths="$4" mkdir -p "$buck_out_directory" cd "$rootpath/$npm_package_path" pnpm run --report-summary "$npm_run_command" if [[ ! -z "$output_paths" ]]; then cp -vr "$output_paths" "$rootpath/$buck_out_directory/" fi """, is_executable = True) out = ctx.actions.declare_output("out", dir = True) output_join = " ".join(ctx.attrs.outs) args = cmd_args( [script, ctx.attrs.path, ctx.attrs.command, out.as_output(), output_join], hidden = [ctx.attrs.srcs, ctx.attrs.deps], ) ctx.actions.run(args, category = "pnpm", identifier = "run_library", local_only = True) return [DefaultInfo(default_outputs = [out])] pnpm_task_library = rule(impl = pnpm_task_library_impl, attrs = { "command": attrs.string(default = "start", doc = """pnpm command to run"""), "path": attrs.string(default = "path", doc = """the path to run the command from"""), "deps": attrs.list(attrs.source(), default = [], doc = """List of dependencies we require"""), "srcs": attrs.list(attrs.source(), default = [], doc = """List of sources we require"""), "outs": attrs.list(attrs.string(), default = [], doc = "List of outputs to copy"), }) def pnpm_task_binary_impl(ctx: AnalysisContext) -> list[[DefaultInfo, RunInfo]]: script = ctx.actions.write("pnpm-run.sh", """\ #!/usr/bin/env bash set -euo pipefail rootpath="$(git rev-parse --show-toplevel)" npm_package_path="$1" npm_run_command="$2" cd "$rootpath/$npm_package_path" pnpm run --report-summary "$npm_run_command" """, is_executable = True) args = cmd_args( [script, ctx.attrs.path, ctx.attrs.command], hidden = [ctx.attrs.deps, ctx.attrs.srcs], ) return [DefaultInfo(), RunInfo(args = args)] pnpm_task_binary = rule(impl = pnpm_task_binary_impl, attrs = { "command": attrs.string(default = "start", doc = """pnpm command to run"""), "path": attrs.string(default = "path", doc = """the path to run the comamnd from"""), "srcs": attrs.list(attrs.source(), default = [], doc = """List of sources we require"""), "deps": attrs.list(attrs.source(), default = [], doc = """List of dependencies we require"""), }) def pnpm_task_test_impl(ctx: AnalysisContext) -> list[[DefaultInfo, ExternalRunnerTestInfo]]: script = ctx.actions.write("pnpm-run.sh", """\ #!/usr/bin/env bash set -euo pipefail rootpath="$(git rev-parse --show-toplevel)" npm_package_path="$1" npm_run_command="$2" cd "$rootpath/$npm_package_path" pnpm install pnpm run --report-summary "$npm_run_command" """, is_executable = True) args = cmd_args( [script, ctx.attrs.path, ctx.attrs.command], hidden = [ctx.attrs.deps, ctx.attrs.srcs], ) return [DefaultInfo(), ExternalRunnerTestInfo(type = "integration", command = [script, ctx.attrs.path, ctx.attrs.command])] pnpm_task_test = rule(impl = pnpm_task_test_impl, attrs = { "command": attrs.string(default = "start", doc = """pnpm command to run"""), "path": attrs.string(default = "path", doc = """the path to run the comamnd from"""), "srcs": attrs.list(attrs.source(), default = [], doc = """List of sources we require"""), "deps": attrs.list(attrs.source(), default = [], doc = """List of dependencies we require"""), })

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/systeminit/si'

If you have feedback or need assistance with the MCP directory API, please join our Discord server