xref: /aosp_15_r20/external/bazel-skylib/rules/private/copy_file_private.bzl (revision bcb5dc7965af6ee42bf2f21341a2ec00233a8c8a)
1*bcb5dc79SHONG Yifan# Copyright 2019 The Bazel Authors. All rights reserved.
2*bcb5dc79SHONG Yifan#
3*bcb5dc79SHONG Yifan# Licensed under the Apache License, Version 2.0 (the "License");
4*bcb5dc79SHONG Yifan# you may not use this file except in compliance with the License.
5*bcb5dc79SHONG Yifan# You may obtain a copy of the License at
6*bcb5dc79SHONG Yifan#
7*bcb5dc79SHONG Yifan#    http://www.apache.org/licenses/LICENSE-2.0
8*bcb5dc79SHONG Yifan#
9*bcb5dc79SHONG Yifan# Unless required by applicable law or agreed to in writing, software
10*bcb5dc79SHONG Yifan# distributed under the License is distributed on an "AS IS" BASIS,
11*bcb5dc79SHONG Yifan# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*bcb5dc79SHONG Yifan# See the License for the specific language governing permissions and
13*bcb5dc79SHONG Yifan# limitations under the License.
14*bcb5dc79SHONG Yifan
15*bcb5dc79SHONG Yifan"""Implementation of copy_file macro and underlying rules.
16*bcb5dc79SHONG Yifan
17*bcb5dc79SHONG YifanThese rules copy a file to another location using Bash (on Linux/macOS) or
18*bcb5dc79SHONG Yifancmd.exe (on Windows). '_copy_xfile' marks the resulting file executable,
19*bcb5dc79SHONG Yifan'_copy_file' does not.
20*bcb5dc79SHONG Yifan"""
21*bcb5dc79SHONG Yifan
22*bcb5dc79SHONG Yifanload(":copy_common.bzl", "COPY_EXECUTION_REQUIREMENTS")
23*bcb5dc79SHONG Yifan
24*bcb5dc79SHONG Yifandef copy_cmd(ctx, src, dst):
25*bcb5dc79SHONG Yifan    # Most Windows binaries built with MSVC use a certain argument quoting
26*bcb5dc79SHONG Yifan    # scheme. Bazel uses that scheme too to quote arguments. However,
27*bcb5dc79SHONG Yifan    # cmd.exe uses different semantics, so Bazel's quoting is wrong here.
28*bcb5dc79SHONG Yifan    # To fix that we write the command to a .bat file so no command line
29*bcb5dc79SHONG Yifan    # quoting or escaping is required.
30*bcb5dc79SHONG Yifan    bat = ctx.actions.declare_file(ctx.label.name + "-cmd.bat")
31*bcb5dc79SHONG Yifan    ctx.actions.write(
32*bcb5dc79SHONG Yifan        output = bat,
33*bcb5dc79SHONG Yifan        # Do not use lib/shell.bzl's shell.quote() method, because that uses
34*bcb5dc79SHONG Yifan        # Bash quoting syntax, which is different from cmd.exe's syntax.
35*bcb5dc79SHONG Yifan        content = "@copy /Y \"%s\" \"%s\" >NUL" % (
36*bcb5dc79SHONG Yifan            src.path.replace("/", "\\"),
37*bcb5dc79SHONG Yifan            dst.path.replace("/", "\\"),
38*bcb5dc79SHONG Yifan        ),
39*bcb5dc79SHONG Yifan        is_executable = True,
40*bcb5dc79SHONG Yifan    )
41*bcb5dc79SHONG Yifan    ctx.actions.run(
42*bcb5dc79SHONG Yifan        inputs = [src, bat],
43*bcb5dc79SHONG Yifan        outputs = [dst],
44*bcb5dc79SHONG Yifan        executable = "cmd.exe",
45*bcb5dc79SHONG Yifan        arguments = ["/C", bat.path.replace("/", "\\")],
46*bcb5dc79SHONG Yifan        mnemonic = "CopyFile",
47*bcb5dc79SHONG Yifan        progress_message = "Copying files",
48*bcb5dc79SHONG Yifan        use_default_shell_env = True,
49*bcb5dc79SHONG Yifan        execution_requirements = COPY_EXECUTION_REQUIREMENTS,
50*bcb5dc79SHONG Yifan    )
51*bcb5dc79SHONG Yifan
52*bcb5dc79SHONG Yifandef copy_bash(ctx, src, dst):
53*bcb5dc79SHONG Yifan    ctx.actions.run_shell(
54*bcb5dc79SHONG Yifan        inputs = [src],
55*bcb5dc79SHONG Yifan        outputs = [dst],
56*bcb5dc79SHONG Yifan        command = "cp -f \"$1\" \"$2\"",
57*bcb5dc79SHONG Yifan        arguments = [src.path, dst.path],
58*bcb5dc79SHONG Yifan        mnemonic = "CopyFile",
59*bcb5dc79SHONG Yifan        progress_message = "Copying files",
60*bcb5dc79SHONG Yifan        use_default_shell_env = True,
61*bcb5dc79SHONG Yifan        execution_requirements = COPY_EXECUTION_REQUIREMENTS,
62*bcb5dc79SHONG Yifan    )
63*bcb5dc79SHONG Yifan
64*bcb5dc79SHONG Yifandef _copy_file_impl(ctx):
65*bcb5dc79SHONG Yifan    if ctx.attr.allow_symlink:
66*bcb5dc79SHONG Yifan        ctx.actions.symlink(
67*bcb5dc79SHONG Yifan            output = ctx.outputs.out,
68*bcb5dc79SHONG Yifan            target_file = ctx.file.src,
69*bcb5dc79SHONG Yifan            is_executable = ctx.attr.is_executable,
70*bcb5dc79SHONG Yifan        )
71*bcb5dc79SHONG Yifan    elif ctx.attr.is_windows:
72*bcb5dc79SHONG Yifan        copy_cmd(ctx, ctx.file.src, ctx.outputs.out)
73*bcb5dc79SHONG Yifan    else:
74*bcb5dc79SHONG Yifan        copy_bash(ctx, ctx.file.src, ctx.outputs.out)
75*bcb5dc79SHONG Yifan
76*bcb5dc79SHONG Yifan    files = depset(direct = [ctx.outputs.out])
77*bcb5dc79SHONG Yifan    runfiles = ctx.runfiles(files = [ctx.outputs.out])
78*bcb5dc79SHONG Yifan    if ctx.attr.is_executable:
79*bcb5dc79SHONG Yifan        return [DefaultInfo(files = files, runfiles = runfiles, executable = ctx.outputs.out)]
80*bcb5dc79SHONG Yifan    else:
81*bcb5dc79SHONG Yifan        # Do not include the copied file into the default runfiles of the
82*bcb5dc79SHONG Yifan        # target, but ensure that it is picked up by native rule's data
83*bcb5dc79SHONG Yifan        # attribute despite https://github.com/bazelbuild/bazel/issues/15043.
84*bcb5dc79SHONG Yifan        return [DefaultInfo(files = files, data_runfiles = runfiles)]
85*bcb5dc79SHONG Yifan
86*bcb5dc79SHONG Yifan_ATTRS = {
87*bcb5dc79SHONG Yifan    "src": attr.label(mandatory = True, allow_single_file = True),
88*bcb5dc79SHONG Yifan    "out": attr.output(mandatory = True),
89*bcb5dc79SHONG Yifan    "is_windows": attr.bool(mandatory = True),
90*bcb5dc79SHONG Yifan    "is_executable": attr.bool(mandatory = True),
91*bcb5dc79SHONG Yifan    "allow_symlink": attr.bool(mandatory = True),
92*bcb5dc79SHONG Yifan}
93*bcb5dc79SHONG Yifan
94*bcb5dc79SHONG Yifan_copy_file = rule(
95*bcb5dc79SHONG Yifan    implementation = _copy_file_impl,
96*bcb5dc79SHONG Yifan    provides = [DefaultInfo],
97*bcb5dc79SHONG Yifan    attrs = _ATTRS,
98*bcb5dc79SHONG Yifan)
99*bcb5dc79SHONG Yifan
100*bcb5dc79SHONG Yifan_copy_xfile = rule(
101*bcb5dc79SHONG Yifan    implementation = _copy_file_impl,
102*bcb5dc79SHONG Yifan    executable = True,
103*bcb5dc79SHONG Yifan    provides = [DefaultInfo],
104*bcb5dc79SHONG Yifan    attrs = _ATTRS,
105*bcb5dc79SHONG Yifan)
106*bcb5dc79SHONG Yifan
107*bcb5dc79SHONG Yifandef copy_file(name, src, out, is_executable = False, allow_symlink = False, **kwargs):
108*bcb5dc79SHONG Yifan    """Copies a file to another location.
109*bcb5dc79SHONG Yifan
110*bcb5dc79SHONG Yifan    `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.
111*bcb5dc79SHONG Yifan
112*bcb5dc79SHONG Yifan    This rule uses a Bash command on Linux/macOS/non-Windows, and a cmd.exe command on Windows (no Bash is required).
113*bcb5dc79SHONG Yifan
114*bcb5dc79SHONG Yifan    Args:
115*bcb5dc79SHONG Yifan      name: Name of the rule.
116*bcb5dc79SHONG Yifan      src: A Label. The file to make a copy of. (Can also be the label of a rule
117*bcb5dc79SHONG Yifan          that generates a file.)
118*bcb5dc79SHONG Yifan      out: Path of the output file, relative to this package.
119*bcb5dc79SHONG Yifan      is_executable: A boolean. Whether to make the output file executable. When
120*bcb5dc79SHONG Yifan          True, the rule's output can be executed using `bazel run` and can be
121*bcb5dc79SHONG Yifan          in the srcs of binary and test rules that require executable sources.
122*bcb5dc79SHONG Yifan          WARNING: If `allow_symlink` is True, `src` must also be executable.
123*bcb5dc79SHONG Yifan      allow_symlink: A boolean. Whether to allow symlinking instead of copying.
124*bcb5dc79SHONG Yifan          When False, the output is always a hard copy. When True, the output
125*bcb5dc79SHONG Yifan          *can* be a symlink, but there is no guarantee that a symlink is
126*bcb5dc79SHONG Yifan          created (i.e., at the time of writing, we don't create symlinks on
127*bcb5dc79SHONG Yifan          Windows). Set this to True if you need fast copying and your tools can
128*bcb5dc79SHONG Yifan          handle symlinks (which most UNIX tools can).
129*bcb5dc79SHONG Yifan      **kwargs: further keyword arguments, e.g. `visibility`
130*bcb5dc79SHONG Yifan    """
131*bcb5dc79SHONG Yifan
132*bcb5dc79SHONG Yifan    copy_file_impl = _copy_file
133*bcb5dc79SHONG Yifan    if is_executable:
134*bcb5dc79SHONG Yifan        copy_file_impl = _copy_xfile
135*bcb5dc79SHONG Yifan
136*bcb5dc79SHONG Yifan    copy_file_impl(
137*bcb5dc79SHONG Yifan        name = name,
138*bcb5dc79SHONG Yifan        src = src,
139*bcb5dc79SHONG Yifan        out = out,
140*bcb5dc79SHONG Yifan        is_windows = select({
141*bcb5dc79SHONG Yifan            "@bazel_tools//src/conditions:host_windows": True,
142*bcb5dc79SHONG Yifan            "//conditions:default": False,
143*bcb5dc79SHONG Yifan        }),
144*bcb5dc79SHONG Yifan        is_executable = is_executable,
145*bcb5dc79SHONG Yifan        allow_symlink = allow_symlink,
146*bcb5dc79SHONG Yifan        **kwargs
147*bcb5dc79SHONG Yifan    )
148