Skip to content

Commit b2955dc

Browse files
authored
feat: add copy_to_bin rule (#69)
1 parent 6e653ca commit b2955dc

11 files changed

+218
-0
lines changed

docs/BUILD.bazel

+5
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ stardoc_with_diff_test(
1717
bzl_library_target = "//lib:copy_to_directory",
1818
)
1919

20+
stardoc_with_diff_test(
21+
name = "copy_to_bin",
22+
bzl_library_target = "//lib:copy_to_bin",
23+
)
24+
2025
stardoc_with_diff_test(
2126
name = "docs",
2227
bzl_library_target = "//lib:docs",

docs/copy_to_bin.md

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<!-- Generated with Stardoc: http://skydoc.bazel.build -->
2+
3+
A rule that copies source files to the output tree.
4+
5+
This rule uses a Bash command (diff) on Linux/macOS/non-Windows, and a cmd.exe
6+
command (fc.exe) on Windows (no Bash is required).
7+
8+
Originally authored in rules_nodejs
9+
https://github.com/bazelbuild/rules_nodejs/blob/8b5d27400db51e7027fe95ae413eeabea4856f8e/internal/common/copy_to_bin.bzl
10+
11+
12+
<a id="#copy_to_bin"></a>
13+
14+
## copy_to_bin
15+
16+
<pre>
17+
copy_to_bin(<a href="#copy_to_bin-name">name</a>, <a href="#copy_to_bin-srcs">srcs</a>, <a href="#copy_to_bin-kwargs">kwargs</a>)
18+
</pre>
19+
20+
Copies a source file to output tree at the same workspace-relative path.
21+
22+
e.g. `<execroot>/path/to/file -> <execroot>/bazel-out/<platform>/bin/path/to/file`
23+
24+
This is useful to populate the output folder with all files needed at runtime, even
25+
those which aren't outputs of a Bazel rule.
26+
27+
This way you can run a binary in the output folder (execroot or runfiles_root)
28+
without that program needing to rely on a runfiles helper library or be aware that
29+
files are divided between the source tree and the output tree.
30+
31+
32+
**PARAMETERS**
33+
34+
35+
| Name | Description | Default Value |
36+
| :------------- | :------------- | :------------- |
37+
| <a id="copy_to_bin-name"></a>name | Name of the rule. | none |
38+
| <a id="copy_to_bin-srcs"></a>srcs | A list of labels. File(s) to copy. | none |
39+
| <a id="copy_to_bin-kwargs"></a>kwargs | further keyword arguments, e.g. <code>visibility</code> | none |
40+
41+

lib/BUILD.bazel

+7
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,13 @@ bzl_library(
9090
deps = ["//lib/private:copy_to_directory"],
9191
)
9292

93+
bzl_library(
94+
name = "copy_to_bin",
95+
srcs = ["copy_to_bin.bzl"],
96+
visibility = ["//visibility:public"],
97+
deps = ["//lib/private:copy_to_bin"],
98+
)
99+
93100
bzl_library(
94101
name = "write_source_files",
95102
srcs = ["write_source_files.bzl"],

lib/copy_to_bin.bzl

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
"""A rule that copies source files to the output tree.
2+
3+
This rule uses a Bash command (diff) on Linux/macOS/non-Windows, and a cmd.exe
4+
command (fc.exe) on Windows (no Bash is required).
5+
6+
Originally authored in rules_nodejs
7+
https://github.com/bazelbuild/rules_nodejs/blob/8b5d27400db51e7027fe95ae413eeabea4856f8e/internal/common/copy_to_bin.bzl
8+
"""
9+
10+
load(
11+
"//lib/private:copy_to_bin.bzl",
12+
_copy_to_bin = "copy_to_bin",
13+
)
14+
15+
copy_to_bin = _copy_to_bin

lib/private/BUILD.bazel

+7
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ bzl_library(
3030
],
3131
)
3232

33+
bzl_library(
34+
name = "copy_to_bin",
35+
srcs = ["copy_to_bin.bzl"],
36+
visibility = ["//lib:__subpackages__"],
37+
deps = [":copy_file"],
38+
)
39+
3340
bzl_library(
3441
name = "params_file",
3542
srcs = ["params_file.bzl"],

lib/private/copy_to_bin.bzl

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Copyright 2019 The Bazel Authors. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Implementation of copy_to_bin macro and underlying rules."""
16+
17+
load(":copy_file.bzl", "copy_file_action")
18+
19+
def _impl(ctx):
20+
all_dst = []
21+
for src in ctx.files.srcs:
22+
if not src.is_source:
23+
fail("A source file must be specified in copy_to_bin rule, %s is not a source file." % src.path)
24+
dst = ctx.actions.declare_file(src.basename, sibling = src)
25+
copy_file_action(ctx, src, dst, is_windows = ctx.attr.is_windows)
26+
all_dst.append(dst)
27+
return DefaultInfo(
28+
files = depset(all_dst),
29+
runfiles = ctx.runfiles(files = all_dst),
30+
)
31+
32+
_copy_to_bin = rule(
33+
implementation = _impl,
34+
provides = [DefaultInfo],
35+
attrs = {
36+
"is_windows": attr.bool(mandatory = True),
37+
"srcs": attr.label_list(mandatory = True, allow_files = True),
38+
},
39+
)
40+
41+
def copy_to_bin(name, srcs, **kwargs):
42+
"""Copies a source file to output tree at the same workspace-relative path.
43+
44+
e.g. `<execroot>/path/to/file -> <execroot>/bazel-out/<platform>/bin/path/to/file`
45+
46+
This is useful to populate the output folder with all files needed at runtime, even
47+
those which aren't outputs of a Bazel rule.
48+
49+
This way you can run a binary in the output folder (execroot or runfiles_root)
50+
without that program needing to rely on a runfiles helper library or be aware that
51+
files are divided between the source tree and the output tree.
52+
53+
Args:
54+
name: Name of the rule.
55+
srcs: A list of labels. File(s) to copy.
56+
**kwargs: further keyword arguments, e.g. `visibility`
57+
"""
58+
_copy_to_bin(
59+
name = name,
60+
srcs = srcs,
61+
is_windows = select({
62+
"@bazel_tools//src/conditions:host_windows": True,
63+
"//conditions:default": False,
64+
}),
65+
**kwargs
66+
)

lib/private/diff_test.bzl

+4
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ def _diff_test_impl(ctx):
4545
file2 = ctx.files.file2[0]
4646
file2_path = _runfiles_path(file2)
4747

48+
if file1 == file2:
49+
msg = "diff_test comparing the same file %s" % file1
50+
fail(msg)
51+
4852
if ctx.attr.is_windows:
4953
test_bin = ctx.actions.declare_file(ctx.label.name + "-test.bat")
5054
ctx.actions.write(

lib/tests/copy_to_bin/BUILD.bazel

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
"tests for copy_to_bin"
2+
3+
load("//lib:copy_to_bin.bzl", "copy_to_bin")
4+
load("//lib:output_files.bzl", "output_files")
5+
6+
copy_to_bin(
7+
name = "copy",
8+
srcs = [
9+
"file1",
10+
"file2",
11+
],
12+
)
13+
14+
output_files(
15+
name = "pull_out_file1",
16+
paths = ["%s/file1" % package_name()],
17+
target = ":copy",
18+
)
19+
20+
output_files(
21+
name = "pull_out_file2",
22+
paths = ["%s/file2" % package_name()],
23+
target = ":copy",
24+
)
25+
26+
sh_test(
27+
name = "file1_test",
28+
srcs = ["test.sh"],
29+
args = [
30+
"lib/tests/copy_to_bin/file1",
31+
"$(execpath file1)",
32+
"$(execpath :pull_out_file1)",
33+
],
34+
data = [
35+
"file1",
36+
":pull_out_file1",
37+
],
38+
)
39+
40+
sh_test(
41+
name = "file2_test",
42+
srcs = ["test.sh"],
43+
args = [
44+
"lib/tests/copy_to_bin/file2",
45+
"$(execpath file2)",
46+
"$(execpath :pull_out_file2)",
47+
],
48+
data = [
49+
"file2",
50+
":pull_out_file2",
51+
],
52+
)

lib/tests/copy_to_bin/file1

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
file1

lib/tests/copy_to_bin/file2

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
file2

lib/tests/copy_to_bin/test.sh

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/usr/bin/env bash
2+
3+
set -o errexit -o nounset
4+
5+
expected_file="$1"
6+
source_file="$2"
7+
bin_file="$3"
8+
if [[ "$expected_file" != "$source_file" ]]; then
9+
echo "ERROR: expected source_file to be $expected_file, but got $source_file"
10+
exit 1
11+
fi
12+
if [[ "$bin_file" != "bazel-out/"* ]]; then
13+
echo "ERROR: expected bin_file to be start with bazel-out/, but got $bin_file"
14+
exit 1
15+
fi
16+
if [[ "$bin_file" != *"/bin/$expected_file" ]]; then
17+
echo "ERROR: expected bin_file to be end with /bin/$expected_file, but got $bin_file"
18+
exit 1
19+
fi

0 commit comments

Comments
 (0)