Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial Toolchain support #645

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ bzl_library(
"//internal/jasmine_node_test:bzl",
"//internal/npm_package:bzl",
"//internal/rollup:bzl",
"//toolchains/node:bzl",
],
)

Expand Down Expand Up @@ -61,6 +62,7 @@ npm_package(
"//internal/npm_install:package_contents",
"//internal/npm_package:package_contents",
"//internal/web_package:package_contents",
"//toolchains/node:package_contents",
],
)

Expand Down
14 changes: 11 additions & 3 deletions internal/common/os_name.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@
"""Helper function for repository rules
"""

OS_ARCH_NAMES = [
("darwin", "amd64"),
("windows", "amd64"),
("linux", "amd64"),
]

OS_NAMES = ["_".join(os_arch_name) for os_arch_name in OS_ARCH_NAMES]

def os_name(repository_ctx):
"""Get the os name for a repository rule

Expand All @@ -26,10 +34,10 @@ def os_name(repository_ctx):
"""
os_name = repository_ctx.os.name.lower()
if os_name.startswith("mac os"):
return "darwin_amd64"
return OS_NAMES[0]
elif os_name.find("windows") != -1:
return "windows_amd64"
return OS_NAMES[1]
elif os_name.startswith("linux"):
return "linux_amd64"
return OS_NAMES[2]
else:
fail("Unsupported operating system: " + os_name)
81 changes: 62 additions & 19 deletions internal/node/node.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ def _short_path_to_manifest_path(ctx, short_path):
return ctx.workspace_name + "/" + short_path

def _nodejs_binary_impl(ctx):
node = ctx.file.node
# node = ctx.file.node
node_modules = depset(ctx.files.node_modules)

# Also include files from npm fine grained deps as inputs.
Expand Down Expand Up @@ -151,15 +151,53 @@ def _nodejs_binary_impl(ctx):
if hasattr(ctx.attr, "expected_exit_code"):
expected_exit_code = ctx.attr.expected_exit_code

node_tool_info = ctx.toolchains["@build_bazel_rules_nodejs//toolchains/node:toolchain_type"].nodeinfo
node_tool_files = []
if node_tool_info.target_tool_path == "" and not node_tool_info.target_tool:
# If tool_path is empty and tool_target is None then there is no local
# node tool, we will just print a nice error message if the user
# attempts to do bazel run
ctx.actions.write(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is a critical failure then using fail("error message") would be better so execution stops at this point

content = ("echo node toolchain was not properly configured so %s cannot be executed." % ctx.attr.name),
output = ctx.outputs.script,
)
else:
node_tool = node_tool_info.target_tool_path
print(node_tool)
if node_tool_info.target_tool:
node_tool = _short_path_to_manifest_path(ctx, node_tool_info.target_tool.files.to_list()[0].short_path)

# print(node.short_path)
# print(_short_path_to_manifest_path(ctx, node.short_path))
# print(node_tool.path)
# print(node_tool.short_path)
# print(_short_path_to_manifest_path(ctx, node_tool.short_path))
# node_tool = _runfiles(ctx, node_tool_info.tool_target.files.to_list()[0])
node_tool_files += node_tool_info.target_tool.files.to_list()

print("------------")

# print(node_tool)
# print(node_tool.path)
# print(_short_path_to_manifest_path(ctx, node_tool))
# print(node.short_path)
# print(_short_path_to_manifest_path(ctx, node.short_path))
# print("------------")
print("node_tool_files", node_tool_files)

target_tool_args = node_tool_info.target_tool_args.files.to_list()[0]

substitutions = {
"TEMPLATED_args": " ".join([
expand_location_into_runfiles(ctx, a)
for a in ctx.attr.templated_args
]),
"TEMPLATED_env_vars": env_vars,
"TEMPLATED_expected_exit_code": str(expected_exit_code),
"TEMPLATED_node": _short_path_to_manifest_path(ctx, node.short_path),
"TEMPLATED_repository_args": _short_path_to_manifest_path(ctx, ctx.file._repository_args.short_path),
# "TEMPLATED_node": _short_path_to_manifest_path(ctx, node.short_path),
"TEMPLATED_node": node_tool,
"TEMPLATED_repository_args": _short_path_to_manifest_path(ctx, target_tool_args.short_path),
# "TEMPLATED_repository_args": "",
"TEMPLATED_script_path": script_path,
}
ctx.actions.expand_template(
Expand All @@ -169,14 +207,15 @@ def _nodejs_binary_impl(ctx):
is_executable = True,
)

runfiles = depset([node, ctx.outputs.loader, ctx.file._repository_args] + ctx.files._node_runfiles, transitive = [sources, node_modules])
runfiles = depset(node_tool_files + [ctx.outputs.loader, target_tool_args], transitive = [node_tool_info.target_tool_runfiles.files, sources, node_modules])
# runfiles = depset(node_tool_files + [ctx.outputs.loader] + node_modules, transitive = [sources])
# runfiles = depset([node, ctx.outputs.loader, ctx.file._repository_args] + ctx.files._node_runfiles, transitive = [sources, node_modules])

return [DefaultInfo(
executable = ctx.outputs.script,
runfiles = ctx.runfiles(
transitive_files = runfiles,
files = [
node,
files = node_tool_files + [
ctx.outputs.loader,
] + ctx.files._source_map_support_files +

Expand Down Expand Up @@ -222,11 +261,11 @@ _NODEJS_EXECUTABLE_ATTRS = {
in TypeScript.""",
default = True,
),
"node": attr.label(
doc = """The node entry point target.""",
default = Label("@nodejs//:node"),
allow_single_file = True,
),
# "node": attr.label(
# doc = """The node entry point target.""",
# default = Label("@nodejs//:node"),
# allow_single_file = True,
# ),
"node_modules": attr.label(
doc = """The npm packages which should be available to `require()` during
execution.
Expand Down Expand Up @@ -308,14 +347,16 @@ _NODEJS_EXECUTABLE_ATTRS = {
default = Label("//internal/node:node_loader.js"),
allow_single_file = True,
),
"_node_runfiles": attr.label(
default = Label("@nodejs//:node_runfiles"),
allow_files = True,
),
"_repository_args": attr.label(
default = Label("@nodejs//:bin/node_args.sh"),
allow_single_file = True,
),
# TODO(markus): Remove and get from toolchain
# "_node_runfiles": attr.label(
# default = Label("@nodejs//:node_runfiles"),
# allow_files = True,
# ),
# # TODO(markus): Remove and get from toolchain
# "_repository_args": attr.label(
# default = Label("@nodejs//:bin/node_args.sh"),
# allow_single_file = True,
# ),
"_source_map_support_files": attr.label_list(
default = [
Label("//third_party/github.com/buffer-from:contents"),
Expand All @@ -340,6 +381,7 @@ nodejs_binary = rule(
attrs = _NODEJS_EXECUTABLE_ATTRS,
executable = True,
outputs = _NODEJS_EXECUTABLE_OUTPUTS,
toolchains = ["@build_bazel_rules_nodejs//toolchains/node:toolchain_type"],
)
"""Runs some JavaScript code in NodeJS.
"""
Expand All @@ -354,6 +396,7 @@ nodejs_test = rule(
}),
test = True,
outputs = _NODEJS_EXECUTABLE_OUTPUTS,
toolchains = ["@build_bazel_rules_nodejs//toolchains/node:toolchain_type"],
)
"""
Identical to `nodejs_binary`, except this can be used with `bazel test` as well.
Expand Down
40 changes: 20 additions & 20 deletions internal/node/node_labels.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -17,37 +17,37 @@
Labels are different on windows and linux/OSX.
"""

def get_node_label(repository_ctx):
if repository_ctx.os.name.lower().find("windows") != -1:
label = Label("@nodejs//:bin/node.cmd")
def get_node_label(os_name):
if os_name.find("windows") != -1:
label = Label("@nodejs_%s//:bin/node.cmd" % os_name)
else:
label = Label("@nodejs//:bin/node")
label = Label("@nodejs_%s//:bin/node" % os_name)
return label

def get_npm_label(repository_ctx):
if repository_ctx.os.name.lower().find("windows") != -1:
label = Label("@nodejs//:bin/npm.cmd")
def get_npm_label(os_name):
if os_name.find("windows") != -1:
label = Label("@nodejs_%s//:bin/npm.cmd" % os_name)
else:
label = Label("@nodejs//:bin/npm")
label = Label("@nodejs_%s//:bin/npm" % os_name)
return label

def get_npm_node_repositories_label(repository_ctx):
if repository_ctx.os.name.lower().find("windows") != -1:
label = Label("@nodejs//:bin/npm_node_repositories.cmd")
def get_npm_node_repositories_label(os_name):
if os_name.find("windows") != -1:
label = Label("@nodejs_%s//:bin/npm_node_repositories.cmd" % os_name)
else:
label = Label("@nodejs//:bin/npm_node_repositories")
label = Label("@nodejs_%s//:bin/npm_node_repositories" % os_name)
return label

def get_yarn_label(repository_ctx):
if repository_ctx.os.name.lower().find("windows") != -1:
label = Label("@nodejs//:bin/yarn.cmd")
def get_yarn_label(os_name):
if os_name.find("windows") != -1:
label = Label("@nodejs_%s//:bin/yarn.cmd" % os_name)
else:
label = Label("@nodejs//:bin/yarn")
label = Label("@nodejs_%s//:bin/yarn" % os_name)
return label

def get_yarn_node_repositories_label(repository_ctx):
if repository_ctx.os.name.lower().find("windows") != -1:
label = Label("@nodejs//:bin/yarn_node_repositories.cmd")
def get_yarn_node_repositories_label(os_name):
if os_name.find("windows") != -1:
label = Label("@nodejs%s//:bin/yarn_node_repositories.cmd" % os_name)
else:
label = Label("@nodejs//:bin/yarn_node_repositories")
label = Label("@nodejs_%s//:bin/yarn_node_repositories" % os_name)
return label
41 changes: 37 additions & 4 deletions internal/node/node_repositories.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ See https://docs.bazel.build/versions/master/skylark/repository_rules.html
"""

load("//internal/common:check_bazel_version.bzl", "check_bazel_version")
load("//internal/common:os_name.bzl", "os_name")
load("//internal/common:os_name.bzl", "OS_NAMES", "os_name")
load("//internal/npm_install:npm_install.bzl", "yarn_install")
load("//third_party/github.com/bazelbuild/bazel-skylib:lib/paths.bzl", "paths")
load("//toolchains/node:node_configure.bzl", node_toolchain_configure = "node_configure")
load(":node_labels.bzl", "get_yarn_node_repositories_label")

# Callers that don't specify a particular version will get these.
Expand Down Expand Up @@ -129,8 +130,10 @@ def _download_node(repository_ctx):
"""
if repository_ctx.attr.vendored_node:
return

host = os_name(repository_ctx)
if repository_ctx.name == "nodejs":
host = os_name(repository_ctx)
else:
host = repository_ctx.name.split("nodejs_", 1)[1]
node_version = repository_ctx.attr.node_version
node_repositories = repository_ctx.attr.node_repositories
node_urls = repository_ctx.attr.node_urls
Expand Down Expand Up @@ -418,7 +421,14 @@ if %errorlevel% neq 0 exit /b %errorlevel%
"TEMPLATED_yarn_dir": YARN_DIR,
},
)
result = repository_ctx.execute([node_entry, "generate_build_file.js"])
host_os = os_name(repository_ctx)
if host_os in repository_ctx.attr.name or repository_ctx.attr.name == "nodejs":
# We have to use the relative path here otherwise bazel report a cycle
result = repository_ctx.execute([node_entry, "generate_build_file.js"])
else:
# Note: It seems we can only get a string identifying the os but not the architecture
result = repository_ctx.execute([repository_ctx.path(Label("@nodejs_%s//:bin/node" % host_os)), "generate_build_file.js"])

if result.return_code:
fail("node failed: \nSTDOUT:\n%s\nSTDERR:\n%s" % (result.stdout, result.stderr))

Expand Down Expand Up @@ -535,6 +545,7 @@ def node_repositories(
# 0.21.0: repository_ctx.report_progress API
check_bazel_version("0.21.0")

# This "nodejs" repo is just for convinience so one does not have to target @nodejs_<os_name>//...
_maybe(
_nodejs_repo,
name = "nodejs",
Expand All @@ -550,6 +561,28 @@ def node_repositories(
preserve_symlinks = preserve_symlinks,
)

# This needs to be setup so toolchains can access nodejs for all different versions
node_repository_names = []
for os_name in OS_NAMES:
node_repository_name = "nodejs_%s" % os_name
_maybe(
_nodejs_repo,
name = node_repository_name,
package_json = package_json,
node_version = node_version,
yarn_version = yarn_version,
vendored_node = vendored_node,
vendored_yarn = vendored_yarn,
node_repositories = node_repositories,
yarn_repositories = yarn_repositories,
node_urls = node_urls,
yarn_urls = yarn_urls,
preserve_symlinks = preserve_symlinks,
)
node_repository_names.append(node_repository_name)

node_toolchain_configure(node_repository_names)

_maybe(
_yarn_repo,
name = "yarn",
Expand Down
12 changes: 7 additions & 5 deletions internal/npm_install/npm_install.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,10 @@ def _add_data_dependencies(repository_ctx):
def _npm_install_impl(repository_ctx):
"""Core implementation of npm_install."""

is_windows = os_name(repository_ctx).find("windows") != -1
node = repository_ctx.path(get_node_label(repository_ctx))
npm = get_npm_label(repository_ctx)
os = os_name(repository_ctx)
is_windows = os.find("windows") != -1
node = repository_ctx.path(get_node_label(os))
npm = get_npm_label(os)
npm_args = ["install"]

if repository_ctx.attr.prod_only:
Expand Down Expand Up @@ -233,8 +234,9 @@ npm_install = repository_rule(
def _yarn_install_impl(repository_ctx):
"""Core implementation of yarn_install."""

node = repository_ctx.path(get_node_label(repository_ctx))
yarn = get_yarn_label(repository_ctx)
os = os_name(repository_ctx)
node = repository_ctx.path(get_node_label(os))
yarn = get_yarn_label(os)

if repository_ctx.attr.yarn_lock:
if repository_ctx.attr.exclude_packages:
Expand Down
Loading