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

Add map_to_output rule #217

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions rules/BUILD
Expand Up @@ -16,6 +16,12 @@ bzl_library(
deps = ["//rules/private:copy_file_private"],
)

bzl_library(
name = "map_to_output",
srcs = ["map_to_output.bzl"],
deps = ["//rules/private:map_to_output_private"],
)

bzl_library(
name = "write_file",
srcs = ["write_file.bzl"],
Expand Down
29 changes: 29 additions & 0 deletions rules/map_to_output.bzl
@@ -0,0 +1,29 @@
# Copyright 2019 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.

"""A rule that copies a source file to bazel-bin at the same execroot path.
Copy link
Contributor

Choose a reason for hiding this comment

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

feels like a maintenance burden to have so much doc duplication between the rule declaration and this public re-export - but I guess you're following conventions in the repo?

Eg. <source_root>/foo/bar/a.txt -> <bazel-bin>/foo/bar/a.txt

We cannot use genrule or copy_file rule to copy a source file to bazel-bin with
the same execroot path, because both rules create label for the output
artifact, which conflicts with the source file label. map_to_output rule
achieves that by avoiding creating label for the output artifact.
"""

load(
"//rules/private:map_to_output_private.bzl",
_map_to_output = "map_to_output",
)

map_to_output = _map_to_output
Copy link
Contributor

Choose a reason for hiding this comment

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

bikeshedding the name: should it be more analogous to the existing rules in this repo? maybe it should start with copy like copy_file?

7 changes: 7 additions & 0 deletions rules/private/BUILD
Expand Up @@ -8,6 +8,13 @@ bzl_library(
visibility = ["//rules:__pkg__"],
)

bzl_library(
name = "map_to_output_private",
srcs = ["map_to_output_private.bzl"],
deps = [":copy_file_private"],
visibility = ["//rules:__pkg__"],
)

bzl_library(
name = "write_file_private",
srcs = ["write_file_private.bzl"],
Expand Down
61 changes: 61 additions & 0 deletions rules/private/map_to_output_private.bzl
@@ -0,0 +1,61 @@
# Copyright 2019 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.

"""map_to_output() rule implementations.

This rule copies a source file to bazel-bin at the same execroot path, we avoid
label conflict with the source file by not creating label for the output
artifact.
"""

load("//rules/private:copy_file_private.bzl", "copy_bash", "copy_cmd")

def _map_to_output_impl(ctx):
src = ctx.file.src
if not src.is_source:
fail("A source file must be specified in map_to_output rule, %s is not a source file." % src.path)
dst = ctx.actions.declare_file(src.basename, sibling = src)
if ctx.attr.is_windows:
copy_cmd(ctx, src, dst)
else:
copy_bash(ctx, src, dst)
return DefaultInfo(files = depset([dst]), runfiles = ctx.runfiles(files = [dst]))

_map_to_output = rule(
implementation = _map_to_output_impl,
attrs = {
"src": attr.label(mandatory = True, allow_single_file = True),
"is_windows": attr.bool(mandatory = True),
}
)

def map_to_output(name, src, **kwargs):
"""Copies a source file to bazel-bin at the same execroot path.

Eg. <source_root>/foo/bar/a.txt -> <bazel-bin>/foo/bar/a.txt

Args:
name: Name of the rule.
src: A Label. The file to to copy.
**kwargs: further keyword arguments, e.g. `visibility`
"""
_map_to_output(
name = name,
src = src,
is_windows = select({
"@bazel_tools//src/conditions:host_windows": True,
"//conditions:default": False,
}),
**kwargs
)
20 changes: 20 additions & 0 deletions tests/map_to_output/BUILD
@@ -0,0 +1,20 @@
load("//rules:map_to_output.bzl", "map_to_output")

licenses(["notice"])

package(default_testonly = 1)

sh_test(
name = "map_to_output_tests",
srcs = ["map_to_output_tests.sh"],
data = [
":a",
"//tests:unittest.bash",
],
deps = ["@bazel_tools//tools/bash/runfiles"],
)

map_to_output(
name = "a",
src = "foo/bar/a.txt",
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it should be a list of srcs as it will be common to have more than one file to copy

)
2 changes: 2 additions & 0 deletions tests/map_to_output/foo/bar/a.txt
@@ -0,0 +1,2 @@
#!/bin/bash
echo aaa
51 changes: 51 additions & 0 deletions tests/map_to_output/map_to_output_tests.sh
@@ -0,0 +1,51 @@
# Copyright 2019 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.

# --- begin runfiles.bash initialization ---
Copy link
Contributor

Choose a reason for hiding this comment

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

why not use the shorter v2 init code?

# Copy-pasted from Bazel's Bash runfiles library (tools/bash/runfiles/runfiles.bash).
set -euo pipefail
if [[ ! -d "${RUNFILES_DIR:-/dev/null}" && ! -f "${RUNFILES_MANIFEST_FILE:-/dev/null}" ]]; then
if [[ -f "$0.runfiles_manifest" ]]; then
export RUNFILES_MANIFEST_FILE="$0.runfiles_manifest"
elif [[ -f "$0.runfiles/MANIFEST" ]]; then
export RUNFILES_MANIFEST_FILE="$0.runfiles/MANIFEST"
elif [[ -f "$0.runfiles/bazel_tools/tools/bash/runfiles/runfiles.bash" ]]; then
export RUNFILES_DIR="$0.runfiles"
fi
fi
if [[ -f "${RUNFILES_DIR:-/dev/null}/bazel_tools/tools/bash/runfiles/runfiles.bash" ]]; then
source "${RUNFILES_DIR}/bazel_tools/tools/bash/runfiles/runfiles.bash"
elif [[ -f "${RUNFILES_MANIFEST_FILE:-/dev/null}" ]]; then
source "$(grep -m1 "^bazel_tools/tools/bash/runfiles/runfiles.bash " \
"$RUNFILES_MANIFEST_FILE" | cut -d ' ' -f 2-)"
else
echo >&2 "ERROR: cannot find @bazel_tools//tools/bash/runfiles:runfiles.bash"
exit 1
fi
# --- end runfiles.bash initialization ---

source "$(rlocation bazel_skylib/tests/unittest.bash)" \
|| { echo "Could not source bazel_skylib/tests/unittest.bash" >&2; exit 1; }

function test_map_to_output() {
echo "$(rlocation bazel_skylib/tests/map_to_output/foo/bar/a.txt)" >"$TEST_log"
# Test the foo/bar/a.txt is copied to bazel-out/
expect_log 'bazel-out/'
cat "$(rlocation bazel_skylib/tests/map_to_output/foo/bar/a.txt)" >"$TEST_log"
# Test the content of foo/bar/a.txt is correct
expect_log '#!/bin/bash'
expect_log '^echo aaa$'
}

run_suite "map_to_output test suite"