114 lines
4.7 KiB
Python
114 lines
4.7 KiB
Python
"""Shared Bun workspace metadata helpers."""
|
|
|
|
BunWorkspaceInfo = provider(
|
|
doc = "Workspace/runtime metadata shared by Bun rules and adapters.",
|
|
fields = {
|
|
"install_metadata_file": "Optional install metadata file from bun_install.",
|
|
"install_repo_runfiles_path": "Runfiles root for the node_modules repository when present.",
|
|
"metadata_file": "Rule-local metadata file describing the staged workspace inputs.",
|
|
"node_modules_files": "Depset of node_modules files from bun_install.",
|
|
"node_modules_roots": "Sorted repo-relative node_modules roots available in runfiles.",
|
|
"package_dir_hint": "Package-relative directory when known at analysis time.",
|
|
"package_json": "Package manifest file when explicitly provided.",
|
|
"primary_file": "Primary source file used to resolve the runtime package context.",
|
|
"runtime_files": "Depset of runtime files required to stage the workspace.",
|
|
},
|
|
)
|
|
|
|
def find_install_metadata_file(files):
|
|
for file in files:
|
|
if file.short_path.endswith("node_modules/.rules_bun/install.json"):
|
|
return file
|
|
return None
|
|
|
|
def _runfiles_workspace(file):
|
|
workspace_name = file.owner.workspace_name
|
|
if workspace_name:
|
|
return workspace_name
|
|
return "_main"
|
|
|
|
def _repo_relative_short_path(file):
|
|
short_path = file.short_path.replace("\\", "/")
|
|
workspace_name = _runfiles_workspace(file)
|
|
external_prefix = "../{}/".format(workspace_name)
|
|
if short_path.startswith(external_prefix):
|
|
return short_path[len(external_prefix):]
|
|
if short_path == "../{}".format(workspace_name):
|
|
return "."
|
|
return short_path
|
|
|
|
def resolve_node_modules_roots(files):
|
|
roots = {}
|
|
marker = "/node_modules/"
|
|
for file in files:
|
|
short_path = _repo_relative_short_path(file)
|
|
if short_path == "node_modules" or short_path.startswith("node_modules/"):
|
|
roots["node_modules"] = True
|
|
|
|
marker_index = short_path.find(marker)
|
|
if marker_index >= 0:
|
|
roots[short_path[:marker_index + len("/node_modules")]] = True
|
|
|
|
return sorted(roots.keys())
|
|
|
|
def create_bun_workspace_info(ctx, primary_file = None, package_json = None, package_dir_hint = ".", extra_files = None):
|
|
direct_runtime_files = []
|
|
if primary_file:
|
|
direct_runtime_files.append(primary_file)
|
|
if package_json and package_json != primary_file:
|
|
direct_runtime_files.append(package_json)
|
|
direct_runtime_files.extend(extra_files or [])
|
|
|
|
node_modules_files = depset()
|
|
install_metadata_file = None
|
|
install_repo_runfiles_path = ""
|
|
node_modules_roots = []
|
|
if getattr(ctx.attr, "node_modules", None):
|
|
node_modules_files = ctx.attr.node_modules[DefaultInfo].files
|
|
node_modules_file_list = node_modules_files.to_list()
|
|
install_metadata_file = find_install_metadata_file(node_modules_file_list)
|
|
node_modules_roots = resolve_node_modules_roots(node_modules_file_list)
|
|
if install_metadata_file:
|
|
install_repo_runfiles_path = _runfiles_workspace(install_metadata_file)
|
|
elif node_modules_file_list:
|
|
install_repo_runfiles_path = _runfiles_workspace(node_modules_file_list[0])
|
|
|
|
metadata_file = ctx.actions.declare_file(ctx.label.name + ".bun_workspace.json")
|
|
ctx.actions.write(
|
|
output = metadata_file,
|
|
content = json.encode({
|
|
"install_metadata": install_metadata_file.short_path if install_metadata_file else "",
|
|
"install_repo_runfiles_path": install_repo_runfiles_path,
|
|
"node_modules_roots": node_modules_roots,
|
|
"package_dir_hint": package_dir_hint or ".",
|
|
"package_json": package_json.short_path if package_json else "",
|
|
"primary_file": primary_file.short_path if primary_file else "",
|
|
}) + "\n",
|
|
)
|
|
direct_runtime_files.append(metadata_file)
|
|
|
|
runtime_files = depset(
|
|
direct = direct_runtime_files,
|
|
transitive = [node_modules_files],
|
|
)
|
|
|
|
return BunWorkspaceInfo(
|
|
install_metadata_file = install_metadata_file,
|
|
install_repo_runfiles_path = install_repo_runfiles_path,
|
|
metadata_file = metadata_file,
|
|
node_modules_files = node_modules_files,
|
|
node_modules_roots = node_modules_roots,
|
|
package_dir_hint = package_dir_hint or ".",
|
|
package_json = package_json,
|
|
primary_file = primary_file,
|
|
runtime_files = runtime_files,
|
|
)
|
|
|
|
def workspace_runfiles(ctx, workspace_info, direct_files = None, transitive_files = None):
|
|
return ctx.runfiles(
|
|
files = direct_files or [],
|
|
transitive_files = depset(
|
|
transitive = [workspace_info.runtime_files] + (transitive_files or []),
|
|
),
|
|
)
|