From acf8b6453abf5ba829a56951cc3939c8c61e2829 Mon Sep 17 00:00:00 2001 From: Javier Maestro Date: Fri, 22 Nov 2024 22:12:28 +0000 Subject: [PATCH] refactor: centralize all of the deb_import functionality in deb_import.bzl Refactor the package repo templates into their own methods and massively cleanup the `for`-loop in `_deb_package_index_impl`. IMHO overall now there's a much better and clear separation of concerns between the "deb_translate_lock" repo and the "package repos" (`apt/private/deb_import.bzl`). --- apt/apt.bzl | 4 +- apt/private/BUILD.bazel | 1 + apt/private/deb_import.bzl | 64 ++++++++++++++++++++++++- apt/private/deb_translate_lock.bzl | 75 ++++++++---------------------- apt/private/package.BUILD.tmpl | 21 ++++++--- docs/apt_macro.md | 2 +- 6 files changed, 100 insertions(+), 67 deletions(-) diff --git a/apt/apt.bzl b/apt/apt.bzl index 2b821be..078fe7c 100644 --- a/apt/apt.bzl +++ b/apt/apt.bzl @@ -114,8 +114,8 @@ def _apt_install( and avoid the DEBUG messages. package_template: (EXPERIMENTAL!) a template file for generated BUILD files. Available template replacement keys are: - `{target_name}`, `{deps}`, `{urls}`, `{name}`, - `{arch}`, `{sha256}`, `{repo_name}` + `{target_name}`, `{src}`, `{deps}`, `{urls}`, + `{name}`, `{arch}`, `{sha256}`, `{repo_name}` resolve_transitive: whether dependencies of dependencies should be resolved and added to the lockfile. """ diff --git a/apt/private/BUILD.bazel b/apt/private/BUILD.bazel index 89dd3da..5473ce6 100644 --- a/apt/private/BUILD.bazel +++ b/apt/private/BUILD.bazel @@ -107,6 +107,7 @@ bzl_library( srcs = ["deb_import.bzl"], visibility = ["//apt:__subpackages__"], deps = [ + ":starlark_codegen", ":util", "@bazel_tools//tools/build_defs/repo:http.bzl", ], diff --git a/apt/private/deb_import.bzl b/apt/private/deb_import.bzl index d05ba49..92e3aa4 100644 --- a/apt/private/deb_import.bzl +++ b/apt/private/deb_import.bzl @@ -1,9 +1,9 @@ "deb_import" load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +load(":starlark_codegen.bzl", "starlark") load(":util.bzl", "util") -# BUILD.bazel template _DEB_IMPORT_BUILD_TMPL = ''' genrule( name = "data", @@ -62,8 +62,68 @@ def make_deb_import_key(repo_name, package): util.sanitize(package.version), ) -def deb_import(**kwargs): +def deb_import(name, url, sha256, **kwargs): http_archive( + name = name, + url = url, + sha256 = sha256, build_file_content = _DEB_IMPORT_BUILD_TMPL, **kwargs ) + +def _deb_import_tmpl(repo_name, package): + deb_import_key = make_deb_import_key(repo_name, package) + + return '''\ + deb_import( + name = "{name}", + url = "{url}", + sha256 = "{sha256}", + ) +'''.format(name = deb_import_key, url = package.url, sha256 = package.sha256) + +def deb_packages(repo_name, packages): + deb_imports = [ + _deb_import_tmpl(repo_name, package) + for architectures in packages.values() + for package in architectures.values() + ] + + return '''\ +"""Generated by rules_distroless. DO NOT EDIT.""" +load("@rules_distroless//apt/private:deb_import.bzl", "deb_import") + +# buildifier: disable=function-docstring +def {repo_name}_packages(): +{deb_imports} +'''.format( + repo_name = repo_name, + deb_imports = "\n".join(deb_imports) if deb_imports else " pass", + ) + +def package_build(package, repo_prefix, repo_name, template): + deb_import_key = make_deb_import_key(repo_name, package) + + pkg_repo_name = "@%s%s" % (repo_prefix, deb_import_key) + + alias_data = starlark.gen("%s//:data" % pkg_repo_name) + alias_control = starlark.gen("%s//:control" % pkg_repo_name) + + deps = [ + "//%s/%s" % (dep.name, package.arch) + for dep in package.dependencies + ] + deps = starlark.gen(deps, indent_count = 1) + + return template.format( + target_name = package.arch, + src = '"@%s%s//:data"' % (repo_prefix, deb_import_key), + deps = deps, + urls = [package.url], + name = package.name, + arch = package.arch, + sha256 = package.sha256, + repo_name = pkg_repo_name, + alias_data = alias_data, + alias_control = alias_control, + ) diff --git a/apt/private/deb_translate_lock.bzl b/apt/private/deb_translate_lock.bzl index 0c9f1fd..6c3e725 100644 --- a/apt/private/deb_translate_lock.bzl +++ b/apt/private/deb_translate_lock.bzl @@ -1,26 +1,8 @@ "repository rule for generating a dependency graph from a lockfile." -load(":deb_import.bzl", "make_deb_import_key") +load(":deb_import.bzl", "deb_packages", "package_build") load(":lockfile.bzl", "lockfile") -# header template for packages.bzl file -_DEB_IMPORT_HEADER_TMPL = '''\ -"""Generated by rules_distroless. DO NOT EDIT.""" -load("@rules_distroless//apt/private:deb_import.bzl", "deb_import") - -# buildifier: disable=function-docstring -def {}_packages(): -''' - -# deb_import template for packages.bzl file -_DEB_IMPORT_TMPL = '''\ - deb_import( - name = "{name}", - urls = {urls}, - sha256 = "{sha256}", - ) -''' - _BUILD_TMPL = """\ exports_files(glob(['packages.bzl'])) @@ -31,51 +13,32 @@ alias( """ def _deb_translate_lock_impl(rctx): - lock_content = rctx.attr.lock_content - package_template = rctx.read(rctx.attr.package_template) - lockf = lockfile.from_json(rctx, lock_content if lock_content else rctx.read(rctx.attr.lock)) - - package_defs = [] - - if not lock_content: - package_defs = [_DEB_IMPORT_HEADER_TMPL.format(rctx.attr.name)] + lockf = lockfile.from_json( + rctx, + rctx.attr.lock_content or rctx.read(rctx.attr.lock), + ) + lockf.write("lock.json") - if not lockf.packages: - package_defs.append(" pass") + repo_prefix = "@" if rctx.attr.lock_content else "" + repo_name = rctx.attr.name for package in lockf.packages(): - deb_import_key = make_deb_import_key(rctx.attr.name, package) - - if not lock_content: - package_defs.append( - _DEB_IMPORT_TMPL.format( - name = deb_import_key, - package_name = package.name, - urls = [package.url], - sha256 = package.sha256, - ), - ) - - repo_name = "%s%s" % ("@" if lock_content else "", deb_import_key) - rctx.file( "%s/%s/BUILD.bazel" % (package.name, package.arch), - package_template.format( - target_name = package.arch, - src = '"@%s//:data"' % repo_name, - deps = ",\n ".join([ - '"//%s/%s"' % (dep.name, package.arch) - for dep in package.dependencies - ]), - urls = [package.url], - name = package.name, - arch = package.arch, - sha256 = package.sha256, - repo_name = "%s" % repo_name, + package_build( + package, + repo_prefix, + repo_name, + rctx.read(rctx.attr.package_template), ), ) - rctx.file("packages.bzl", "\n".join(package_defs)) + if rctx.attr.lock_content: + packages_bzl = "" + else: + packages_bzl = deb_packages(repo_name, lockf.packages) + + rctx.file("packages.bzl", packages_bzl) rctx.file("BUILD.bazel", _BUILD_TMPL.format(rctx.attr.name.split("~")[-1])) deb_translate_lock = repository_rule( diff --git a/apt/private/package.BUILD.tmpl b/apt/private/package.BUILD.tmpl index b5d074a..5d5a5ed 100644 --- a/apt/private/package.BUILD.tmpl +++ b/apt/private/package.BUILD.tmpl @@ -1,19 +1,28 @@ +"""Generated by rules_distroless. DO NOT EDIT.""" + alias( name = "data", - actual = "@{repo_name}//:data", + actual = {alias_data}, visibility = ["//visibility:public"], ) alias( name = "control", - actual = "@{repo_name}//:control", + actual = {alias_control}, visibility = ["//visibility:public"], ) filegroup( - name = "{target_name}", + name = "deps", + srcs = {deps}, visibility = ["//visibility:public"], +) + +filegroup( + name = "{target_name}", srcs = [ - {deps} - ] + [":data"] -) \ No newline at end of file + ":deps", + ":data", + ], + visibility = ["//visibility:public"], +) diff --git a/docs/apt_macro.md b/docs/apt_macro.md index 4576efc..2de943d 100644 --- a/docs/apt_macro.md +++ b/docs/apt_macro.md @@ -116,7 +116,7 @@ https://snapshot.ubuntu.com. | manifest | label to a `manifest.yaml` | none | | lock | label to a `lock.json` | `None` | | nolock | bool, set to True if you explicitly want to run without a lock and avoid the DEBUG messages. | `False` | -| package_template | (EXPERIMENTAL!) a template file for generated BUILD files. Available template replacement keys are: `{target_name}`, `{deps}`, `{urls}`, `{name}`, `{arch}`, `{sha256}`, `{repo_name}` | `None` | +| package_template | (EXPERIMENTAL!) a template file for generated BUILD files. Available template replacement keys are: `{target_name}`, `{src}`, `{deps}`, `{urls}`, `{name}`, `{arch}`, `{sha256}`, `{repo_name}` | `None` | | resolve_transitive | whether dependencies of dependencies should be resolved and added to the lockfile. | `True` |