-
Notifications
You must be signed in to change notification settings - Fork 148
/
Copy pathdefs.bzl
329 lines (284 loc) · 10.5 KB
/
defs.bzl
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
"""Utility macros for buildpacks."""
load("@rules_pkg//pkg:mappings.bzl", "pkg_mklink")
load("@rules_pkg//pkg:tar.bzl", "pkg_tar")
def buildpack(name, executables, prefix, version, api = "0.8", srcs = None, extension = "tgz", strip_prefix = ".", visibility = None):
"""Macro to create a single buildpack as a tgz or tar archive.
The result is a tar or tgz archive with a buildpack descriptor
(`buildpack.toml`) and interface scripts (bin/detect, bin/build).
As this is a macro, the actual target name for the buildpack is `name.extension`.
The builder.toml spec allows either tar or tgz archives.
Args:
name: the base name of the tar archive
srcs: list of other files to include
prefix: the language name or group used as a namespace in the buildpack ID
version: the version of the buildpack
api: the buildpacks API version
executables: list of labels of buildpack binaries
strip_prefix: by default preserves the paths of srcs
extension: tgz by default
visibility: the visibility
"""
if len(executables) != 1:
fail("You must provide exactly one buildpack executable")
pkg_mklink(
name = "_link_build" + name,
target = "main",
link_name = "bin/build",
)
pkg_mklink(
name = "_link_detect" + name,
target = "main",
link_name = "bin/detect",
)
_buildpack_descriptor(
name = name + ".descriptor",
api = api,
version = version,
prefix = prefix,
bp_name = name,
output = "buildpack.toml",
)
if not srcs:
srcs = []
pkg_tar(
name = name,
extension = extension,
srcs = [
name + ".descriptor",
"_link_build" + name,
"_link_detect" + name,
] + srcs,
files = {
executables[0]: "/bin/main",
},
strip_prefix = strip_prefix,
visibility = visibility,
)
def _buildpack_descriptor_impl(ctx):
ctx.actions.expand_template(
output = ctx.outputs.output,
substitutions = {
"${API}": ctx.attr.api,
"${VERSION}": ctx.attr.version,
"${ID}": "google.{prefix}.{name}".format(
prefix = ctx.attr.prefix,
name = ctx.attr.bp_name.replace("_", "-"),
),
"${NAME}": "{prefix} - {name}".format(
prefix = _pretty_prefix(ctx.attr.prefix),
name = ctx.attr.bp_name.replace("_", " ").title(),
),
},
template = ctx.file._template,
)
_buildpack_descriptor = rule(
implementation = _buildpack_descriptor_impl,
attrs = {
"api": attr.string(mandatory = True),
"version": attr.string(mandatory = True),
"bp_name": attr.string(mandatory = True),
"prefix": attr.string(mandatory = True),
"output": attr.output(mandatory = True),
"_template": attr.label(
default = ":buildpack.toml.template",
allow_single_file = True,
),
},
)
def _pretty_prefix(prefix):
"""Helper function to convert a buildpack prefix into a human readable name.
Args:
prefix: the namespace used in the buildpack id (eg dotnet, nodejs).
"""
if prefix == "dotnet":
return ".NET"
if prefix == "php":
return "PHP"
if prefix == "nodejs":
return "Node.js"
if prefix == "cpp":
return "C++"
return prefix.title()
def builder(
name,
image,
descriptor = "builder.toml",
buildpacks = None,
groups = None,
visibility = None,
builder_template = None,
stack = None):
"""Macro to create a set of targets for a builder with specified buildpacks.
`name` and `name.tar`:
Creates tar archive with a builder descriptor (`builder.toml`) and its
associated buildpacks. The buildpacks should either have unique names
or be assigned to different groups. The grouped buildpacks are placed
in directories named by the key. Both `buildpacks` and `groups` may
be used simultaneously.
`name.image` and `name.sha`:
Creates a builder image based on the source from `name.tar` using pack
and outputs the image SHA into the `name.sha` file. The builder will
be named `image`.
Args:
name: the base name of the tar archive
image: the name of the builder image
descriptor: path to the `builder.toml`
buildpacks: list of labels to buildpacks (tar or tgz archives)
groups: dict(name -> list of labels to buildpacks);
the buildpacks are grouped under a single-level directory named <key>
visibility: the visibility
builder_template: if builder.toml needs to be generated for input stack
stack: Either of google.gae.22 or google.gae.18 representing ubuntu-22 or ubuntu-18 stacks
"""
srcs = []
# Determine the builder descriptor source.
# If a builder template and stack are provided, generate a custom descriptor.
# Otherwise, use the default descriptor.
srcs = []
if builder_template and stack:
srcs.append(_generate_builder_descriptor(name, descriptor, builder_template, stack))
else:
srcs.append(descriptor)
srcs += buildpacks if buildpacks else []
deps = _package_buildpack_groups(name, groups) if groups else []
# `name` and `name.tar` rules.
pkg_tar(
name = name,
extension = "tar",
srcs = srcs,
deps = deps,
visibility = visibility,
)
# `name.image` and `name.sha` rules.
native.genrule(
name = name + ".image",
srcs = [name + ".tar"],
outs = [name + ".sha"],
local = 1,
tools = [
"//tools/checktools:main",
"//tools:create_builder",
],
cmd = """$(execpath {check_script}) && $(execpath {create_script}) {image} $(execpath {tar}) "{descriptor}" $@""".format(
image = image,
tar = name + ".tar",
descriptor = descriptor,
check_script = "//tools/checktools:main",
create_script = "//tools:create_builder",
),
)
def _generate_builder_descriptor(name, descriptor, builder_template, stack):
"""Generates a builder descriptor from a template for a specific stack."""
gae_stack = "google-gae-22" if stack == "google.gae.22" else "google-gae-18"
image_prefix = "gcr.io/gae-runtimes/buildpacks/stacks/{}/".format(gae_stack)
build_image = image_prefix + "build"
run_image = image_prefix + "run"
_builder_descriptor(
name = name + ".descriptor",
stack_id = stack,
stack_build_image = build_image,
stack_run_image = run_image,
template = builder_template,
output = name + "/" + descriptor,
)
return name + ".descriptor"
def _package_buildpack_groups(name, groups):
"""Packages buildpacks into groups."""
deps = []
for (k, v) in groups.items():
pkg_tar(name = name + "_" + k, srcs = v, package_dir = k)
deps.append(name + "_" + k)
return deps
def _builder_descriptor_impl(ctx):
ctx.actions.expand_template(
output = ctx.outputs.output,
substitutions = {
"${STACK_ID}": ctx.attr.stack_id,
"${STACK_BUILD_IMAGE}": ctx.attr.stack_build_image,
"${STACK_RUN_IMAGE}": ctx.attr.stack_run_image,
},
template = ctx.file.template,
)
_builder_descriptor = rule(
implementation = _builder_descriptor_impl,
attrs = {
"stack_id": attr.string(mandatory = True),
"stack_build_image": attr.string(mandatory = True),
"stack_run_image": attr.string(mandatory = True),
"template": attr.label(
default = ":buildpack.toml.template",
allow_single_file = True,
),
"output": attr.output(mandatory = True),
},
)
def buildpackage(name, buildpacks, descriptor = "buildpack.toml", visibility = None):
"""Macro to create a set of targets for a meta-buildpack containing the specified buildpacks.
The result is a meta-builpack packages as a ".cnb" file created via the `pack buildpack package`
command.
`name` and `name.cnb`:
Creates meta-buildpack persisted to disk as a ".cnb" file.
`name.package`:
Creates a package TOML file describing the contents of the meta-buildpack.
`name.tar` and `name.tar.tar`:
Creates source tarball for the meta-buildpacks that includes the specified buildpacks, the
package TOML, and the buildpack TOML.
Args:
name: the name of the buildpackage to create.
descriptor: path to the `buildpack.toml`
buildpacks: list of labels to buildpacks (tar or tgz archives)
visibility: the visibility
"""
files = {
descriptor: descriptor,
"package.toml": "package.toml",
}
manifest = '''[buildpack]
uri = "./"'''
for b in buildpacks:
# add the buildpack to the tarball fileset at the namespaced filepath
files[b] = _buildpack_filepath(b)
# add the buildpack to manifest at the namespaced filepath
manifest += '''
[[dependencies]]
uri = "./{tarname}"'''.format(tarname = _buildpack_filepath(b))
native.genrule(
name = name + ".package",
outs = ["package.toml"],
cmd = "echo '{manifest}' > $@".format(manifest = manifest),
)
pkg_tar(
name = name + ".tar",
extension = "tar",
files = files,
visibility = visibility,
)
# `name.image` and `name.sha` rules.
native.genrule(
name = name,
srcs = [name + ".tar"],
outs = [name + ".cnb"],
local = 1,
tools = [
"//tools/checktools:main",
"//tools:create_buildpackage",
],
cmd = """$(execpath {check_script}) && $(execpath {create_script}) $(execpath {tar}) $@""".format(
tar = name + ".tar",
check_script = "//tools/checktools:main",
create_script = "//tools:create_buildpackage",
),
)
def _buildpack_filepath(symbol):
"""Helper function to convert a symbol pointing to a buildpack into a filepath.
This prevents collisions by re-using the directory structure inside of the /cmd directory.
Args:
symbol: a build symbol of a buildpack to get a relative filepath for.
"""
paths = symbol.split("/cmd/")
if len(paths) != 2:
fail("Buildpack symbol was not in cmd/: " + symbol)
parts = paths[1].split(":")
if len(parts) != 2:
fail("Buildpack symbol was invalid: " + symbol)
return parts[0] + ".tgz"