Skip to content

Commit 84ffedd

Browse files
committed
Temp commit - Adding pkg_rules support
1 parent 2e40dfb commit 84ffedd

5 files changed

Lines changed: 228 additions & 54 deletions

File tree

MODULE.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,4 @@ bazel_dep(name = "tar.bzl", version = "0.7.0")
4545
bazel_dep(name = "score_tooling", version = "1.1.2")
4646
bazel_dep(name = "aspect_rules_lint", version = "2.3.0")
4747
bazel_dep(name = "buildifier_prebuilt", version = "8.5.1")
48+
bazel_dep(name = "rules_pkg", version = "1.2.0")

MODULE.bazel.lock

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rules/qnx/common/pkg.bzl

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
"""
2+
Supports QNX FS image generation from rules_pkg providers. Filters rules_pkg
3+
targets from srcs and generates QNX build file entries from their contents.
4+
"""
5+
6+
load("@bazel_skylib//lib:paths.bzl", "paths")
7+
load("@rules_pkg//pkg:providers.bzl", "PackageDirsInfo", "PackageFilegroupInfo", "PackageFilesInfo", "PackageSymlinkInfo")
8+
9+
_DEFAULT_FILE_MODE = "0644"
10+
_DEFAULT_DIR_MODE = "0755"
11+
_DEFAULT_LINK_MODE = "0777"
12+
_DEFAULT_UID = 0
13+
_DEFAULT_GID = 0
14+
_FIXED_MTIME = "2021-03-22-20:20:00"
15+
16+
def _get_pkg_attr(attributes, field, default):
17+
"""Get a single field from a pkg_attributes dict, defaulting if absent or None."""
18+
if attributes == None:
19+
return default
20+
value = attributes.get(field)
21+
if value == None:
22+
return default
23+
return value
24+
25+
def qnx_build_inputs_from_pkg(ctx, pkg_srcs, per_file_attrs = None):
26+
"""Generate QNX build file and collect contents from rules_pkg sources.
27+
28+
Args:
29+
ctx: Rule context.
30+
pkg_srcs: List of targets providing rules_pkg providers.
31+
per_file_attrs: Optional list of extra attributes for file entries
32+
(e.g. ["-optional"]).
33+
Returns:
34+
fs_contents: List of Files to include in the image.
35+
build_file: Generated QNX build file.
36+
"""
37+
content = "[mtime={}]\n".format(_FIXED_MTIME)
38+
fs_contents = []
39+
extra_attrs_str = ""
40+
if per_file_attrs:
41+
extra_attrs_str = " ".join(per_file_attrs) + " "
42+
43+
for src in pkg_srcs:
44+
# Normalize to lists of (provider, label) tuples regardless of source type
45+
if PackageFilegroupInfo in src:
46+
pfgi = src[PackageFilegroupInfo]
47+
files_list = pfgi.pkg_files
48+
dirs_list = pfgi.pkg_dirs
49+
symlinks_list = pfgi.pkg_symlinks
50+
elif (
51+
PackageFilesInfo in src or
52+
PackageDirsInfo in src or
53+
PackageSymlinkInfo in src
54+
):
55+
# src.label is included in the manually-constructed tuples to match the (provider, label) structure from PackageFilegroupInfo.
56+
files_list = [(src[PackageFilesInfo], src.label)] if PackageFilesInfo in src else []
57+
dirs_list = [(src[PackageDirsInfo], src.label)] if PackageDirsInfo in src else []
58+
symlinks_list = [(src[PackageSymlinkInfo], src.label)] if PackageSymlinkInfo in src else []
59+
else:
60+
fail("Target {} does not provide any rules_pkg provider".format(src.label))
61+
62+
# Process directories
63+
for pdi, _label in dirs_list:
64+
mode = _get_pkg_attr(pdi.attributes, "mode", _DEFAULT_DIR_MODE)
65+
uid = _get_pkg_attr(pdi.attributes, "uid", _DEFAULT_UID)
66+
gid = _get_pkg_attr(pdi.attributes, "gid", _DEFAULT_GID)
67+
for dir_path in pdi.dirs:
68+
dir_path = paths.normalize(dir_path)
69+
content += "[type=dir uid={} gid={} perms={}] /{}\n".format(
70+
uid,
71+
gid,
72+
mode,
73+
dir_path,
74+
)
75+
76+
# Process files
77+
for pfi, _label in files_list:
78+
mode = _get_pkg_attr(pfi.attributes, "mode", _DEFAULT_FILE_MODE)
79+
uid = _get_pkg_attr(pfi.attributes, "uid", _DEFAULT_UID)
80+
gid = _get_pkg_attr(pfi.attributes, "gid", _DEFAULT_GID)
81+
for dest, src_file in sorted(pfi.dest_src_map.items()):
82+
content += "[{}uid={} gid={} perms={}] /{}={}\n".format(
83+
extra_attrs_str,
84+
uid,
85+
gid,
86+
mode,
87+
dest,
88+
src_file.path,
89+
)
90+
fs_contents.append(src_file)
91+
92+
# Process symlinks
93+
for psi, _label in symlinks_list:
94+
mode = _get_pkg_attr(psi.attributes, "mode", _DEFAULT_LINK_MODE)
95+
uid = _get_pkg_attr(psi.attributes, "uid", _DEFAULT_UID)
96+
gid = _get_pkg_attr(psi.attributes, "gid", _DEFAULT_GID)
97+
dest = paths.normalize(psi.destination)
98+
content += "[type=link uid={} gid={} perms={}] /{}={}\n".format(
99+
uid,
100+
gid,
101+
mode,
102+
dest,
103+
psi.target,
104+
)
105+
106+
build_file = ctx.actions.declare_file("{}_pkg_content.build".format(ctx.attr.name))
107+
ctx.actions.write(build_file, content)
108+
109+
return fs_contents, build_file

rules/qnx/common/qnx_image.bzl

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
load(":common/pkg.bzl", "qnx_build_inputs_from_pkg")
2+
3+
def _gen_main_build_file(
4+
ctx,
5+
extra_build_files,
6+
global_attrs = None):
7+
"""
8+
Generates the main build file used to create a qnx6fs image.
9+
10+
Args:
11+
ctx: Context.
12+
extra_build_files: extra build files to be appended
13+
global_attrs:
14+
Global options, apply to both the image and extra build files.
15+
Accepts a list of a mix of strings or dicts, to represent static
16+
options (e.g. -optional) or mapped values (e.g. block_size=4096)
17+
18+
Returns:
19+
main_{}.build
20+
"""
21+
file_name = "main_{}.build".format(ctx.attr.name)
22+
main_build_file = ctx.actions.declare_file(file_name)
23+
24+
content = ""
25+
if global_attrs:
26+
for attr in global_attrs:
27+
if type(attr) == "string":
28+
content += "[{}]\n".format(attr)
29+
elif type(attr) == "dict":
30+
for key, value in attr.items():
31+
content += "[{}={}]\n".format(key, value)
32+
else:
33+
fail("Unsupported attribute type '{}', must be string or dict".format(type(attr)))
34+
35+
for build_file in extra_build_files:
36+
content += "[+include] {}\n".format(build_file.path)
37+
38+
ctx.actions.write(main_build_file, content)
39+
40+
return main_build_file
41+
42+
def gen_image_definition(
43+
ctx,
44+
srcs,
45+
global_attrs = None,
46+
extra_build_file = None,
47+
extra_build_files = [],
48+
repo_mapping = {},
49+
repo_mapping_srcs = None):
50+
"""
51+
Process inputs for QNX image definition, return contents and builds files.
52+
53+
Args:
54+
ctx: Rule context.
55+
srcs: Input srcs for FS, can be mix of DUI, rules_pkg, and regular.
56+
global_attrs: Attributes set globally on main build file.
57+
extra_build_file: Additional build file to be included.
58+
extra_build_files: Additional build files to be included after the
59+
extra_build_file.
60+
repo_mapping: Map of Bazel location expressions to hardcoded variable
61+
names in extra build file.
62+
repo_mapping_srcs: Bazel targets referenced in the location expressions
63+
of repo_mapping.
64+
Returns:
65+
main_build_file: Main entrypoint QNX build file.
66+
build_files: QNX build files inluded in the main.
67+
fs_contents: Files to be included in the QNX image.
68+
expanded_repo_map: Expanded Bazel locations with paths of files to be
69+
included.
70+
"""
71+
72+
build_files = []
73+
fs_contents = []
74+
75+
# Add extra build files
76+
build_files.append(extra_build_file)
77+
build_files.extend(extra_build_files)
78+
79+
# # Rules_pkg contents
80+
pkg_contents, pkg_build_file = qnx_build_inputs_from_pkg(
81+
ctx,
82+
srcs,
83+
per_file_attrs = None,
84+
)
85+
86+
build_files.append(pkg_build_file)
87+
fs_contents.extend(pkg_contents)
88+
89+
# Generate main build file which imports others
90+
main_build_file = _gen_main_build_file(
91+
ctx,
92+
build_files,
93+
global_attrs,
94+
)
95+
96+
return main_build_file, build_files, fs_contents

rules/qnx/ifs.bzl

Lines changed: 19 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -20,31 +20,10 @@ other build files or perform other operations like packaging any file into the
2020
created IFS.
2121
"""
2222

23-
QNX_FS_TOOLCHAIN = "@score_rules_imagefs//toolchains/qnx:ifs_toolchain_type"
24-
TAR_TOOLCHAIN = "@tar.bzl//tar/toolchain:type"
25-
26-
# todo: Consider to contribute this to "@tar.bzl"
27-
def _untar(ctx, tarball, output_folder):
28-
tarball_as_list = tarball.files.to_list()
29-
if len(tarball_as_list) > 1:
30-
fail("Provided more then one tar-ball for one key.")
31-
tarball = tarball_as_list[0]
32-
bsdtar = ctx.toolchains[TAR_TOOLCHAIN]
23+
load("@rules_pkg//pkg:providers.bzl", "PackageDirsInfo", "PackageFilegroupInfo", "PackageFilesInfo", "PackageSymlinkInfo")
24+
load(":common/qnx_image.bzl", "gen_image_definition")
3325

34-
args = ctx.actions.args()
35-
args.add("-x")
36-
args.add("-C").add(output_folder.path)
37-
args.add("-f").add(tarball.path)
38-
39-
ctx.actions.run(
40-
outputs = [output_folder],
41-
inputs = [tarball],
42-
arguments = [args],
43-
executable = bsdtar.tarinfo.binary,
44-
toolchain = TAR_TOOLCHAIN,
45-
mnemonic = "Untar",
46-
progress_message = "untar %{input}",
47-
)
26+
QNX_FS_TOOLCHAIN = "@score_rules_imagefs//toolchains/qnx:ifs_toolchain_type"
4827

4928
def _qnx_ifs_impl(ctx):
5029
""" Implementation function of qnx_ifs rule.
@@ -61,13 +40,20 @@ def _qnx_ifs_impl(ctx):
6140
fail("qnx_ifs.out must be a filename without path components, got: {}".format(out_name))
6241

6342
out_ifs = ctx.actions.declare_file(out_name)
64-
6543
ifs_tool_info = ctx.toolchains[QNX_FS_TOOLCHAIN].ifs_toolchain_info
6644

45+
main_build_file_2, build_files, fs_contents = gen_image_definition(
46+
ctx,
47+
srcs = ctx.attr.all_files,
48+
extra_build_file = ctx.file.build_file,
49+
extra_build_files = ctx.files.extra_build_files,
50+
)
51+
6752
main_build_file = ctx.file.build_file
6853

69-
inputs.append(main_build_file)
70-
inputs.extend(ctx.files.srcs)
54+
inputs.append(main_build_file_2)
55+
inputs.extend(build_files)
56+
inputs.extend(fs_contents)
7157

7258
args = ctx.actions.args()
7359

@@ -87,19 +73,6 @@ def _qnx_ifs_impl(ctx):
8773
env_to_append = {}
8874
env_to_append = env_to_append | ifs_tool_info.env
8975

90-
for key, item in ctx.attr.ext_repo_mapping.items():
91-
env_to_append.update({key: ctx.expand_location(item)})
92-
93-
env_to_append.update({"MAIN_BUILD_FILE_DIR": main_build_file.dirname})
94-
95-
# Unpack tarballs and add locations as env variables
96-
for key, tarball in ctx.attr.tars.items():
97-
unpacked_tarball = ctx.actions.declare_directory("{}_{}".format(ctx.attr.name, key))
98-
_untar(ctx, tarball, unpacked_tarball)
99-
100-
env_to_append.update({key: unpacked_tarball.path})
101-
inputs.append(unpacked_tarball)
102-
10376
print(env_to_append)
10477

10578
ctx.actions.run(
@@ -119,6 +92,9 @@ qnx_ifs = rule(
11992
implementation = _qnx_ifs_impl,
12093
toolchains = [QNX_FS_TOOLCHAIN, TAR_TOOLCHAIN],
12194
attrs = {
95+
"all_files": attr.label_list(
96+
mandatory = True,
97+
),
12298
"build_file": attr.label(
12399
allow_single_file = True,
124100
doc = "Single label that points to the main build file (entrypoint)",
@@ -128,20 +104,10 @@ qnx_ifs = rule(
128104
default = "ifs",
129105
doc = "Extension for the generated IFS image. Manipulating this extensions is a workaround for IPNext startup code limitation, when interpreting ifs images. This attribute will either disappear or will be replaced by toolchain configuration in order to keep output files consistent.",
130106
),
131-
"srcs": attr.label_list(
107+
"extra_build_files": attr.label_list(
132108
allow_files = True,
133-
doc = "List of labels that are used by the `build_file`",
134-
allow_empty = True,
135-
),
136-
"ext_repo_mapping": attr.string_dict(
137-
allow_empty = True,
138-
default = {},
139-
doc = "We are using dict to map env. variables with of external repository",
140-
),
141-
"tars": attr.string_keyed_label_dict(
142-
allow_files = [".tar"],
143-
doc = "A map of tar-balls that can be added to the IFS image. The key will be available als variable in the `IFS Build File`, to determine where it should be packaged. e.g. `FOO: '//:my_tar'` can be packaged as /SOME_DIR=${FOO}.",
144-
allow_empty = True,
109+
default = [],
110+
doc = "Additional build files to be included after the main build_file.",
145111
),
146112
"out": attr.string(
147113
default = "",

0 commit comments

Comments
 (0)