feat: copy_to_directory copies files and directories to an output directory

This commit is contained in:
Greg Magolan 2021-11-16 21:30:32 -08:00
parent 905cbb582f
commit 0d2981f288
115 changed files with 849 additions and 15 deletions

View File

@ -2,6 +2,10 @@
# Take care to document any settings that you expect users to apply.
# Settings that apply only to CI are in .github/workflows/ci.bazelrc
# Allow the Bazel server to check directory sources for changes
# Avoids warning spam with rules_nodejs feature that models node_modules as directories
# See https://github.com/bazelbuild/rules_nodejs/releases/tag/3.6.0
startup --host_jvm_args=-DBAZEL_TRACK_SOURCE_DIRECTORIES=1
# Load any settings specific to the current user.
# .bazelrc.user should appear in .gitignore so that settings are not shared with team members

View File

@ -15,6 +15,12 @@ load("@bazel_skylib//lib:unittest.bzl", "register_unittest_toolchains")
register_unittest_toolchains()
# An external repository for test to use
local_repository(
name = "external_test_repo",
path = "./lib/tests/external_test_repo",
)
############################################
# Gazelle, for generating bzl_library targets
load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")

View File

@ -2,6 +2,11 @@
# so that the dependency on stardoc doesn't leak to them.
load("//lib:docs.bzl", "stardoc_with_diff_test", "update_docs")
stardoc_with_diff_test(
bzl_library_target = "//lib/private:copy_to_directory",
out_label = "//docs:copy_to_directory.md",
)
stardoc_with_diff_test(
bzl_library_target = "//lib:docs",
out_label = "//docs:docs.md",

50
docs/copy_to_directory.md Normal file
View File

@ -0,0 +1,50 @@
<!-- Generated with Stardoc: http://skydoc.bazel.build -->
Copy files and directories to an output directory
<a id="#copy_to_directory"></a>
## copy_to_directory
<pre>
copy_to_directory(<a href="#copy_to_directory-name">name</a>, <a href="#copy_to_directory-is_windows">is_windows</a>, <a href="#copy_to_directory-replace_prefixes">replace_prefixes</a>, <a href="#copy_to_directory-root_paths">root_paths</a>, <a href="#copy_to_directory-srcs">srcs</a>)
</pre>
Copies files and directories to an output directory.
Files and directories can be arranged as needed in the output directory using
the `root_paths` and `replace_prefixes` attributes.
NB: This rule is not yet implemented for Windows
**ATTRIBUTES**
| Name | Description | Type | Mandatory | Default |
| :------------- | :------------- | :------------- | :------------- | :------------- |
| <a id="copy_to_directory-name"></a>name | A unique name for this target. | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required | |
| <a id="copy_to_directory-is_windows"></a>is_windows | - | Boolean | required | |
| <a id="copy_to_directory-replace_prefixes"></a>replace_prefixes | Map of paths prefixes to replace in the output directory path when copying files.<br><br>If the output directory path for a file or directory starts with or is equal to a key in the dict then the matching portion of the output directory path is replaced with the dict value for that key.<br><br>Forward slashes (<code>/</code>) should be used as path separators. The final path segment of the key can be a partial match in the corresponding segment of the output directory path.<br><br>If there are multiple keys that match, the longest match wins. | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | optional | {} |
| <a id="copy_to_directory-root_paths"></a>root_paths | List of paths that are roots in the output directory. If a file or directory being copied is in one of the listed paths or one of its subpaths, the output directory path is the path relative to the root path instead of the path relative to the file's workspace.<br><br>Forward slashes (<code>/</code>) should be used as path separators. Partial matches on the final path segment of a root path against the corresponding segment in the full workspace relative path of a file are not matched.<br><br>If there are multiple root paths that match, the longest match wins.<br><br>Defaults to [package_name()] so that the output directory path of files in the target's package and and sub-packages are relative to the target's package and files outside of that retain their full workspace relative paths. | List of strings | optional | [] |
| <a id="copy_to_directory-srcs"></a>srcs | Files and/or directories to copy into the output directory | <a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a> | optional | [] |
<a id="#copy_to_directory_lib.impl"></a>
## copy_to_directory_lib.impl
<pre>
copy_to_directory_lib.impl(<a href="#copy_to_directory_lib.impl-ctx">ctx</a>)
</pre>
**PARAMETERS**
| Name | Description | Default Value |
| :------------- | :------------- | :------------- |
| <a id="copy_to_directory_lib.impl-ctx"></a>ctx | <p align="center"> - </p> | none |

View File

@ -33,7 +33,11 @@ The relative path from frm_file to to_file, including the file name
to_manifest_path(<a href="#to_manifest_path-ctx">ctx</a>, <a href="#to_manifest_path-file">file</a>)
</pre>
The runfiles manifest entry for a file
The runfiles manifest entry path for a file
This is the full runfiles path of a file including its workspace name as
the first segment. We refert to it as the manifest path as it is the path
flavor that is used for in the runfiles MANIFEST file.
We must avoid using non-normalized paths (workspace/../other_workspace/path)
in order to locate entries by their key.
@ -49,6 +53,34 @@ in order to locate entries by their key.
**RETURNS**
a key that can lookup the path from the runfiles manifest
The runfiles manifest entry path for a file
<a id="#to_workspace_path"></a>
## to_workspace_path
<pre>
to_workspace_path(<a href="#to_workspace_path-ctx">ctx</a>, <a href="#to_workspace_path-file">file</a>)
</pre>
The workspace relative path for a file
This is the full runfiles path of a file excluding its workspace name.
This differs from root path and manifest path as it does not include the
repository name if the file is from an external repository.
**PARAMETERS**
| Name | Description | Default Value |
| :------------- | :------------- | :------------- |
| <a id="to_workspace_path-ctx"></a>ctx | starlark rule execution context | none |
| <a id="to_workspace_path-file"></a>file | a File object | none |
**RETURNS**
The workspace relative path for a file

View File

@ -1,7 +1,12 @@
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
# For stardoc to reference the files
exports_files(glob(["*.bzl"]))
exports_files(
glob(["*.bzl"]),
visibility = [
"//docs:__pkg__",
"//lib:__subpackages__",
],
)
filegroup(
name = "package_content",

35
lib/copy_file.bzl Normal file
View File

@ -0,0 +1,35 @@
# 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.
# LOCAL MODIFICATIONS
# this has two PRs patched in on top of the original
# https://github.com/bazelbuild/bazel-skylib/blob/7b859037a673db6f606661323e74c5d4751595e6/rules/private/copy_file_private.bzl
# 1) https://github.com/bazelbuild/bazel-skylib/pull/323
# 2) https://github.com/bazelbuild/bazel-skylib/pull/324
"""A rule that copies a file to another place.
native.genrule() is sometimes used to copy files (often wishing to rename them).
The 'copy_file' rule does this with a simpler interface than genrule.
The rule uses a Bash command on Linux/macOS/non-Windows, and a cmd.exe command
on Windows (no Bash is required).
"""
load(
"//lib/private:copy_file.bzl",
_copy_file = "copy_file",
)
copy_file = _copy_file

25
lib/copy_to_directory.bzl Normal file
View File

@ -0,0 +1,25 @@
"Public API for copy_to_directory"
load(
"//lib/private:copy_to_directory.bzl",
lib = "copy_to_directory_lib",
)
_copy_to_directory = rule(
implementation = lib.impl,
provides = lib.provides,
attrs = lib.attrs,
)
def copy_to_directory(name, root_paths = None, **kwargs):
if root_paths == None:
root_paths = [native.package_name()]
_copy_to_directory(
name = name,
root_paths = root_paths,
is_windows = select({
"@bazel_tools//src/conditions:host_windows": True,
"//conditions:default": False,
}),
**kwargs
)

View File

@ -4,10 +4,11 @@ load("//lib/private:paths.bzl", "paths")
relative_file = paths.relative_file
to_manifest_path = paths.to_manifest_path
to_workspace_path = paths.to_workspace_path
# Bash helper function for looking up runfiles.
# See windows_utils.bzl for the cmd.exe equivalent.
# Vendored from
# Vendored from
# https://github.com/bazelbuild/bazel/blob/master/tools/bash/runfiles/runfiles.bash
BASH_RLOCATION_FUNCTION = r"""
# --- begin runfiles.bash initialization v2 ---

View File

@ -1,5 +1,10 @@
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
exports_files(
glob(["*.bzl"]),
visibility = ["//docs:__pkg__"],
)
filegroup(
name = "package_content",
srcs = glob([
@ -9,6 +14,16 @@ filegroup(
visibility = ["//lib:__pkg__"],
)
bzl_library(
name = "copy_to_directory",
srcs = ["copy_to_directory.bzl"],
visibility = ["//docs:__pkg__"],
deps = [
":paths",
"@bazel_skylib//lib:paths",
],
)
bzl_library(
name = "params_file",
srcs = ["params_file.bzl"],

219
lib/private/copy_file.bzl Normal file
View File

@ -0,0 +1,219 @@
# 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.
# LOCAL MODIFICATIONS
# this has two PRs patched in on top of the original
# https://github.com/bazelbuild/bazel-skylib/blob/7b859037a673db6f606661323e74c5d4751595e6/rules/private/copy_file_private.bzl
# 1) https://github.com/bazelbuild/bazel-skylib/pull/323
# 2) https://github.com/bazelbuild/bazel-skylib/pull/324
"""Implementation of copy_file macro and underlying rules.
These rules copy a file or directory to another location using Bash (on Linux/macOS) or
cmd.exe (on Windows). `_copy_xfile` marks the resulting file executable,
`_copy_file` does not.
"""
# Hints for Bazel spawn strategy
_execution_requirements = {
# Copying files is entirely IO-bound and there is no point doing this work remotely.
# Also, remote-execution does not allow source directory inputs, see
# https://github.com/bazelbuild/bazel/commit/c64421bc35214f0414e4f4226cc953e8c55fa0d2
# So we must not attempt to execute remotely in that case.
"no-remote-exec": "1",
}
def _hash_file(file):
return str(hash(file.path))
# buildifier: disable=function-docstring
def copy_cmd(ctx, src, dst):
# Most Windows binaries built with MSVC use a certain argument quoting
# scheme. Bazel uses that scheme too to quote arguments. However,
# cmd.exe uses different semantics, so Bazel's quoting is wrong here.
# To fix that we write the command to a .bat file so no command line
# quoting or escaping is required.
# Put a hash of the file name into the name of the generated batch file to
# make it unique within the package, so that users can define multiple copy_file's.
bat = ctx.actions.declare_file("%s-%s-cmd.bat" % (ctx.label.name, _hash_file(src)))
# Flags are documented at
# https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/copy
# https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/xcopy
if dst.is_directory:
cmd_tmpl = "@xcopy \"%s\" \"%s\\\" /V /E /H /Y /Q >NUL"
mnemonic = "CopyDirectory"
progress_message = "Copying directory"
else:
cmd_tmpl = "@copy /Y \"%s\" \"%s\" >NUL"
mnemonic = "CopyFile"
progress_message = "Copying file"
ctx.actions.write(
output = bat,
# Do not use lib/shell.bzl's shell.quote() method, because that uses
# Bash quoting syntax, which is different from cmd.exe's syntax.
content = cmd_tmpl % (
src.path.replace("/", "\\"),
dst.path.replace("/", "\\"),
),
is_executable = True,
)
ctx.actions.run(
inputs = [src],
tools = [bat],
outputs = [dst],
executable = "cmd.exe",
arguments = ["/C", bat.path.replace("/", "\\")],
mnemonic = mnemonic,
progress_message = progress_message,
use_default_shell_env = True,
execution_requirements = _execution_requirements,
)
# buildifier: disable=function-docstring
def copy_bash(ctx, src, dst):
if dst.is_directory:
cmd_tmpl = "rm -rf \"$2\" && cp -rf \"$1/\" \"$2\""
mnemonic = "CopyDirectory"
progress_message = "Copying directory"
else:
cmd_tmpl = "cp -f \"$1\" \"$2\""
mnemonic = "CopyFile"
progress_message = "Copying file"
ctx.actions.run_shell(
tools = [src],
outputs = [dst],
command = cmd_tmpl,
arguments = [src.path, dst.path],
mnemonic = mnemonic,
progress_message = progress_message,
use_default_shell_env = True,
execution_requirements = _execution_requirements,
)
def _copy_file_impl(ctx):
# When creating a directory, declare that to Bazel so downstream rules
# see it as a TreeArtifact and handle correctly, e.g. for remote execution
if getattr(ctx.attr, "is_directory", False):
output = ctx.actions.declare_directory(ctx.attr.out)
else:
output = ctx.outputs.out
if ctx.attr.allow_symlink:
if output.is_directory:
fail("Cannot use both is_directory and allow_symlink")
ctx.actions.symlink(
output = output,
target_file = ctx.file.src,
is_executable = ctx.attr.is_executable,
)
elif ctx.attr.is_windows:
copy_cmd(ctx, ctx.file.src, output)
else:
copy_bash(ctx, ctx.file.src, output)
files = depset(direct = [output])
runfiles = ctx.runfiles(files = [output])
if ctx.attr.is_executable:
return [DefaultInfo(files = files, runfiles = runfiles, executable = output)]
else:
return [DefaultInfo(files = files, runfiles = runfiles)]
_ATTRS = {
"src": attr.label(mandatory = True, allow_single_file = True),
"is_windows": attr.bool(mandatory = True),
"is_executable": attr.bool(mandatory = True),
"allow_symlink": attr.bool(mandatory = True),
}
_copy_directory = rule(
implementation = _copy_file_impl,
provides = [DefaultInfo],
attrs = dict(_ATTRS, **{
"is_directory": attr.bool(default = True),
# Cannot declare out as an output here, because there's no API for declaring
# TreeArtifact outputs.
"out": attr.string(mandatory = True),
}),
)
_copy_file = rule(
implementation = _copy_file_impl,
provides = [DefaultInfo],
attrs = dict(_ATTRS, **{
"out": attr.output(mandatory = True),
}),
)
_copy_xfile = rule(
implementation = _copy_file_impl,
executable = True,
provides = [DefaultInfo],
attrs = dict(_ATTRS, **{
"out": attr.output(mandatory = True),
}),
)
def copy_file(name, src, out, is_directory = False, is_executable = False, allow_symlink = False, **kwargs):
"""Copies a file or directory to another location.
`native.genrule()` is sometimes used to copy files (often wishing to rename them). The 'copy_file' rule does this with a simpler interface than genrule.
This rule uses a Bash command on Linux/macOS/non-Windows, and a cmd.exe command on Windows (no Bash is required).
If using this rule with source directories, it is recommended that you use the
`--host_jvm_args=-DBAZEL_TRACK_SOURCE_DIRECTORIES=1` startup option so that changes
to files within source directories are detected. See
https://github.com/bazelbuild/bazel/commit/c64421bc35214f0414e4f4226cc953e8c55fa0d2
for more context.
Args:
name: Name of the rule.
src: A Label. The file or directory to make a copy of.
(Can also be the label of a rule that generates a file or directory.)
out: Path of the output file, relative to this package.
is_directory: treat the source file as a directory
Workaround for https://github.com/bazelbuild/bazel/issues/12954
is_executable: A boolean. Whether to make the output file executable. When
True, the rule's output can be executed using `bazel run` and can be
in the srcs of binary and test rules that require executable sources.
WARNING: If `allow_symlink` is True, `src` must also be executable.
allow_symlink: A boolean. Whether to allow symlinking instead of copying.
When False, the output is always a hard copy. When True, the output
*can* be a symlink, but there is no guarantee that a symlink is
created (i.e., at the time of writing, we don't create symlinks on
Windows). Set this to True if you need fast copying and your tools can
handle symlinks (which most UNIX tools can).
**kwargs: further keyword arguments, e.g. `visibility`
"""
copy_file_impl = _copy_file
if is_executable:
copy_file_impl = _copy_xfile
elif is_directory:
copy_file_impl = _copy_directory
copy_file_impl(
name = name,
src = src,
out = out,
is_windows = select({
"@bazel_tools//src/conditions:host_windows": True,
"//conditions:default": False,
}),
is_executable = is_executable,
allow_symlink = allow_symlink,
**kwargs
)

View File

@ -0,0 +1,149 @@
"Copy files and directories to an output directory"
load("@bazel_skylib//lib:paths.bzl", skylib_paths = "paths")
load(":paths.bzl", "paths")
_DOC = """Copies files and directories to an output directory.
Files and directories can be arranged as needed in the output directory using
the `root_paths` and `replace_prefixes` attributes.
NB: This rule is not yet implemented for Windows
"""
_copy_to_directory_attr = {
"srcs": attr.label_list(
allow_files = True,
doc = """Files and/or directories to copy into the output directory""",
),
"root_paths": attr.string_list(
default = [],
doc = """
List of paths that are roots in the output directory. If a file or directory
being copied is in one of the listed paths or one of its subpaths, the output
directory path is the path relative to the root path instead of the path
relative to the file's workspace.
Forward slashes (`/`) should be used as path separators. Partial matches
on the final path segment of a root path against the corresponding segment
in the full workspace relative path of a file are not matched.
If there are multiple root paths that match, the longest match wins.
Defaults to [package_name()] so that the output directory path of files in the
target's package and and sub-packages are relative to the target's package and
files outside of that retain their full workspace relative paths.
""",
),
"replace_prefixes": attr.string_dict(
default = {},
doc = """
Map of paths prefixes to replace in the output directory path when copying files.
If the output directory path for a file or directory starts with or is equal to
a key in the dict then the matching portion of the output directory path is
replaced with the dict value for that key.
Forward slashes (`/`) should be used as path separators. The final path segment
of the key can be a partial match in the corresponding segment of the output
directory path.
If there are multiple keys that match, the longest match wins.
""",
),
"is_windows": attr.bool(mandatory = True),
}
# Hints for Bazel spawn strategy
_execution_requirements = {
# Copying files is entirely IO-bound and there is no point doing this work
# remotely. Also, remote-execution does not allow source directory inputs,
# see
# https://github.com/bazelbuild/bazel/commit/c64421bc35214f0414e4f4226cc953e8c55fa0d2
# So we must not attempt to execute remotely in that case.
"no-remote-exec": "1",
}
def _longest_match(subject, tests, allow_partial = False):
match = None
high_score = 0
for test in tests:
starts_with_test = test if allow_partial else test + "/"
if subject == test or subject.startswith(starts_with_test):
score = len(test)
if score > high_score:
match = test
high_score = score
return match
def _output_path(ctx, src):
result = paths.to_workspace_path(ctx, src)
# strip root paths
root_path = _longest_match(result, ctx.attr.root_paths)
if root_path:
strip_depth = len(root_path.split("/"))
result = "/".join(result.split("/")[strip_depth:])
# apply a replacement if one is found
match = _longest_match(result, ctx.attr.replace_prefixes.keys(), True)
if match:
result = ctx.attr.replace_prefixes[match] + result[len(match):]
return result
def _copy_to_dir_bash(ctx, srcs, dst_dir):
cmds = [
"set -o errexit -o nounset -o pipefail",
"mkdir -p \"%s\"" % dst_dir.path,
]
for src in srcs:
output_path = _output_path(ctx, src)
dst_path = skylib_paths.normalize("/".join([dst_dir.path, output_path]))
cmds.append("""
if [[ ! -e "{src}" ]]; then echo "file '{src}' does not exist"; exit 1; fi
if [[ -f "{src}" ]]; then
mkdir -p "{dst_dir}"
cp -f "{src}" "{dst}"
else
mkdir -p "{dst}"
cp -rf "{src}"/* "{dst}"
fi
""".format(src = src.path, dst_dir = skylib_paths.dirname(dst_path), dst = dst_path))
ctx.actions.run_shell(
inputs = srcs,
outputs = [dst_dir],
command = "\n".join(cmds),
mnemonic = "CopyToDirectory",
progress_message = "Copying files to directory",
use_default_shell_env = True,
execution_requirements = _execution_requirements,
)
def _copy_to_directory_impl(ctx):
if not ctx.files.srcs:
msg = "srcs must not be empty in copy_to_directory %s" % ctx.label
fail(msg)
output = ctx.actions.declare_directory(ctx.attr.name)
if ctx.attr.is_windows:
# TODO: Windows implementation
fail("not yet implemented")
else:
_copy_to_dir_bash(ctx, ctx.files.srcs, output)
return [
DefaultInfo(files = depset([output])),
]
copy_to_directory_lib = struct(
attrs = _copy_to_directory_attr,
impl = _copy_to_directory_impl,
provides = [DefaultInfo],
)
# For stardoc to generate documentation for the rule rather than a wrapper macro
copy_to_directory = rule(
doc = _DOC,
implementation = copy_to_directory_lib.impl,
attrs = copy_to_directory_lib.attrs,
provides = copy_to_directory_lib.provides,
)

View File

@ -43,17 +43,21 @@ def _relative_file(to_file, frm_file):
)
def _to_manifest_path(ctx, file):
"""The runfiles manifest entry for a file
"""The runfiles manifest entry path for a file
This is the full runfiles path of a file including its workspace name as
the first segment. We refert to it as the manifest path as it is the path
flavor that is used for in the runfiles MANIFEST file.
We must avoid using non-normalized paths (workspace/../other_workspace/path)
in order to locate entries by their key.
Args:
ctx: starlark rule execution context
file: a File object
Returns:
a key that can lookup the path from the runfiles manifest
The runfiles manifest entry path for a file
"""
if file.short_path.startswith("../"):
@ -61,7 +65,28 @@ def _to_manifest_path(ctx, file):
else:
return ctx.workspace_name + "/" + file.short_path
def _to_workspace_path(ctx, file):
"""The workspace relative path for a file
This is the full runfiles path of a file excluding its workspace name.
This differs from root path and manifest path as it does not include the
repository name if the file is from an external repository.
Args:
ctx: starlark rule execution context
file: a File object
Returns:
The workspace relative path for a file
"""
if file.short_path.startswith("../"):
return "/".join(file.short_path.split("/")[2:])
else:
return file.short_path
paths = struct(
relative_file = _relative_file,
to_manifest_path = _to_manifest_path,
to_workspace_path = _to_workspace_path,
)

View File

@ -0,0 +1,131 @@
"tests for copy_to_directory"
load("@bazel_skylib//rules:diff_test.bzl", "diff_test")
load("//lib:copy_file.bzl", "copy_file")
load("//lib:copy_to_directory.bzl", "copy_to_directory")
[
copy_file(
name = "%s" % d,
src = "dir_%s" % d,
out = "%s" % d,
is_directory = True,
)
for d in [
"a",
"b",
"expected_1",
"expected_2",
"expected_3",
"expected_4",
"expected_5",
]
]
case_srcs = [
":a",
":b",
":c",
":d",
":e/e",
":e/e2",
"//lib/tests/copy_to_directory/f/f2:f",
"//lib/tests/copy_to_directory/f/f2:f2",
"@external_test_repo//:test_a",
"@external_test_repo//:test_b",
"@external_test_repo//:test_c",
"@external_test_repo//:test_d",
]
# Case 1: default settings
copy_to_directory(
name = "case_1",
srcs = case_srcs,
)
diff_test(
name = "case_1_test",
file1 = "case_1",
file2 = ":expected_1",
)
# Case 2: replace_prefixes
copy_to_directory(
name = "case_2",
srcs = case_srcs,
replace_prefixes = {
# merge a, b, c, d into a new/abcd dest folder
"a": "new/abcd",
"b": "//new///abcd////",
"c": "new/abcd/c",
"d": "////new/////abcd////d",
# put e into new/e except for e/e2 which goes into new/e2
"e": "new/e",
"e/e2": "new/e2/e2",
# f/f2/f => new/ff and f/f2/f2 => new/f2/f2
"f/f2/": "////new/////f",
"f/f2/f2": "////new/////f2///f2",
# flatten test_a & test_b to the root
"test_a": "",
"test_b": "",
# some paths that won't match
"a/": "wont_match_a_is_terminal_path",
"a/a2": "wont_match_since_a2_is_in_a_tree_artifact",
},
)
diff_test(
name = "case_2_test",
file1 = "case_2",
file2 = ":expected_2",
)
# Case 3: no root_paths
copy_to_directory(
name = "case_3",
srcs = case_srcs,
root_paths = [],
)
diff_test(
name = "case_3_test",
file1 = "case_3",
file2 = ":expected_3",
)
# Case 4: no root_paths + replace_prefixes
copy_to_directory(
name = "case_4",
srcs = case_srcs,
replace_prefixes = {
# strip lib/tests from paths
"lib/tests/": "",
# except for a few which should match due to longest match wins
"lib/tests/copy_to_directory/a": "lib/other/copy_to_directory",
"lib/tests/copy_to_directory/c": "lib/other/copy_to_directory/c",
},
root_paths = [],
)
diff_test(
name = "case_4_test",
file1 = "case_4",
file2 = ":expected_4",
)
# Case 5: custom root packages
copy_to_directory(
name = "case_5",
srcs = case_srcs,
root_paths = [
package_name(),
"%s/e" % package_name(),
"%s/f" % package_name(),
],
)
diff_test(
name = "case_5_test",
file1 = "case_5",
file2 = ":expected_5",
)

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1 @@
foobar

Some files were not shown because too many files have changed in this diff Show More