feat: add executable attribute to write_source_files
This commit is contained in:
parent
e9b66b5e0a
commit
9059f8fa5e
|
@ -17,7 +17,7 @@ Otherwise later tooling on CI may yell at you about formatting/linting violation
|
||||||
|
|
||||||
Some targets are generated from sources.
|
Some targets are generated from sources.
|
||||||
Currently this is just the `bzl_library` targets.
|
Currently this is just the `bzl_library` targets.
|
||||||
Run `bazel run //:gazelle` to keep them up-to-date.
|
Run `bazel run //:gazelle` to keep them up to date.
|
||||||
|
|
||||||
## Using this as a development dependency of other rules
|
## Using this as a development dependency of other rules
|
||||||
|
|
||||||
|
|
|
@ -7,11 +7,15 @@ Public API for write_source_files
|
||||||
## write_source_files
|
## write_source_files
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
write_source_files(<a href="#write_source_files-name">name</a>, <a href="#write_source_files-files">files</a>, <a href="#write_source_files-additional_update_targets">additional_update_targets</a>, <a href="#write_source_files-suggested_update_target">suggested_update_target</a>, <a href="#write_source_files-diff_test">diff_test</a>,
|
write_source_files(<a href="#write_source_files-name">name</a>, <a href="#write_source_files-files">files</a>, <a href="#write_source_files-executable">executable</a>, <a href="#write_source_files-additional_update_targets">additional_update_targets</a>, <a href="#write_source_files-suggested_update_target">suggested_update_target</a>,
|
||||||
<a href="#write_source_files-kwargs">kwargs</a>)
|
<a href="#write_source_files-diff_test">diff_test</a>, <a href="#write_source_files-kwargs">kwargs</a>)
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
Write to one or more files or folders in the source tree. Stamp out tests that ensure the sources exist and are up to date.
|
Write one or more files and/or directories to the source tree.
|
||||||
|
|
||||||
|
By default, `diff_test` targets are generated that ensure the source tree files and/or directories to be written to
|
||||||
|
are up to date and the rule also checks that all source tree files and/or directories to be written to exist.
|
||||||
|
To disable the exists check and up-to-date tests set `diff_test` to `False`.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
|
@ -27,11 +31,16 @@ write_source_files(
|
||||||
```
|
```
|
||||||
|
|
||||||
To update the source file, run:
|
To update the source file, run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bazel run //:write_foobar
|
bazel run //:write_foobar
|
||||||
```
|
```
|
||||||
|
|
||||||
A test will fail if the source file doesn't exist or if it's out of date with instructions on how to create/update it.
|
The generated `diff_test` will fail if the file is out of date and print out instructions on
|
||||||
|
how to update it.
|
||||||
|
|
||||||
|
If the file does not exist, Bazel will fail at analysis time and print out instructions on
|
||||||
|
how to create it.
|
||||||
|
|
||||||
You can declare a tree of generated source file targets:
|
You can declare a tree of generated source file targets:
|
||||||
|
|
||||||
|
@ -54,7 +63,8 @@ And update them with a single run:
|
||||||
bazel run //:write_all
|
bazel run //:write_all
|
||||||
```
|
```
|
||||||
|
|
||||||
When a file is out of date, you can leave a suggestion to run a target further up in the tree by specifying `suggested_update_target`. E.g.,
|
When a file is out of date, you can leave a suggestion to run a target further up in the tree by specifying `suggested_update_target`.
|
||||||
|
For example,
|
||||||
|
|
||||||
```starlark
|
```starlark
|
||||||
write_source_files(
|
write_source_files(
|
||||||
|
@ -66,7 +76,7 @@ write_source_files(
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
A test failure from foo.json being out of date will yield the following message:
|
A test failure from `foo.json` being out of date will yield the following message:
|
||||||
|
|
||||||
```
|
```
|
||||||
//a/b:c:foo.json is out of date. To update this and other generated files, run:
|
//a/b:c:foo.json is out of date. To update this and other generated files, run:
|
||||||
|
@ -78,9 +88,11 @@ To update *only* this file, run:
|
||||||
bazel run //a/b/c:write_foo
|
bazel run //a/b/c:write_foo
|
||||||
```
|
```
|
||||||
|
|
||||||
If you have many sources that you want to update as a group, we recommend wrapping write_source_files in a macro that defaults `suggested_update_target` to the umbrella update target.
|
If you have many `write_source_files` targets that you want to update as a group, we recommend wrapping
|
||||||
|
`write_source_files` in a macro that defaults `suggested_update_target` to the umbrella update target.
|
||||||
|
|
||||||
NOTE: If you run formatters or linters on your codebase, it is advised that you exclude/ignore the outputs of this rule from those formatters/linters so as to avoid causing collisions and failing tests.
|
NOTE: If you run formatters or linters on your codebase, it is advised that you exclude/ignore the outputs of this
|
||||||
|
rule from those formatters/linters so as to avoid causing collisions and failing tests.
|
||||||
|
|
||||||
|
|
||||||
**PARAMETERS**
|
**PARAMETERS**
|
||||||
|
@ -88,11 +100,12 @@ NOTE: If you run formatters or linters on your codebase, it is advised that you
|
||||||
|
|
||||||
| Name | Description | Default Value |
|
| Name | Description | Default Value |
|
||||||
| :------------- | :------------- | :------------- |
|
| :------------- | :------------- | :------------- |
|
||||||
| <a id="write_source_files-name"></a>name | Name of the executable target that creates or updates the source file | none |
|
| <a id="write_source_files-name"></a>name | Name of the runnable target that creates or updates the source tree files and/or directories. | none |
|
||||||
| <a id="write_source_files-files"></a>files | A dict where the keys are source files or folders to write to and the values are labels pointing to the desired content. Sources must be within the same bazel package as the target. | <code>{}</code> |
|
| <a id="write_source_files-files"></a>files | A dict where the keys are files or directories in the source tree to write to and the values are labels pointing to the desired content, typically file or directory outputs of other targets.<br><br>Source tree files and directories must be within the same bazel package as the target. | <code>{}</code> |
|
||||||
| <a id="write_source_files-additional_update_targets"></a>additional_update_targets | (Optional) List of other write_source_file or other executable updater targets to call in the same run | <code>[]</code> |
|
| <a id="write_source_files-executable"></a>executable | Whether source tree files written should be made executable.<br><br>This applies to all source tree files written by this target. This attribute is not propagated to <code>additional_update_targets</code>.<br><br>To set different executable permissions on different source tree files use multiple <code>write_source_files</code> targets. | <code>False</code> |
|
||||||
| <a id="write_source_files-suggested_update_target"></a>suggested_update_target | (Optional) Label of the write_source_file target to suggest running when files are out of date | <code>None</code> |
|
| <a id="write_source_files-additional_update_targets"></a>additional_update_targets | List of other <code>write_source_files</code> or other executable updater targets to call in the same run. | <code>[]</code> |
|
||||||
| <a id="write_source_files-diff_test"></a>diff_test | (Optional) Generate a test target to check that the source file(s) exist and are up to date with the generated files(s). | <code>True</code> |
|
| <a id="write_source_files-suggested_update_target"></a>suggested_update_target | Label of the <code>write_source_files</code> target to suggest running when files are out of date. | <code>None</code> |
|
||||||
|
| <a id="write_source_files-diff_test"></a>diff_test | Test that the source tree files and/or directories exist and are up to date. | <code>True</code> |
|
||||||
| <a id="write_source_files-kwargs"></a>kwargs | Other common named parameters such as <code>tags</code> or <code>visibility</code> | none |
|
| <a id="write_source_files-kwargs"></a>kwargs | Other common named parameters such as <code>tags</code> or <code>visibility</code> | none |
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
load("@aspect_bazel_lib//lib:copy_to_directory.bzl", "copy_to_directory")
|
load("@aspect_bazel_lib//lib:copy_to_directory.bzl", "copy_to_directory")
|
||||||
load("@aspect_bazel_lib//lib:diff_test.bzl", "diff_test")
|
load("@aspect_bazel_lib//lib:diff_test.bzl", "diff_test")
|
||||||
|
|
||||||
# TODO: figure out ERROR: cannot compare a directory against a file
|
|
||||||
_TODO = ["no-remote-exec"]
|
|
||||||
|
|
||||||
# Test special cases of using "." and "./**" patterns in the root package
|
# Test special cases of using "." and "./**" patterns in the root package
|
||||||
|
|
||||||
copy_to_directory(
|
copy_to_directory(
|
||||||
|
@ -30,14 +27,16 @@ diff_test(
|
||||||
name = "test1",
|
name = "test1",
|
||||||
file1 = ":dir1",
|
file1 = ":dir1",
|
||||||
file2 = ":expected1",
|
file2 = ":expected1",
|
||||||
tags = _TODO,
|
# Source directories are not support on remote execution.
|
||||||
|
tags = ["no-remote-exec"],
|
||||||
)
|
)
|
||||||
|
|
||||||
diff_test(
|
diff_test(
|
||||||
name = "test1b",
|
name = "test1b",
|
||||||
file1 = ":dir1b",
|
file1 = ":dir1b",
|
||||||
file2 = ":expected1",
|
file2 = ":expected1",
|
||||||
tags = _TODO,
|
# Source directories are not support on remote execution.
|
||||||
|
tags = ["no-remote-exec"],
|
||||||
)
|
)
|
||||||
|
|
||||||
copy_to_directory(
|
copy_to_directory(
|
||||||
|
@ -66,14 +65,16 @@ diff_test(
|
||||||
name = "test2",
|
name = "test2",
|
||||||
file1 = ":dir2",
|
file1 = ":dir2",
|
||||||
file2 = ":expected2",
|
file2 = ":expected2",
|
||||||
tags = _TODO,
|
# Source directories are not support on remote execution.
|
||||||
|
tags = ["no-remote-exec"],
|
||||||
)
|
)
|
||||||
|
|
||||||
diff_test(
|
diff_test(
|
||||||
name = "test2b",
|
name = "test2b",
|
||||||
file1 = ":dir2b",
|
file1 = ":dir2b",
|
||||||
file2 = ":expected2",
|
file2 = ":expected2",
|
||||||
tags = _TODO,
|
# Source directories are not support on remote execution.
|
||||||
|
tags = ["no-remote-exec"],
|
||||||
)
|
)
|
||||||
|
|
||||||
copy_to_directory(
|
copy_to_directory(
|
||||||
|
@ -102,12 +103,14 @@ diff_test(
|
||||||
name = "test3",
|
name = "test3",
|
||||||
file1 = ":dir3",
|
file1 = ":dir3",
|
||||||
file2 = ":expected3",
|
file2 = ":expected3",
|
||||||
tags = _TODO,
|
# Source directories are not support on remote execution.
|
||||||
|
tags = ["no-remote-exec"],
|
||||||
)
|
)
|
||||||
|
|
||||||
diff_test(
|
diff_test(
|
||||||
name = "test3b",
|
name = "test3b",
|
||||||
file1 = ":dir3b",
|
file1 = ":dir3b",
|
||||||
file2 = ":expected3",
|
file2 = ":expected3",
|
||||||
tags = _TODO,
|
# Source directories are not support on remote execution.
|
||||||
|
tags = ["no-remote-exec"],
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
set -o errexit -o nounset -o pipefail
|
||||||
set -e
|
|
||||||
|
|
||||||
case "$(uname -s)" in
|
case "$(uname -s)" in
|
||||||
CYGWIN*|MINGW32*|MSYS*|MINGW*)
|
CYGWIN*|MINGW32*|MSYS*|MINGW*)
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
set -o errexit -o nounset -o pipefail
|
||||||
set -e
|
|
||||||
|
|
||||||
case "$(uname -s)" in
|
case "$(uname -s)" in
|
||||||
CYGWIN*|MINGW32*|MSYS*|MINGW*)
|
CYGWIN*|MINGW32*|MSYS*|MINGW*)
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -o errexit -o nounset -o pipefail
|
||||||
|
|
||||||
|
function run_test {
|
||||||
|
bazel run //lib/tests/write_source_files:write_dist
|
||||||
|
local expected_out="lib/tests/write_source_files/dist.js"
|
||||||
|
if [ ! -e "$expected_out" ]; then
|
||||||
|
echo "ERROR: expected $expected_out to exist"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -x "$expected_out" ]; then
|
||||||
|
echo "ERROR: expected $expected_out to not be executable"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
bazel run //lib/tests/write_source_files:write_dist_executable
|
||||||
|
local expected_out="lib/tests/write_source_files/dist_executable.js"
|
||||||
|
if [ ! -e "$expected_out" ]; then
|
||||||
|
echo "ERROR: expected $expected_out to exist"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ ! -x "$expected_out" ]; then
|
||||||
|
echo "ERROR: expected $expected_out to be executable"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run twice to make sure we can have permission to overwrite the outputs of a previous run
|
||||||
|
run_test
|
||||||
|
run_test
|
||||||
|
echo "All tests passed"
|
|
@ -1,6 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
bazel run //lib/tests/write_source_files:write_dist
|
|
||||||
[ -e lib/tests/write_source_files/dist.js ]
|
|
|
@ -1,6 +1,20 @@
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
set -o errexit -o nounset -o pipefail
|
||||||
|
|
||||||
set -e
|
function run_test {
|
||||||
|
bazel run //:write_source_file_root-test
|
||||||
|
local expected_out="test-out/dist/write_source_file_root-test/test.txt"
|
||||||
|
if [ ! -e "$expected_out" ]; then
|
||||||
|
echo "ERROR: expected $expected_out to exist"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -x "$expected_out" ]; then
|
||||||
|
echo "ERROR: expected $expected_out to not be executable"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
bazel run //:write_source_file_root-test
|
# Run twice to make sure we can have permission to overwrite the outputs of a previous run
|
||||||
[ -e test-out/dist/write_source_file_root-test/test.txt ]
|
run_test
|
||||||
|
run_test
|
||||||
|
echo "All tests passed"
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -o errexit -o nounset -o pipefail
|
||||||
|
|
||||||
|
function run_test {
|
||||||
|
bazel run //lib/tests/write_source_files:write_subdir
|
||||||
|
local expected_out="lib/tests/write_source_files/subdir_test/a/b/c/test.txt"
|
||||||
|
if [ ! -e "$expected_out" ]; then
|
||||||
|
echo "ERROR: expected $expected_out to exist"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -x "$expected_out" ]; then
|
||||||
|
echo "ERROR: expected $expected_out to not be executable"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
bazel run //lib/tests/write_source_files:write_subdir_executable
|
||||||
|
local expected_out="lib/tests/write_source_files/subdir_executable_test/a/b/c/test.txt"
|
||||||
|
if [ ! -e "$expected_out" ]; then
|
||||||
|
echo "ERROR: expected $expected_out to exist"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ ! -x "$expected_out" ]; then
|
||||||
|
echo "ERROR: expected $expected_out to be executable"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run twice to make sure we can have permission to overwrite the outputs of a previous run
|
||||||
|
rm -rf lib/tests/write_source_files/subdir_test
|
||||||
|
rm -rf lib/tests/write_source_files/subdir_executable_test
|
||||||
|
run_test
|
||||||
|
run_test
|
||||||
|
echo "All tests passed"
|
|
@ -1,9 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
bazel run //lib/tests/write_source_files:write_subdir
|
|
||||||
[ -e lib/tests/write_source_files/subdir_test/a/b/c/test.txt ]
|
|
||||||
|
|
||||||
bazel run //lib/tests/write_source_files:write_subdir
|
|
||||||
[ -e lib/tests/write_source_files/subdir_test/a/b/c/test.txt ]
|
|
|
@ -1,18 +1,39 @@
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
set -o errexit -o nounset -o pipefail
|
||||||
|
|
||||||
set -e
|
function run_test {
|
||||||
|
bazel run //lib/tests/write_source_files:write_symlinks
|
||||||
|
|
||||||
bazel run //lib/tests/write_source_files:write_symlinks
|
local expected_out="lib/tests/write_source_files/symlink_test/a/test.txt"
|
||||||
|
if [ ! -e "$expected_out" ]; then
|
||||||
|
echo "ERROR: expected $expected_out to exist"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -x "$expected_out" ]; then
|
||||||
|
echo "ERROR: expected $expected_out to not be executable"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -L "$expected_out" ]; then
|
||||||
|
echo "ERROR: expected $expected_out to not be a symlink"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# Ensure exists
|
local expected_out="lib/tests/write_source_files/symlink_test/b/test.txt"
|
||||||
[ -e lib/tests/write_source_files/symlink_test/a/test.txt ]
|
if [ ! -e "$expected_out" ]; then
|
||||||
[ -e lib/tests/write_source_files/symlink_test/b/test.txt ]
|
echo "ERROR: expected $expected_out to exist"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -x "$expected_out" ]; then
|
||||||
|
echo "ERROR: expected $expected_out to not be executable"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -L "$expected_out" ]; then
|
||||||
|
echo "ERROR: expected $expected_out to not be a symlink"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# Exit if any symlinks
|
# Run twice to make sure we can have permission to overwrite the outputs of a previous run
|
||||||
if [ -L lib/tests/write_source_files/symlink_test/a/test.txt ]; then
|
run_test
|
||||||
exit 1
|
run_test
|
||||||
fi
|
echo "All tests passed"
|
||||||
|
|
||||||
if [ -L lib/tests/write_source_files/symlink_test/b/test.txt ]; then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
|
@ -14,6 +14,9 @@
|
||||||
|
|
||||||
"""A test rule that compares two binary files or two directories.
|
"""A test rule that compares two binary files or two directories.
|
||||||
|
|
||||||
|
Similar to `bazel-skylib`'s [`diff_test`](https://github.com/bazelbuild/bazel-skylib/blob/main/rules/diff_test.bzl)
|
||||||
|
but also supports comparing directories.
|
||||||
|
|
||||||
The rule uses a Bash command (diff) on Linux/macOS/non-Windows, and a cmd.exe
|
The rule uses a Bash command (diff) on Linux/macOS/non-Windows, and a cmd.exe
|
||||||
command (fc.exe) on Windows (no Bash is required).
|
command (fc.exe) on Windows (no Bash is required).
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -14,6 +14,9 @@
|
||||||
|
|
||||||
"""A test rule that compares two binary files or two directories.
|
"""A test rule that compares two binary files or two directories.
|
||||||
|
|
||||||
|
Similar to `bazel-skylib`'s [`diff_test`](https://github.com/bazelbuild/bazel-skylib/blob/main/rules/diff_test.bzl)
|
||||||
|
but also supports comparing directories.
|
||||||
|
|
||||||
The rule uses a Bash command (diff) on Linux/macOS/non-Windows, and a cmd.exe
|
The rule uses a Bash command (diff) on Linux/macOS/non-Windows, and a cmd.exe
|
||||||
command (fc.exe) on Windows (no Bash is required).
|
command (fc.exe) on Windows (no Bash is required).
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -o errexit -o nounset -o pipefail
|
||||||
escape() {
|
escape() {
|
||||||
echo "$1" \
|
echo "$1" \
|
||||||
| sed 's/&/\&/g; s/</\</g; s/>/\>/g; s/"/\"/g; s/'"'"'/\'/g' \
|
| sed 's/&/\&/g; s/</\</g; s/>/\>/g; s/"/\"/g; s/'"'"'/\'/g' \
|
||||||
|
|
|
@ -16,19 +16,34 @@ def write_source_file(
|
||||||
name,
|
name,
|
||||||
in_file = None,
|
in_file = None,
|
||||||
out_file = None,
|
out_file = None,
|
||||||
|
executable = False,
|
||||||
additional_update_targets = [],
|
additional_update_targets = [],
|
||||||
suggested_update_target = None,
|
suggested_update_target = None,
|
||||||
diff_test = True,
|
diff_test = True,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
"""Write a file or folder to the output tree. Stamp out tests that ensure the sources exist and are up to date.
|
"""Write a file or directory to the source tree.
|
||||||
|
|
||||||
|
By default, `diff_test` targets are generated that ensure the source tree file or directory to be written to
|
||||||
|
is up to date and the rule also checks that the source tree file or directory to be written to exists.
|
||||||
|
To disable the exists check and up-to-date test set `diff_test` to `False`.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
name: Name of the executable target that creates or updates the source file
|
name: Name of the runnable target that creates or updates the source tree file or directory.
|
||||||
in_file: File to use as the desired content to write to out_file. If in_file is a TreeArtifact then entire directory contents are copied.
|
|
||||||
out_file: The file to write to in the source tree. Must be within the same bazel package as the target.
|
in_file: File or directory to use as the desired content to write to `out_file`.
|
||||||
additional_update_targets: List of other write_source_file or other executable updater targets to call in the same run
|
|
||||||
suggested_update_target: Label of the write_source_file target to suggest running when files are out of date
|
This is typically a file or directory output of another target. If `in_file` is a directory then entire directory contents are copied.
|
||||||
diff_test: Generate a test target to check that the source file(s) exist and are up to date with the generated files(s).
|
|
||||||
|
out_file: The file or directory to write to in the source tree. Must be within the same bazel package as the target.
|
||||||
|
|
||||||
|
executable: Whether source tree file or files within the source tree directory written should be made executable.
|
||||||
|
|
||||||
|
additional_update_targets: List of other `write_source_files`, write_source_file` or other executable updater targets to call in the same run.
|
||||||
|
|
||||||
|
suggested_update_target: Label of the `write_source_files` or `write_source_file` target to suggest running when files are out of date.
|
||||||
|
|
||||||
|
diff_test: Test that the source tree file or directory exist and is up to date.
|
||||||
|
|
||||||
**kwargs: Other common named parameters such as `tags` or `visibility`
|
**kwargs: Other common named parameters such as `tags` or `visibility`
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
@ -57,6 +72,7 @@ def write_source_file(
|
||||||
name = name,
|
name = name,
|
||||||
in_file = in_file,
|
in_file = in_file,
|
||||||
out_file = out_file.name if out_file else None,
|
out_file = out_file.name if out_file else None,
|
||||||
|
executable = executable,
|
||||||
additional_update_targets = additional_update_targets,
|
additional_update_targets = additional_update_targets,
|
||||||
**kwargs
|
**kwargs
|
||||||
)
|
)
|
||||||
|
@ -140,12 +156,16 @@ _write_source_file_attrs = {
|
||||||
# and it goes into an infinite update, notify loop when running this target.
|
# and it goes into an infinite update, notify loop when running this target.
|
||||||
# See https://github.com/aspect-build/bazel-lib/pull/52 for more context.
|
# See https://github.com/aspect-build/bazel-lib/pull/52 for more context.
|
||||||
"out_file": attr.string(mandatory = False),
|
"out_file": attr.string(mandatory = False),
|
||||||
|
"executable": attr.bool(),
|
||||||
# buildifier: disable=attr-cfg
|
# buildifier: disable=attr-cfg
|
||||||
"additional_update_targets": attr.label_list(cfg = "host", mandatory = False, providers = [WriteSourceFileInfo]),
|
"additional_update_targets": attr.label_list(cfg = "host", mandatory = False, providers = [WriteSourceFileInfo]),
|
||||||
"_windows_constraint": attr.label(default = "@platforms//os:windows"),
|
"_windows_constraint": attr.label(default = "@platforms//os:windows"),
|
||||||
|
"_macos_constraint": attr.label(default = "@platforms//os:macos"),
|
||||||
}
|
}
|
||||||
|
|
||||||
def _write_source_file_sh(ctx, paths):
|
def _write_source_file_sh(ctx, paths):
|
||||||
|
is_macos = ctx.target_platform_has_constraint(ctx.attr._macos_constraint[platform_common.ConstraintValueInfo])
|
||||||
|
|
||||||
updater = ctx.actions.declare_file(
|
updater = ctx.actions.declare_file(
|
||||||
ctx.label.name + "_update.sh",
|
ctx.label.name + "_update.sh",
|
||||||
)
|
)
|
||||||
|
@ -162,24 +182,46 @@ if [[ ! -z "${BUILD_WORKSPACE_DIRECTORY:-}" ]]; then
|
||||||
cd "$BUILD_WORKSPACE_DIRECTORY"
|
cd "$BUILD_WORKSPACE_DIRECTORY"
|
||||||
fi"""]
|
fi"""]
|
||||||
|
|
||||||
|
if ctx.attr.executable:
|
||||||
|
executable_file = "chmod +x \"$out\""
|
||||||
|
executable_dir = "chmod -R +x \"$out\"/*"
|
||||||
|
else:
|
||||||
|
executable_file = "chmod -x \"$out\""
|
||||||
|
if is_macos:
|
||||||
|
# -x+X doesn't work on macos so we have to find files and remove the execute bits only from those
|
||||||
|
executable_dir = "find \"$out\" -type file | xargs chmod -x"
|
||||||
|
else:
|
||||||
|
# Remove execute/search bit recursively from files bit not directories: https://superuser.com/a/434418
|
||||||
|
executable_dir = "chmod -R -x+X \"$out\"/*"
|
||||||
|
|
||||||
for in_path, out_path in paths:
|
for in_path, out_path in paths:
|
||||||
contents.append("""
|
contents.append("""
|
||||||
in=$runfiles_dir/{in_path}
|
in=$runfiles_dir/{in_path}
|
||||||
out={out_path}
|
out={out_path}
|
||||||
|
|
||||||
mkdir -p "$(dirname "$out")"
|
mkdir -p "$(dirname "$out")"
|
||||||
echo "Copying $in to $out in $PWD"
|
|
||||||
|
|
||||||
if [[ -f "$in" ]]; then
|
if [[ -f "$in" ]]; then
|
||||||
|
echo "Copying file $in to $out in $PWD"
|
||||||
|
rm -Rf "$out"
|
||||||
cp -f "$in" "$out"
|
cp -f "$in" "$out"
|
||||||
|
# cp should make the file writable but call chmod anyway as a defense in depth
|
||||||
chmod ug+w "$out"
|
chmod ug+w "$out"
|
||||||
|
# cp should make the file not-executable but set the desired execute bit in both cases as a defense in depth
|
||||||
|
{executable_file}
|
||||||
else
|
else
|
||||||
|
echo "Copying directory $in to $out in $PWD"
|
||||||
rm -Rf "$out"/*
|
rm -Rf "$out"/*
|
||||||
mkdir -p "$out"
|
mkdir -p "$out"
|
||||||
cp -fRL "$in"/* "$out"
|
cp -fRL "$in"/* "$out"
|
||||||
chmod -R ug+w "$out"/*
|
chmod -R ug+w "$out"/*
|
||||||
|
{executable_dir}
|
||||||
fi
|
fi
|
||||||
""".format(in_path = in_path, out_path = out_path))
|
""".format(
|
||||||
|
in_path = in_path,
|
||||||
|
out_path = out_path,
|
||||||
|
executable_file = executable_file,
|
||||||
|
executable_dir = executable_dir,
|
||||||
|
))
|
||||||
|
|
||||||
contents.extend([
|
contents.extend([
|
||||||
"cd \"$runfiles_dir\"",
|
"cd \"$runfiles_dir\"",
|
||||||
|
|
|
@ -24,8 +24,8 @@ write_file(
|
||||||
name = "gen_template",
|
name = "gen_template",
|
||||||
out = "template.txt",
|
out = "template.txt",
|
||||||
content = [
|
content = [
|
||||||
"#!/bin/bash",
|
"#!/usr/bin/env bash",
|
||||||
"set -o errexit",
|
"set -o errexit -o nounset -o pipefail",
|
||||||
"""[ "{thing}" == "stuff" ]""",
|
"""[ "{thing}" == "stuff" ]""",
|
||||||
"""[ "%path%" == "{BINDIR}/lib/tests/template.txt" ]""",
|
"""[ "%path%" == "{BINDIR}/lib/tests/template.txt" ]""",
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
"""A simple rule that generates provides a DefaultOutput with some files"""
|
"""A simple rule that generates and provides a DefaultOutput with some files"""
|
||||||
|
|
||||||
def _generate_outputs_impl(ctx):
|
def _generate_outputs_impl(ctx):
|
||||||
if len(ctx.attr.output_files) != len(ctx.attr.output_contents):
|
if len(ctx.attr.output_files) != len(ctx.attr.output_contents):
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
dist.js
|
dist.js
|
||||||
|
dist_executable.js
|
||||||
subdir_test
|
subdir_test
|
||||||
|
subdir_executable_test
|
||||||
symlink_test
|
symlink_test
|
|
@ -1,6 +1,7 @@
|
||||||
load("//lib/tests/write_source_files:write_source_file_test.bzl", "write_source_file_test")
|
load("//lib/tests/write_source_files:write_source_file_test.bzl", "write_source_file_test")
|
||||||
load("//lib/tests:generate_outputs.bzl", "generate_outputs")
|
load("//lib/tests:generate_outputs.bzl", "generate_outputs")
|
||||||
load("//lib:write_source_files.bzl", "write_source_files")
|
load("//lib:write_source_files.bzl", "write_source_files")
|
||||||
|
load("//lib/private:write_source_file.bzl", "write_source_file")
|
||||||
load("//lib:copy_to_directory.bzl", "copy_to_directory")
|
load("//lib:copy_to_directory.bzl", "copy_to_directory")
|
||||||
load("//lib:directory_path.bzl", "directory_path")
|
load("//lib:directory_path.bzl", "directory_path")
|
||||||
load("//lib:output_files.bzl", "output_files")
|
load("//lib:output_files.bzl", "output_files")
|
||||||
|
@ -51,6 +52,14 @@ copy_to_directory(
|
||||||
srcs = [":e-contained"],
|
srcs = [":e-contained"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
copy_to_directory(
|
||||||
|
name = "es_dir-desired",
|
||||||
|
srcs = [":e-contained"],
|
||||||
|
replace_prefixes = {
|
||||||
|
"e-contained.js": "subdir/e-contained.js",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
genrule(
|
genrule(
|
||||||
name = "f-contained",
|
name = "f-contained",
|
||||||
outs = ["f-contained.js"],
|
outs = ["f-contained.js"],
|
||||||
|
@ -93,25 +102,47 @@ output_files(
|
||||||
)
|
)
|
||||||
|
|
||||||
write_source_file_test(
|
write_source_file_test(
|
||||||
name = "write_to_source_files_a_test",
|
name = "a_test",
|
||||||
in_file = ":a-desired",
|
in_file = ":a-desired",
|
||||||
out_file = "a.js",
|
out_file = "a.js",
|
||||||
)
|
)
|
||||||
|
|
||||||
write_source_file_test(
|
write_source_file_test(
|
||||||
name = "write_to_source_files_b_test",
|
name = "b_test",
|
||||||
in_file = ":b-desired",
|
in_file = ":b-desired",
|
||||||
out_file = "b.js",
|
out_file = "b.js",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
write_source_file(
|
||||||
|
name = "e_dir_test",
|
||||||
|
in_file = ":e_dir-desired",
|
||||||
|
out_file = "e_dir",
|
||||||
|
# The diff_test that is contained within this macro takes `out_file` which is a source directory
|
||||||
|
# as an input but source directories are not supported on remote execution so we must tag that
|
||||||
|
# rule with "no-remote-exec".
|
||||||
|
# ERROR: cannot compare a directory "lib/tests/write_source_files/e_dir-desired" against a file "lib/tests/write_source_files/e_dir"
|
||||||
|
tags = ["no-remote-exec"],
|
||||||
|
)
|
||||||
|
|
||||||
|
write_source_file(
|
||||||
|
name = "es_dir_test",
|
||||||
|
in_file = ":es_dir-desired",
|
||||||
|
out_file = "es_dir",
|
||||||
|
# The diff_test that is contained within this macro takes `out_file` which is a source directory
|
||||||
|
# as an input but source directories are not supported on remote execution so we must tag that
|
||||||
|
# rule with "no-remote-exec".
|
||||||
|
# ERROR: cannot compare a directory "lib/tests/write_source_files/es_dir-desired" against a file "lib/tests/write_source_files/es_dir"
|
||||||
|
tags = ["no-remote-exec"],
|
||||||
|
)
|
||||||
|
|
||||||
write_source_file_test(
|
write_source_file_test(
|
||||||
name = "write_to_source_files_f_test",
|
name = "f_test",
|
||||||
in_file = ":f-desired",
|
in_file = ":f-desired",
|
||||||
out_file = "f.js",
|
out_file = "f.js",
|
||||||
)
|
)
|
||||||
|
|
||||||
write_source_file_test(
|
write_source_file_test(
|
||||||
name = "write_to_source_files_g_test",
|
name = "g_test",
|
||||||
in_file = ":g-desired",
|
in_file = ":g-desired",
|
||||||
out_file = "g.js",
|
out_file = "g.js",
|
||||||
)
|
)
|
||||||
|
@ -125,10 +156,13 @@ write_source_files(
|
||||||
"a2.js": ":a-desired",
|
"a2.js": ":a-desired",
|
||||||
"b2.js": ":b-desired",
|
"b2.js": ":b-desired",
|
||||||
"e2_dir": ":e_dir-desired",
|
"e2_dir": ":e_dir-desired",
|
||||||
|
"es2_dir": ":es_dir-desired",
|
||||||
"f2.js": ":f-desired",
|
"f2.js": ":f-desired",
|
||||||
"g2.js": ":g-desired",
|
"g2.js": ":g-desired",
|
||||||
},
|
},
|
||||||
# TODO: figure out ERROR: cannot compare a directory against a file
|
# The diff_test that is contained within this macro takes output directories `es_dir` and
|
||||||
|
# `es2dir` which are source directories as inputs but source directories are not supported on
|
||||||
|
# remote execution so we must tag that rule with "no-remote-exec".
|
||||||
tags = ["no-remote-exec"],
|
tags = ["no-remote-exec"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -138,22 +172,28 @@ genrule(
|
||||||
cmd = "echo 'dist' > $@",
|
cmd = "echo 'dist' > $@",
|
||||||
)
|
)
|
||||||
|
|
||||||
# ibazel run //lib/tests/write_source_files:write_dist
|
# See e2e/write_source_files
|
||||||
# See e2e/write_source_files_gitignored
|
|
||||||
write_source_files(
|
write_source_files(
|
||||||
name = "write_dist",
|
name = "write_dist",
|
||||||
diff_test = False,
|
diff_test = False,
|
||||||
files = {"dist.js": ":dist"},
|
files = {"dist.js": ":dist"},
|
||||||
)
|
)
|
||||||
|
|
||||||
# Generate a readonly file in nested readonly directories
|
# See e2e/write_source_files
|
||||||
|
write_source_files(
|
||||||
|
name = "write_dist_executable",
|
||||||
|
diff_test = False,
|
||||||
|
executable = True,
|
||||||
|
files = {"dist_executable.js": ":dist"},
|
||||||
|
)
|
||||||
|
|
||||||
|
# Generate a file in nested directories
|
||||||
genrule(
|
genrule(
|
||||||
name = "subdir",
|
name = "subdir",
|
||||||
outs = ["subdir_test"],
|
outs = ["subdir_test"],
|
||||||
cmd = ";".join([
|
cmd = ";".join([
|
||||||
"mkdir -p $@/a/b/c",
|
"mkdir -p $@/a/b/c",
|
||||||
"echo 'test' > $@/a/b/c/test.txt",
|
"echo 'test' > $@/a/b/c/test.txt",
|
||||||
"chmod -R -w $@/*",
|
|
||||||
]),
|
]),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -165,6 +205,15 @@ write_source_files(
|
||||||
files = {"subdir_test": ":subdir"},
|
files = {"subdir_test": ":subdir"},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Write nested subdirectories to source
|
||||||
|
# See e2e/write_source_files_subdir_multiple_runs
|
||||||
|
write_source_files(
|
||||||
|
name = "write_subdir_executable",
|
||||||
|
diff_test = False,
|
||||||
|
executable = True,
|
||||||
|
files = {"subdir_executable_test": ":subdir"},
|
||||||
|
)
|
||||||
|
|
||||||
# Generate some directories including symlinks
|
# Generate some directories including symlinks
|
||||||
genrule(
|
genrule(
|
||||||
name = "symlinks",
|
name = "symlinks",
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
console.log("e");
|
console.log("e*");
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
console.log("e*");
|
|
@ -0,0 +1 @@
|
||||||
|
console.log("e*");
|
|
@ -5,14 +5,22 @@ load(
|
||||||
_write_source_file = "write_source_file",
|
_write_source_file = "write_source_file",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# TODO: Make write_source_file part of the public API
|
||||||
|
# write_source_file = _write_source_file
|
||||||
|
|
||||||
def write_source_files(
|
def write_source_files(
|
||||||
name,
|
name,
|
||||||
files = {},
|
files = {},
|
||||||
|
executable = False,
|
||||||
additional_update_targets = [],
|
additional_update_targets = [],
|
||||||
suggested_update_target = None,
|
suggested_update_target = None,
|
||||||
diff_test = True,
|
diff_test = True,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
"""Write to one or more files or folders in the source tree. Stamp out tests that ensure the sources exist and are up to date.
|
"""Write one or more files and/or directories to the source tree.
|
||||||
|
|
||||||
|
By default, `diff_test` targets are generated that ensure the source tree files and/or directories to be written to
|
||||||
|
are up to date and the rule also checks that all source tree files and/or directories to be written to exist.
|
||||||
|
To disable the exists check and up-to-date tests set `diff_test` to `False`.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
|
@ -28,11 +36,16 @@ def write_source_files(
|
||||||
```
|
```
|
||||||
|
|
||||||
To update the source file, run:
|
To update the source file, run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bazel run //:write_foobar
|
bazel run //:write_foobar
|
||||||
```
|
```
|
||||||
|
|
||||||
A test will fail if the source file doesn't exist or if it's out of date with instructions on how to create/update it.
|
The generated `diff_test` will fail if the file is out of date and print out instructions on
|
||||||
|
how to update it.
|
||||||
|
|
||||||
|
If the file does not exist, Bazel will fail at analysis time and print out instructions on
|
||||||
|
how to create it.
|
||||||
|
|
||||||
You can declare a tree of generated source file targets:
|
You can declare a tree of generated source file targets:
|
||||||
|
|
||||||
|
@ -55,7 +68,8 @@ def write_source_files(
|
||||||
bazel run //:write_all
|
bazel run //:write_all
|
||||||
```
|
```
|
||||||
|
|
||||||
When a file is out of date, you can leave a suggestion to run a target further up in the tree by specifying `suggested_update_target`. E.g.,
|
When a file is out of date, you can leave a suggestion to run a target further up in the tree by specifying `suggested_update_target`.
|
||||||
|
For example,
|
||||||
|
|
||||||
```starlark
|
```starlark
|
||||||
write_source_files(
|
write_source_files(
|
||||||
|
@ -67,7 +81,7 @@ def write_source_files(
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
A test failure from foo.json being out of date will yield the following message:
|
A test failure from `foo.json` being out of date will yield the following message:
|
||||||
|
|
||||||
```
|
```
|
||||||
//a/b:c:foo.json is out of date. To update this and other generated files, run:
|
//a/b:c:foo.json is out of date. To update this and other generated files, run:
|
||||||
|
@ -79,17 +93,32 @@ def write_source_files(
|
||||||
bazel run //a/b/c:write_foo
|
bazel run //a/b/c:write_foo
|
||||||
```
|
```
|
||||||
|
|
||||||
If you have many sources that you want to update as a group, we recommend wrapping write_source_files in a macro that defaults `suggested_update_target` to the umbrella update target.
|
If you have many `write_source_files` targets that you want to update as a group, we recommend wrapping
|
||||||
|
`write_source_files` in a macro that defaults `suggested_update_target` to the umbrella update target.
|
||||||
NOTE: If you run formatters or linters on your codebase, it is advised that you exclude/ignore the outputs of this rule from those formatters/linters so as to avoid causing collisions and failing tests.
|
|
||||||
|
NOTE: If you run formatters or linters on your codebase, it is advised that you exclude/ignore the outputs of this
|
||||||
|
rule from those formatters/linters so as to avoid causing collisions and failing tests.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
name: Name of the executable target that creates or updates the source file
|
name: Name of the runnable target that creates or updates the source tree files and/or directories.
|
||||||
files: A dict where the keys are source files or folders to write to and the values are labels pointing to the desired content.
|
|
||||||
Sources must be within the same bazel package as the target.
|
files: A dict where the keys are files or directories in the source tree to write to and the values are labels
|
||||||
additional_update_targets: (Optional) List of other write_source_file or other executable updater targets to call in the same run
|
pointing to the desired content, typically file or directory outputs of other targets.
|
||||||
suggested_update_target: (Optional) Label of the write_source_file target to suggest running when files are out of date
|
|
||||||
diff_test: (Optional) Generate a test target to check that the source file(s) exist and are up to date with the generated files(s).
|
Source tree files and directories must be within the same bazel package as the target.
|
||||||
|
|
||||||
|
executable: Whether source tree files written should be made executable.
|
||||||
|
|
||||||
|
This applies to all source tree files written by this target. This attribute is not propagated to `additional_update_targets`.
|
||||||
|
|
||||||
|
To set different executable permissions on different source tree files use multiple `write_source_files` targets.
|
||||||
|
|
||||||
|
additional_update_targets: List of other `write_source_files` or other executable updater targets to call in the same run.
|
||||||
|
|
||||||
|
suggested_update_target: Label of the `write_source_files` target to suggest running when files are out of date.
|
||||||
|
|
||||||
|
diff_test: Test that the source tree files and/or directories exist and are up to date.
|
||||||
|
|
||||||
**kwargs: Other common named parameters such as `tags` or `visibility`
|
**kwargs: Other common named parameters such as `tags` or `visibility`
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -113,6 +142,7 @@ def write_source_files(
|
||||||
name = update_target_name,
|
name = update_target_name,
|
||||||
in_file = in_file,
|
in_file = in_file,
|
||||||
out_file = out_file,
|
out_file = out_file,
|
||||||
|
executable = executable,
|
||||||
additional_update_targets = additional_update_targets if single_update_target else [],
|
additional_update_targets = additional_update_targets if single_update_target else [],
|
||||||
suggested_update_target = this_suggested_update_target,
|
suggested_update_target = this_suggested_update_target,
|
||||||
diff_test = diff_test,
|
diff_test = diff_test,
|
||||||
|
|
Loading…
Reference in New Issue