1# Protocol Buffers - Google's data interchange format 2# Copyright 2023 Google Inc. All rights reserved. 3# 4# Use of this source code is governed by a BSD-style 5# license that can be found in the LICENSE file or at 6# https://developers.google.com/open-source/licenses/bsd 7""" 8Provide a rule for generating the intermediate feature set defaults used for feature resolution. 9 10See go/life-of-a-featureset for more information. 11""" 12 13load("//bazel/common:proto_info.bzl", "ProtoInfo") 14 15def _compile_edition_defaults_impl(ctx): 16 out_file = ctx.actions.declare_file(ctx.outputs.output.basename) 17 sources = [] 18 paths = [] 19 for src in ctx.attr.srcs: 20 sources.extend(src[ProtoInfo].transitive_sources.to_list()) 21 paths.extend(src[ProtoInfo].transitive_proto_path.to_list()) 22 23 args = ctx.actions.args() 24 args.add("--edition_defaults_out", out_file) 25 26 args.add("--edition_defaults_minimum", ctx.attr.minimum_edition) 27 args.add("--edition_defaults_maximum", ctx.attr.maximum_edition) 28 for p in paths: 29 args.add("--proto_path", p) 30 for source in sources: 31 args.add(source) 32 ctx.actions.run( 33 outputs = [out_file], 34 inputs = sources, 35 executable = ctx.executable.protoc or ctx.executable._protoc_minimal, 36 arguments = [args], 37 progress_message = "Generating edition defaults", 38 ) 39 40compile_edition_defaults = rule( 41 attrs = { 42 "srcs": attr.label_list( 43 mandatory = True, 44 allow_rules = ["proto_library"], 45 providers = [ProtoInfo], 46 ), 47 "minimum_edition": attr.string(mandatory = True), 48 "maximum_edition": attr.string(mandatory = True), 49 "protoc": attr.label( 50 mandatory = False, 51 executable = True, 52 cfg = "exec", 53 ), 54 "_protoc_minimal": attr.label( 55 default = "//src/google/protobuf/compiler:protoc_minimal", 56 executable = True, 57 cfg = "exec", 58 ), 59 }, 60 implementation = _compile_edition_defaults_impl, 61 outputs = { 62 "output": "%{name}.binpb", 63 }, 64) 65 66def _embed_edition_defaults_impl(ctx): 67 if ctx.attr.encoding == "base64": 68 args = "--encoding=base64" 69 elif ctx.attr.encoding == "octal": 70 args = "--encoding=octal" 71 else: 72 fail("Unknown encoding %s" % ctx.attr.encoding) 73 ctx.actions.run_shell( 74 outputs = [ctx.outputs.output], 75 inputs = [ctx.file.defaults, ctx.file.template], 76 tools = [ctx.executable._escape], 77 command = """ 78 DEFAULTS_RAW=$({escape} {args} < {defaults}) 79 # Windows requires extra escaping. 80 DEFAULTS_ESCAPED=$(echo $DEFAULTS_RAW | sed 's/\\\\/\\\\\\\\/g' || 81 echo $DEFAULTS_RAW | sed 's/\\\\\\\\/\\\\\\\\\\\\\\\\/g') 82 cp -f {template} {output} 83 # MacOS requires a backup file. 84 sed -i.bak \"s|{placeholder}|$DEFAULTS_ESCAPED|g\" {output} 85 """.format( 86 escape = ctx.executable._escape.path, 87 args = args, 88 defaults = ctx.file.defaults.path, 89 template = ctx.file.template.path, 90 output = ctx.outputs.output.path, 91 placeholder = ctx.attr.placeholder, 92 ), 93 ) 94 95embed_edition_defaults = rule( 96 doc = "genrule to embed edition defaults binary data into a template file.", 97 attrs = { 98 "defaults": attr.label( 99 mandatory = True, 100 allow_single_file = True, 101 allow_rules = ["compile_edition_defaults"], 102 providers = [ProtoInfo], 103 doc = "The compile_edition_defaults rule to embed", 104 ), 105 "output": attr.output( 106 mandatory = True, 107 doc = "The name of the output file", 108 ), 109 "template": attr.label( 110 mandatory = True, 111 allow_single_file = True, 112 doc = "The template to use for generating the output file", 113 ), 114 "placeholder": attr.string( 115 mandatory = True, 116 doc = "The placeholder to replace with a serialized string in the template", 117 ), 118 "encoding": attr.string( 119 default = "octal", 120 values = ["octal", "base64"], 121 doc = "The encoding format to use for the binary data (octal or base64)", 122 ), 123 "_escape": attr.label( 124 default = "//editions:internal_defaults_escape", 125 executable = True, 126 cfg = "exec", 127 ), 128 }, 129 implementation = _embed_edition_defaults_impl, 130) 131