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