1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
"""Generics support via go_generics.
A Go template is similar to a go library, except that it has certain types that
can be replaced before usage. For example, one could define a templatized List
struct, whose elements are of type T, then instantiate that template for
T=segment, where "segment" is the concrete type.
"""
TemplateInfo = provider(
"Information about a go_generics template.",
fields = {
"unsafe": "whether the template requires unsafe code",
"types": "required types",
"opt_types": "optional types",
"consts": "required consts",
"opt_consts": "optional consts",
"deps": "package dependencies",
"template": "merged template source file",
},
)
def _go_template_impl(ctx):
srcs = ctx.files.srcs
template = ctx.actions.declare_file(ctx.label.name + "_template.go")
args = ["-o=%s" % template.path] + [f.path for f in srcs]
ctx.actions.run(
inputs = srcs,
outputs = [template],
mnemonic = "GoGenericsTemplate",
progress_message = "Building Go template %s" % ctx.label,
arguments = args,
executable = ctx.executable._tool,
)
return [TemplateInfo(
types = ctx.attr.types,
opt_types = ctx.attr.opt_types,
consts = ctx.attr.consts,
opt_consts = ctx.attr.opt_consts,
deps = ctx.attr.deps,
template = template,
)]
go_template = rule(
implementation = _go_template_impl,
attrs = {
"srcs": attr.label_list(doc = "the list of source files that comprise the template", mandatory = True, allow_files = True),
"deps": attr.label_list(doc = "the standard dependency list", allow_files = True, cfg = "target"),
"types": attr.string_list(doc = "the list of generic types in the template that are required to be specified"),
"opt_types": attr.string_list(doc = "the list of generic types in the template that can but aren't required to be specified"),
"consts": attr.string_list(doc = "the list of constants in the template that are required to be specified"),
"opt_consts": attr.string_list(doc = "the list of constants in the template that can but aren't required to be specified"),
"_tool": attr.label(executable = True, cfg = "host", default = Label("//tools/go_generics/go_merge")),
},
)
def _go_template_instance_impl(ctx):
info = ctx.attr.template[TemplateInfo]
output = ctx.outputs.out
# Check that all required types are defined.
for t in info.types:
if t not in ctx.attr.types:
fail("Missing value for type %s in %s" % (t, ctx.attr.template.label))
# Check that all defined types are expected by the template.
for t in ctx.attr.types:
if (t not in info.types) and (t not in info.opt_types):
fail("Type %s is not a parameter to %s" % (t, ctx.attr.template.label))
# Check that all required consts are defined.
for t in info.consts:
if t not in ctx.attr.consts:
fail("Missing value for constant %s in %s" % (t, ctx.attr.template.label))
# Check that all defined consts are expected by the template.
for t in ctx.attr.consts:
if (t not in info.consts) and (t not in info.opt_consts):
fail("Const %s is not a parameter to %s" % (t, ctx.attr.template.label))
# Build the argument list.
args = ["-i=%s" % info.template.path, "-o=%s" % output.path]
if ctx.attr.package:
args.append("-p=%s" % ctx.attr.package)
if len(ctx.attr.prefix) > 0:
args.append("-prefix=%s" % ctx.attr.prefix)
if len(ctx.attr.suffix) > 0:
args.append("-suffix=%s" % ctx.attr.suffix)
args += [("-t=%s=%s" % (p[0], p[1])) for p in ctx.attr.types.items()]
args += [("-c=%s=%s" % (p[0], p[1])) for p in ctx.attr.consts.items()]
args += [("-import=%s=%s" % (p[0], p[1])) for p in ctx.attr.imports.items()]
if ctx.attr.anon:
args.append("-anon")
ctx.actions.run(
inputs = [info.template],
outputs = [output],
mnemonic = "GoGenericsInstance",
progress_message = "Building Go template instance %s" % ctx.label,
arguments = args,
executable = ctx.executable._tool,
)
return [DefaultInfo(
files = depset([output]),
)]
go_template_instance = rule(
implementation = _go_template_instance_impl,
attrs = {
"template": attr.label(doc = "the label of the template to be instantiated", mandatory = True),
"prefix": attr.string(doc = "a prefix to be added to globals in the template"),
"suffix": attr.string(doc = "a suffix to be added to globals in the template"),
"types": attr.string_dict(doc = "the map from generic type names to concrete ones"),
"consts": attr.string_dict(doc = "the map from constant names to their values"),
"imports": attr.string_dict(doc = "the map from imports used in types/consts to their import paths"),
"anon": attr.bool(doc = "whether anoymous fields should be processed", mandatory = False, default = False),
"package": attr.string(doc = "the package for the generated source file", mandatory = False),
"out": attr.output(doc = "output file", mandatory = True),
"_tool": attr.label(executable = True, cfg = "host", default = Label("//tools/go_generics")),
},
)
|