diff --git a/README.md b/README.md index 5baf280435..24a4543bad 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ nodejs_binary( "@//:node_modules", "main.js", ], - entry_point = "workspace_name/main.js", + entry_point = "$(location :main.js)", args = ["--node_options=--expose-gc"], ) ``` diff --git a/examples/program/BUILD.bazel b/examples/program/BUILD.bazel index 1ac14475e2..9078ec947a 100644 --- a/examples/program/BUILD.bazel +++ b/examples/program/BUILD.bazel @@ -1,4 +1,18 @@ -load("@build_bazel_rules_nodejs//:defs.bzl", "jasmine_node_test") +# Copyright 2017 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("@build_bazel_rules_nodejs//:defs.bzl", "jasmine_node_test", "nodejs_binary") load("@build_bazel_rules_nodejs//:internal/typescript_mock.bzl", "mock_typescript_lib") # Make the jasmine library available at runtime by exposing our node_modules @@ -13,21 +27,51 @@ filegroup( visibility = ["//visibility:public"], ) +# Mock out the ts_library rule from rules_typescript +# We want to test that TypeScript outputs can be used in nodejs rules, but +# don't want a cyclical dependency between this repository and rules_typescript. mock_typescript_lib( name = "mock_ts_lib", srcs = ["decrement.js"], ) -# This is like a "js_library", but there are no actions to run on JS files so a -# filegroup is semantically equivalent. -filegroup( - name = "program", - srcs = ["index.js"], +# This binary wraps up our program in a way that can be `bazel run`, and also +# produces a .exe file on Windows. +nodejs_binary( + name = "bin", + # The script we'll ask node to run + # Note: the label given here must exactly match an entry in "data" + entry_point = "$(location :index.js)", + # Runtime dependencies, in our case the script is standalone. + data = [":index.js"], + # Only needed because we'll typically run this binary from the workspace + # in the parent directory. The default value for `node_modules` is + # @//:node_modules, where the leading @ means "the workspace where the user + # runs the target" + node_modules = "//:node_modules", ) +# Unit tests for the files in the package. +# Convenient to use with `ibazel test` jasmine_node_test( name = "test", + # The typical Bazel idiom is for srcs to be the files directly consumed. + # In the case of a unit test, that's the spec files. + # See https://docs.bazel.build/versions/master/build-ref.html#types_of_dependencies srcs = glob(["*.spec.js"]), - deps = [":program", ":mock_ts_lib"], - node_modules = "//:node_modules" + # The deps is the runtime dependencies. These can point to compiled files + # such as the TypeScript library we mocked out. + deps = [":index.js", ":mock_ts_lib"], + # See comment about node_modules above. + node_modules = "//:node_modules", +) + +# An end-to-end test for the program. +# It's written in Python just because this is convenient and cross-platform. +# See https://docs.bazel.build/versions/master/be/python.html#py_test +py_test( + name = "bin_test", + srcs = ["bin_test.py"], + deps = ["@build_bazel_rules_nodejs//internal:runfiles"], + data = [":bin"], ) diff --git a/examples/program/bin_test.py b/examples/program/bin_test.py new file mode 100644 index 0000000000..15f8deb4e1 --- /dev/null +++ b/examples/program/bin_test.py @@ -0,0 +1,23 @@ +"""End-to-end test for a nodejs_binary + +Simply find the binary and run it, asserting that it produces correct output. +""" + +from subprocess import check_output +from sys import platform +import unittest + +from build_bazel_rules_nodejs.internal.runfiles import resolve_runfile + +class BinTest(unittest.TestCase): + + def testRuns(self): + if platform == "win32" or platform == "win64": + program = 'program_example/bin.exe' + else: + program = 'program_example/bin' + actual = check_output([resolve_runfile(program)]) + self.assertEqual(actual, '2\n') + +if __name__ == '__main__': + unittest.main() diff --git a/examples/program/index.js b/examples/program/index.js index 88ade89fb7..97f6ab2e2a 100644 --- a/examples/program/index.js +++ b/examples/program/index.js @@ -3,3 +3,7 @@ function increment(n) { } exports.increment = increment; + +if (require.main === module) { + console.log(increment(1)); +} diff --git a/internal/BUILD.bazel b/internal/BUILD.bazel index bdf048cd89..9f7dc945c3 100644 --- a/internal/BUILD.bazel +++ b/internal/BUILD.bazel @@ -16,9 +16,15 @@ package(default_visibility = ["//visibility:public"]) exports_files(["node_launcher.sh", "node_loader.js", "jasmine_runner.js"]) +py_library( + name = "runfiles", + srcs = ["runfiles.py"], +) + py_test( name = "check_bazel_version_test", srcs = ["check_bazel_version_test.py"], + deps = [":runfiles"], data = [":check_bazel_version.bzl"], size = "small", ) diff --git a/internal/check_bazel_version_test.py b/internal/check_bazel_version_test.py index 30672383af..620a3e9a11 100644 --- a/internal/check_bazel_version_test.py +++ b/internal/check_bazel_version_test.py @@ -1,17 +1,5 @@ -import os import unittest - -def resolve_runfile(path): - if os.getenv('RUNFILES_MANIFEST_ONLY') != "1": - return os.path.join(os.environ['TEST_SRCDIR'], path) - - manifest = os.getenv('RUNFILES_MANIFEST_FILE') - with open(manifest) as f: - for line in f.readlines(): - if line.split()[0] == path: - return line.split()[1] - raise "Cannot find %s in manifest %s" % (path, manifest) - +from runfiles import resolve_runfile class MockSkylark: """A class that returns mocked bazel version and fail(). diff --git a/internal/jasmine_node_test.bzl b/internal/jasmine_node_test.bzl index 84ee3fb817..4b60884013 100644 --- a/internal/jasmine_node_test.bzl +++ b/internal/jasmine_node_test.bzl @@ -8,15 +8,16 @@ def jasmine_node_test(name, srcs, data = [], deps = [], **kwargs): testonly = 1, ) - all_data = data + srcs + deps - all_data += [Label("//internal:jasmine_runner.js")] - all_data += [":%s_devmode_srcs.MF" % name] - entry_point = "build_bazel_rules_nodejs/internal/jasmine_runner.js" + runner_js = "@build_bazel_rules_nodejs//internal:jasmine_runner.js" + all_data = data + srcs + deps + [ + runner_js, + ":%s_devmode_srcs.MF" % name, + ] nodejs_test( name = name, data = all_data, - entry_point = entry_point, + entry_point = "$(location %s)" % runner_js, templated_args = ["$(location :%s_devmode_srcs.MF)" % name], testonly = 1, **kwargs diff --git a/internal/node.bzl b/internal/node.bzl index 1bd7f6a4c5..7d3ce47064 100644 --- a/internal/node.bzl +++ b/internal/node.bzl @@ -51,7 +51,7 @@ def _write_loader_script(ctx): output=ctx.outputs.loader, substitutions={ "TEMPLATED_module_roots": "\n " + ",\n ".join(module_mappings), - "TEMPLATED_entry_point": ctx.attr.entry_point, + "TEMPLATED_entry_point": expand_location_into_runfiles(ctx, ctx.attr.entry_point), "TEMPLATED_label_package": ctx.attr.node_modules.label.package, # If the label being built is in another workspace, look for runfiles # produced by that workspace diff --git a/internal/runfiles.py b/internal/runfiles.py new file mode 100644 index 0000000000..cd2d1df55f --- /dev/null +++ b/internal/runfiles.py @@ -0,0 +1,12 @@ +import os + +def resolve_runfile(path): + if os.getenv('RUNFILES_MANIFEST_ONLY') != "1": + return os.path.join(os.environ['TEST_SRCDIR'], path) + + manifest = os.getenv('RUNFILES_MANIFEST_FILE') + with open(manifest) as f: + for line in f.readlines(): + if line.split()[0] == path: + return line.split()[1] + raise "Cannot find %s in manifest %s" % (path, manifest)