1# Copyright 2019 The Bazel Authors. All rights reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"""Implementation of write_file macro and underlying rules. 16 17These rules write a UTF-8 encoded text file, using Bazel's FileWriteAction. 18'_write_xfile' marks the resulting file executable, '_write_file' does not. 19""" 20 21def _common_impl(ctx, is_windows, is_executable): 22 if ctx.attr.newline == "auto": 23 newline = "\r\n" if is_windows else "\n" 24 elif ctx.attr.newline == "windows": 25 newline = "\r\n" 26 else: 27 newline = "\n" 28 29 # ctx.actions.write creates a FileWriteAction which uses UTF-8 encoding. 30 ctx.actions.write( 31 output = ctx.outputs.out, 32 content = newline.join(ctx.attr.content) if ctx.attr.content else "", 33 is_executable = is_executable, 34 ) 35 files = depset(direct = [ctx.outputs.out]) 36 runfiles = ctx.runfiles(files = [ctx.outputs.out]) 37 if is_executable: 38 return [DefaultInfo(files = files, runfiles = runfiles, executable = ctx.outputs.out)] 39 else: 40 # Do not include the copied file into the default runfiles of the 41 # target, but ensure that it is picked up by native rule's data 42 # attribute despite https://github.com/bazelbuild/bazel/issues/15043. 43 return [DefaultInfo(files = files, data_runfiles = runfiles)] 44 45def _impl(ctx): 46 return _common_impl(ctx, ctx.attr.is_windows, False) 47 48def _ximpl(ctx): 49 return _common_impl(ctx, ctx.attr.is_windows, True) 50 51_ATTRS = { 52 "out": attr.output(mandatory = True), 53 "content": attr.string_list(mandatory = False, allow_empty = True), 54 "newline": attr.string(values = ["unix", "windows", "auto"], default = "auto"), 55 "is_windows": attr.bool(mandatory = True), 56} 57 58_write_file = rule( 59 implementation = _impl, 60 provides = [DefaultInfo], 61 attrs = _ATTRS, 62) 63 64_write_xfile = rule( 65 implementation = _ximpl, 66 executable = True, 67 provides = [DefaultInfo], 68 attrs = _ATTRS, 69) 70 71def write_file( 72 name, 73 out, 74 content = [], 75 is_executable = False, 76 newline = "auto", 77 **kwargs): 78 """Creates a UTF-8 encoded text file. 79 80 Args: 81 name: Name of the rule. 82 out: Path of the output file, relative to this package. 83 content: A list of strings. Lines of text, the contents of the file. 84 Newlines are added automatically after every line except the last one. 85 is_executable: A boolean. Whether to make the output file executable. 86 When True, the rule's output can be executed using `bazel run` and can 87 be in the srcs of binary and test rules that require executable 88 sources. 89 newline: one of ["auto", "unix", "windows"]: line endings to use. "auto" 90 for platform-determined, "unix" for LF, and "windows" for CRLF. 91 **kwargs: further keyword arguments, e.g. `visibility` 92 """ 93 if is_executable: 94 _write_xfile( 95 name = name, 96 content = content, 97 out = out, 98 newline = newline or "auto", 99 is_windows = select({ 100 "@bazel_tools//src/conditions:host_windows": True, 101 "//conditions:default": False, 102 }), 103 **kwargs 104 ) 105 else: 106 _write_file( 107 name = name, 108 content = content, 109 out = out, 110 newline = newline or "auto", 111 is_windows = select({ 112 "@bazel_tools//src/conditions:host_windows": True, 113 "//conditions:default": False, 114 }), 115 **kwargs 116 ) 117