Skip to content

Commit

Permalink
Enable: bazel run {path/to/apko_image_target}.resolve that regenerate…
Browse files Browse the repository at this point in the history
…s resolved.json file. (#37)
  • Loading branch information
sfc-gh-ptabor authored Nov 30, 2023
1 parent 092cf1f commit 16ce9af
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 76 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,12 @@ Than you import these base layers into Bazel:
- With Bazel 6 and [bzlmod], call `apk.translate_lock` in `MODULE.bazel`
- Otherwise, call `translate_apko_lock` in `WORKSPACE`

Periodically one can call `apko resolve path/to/apko.yaml` or `bazel run @rules_apko//apko resolve path/to/apko.yaml`
to regenerate `apko.resolved.json` and use the `apko_image` rule to build the image, producing an OCI format output.
Now you can use the `apko_image` rule to build the image, producing an OCI format output.
As long as the apko `.yaml` file is in the same directory as the `apko_image` you can periodically refresh the
`apko.resolved.json` file by just calling: `bazel run path/to/image.resolve`.
Alternatively you can call `apko resolve path/to/apko.yaml` or `bazel run @rules_apko//apko resolve path/to/apko.yaml`
to regenerate the `apko.resolved.json` file manually.
To resolve all the files in the repository, such a [snippet](./examples/resolve.sh) can be useful.

Finally, we recommend using <https://github.com/bazel-contrib/rules_oci> as the next step in your Bazel build
to add application code from your repo as the next layers of the image.
Expand Down
7 changes: 7 additions & 0 deletions apko/private/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ bzl_library(
name = "apko_image",
srcs = ["apko_image.bzl"],
visibility = ["//apko:__subpackages__"],
deps = ["apko_run"],
)

bzl_library(
name = "apko_run",
srcs = ["apko_run.bzl"],
visibility = ["//apko:__subpackages__"],
)

bzl_library(
Expand Down
108 changes: 71 additions & 37 deletions apko/private/apko_image.bzl
Original file line number Diff line number Diff line change
@@ -1,39 +1,6 @@
"A rule for running apko with prepopulated cache"

_DOC = """Build OCI images from APK packages directly without Dockerfile
This rule creates Alpine images using the 'apko.yaml' configuration file and relies on cache contents generated by [translate_lock](./translate_lock.md) to be fast.
```starlark
apko_image(
name = "example",
config = "apko.yaml",
contents = "@example_lock//:contents",
tag = "example:latest",
)
```
The label `@example_lock//:contents` is generated by the `translate_lock` extension, which consumes an 'apko.resolved.json' file.
For more details, refer to the [documentation](./docs/apko-cache.md).
An example demonstrating usage with [rules_oci](https://github.com/bazel-contrib/rules_oci)
```starlark
apko_image(
name = "alpine_base",
config = "apko.yaml",
contents = "@alpine_base_lock//:contents",
tag = "alpine_base:latest",
)
oci_image(
name = "app",
base = ":alpine_base"
)
```
For more examples checkout the [examples](/examples) directory.
"""
load("//apko/private:apko_run.bzl", "apko_run")

_ATTRS = {
"contents": attr.label(doc = "Label to the contents repository generated by translate_lock. See [apko-cache](./apko-cache.md) documentation.", mandatory = True),
Expand Down Expand Up @@ -96,14 +63,81 @@ def _impl(ctx):

apko_image_lib = struct(
attrs = _ATTRS,
documentation = _DOC,
implementation = _impl,
toolchains = ["@rules_apko//apko:toolchain_type"],
)

apko_image = rule(
_apko_image = rule(
implementation = apko_image_lib.implementation,
attrs = apko_image_lib.attrs,
toolchains = apko_image_lib.toolchains,
doc = apko_image_lib.documentation,
)

def apko_image(name, contents, config, tag, output = "oci", architecture = None, args = [], **kwargs):
"""Build OCI images from APK packages directly without Dockerfile
This rule creates images using the 'apko.yaml' configuration file and relies on cache contents generated by [translate_lock](./translate_lock.md) to be fast.
```starlark
apko_image(
name = "example",
config = "apko.yaml",
contents = "@example_lock//:contents",
tag = "example:latest",
)
```
The label `@example_lock//:contents` is generated by the `translate_lock` extension, which consumes an 'apko.resolved.json' file.
For more details, refer to the [documentation](./docs/apko-cache.md).
An example demonstrating usage with [rules_oci](https://github.com/bazel-contrib/rules_oci)
```starlark
apko_image(
name = "alpine_base",
config = "apko.yaml",
contents = "@alpine_base_lock//:contents",
tag = "alpine_base:latest",
)
oci_image(
name = "app",
base = ":alpine_base"
)
```
For more examples checkout the [examples](/examples) directory.
Args:
name: of the target for the generated image.
contents: Label to the contents repository generated by translate_lock. See [apko-cache](./apko-cache.md) documentation.
config: Label to the `apko.yaml` file.
output: "oci" of "docker",
architecture: the CPU architecture which this image should be built to run on. See https://github.com/chainguard-dev/apko/blob/main/docs/apko_file.md#archs-top-level-element"),
tag: tag to apply to the resulting docker tarball. only applicable when `output` is `docker`
args: additional arguments to provide when running the `apko build` command.
**kwargs: other common arguments like: tags, visibility.
"""
_apko_image(
name = name,
config = config,
contents = contents,
output = output,
architecture = architecture,
tag = tag,
args = args,
**kwargs
)
config_label = native.package_relative_label(config)

# We generate the `.resolve` target only if the config (apko.yaml file) is in the same package as the apko_image rule.
if config_label.workspace_name == "" and config_label.package == native.package_name() and config_label.name.endswith(".yaml"):
resolved_json_name = config_label.name.removesuffix(".yaml") + ".resolved.json"

# We generate the .resolve target only if the `.apko.resolved.json` file exists in the same package.
for _ in native.glob([resolved_json_name]):
apko_run(
name = name + ".resolve",
args = ["resolve", config_label.package + "/" + config_label.name],
workdir = "workspace",
)
18 changes: 15 additions & 3 deletions apko/private/apko_run.bzl
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
"A rule for running apko - convenience layer to stay within consistent versions."

_WORKDIR_DOC = """
The dir where apko will get executed:
- working - the dir where bazel was called.
- workspace - the root directory of the bazel workspace (usually repository root)"""

_ATTRS = {
"workdir": attr.string(default = "working", doc = _WORKDIR_DOC, mandatory = False, values = ["working", "workspace"]),
}

_DOC = """
Expand All @@ -15,8 +21,8 @@ LAUNCHER_TEMPLATE = """
set -e
LAUNCHER_DIR="${PWD}"
if test "${BUILD_WORKING_DIRECTORY+x}"; then
cd $BUILD_WORKING_DIRECTORY
if test "${{{workdir_env}}+x}"; then
cd ${{workdir_env}}
fi
echo "Workdir: ${PWD}" >&2
Expand All @@ -27,7 +33,13 @@ def _impl(ctx):
output = ctx.actions.declare_file("_{}_run.sh".format(ctx.label.name))
apko_info = ctx.toolchains["@rules_apko//apko:toolchain_type"].apko_info

ctx.actions.write(output = output, content = LAUNCHER_TEMPLATE.replace("{{apko_binary}}", apko_info.binary.path), is_executable = True)
ctx.actions.write(
output = output,
content = LAUNCHER_TEMPLATE
.replace("{{apko_binary}}", apko_info.binary.path)
.replace("{{workdir_env}}", "BUILD_" + ctx.attr.workdir.upper() + "_DIRECTORY"),
is_executable = True,
)

return DefaultInfo(executable = output, runfiles = ctx.runfiles(files = [apko_info.binary]))

Expand Down
67 changes: 34 additions & 33 deletions docs/rules.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion examples/resolve.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
#!/bin/bash

# Resolves all targets in the examples.

set -e -x

find . -name apko.yaml | xargs bazel run @rules_apko//apko resolve
TARGETS=$(bazel query 'filter(".resolve$", kind("apko_run", ...))')
for target in ${TARGETS}; do
bazel run "${target}"
done

0 comments on commit 16ce9af

Please sign in to comment.