Skip to content

Commit 2707184

Browse files
committed
Bazel: add codeql specific packaging library
This encapsulate arch specific logic, local installation and separation of zip files into generic and arch-specific parts as required by the internal build.
1 parent 6233da3 commit 2707184

File tree

8 files changed

+358
-131
lines changed

8 files changed

+358
-131
lines changed

misc/bazel/internal/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
exports_files(["install.py"])

misc/bazel/internal/install.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import argparse
2+
import pathlib
3+
import shutil
4+
import subprocess
5+
from python.runfiles import runfiles
6+
7+
runfiles = runfiles.Create()
8+
if not runfiles:
9+
raise Exception("Installer should be run with `bazel run`")
10+
11+
parser = argparse.ArgumentParser()
12+
parser.add_argument("--destdir", type=pathlib.Path, required=True)
13+
parser.add_argument("--script", required=True)
14+
parser.add_argument("--build-file", required=True)
15+
opts = parser.parse_args()
16+
17+
script = runfiles.Rlocation(opts.script)
18+
build_file = runfiles.Rlocation(opts.build_file)
19+
destdir = pathlib.Path(build_file).parent / opts.destdir
20+
21+
if destdir.exists():
22+
shutil.rmtree(destdir)
23+
24+
destdir.mkdir(parents=True)
25+
subprocess.run([script, "--destdir", destdir], check=True)

misc/bazel/pkg.bzl

Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
"""
2+
Wrappers and helpers around `rules_pkg` to build codeql packs.
3+
"""
4+
5+
load("@rules_pkg//pkg:install.bzl", "pkg_install")
6+
load("@rules_pkg//pkg:mappings.bzl", "pkg_attributes", "pkg_filegroup", "pkg_files", _strip_prefix = "strip_prefix")
7+
load("@rules_pkg//pkg:pkg.bzl", "pkg_zip")
8+
load("@rules_python//python:defs.bzl", "py_binary")
9+
load("//:defs.bzl", "codeql_platform")
10+
11+
def _make_internal(name):
12+
def internal(suffix):
13+
return "%s-%s" % (name, suffix)
14+
15+
return internal
16+
17+
def _get_subrule(label, suffix):
18+
if ":" in label or "/" not in label:
19+
return "%s-%s" % (label, suffix)
20+
path, _, pkg = label.rpartition("/")
21+
return "%s/%s:%s-%s" % (path, pkg, pkg, suffix)
22+
23+
def codeql_pkg_files(
24+
*,
25+
name,
26+
arch_specific = False,
27+
srcs = None,
28+
exes = None,
29+
renames = None,
30+
prefix = None,
31+
visibility = None,
32+
**kwargs):
33+
"""
34+
Wrapper around `pkg_files`. Added functionality:
35+
* `exes` get their file attributes set to be executable. This is important only for POSIX files, there's no need
36+
to mark windows executables as such
37+
* `arch_specific` auto-adds the codeql platform specific directory (linux64, osx64 or windows64), and will be
38+
consumed by a downstream `codeql_pack` to create the arch specific zip.
39+
This should be consumed by `codeql_pkg_filegroup` and `codeql_pack` only.
40+
"""
41+
internal = _make_internal(name)
42+
main_rule = internal("generic")
43+
empty_rule = internal("arch")
44+
if arch_specific:
45+
main_rule, empty_rule = empty_rule, main_rule
46+
prefix = (prefix + "/" if prefix else "") + codeql_platform
47+
pkg_files(
48+
name = empty_rule,
49+
srcs = [],
50+
visibility = visibility,
51+
)
52+
if not srcs and not exes:
53+
fail("either srcs or exes should be specified for %s" % name)
54+
if srcs and exes:
55+
if renames:
56+
src_renames = {k: v for k, v in renames.items() if k in srcs}
57+
exe_renames = {k: v for k, v in renames.items() if k in exes}
58+
else:
59+
src_renames = None
60+
exe_renames = None
61+
pkg_files(
62+
name = internal("srcs"),
63+
srcs = srcs,
64+
renames = src_renames,
65+
prefix = prefix,
66+
visibility = ["//visibility:private"],
67+
**kwargs
68+
)
69+
pkg_files(
70+
name = internal("exes"),
71+
srcs = exes,
72+
renames = exe_renames,
73+
prefix = prefix,
74+
visibility = ["//visibility:private"],
75+
attributes = pkg_attributes(mode = "0755"),
76+
**kwargs
77+
)
78+
pkg_filegroup(
79+
name = main_rule,
80+
srcs = [internal("srcs"), internal("exes")],
81+
visibility = visibility,
82+
)
83+
else:
84+
pkg_files(
85+
name = main_rule,
86+
srcs = srcs or exes,
87+
attributes = pkg_attributes(mode = "0755") if exes else None,
88+
prefix = prefix,
89+
visibility = visibility,
90+
**kwargs
91+
)
92+
native.filegroup(
93+
name = name,
94+
srcs = [main_rule],
95+
visibility = visibility,
96+
)
97+
98+
def codeql_pkg_wrap(*, name, srcs, arch_specific = False, prefix = None, visibility = None, **kwargs):
99+
"""
100+
Wrap a native `rules_pkg` rule, providing the `arch_specific` functionality and making it consumable by
101+
`codeql_pkg_filegroup` and `codeql_pack`.
102+
"""
103+
internal = _make_internal(name)
104+
main_rule = internal("generic")
105+
empty_rule = internal("arch")
106+
if arch_specific:
107+
main_rule, empty_rule = empty_rule, main_rule
108+
prefix = (prefix + "/" if prefix else "") + codeql_platform
109+
pkg_filegroup(
110+
name = main_rule,
111+
srcs = srcs,
112+
prefix = prefix,
113+
visibility = visibility,
114+
**kwargs
115+
)
116+
pkg_files(
117+
name = empty_rule,
118+
srcs = [],
119+
visibility = visibility,
120+
)
121+
native.filegroup(
122+
name = name,
123+
srcs = [main_rule],
124+
visibility = visibility,
125+
)
126+
127+
def codeql_pkg_filegroup(
128+
*,
129+
name,
130+
srcs,
131+
srcs_select = None,
132+
visibility = None,
133+
**kwargs):
134+
"""
135+
Combine `codeql_pkg_files` and other `codeql_pkg_filegroup` rules, similar to what `pkg_filegroup` does.
136+
`srcs` is not selectable, but `srcs_select` accepts the same dictionary that a select would accept.
137+
"""
138+
internal = _make_internal(name)
139+
140+
def transform(srcs, suffix):
141+
return [_get_subrule(src, suffix) for src in srcs]
142+
143+
pkg_filegroup(
144+
name = internal("generic"),
145+
srcs = transform(srcs, "generic") + (select(
146+
{k: transform(v, "generic") for k, v in srcs_select.items()},
147+
) if srcs_select else []),
148+
visibility = visibility,
149+
**kwargs
150+
)
151+
pkg_filegroup(
152+
name = internal("arch"),
153+
srcs = transform(srcs, "arch") + (select(
154+
{k: transform(v, "arch") for k, v in srcs_select.items()},
155+
) if srcs_select else []),
156+
visibility = visibility,
157+
**kwargs
158+
)
159+
native.filegroup(
160+
name = name,
161+
srcs = [internal("generic"), internal("arch")],
162+
visibility = visibility,
163+
)
164+
165+
def codeql_pack(*, name, srcs, zip_prefix = None, zip_filename = "extractor", visibility = visibility, install_dest = "extractor-pack", **kwargs):
166+
"""
167+
Define a codeql pack. This accepts the same arguments as `codeql_pkg_filegroup`, and additionally:
168+
* defines a `<name>-generic-zip` target creating a `<zip_filename>-generic.zip` archive with the generic bits,
169+
prefixed with `zip_prefix` (`name` by default)
170+
* defines a `<name>-arch-zip` target creating a `<zip_filename>-<codeql_platform>.zip` archive with the
171+
arch-specific bits, prefixed with `zip_prefix` (`name` by default)
172+
* defines a runnable `<name>-installer` target that will install the pack in `install_dest`, relative to where the
173+
rule is used. The install destination can be overridden appending `-- --destdir=...` to the `bazel run`
174+
invocation. This installation does not use the `zip_prefix`.
175+
"""
176+
internal = _make_internal(name)
177+
zip_prefix = zip_prefix or name
178+
zip_filename = zip_filename or name
179+
codeql_pkg_filegroup(
180+
name = name,
181+
srcs = srcs,
182+
visibility = visibility,
183+
**kwargs
184+
)
185+
codeql_pkg_filegroup(
186+
name = internal("zip-contents"),
187+
srcs = [name],
188+
prefix = zip_prefix,
189+
visibility = ["//visibility:private"],
190+
)
191+
pkg_zip(
192+
name = internal("generic-zip"),
193+
srcs = [internal("zip-contents-generic")],
194+
package_file_name = zip_filename + "-generic.zip",
195+
visibility = visibility,
196+
)
197+
pkg_zip(
198+
name = internal("arch-zip"),
199+
srcs = [internal("zip-contents-arch")],
200+
package_file_name = zip_filename + "-" + codeql_platform + ".zip",
201+
visibility = visibility,
202+
)
203+
pkg_install(
204+
name = internal("script"),
205+
srcs = [internal("generic"), internal("arch")],
206+
visibility = ["//visibility:private"],
207+
)
208+
native.filegroup(
209+
# used to locate current source directory
210+
name = internal("build-file"),
211+
srcs = ["BUILD.bazel"],
212+
visibility = ["//visibility:private"],
213+
)
214+
py_binary(
215+
name = internal("installer"),
216+
srcs = ["//misc/bazel/internal:install.py"],
217+
main = "//misc/bazel/internal:install.py",
218+
data = [internal("build-file"), internal("script")],
219+
deps = ["@rules_python//python/runfiles"],
220+
args = [
221+
"--build-file=$(rlocationpath %s)" % internal("build-file"),
222+
"--script=$(rlocationpath %s)" % internal("script"),
223+
"--destdir",
224+
install_dest,
225+
],
226+
visibility = visibility,
227+
)
228+
229+
strip_prefix = _strip_prefix
230+
231+
def _runfiles_group_impl(ctx):
232+
files = []
233+
for src in ctx.attr.srcs:
234+
rf = src[DefaultInfo].default_runfiles
235+
if rf != None:
236+
files.append(rf.files)
237+
return [
238+
DefaultInfo(
239+
files = depset(transitive = files),
240+
),
241+
]
242+
243+
_runfiles_group = rule(
244+
implementation = _runfiles_group_impl,
245+
attrs = {
246+
"srcs": attr.label_list(),
247+
},
248+
)
249+
250+
def codeql_pkg_runfiles(*, name, exes, **kwargs):
251+
"""
252+
Create a `codeql_pkg_files` with all runfiles from files in `exes`, flattened together.
253+
"""
254+
internal = _make_internal(name)
255+
_runfiles_group(
256+
name = internal("runfiles"),
257+
srcs = exes,
258+
visibility = ["//visibility:private"],
259+
)
260+
codeql_pkg_files(
261+
name = name,
262+
exes = [internal("runfiles")],
263+
**kwargs
264+
)

misc/bazel/pkg_runfiles.bzl

Lines changed: 0 additions & 33 deletions
This file was deleted.

0 commit comments

Comments
 (0)