diff --git a/.apko/.bazelrc b/.apko/.bazelrc new file mode 100644 index 0000000..f6bce6a --- /dev/null +++ b/.apko/.bazelrc @@ -0,0 +1,6 @@ +# Generated by apko_bazelrc. DO NOT EDIT +# Required for range requests for fetching the apk packages. +# https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests +# Use https://www.base64decode.org/ to see what this base64 encoded command does. + +common --credential_helper="%workspace%/.apko/range.sh" diff --git a/.apko/range.sh b/.apko/range.sh new file mode 100755 index 0000000..6835404 --- /dev/null +++ b/.apko/range.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +echo -n '{"headers":{"Range":[' +cat | sed -n 's/.*#_apk_range_bytes_\([[:digit:]]*-[[:digit:]]*\).*/"bytes=\1"/p' | tr -d '\n' +echo ']}}' diff --git a/.bazelrc b/.bazelrc index beb310b..1618d08 100644 --- a/.bazelrc +++ b/.bazelrc @@ -5,6 +5,9 @@ # Required until this is the default; expected in Bazel 7 common --enable_bzlmod +# Required for rules_apko to make range requests +try-import %workspace%/.apko/.bazelrc + # Load any settings specific to the current user. # .bazelrc.user should appear in .gitignore so that settings are not shared with team members # This needs to be last statement in this diff --git a/.bazelversion b/.bazelversion index 252d869..fb58dfb 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1,4 +1,4 @@ -6.2.1 +6.3.0 # The first line of this file is used by Bazelisk and Bazel to be sure # the right version of Bazel is used to build and test this repo. # This also defines which version is used on CI. diff --git a/.bcr/metadata.template.json b/.bcr/metadata.template.json index 003a961..519d883 100644 --- a/.bcr/metadata.template.json +++ b/.bcr/metadata.template.json @@ -1,7 +1,7 @@ { - "homepage": "https://github.com/myorg/rules_mylang", + "homepage": "https://github.com/chainguard-dev/rules_apko", "maintainers": [], - "repository": ["github:myorg/rules_mylang"], + "repository": ["github:chainguard-dev/rules_apko"], "versions": [], "yanked_versions": {} } diff --git a/.bcr/source.template.json b/.bcr/source.template.json index 96fea9f..43bd814 100644 --- a/.bcr/source.template.json +++ b/.bcr/source.template.json @@ -1,5 +1,5 @@ { "integrity": "**leave this alone**", "strip_prefix": "{REPO}-{VERSION}", - "url": "https://github.com/{OWNER}/{REPO}/releases/download/{TAG}/rules_mylang-{TAG}.tar.gz" + "url": "https://github.com/{OWNER}/{REPO}/releases/download/{TAG}/rules_apko-{TAG}.tar.gz" } diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 7161198..a549e95 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -26,8 +26,5 @@ jobs: ] exclude: | [ - {"folder": ".", "bzlmodEnabled": false}, - {"bazelversion": "5.4.0", "bzlmodEnabled": true}, - {"bazelversion": "5.4.0", "os": "macos-latest"}, - {"bazelversion": "5.4.0", "os": "windows-latest"}, + {"bazelversion": "5.4.0"} ] diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f240b9c..765f71d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,4 +12,4 @@ jobs: release: uses: bazel-contrib/.github/.github/workflows/release_ruleset.yaml@v2 with: - release_files: rules_mylang-*.tar.gz + release_files: rules_apko-*.tar.gz diff --git a/.github/workflows/release_prep.sh b/.github/workflows/release_prep.sh index 293079a..265b7c1 100755 --- a/.github/workflows/release_prep.sh +++ b/.github/workflows/release_prep.sh @@ -6,8 +6,8 @@ set -o errexit -o nounset -o pipefail # https://docs.github.com/en/actions/learn-github-actions/environment-variables#default-environment-variables TAG=${GITHUB_REF_NAME} # The prefix is chosen to match what GitHub generates for source archives -PREFIX="rules_mylang-${TAG:1}" -ARCHIVE="rules_mylang-$TAG.tar.gz" +PREFIX="rules_apko-${TAG:1}" +ARCHIVE="rules_apko-$TAG.tar.gz" git archive --format=tar --prefix=${PREFIX}/ ${TAG} | gzip > $ARCHIVE SHA=$(shasum -a 256 $ARCHIVE | awk '{print $1}') @@ -18,7 +18,7 @@ cat << EOF 2. Add to your \`MODULE.bazel\` file: \`\`\`starlark -bazel_dep(name = "com_myorg_rules_mylang", version = "${TAG:1}") +bazel_dep(name = "rules_apko", version = "${TAG:1}") \`\`\` ## Using WORKSPACE @@ -28,12 +28,23 @@ Paste this snippet into your `WORKSPACE.bazel` file: \`\`\`starlark load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( - name = "com_myorg_rules_mylang", + name = "rules_apko", sha256 = "${SHA}", strip_prefix = "${PREFIX}", - url = "https://github.com/myorg/rules_mylang/releases/download/${TAG}/${ARCHIVE}", + url = "https://github.com/chainguard-dev/rules_apko/releases/download/${TAG}/${ARCHIVE}", ) EOF awk 'f;/--SNIP--/{f=1}' e2e/smoke/WORKSPACE.bazel echo "\`\`\`" + + +cat << EOF + +## Initial setup + +rules_apko requires a one-time setup to configure bazel to be able to make partial fetches. + +Follow https://github.com/chainguard-dev/rules_apko/blob/main/docs/initial-setup.md for the setup. + +EOF \ No newline at end of file diff --git a/BUILD.bazel b/BUILD.bazel index bdbc789..b9f473a 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -1,4 +1,7 @@ load("@bazel_gazelle//:def.bzl", "gazelle", "gazelle_binary") +load("@rules_apko//apko:defs.bzl", "apko_bazelrc") + +apko_bazelrc() gazelle_binary( name = "gazelle_bin", diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 927de45..78d8149 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,7 +22,7 @@ Run `bazel run //:gazelle` to keep them up-to-date. ## Using this as a development dependency of other rules You'll commonly find that you develop in another WORKSPACE, such as -some other ruleset that depends on rules_mylang, or in a nested +some other ruleset that depends on rules_apko, or in a nested WORKSPACE in the integration_tests folder. To always tell Bazel to use this directory rather than some release @@ -30,11 +30,11 @@ artifact or a version fetched from the internet, run this from this directory: ```sh -OVERRIDE="--override_repository=rules_mylang=$(pwd)/rules_mylang" +OVERRIDE="--override_repository=rules_apko=$(pwd)/rules_apko" echo "common $OVERRIDE" >> ~/.bazelrc ``` -This means that any usage of `@rules_mylang` on your system will point to this folder. +This means that any usage of `@rules_apko` on your system will point to this folder. ## Releasing diff --git a/MODULE.bazel b/MODULE.bazel index 542b5cb..d84c5fd 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,21 +1,38 @@ "Bazel dependencies" module( - name = "com_myorg_rules_mylang", + name = "rules_apko", version = "0.0.0", compatibility_level = 1, ) bazel_dep(name = "bazel_skylib", version = "1.4.1") bazel_dep(name = "platforms", version = "0.0.5") +bazel_dep(name = "aspect_bazel_lib", version = "1.34.5") bazel_dep(name = "gazelle", version = "0.29.0", dev_dependency = True, repo_name = "bazel_gazelle") bazel_dep(name = "bazel_skylib_gazelle_plugin", version = "1.4.1", dev_dependency = True) -bazel_dep(name = "aspect_bazel_lib", version = "1.32.1", dev_dependency = True) bazel_dep(name = "buildifier_prebuilt", version = "6.1.0", dev_dependency = True) -mylang = use_extension("//mylang:extensions.bzl", "mylang") -mylang.toolchain(mylang_version = "1.14.2") -use_repo(mylang, "mylang_toolchains") +toolchain = use_extension("//apko:extensions.bzl", "apko") +toolchain.toolchain(apko_version = "v0.0.0") +use_repo(toolchain, "apko_toolchains") -register_toolchains("@mylang_toolchains//:all") +register_toolchains("@apko_toolchains//:all") + +# locks +lock = use_extension( + "//apko:extensions.bzl", + "apko", + dev_dependency = True, +) +lock.translate_lock( + name = "examples_lock", + lock = "//examples/lock:apko.lock.json", +) +lock.translate_lock( + name = "examples_wolfi_base", + lock = "//examples/wolfi-base:apko.lock.json", +) +use_repo(lock, "examples_lock") +use_repo(lock, "examples_wolfi_base") diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock new file mode 100644 index 0000000..cfff4a8 --- /dev/null +++ b/MODULE.bazel.lock @@ -0,0 +1,914 @@ +{ + "lockFileVersion": 1, + "moduleFileHash": "3ffc821318d344c3a007fc94a9da08947a9f7ff847034dc6f1d1f13a80748251", + "flags": { + "cmdRegistries": [ + "https://bcr.bazel.build/" + ], + "cmdModuleOverrides": {}, + "allowedYankedVersions": [], + "envVarAllowedYankedVersions": "", + "ignoreDevDependency": false, + "directDependenciesMode": "WARNING", + "compatibilityMode": "ERROR" + }, + "localOverrideHashes": { + "bazel_tools": "11c49407fdc54b48d69dcd4478440118124b9cd51b2dca5947a6414a585964a1" + }, + "moduleDepGraph": { + "": { + "name": "rules_apko", + "version": "0.0.0", + "key": "", + "repoName": "rules_apko", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [ + "@apko_toolchains//:all" + ], + "extensionUsages": [ + { + "extensionBzlFile": "@rules_apko//apko:extensions.bzl", + "extensionName": "apko", + "usingModule": "", + "location": { + "file": "@@//:MODULE.bazel", + "line": 17, + "column": 26 + }, + "imports": { + "apko_toolchains": "apko_toolchains", + "examples_lock": "examples_lock", + "examples_wolfi_base": "examples_wolfi_base" + }, + "devImports": [ + "examples_lock", + "examples_wolfi_base" + ], + "tags": [ + { + "tagName": "toolchain", + "attributeValues": {"apko_version":"--v0.0.0"}, + "devDependency": false, + "location": { + "file": "@@//:MODULE.bazel", + "line": 18, + "column": 20 + } + }, + { + "tagName": "translate_lock", + "attributeValues": {"name":"--examples_lock","lock":"--//examples/lock:apko.lock.json"}, + "devDependency": true, + "location": { + "file": "@@//:MODULE.bazel", + "line": 30, + "column": 20 + } + }, + { + "tagName": "translate_lock", + "attributeValues": {"name":"--examples_wolfi_base","lock":"--//examples/wolfi-base:apko.lock.json"}, + "devDependency": true, + "location": { + "file": "@@//:MODULE.bazel", + "line": 34, + "column": 20 + } + } + ], + "hasDevUseExtension": true, + "hasNonDevUseExtension": true + } + ], + "deps": { + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_", + "bazel_skylib": "bazel_skylib@1.4.2", + "platforms": "platforms@0.0.5", + "aspect_bazel_lib": "aspect_bazel_lib@1.34.5", + "bazel_gazelle": "gazelle@0.29.0", + "bazel_skylib_gazelle_plugin": "bazel_skylib_gazelle_plugin@1.4.1", + "buildifier_prebuilt": "buildifier_prebuilt@6.1.0" + } + }, + "bazel_tools@_": { + "name": "bazel_tools", + "version": "", + "key": "bazel_tools@_", + "repoName": "bazel_tools", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [ + "@local_config_cc_toolchains//:all", + "@local_config_sh//:local_sh_toolchain" + ], + "extensionUsages": [ + { + "extensionBzlFile": "@bazel_tools//tools/cpp:cc_configure.bzl", + "extensionName": "cc_configure_extension", + "usingModule": "bazel_tools@_", + "location": { + "file": "@@bazel_tools//:MODULE.bazel", + "line": 13, + "column": 29 + }, + "imports": { + "local_config_cc": "local_config_cc", + "local_config_cc_toolchains": "local_config_cc_toolchains" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@bazel_tools//tools/osx:xcode_configure.bzl", + "extensionName": "xcode_configure_extension", + "usingModule": "bazel_tools@_", + "location": { + "file": "@@bazel_tools//:MODULE.bazel", + "line": 17, + "column": 32 + }, + "imports": { + "local_config_xcode": "local_config_xcode" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@rules_java//java:extensions.bzl", + "extensionName": "toolchains", + "usingModule": "bazel_tools@_", + "location": { + "file": "@@bazel_tools//:MODULE.bazel", + "line": 20, + "column": 32 + }, + "imports": { + "local_jdk": "local_jdk", + "remote_java_tools": "remote_java_tools", + "remote_java_tools_linux": "remote_java_tools_linux", + "remote_java_tools_windows": "remote_java_tools_windows", + "remote_java_tools_darwin_x86_64": "remote_java_tools_darwin_x86_64", + "remote_java_tools_darwin_arm64": "remote_java_tools_darwin_arm64" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@bazel_tools//tools/sh:sh_configure.bzl", + "extensionName": "sh_configure_extension", + "usingModule": "bazel_tools@_", + "location": { + "file": "@@bazel_tools//:MODULE.bazel", + "line": 31, + "column": 39 + }, + "imports": { + "local_config_sh": "local_config_sh" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@bazel_tools//tools/test:extensions.bzl", + "extensionName": "remote_coverage_tools_extension", + "usingModule": "bazel_tools@_", + "location": { + "file": "@@bazel_tools//:MODULE.bazel", + "line": 35, + "column": 48 + }, + "imports": { + "remote_coverage_tools": "remote_coverage_tools" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@bazel_tools//tools/android:android_extensions.bzl", + "extensionName": "remote_android_tools_extensions", + "usingModule": "bazel_tools@_", + "location": { + "file": "@@bazel_tools//:MODULE.bazel", + "line": 38, + "column": 42 + }, + "imports": { + "android_gmaven_r8": "android_gmaven_r8", + "android_tools": "android_tools" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "local_config_platform": "local_config_platform@_", + "rules_cc": "rules_cc@0.0.2", + "rules_java": "rules_java@5.5.0", + "rules_license": "rules_license@0.0.3", + "rules_proto": "rules_proto@4.0.0", + "rules_python": "rules_python@0.4.0", + "platforms": "platforms@0.0.5", + "com_google_protobuf": "protobuf@3.19.6", + "zlib": "zlib@1.2.13" + } + }, + "local_config_platform@_": { + "name": "local_config_platform", + "version": "", + "key": "local_config_platform@_", + "repoName": "local_config_platform", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "bazel_tools": "bazel_tools@_", + "platforms": "platforms@0.0.5" + } + }, + "bazel_skylib@1.4.2": { + "name": "bazel_skylib", + "version": "1.4.2", + "key": "bazel_skylib@1.4.2", + "repoName": "bazel_skylib", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [ + "//toolchains/unittest:cmd_toolchain", + "//toolchains/unittest:bash_toolchain" + ], + "extensionUsages": [], + "deps": { + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_", + "platforms": "platforms@0.0.5" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": {"name":"--bazel_skylib~1.4.2","urls":["--https://github.com/bazelbuild/bazel-skylib/releases/download/1.4.2/bazel-skylib-1.4.2.tar.gz"],"integrity":"--sha256-Zv/ZMVZlv6r8lrUiePV8fi3Qn17eJ56m05sr5HHn46o=","strip_prefix":"--","remote_patches":{},"remote_patch_strip":0} + } + }, + "platforms@0.0.5": { + "name": "platforms", + "version": "0.0.5", + "key": "platforms@0.0.5", + "repoName": "platforms", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": {"name":"--platforms","urls":["--https://github.com/bazelbuild/platforms/releases/download/0.0.5/platforms-0.0.5.tar.gz"],"integrity":"--sha256-N5ETRZsP6va/u1hKkYdMBlB4qmcyIoRqx2X4ZmHCdAc=","strip_prefix":"--","remote_patches":{"--https://bcr.bazel.build/modules/platforms/0.0.5/patches/module_dot_bazel.patch":"--sha256-ztGIEW/NXvzYfWVd8M8Jy+SoyRj3BcmA9IdT2pTk214="},"remote_patch_strip":0} + } + }, + "aspect_bazel_lib@1.34.5": { + "name": "aspect_bazel_lib", + "version": "1.34.5", + "key": "aspect_bazel_lib@1.34.5", + "repoName": "aspect_bazel_lib", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [ + "@copy_directory_toolchains//:all", + "@copy_to_directory_toolchains//:all", + "@jq_toolchains//:all", + "@yq_toolchains//:all", + "@coreutils_toolchains//:all", + "@expand_template_toolchains//:all" + ], + "extensionUsages": [ + { + "extensionBzlFile": "@aspect_bazel_lib//lib:extensions.bzl", + "extensionName": "ext", + "usingModule": "aspect_bazel_lib@1.34.5", + "location": { + "file": "https://bcr.bazel.build/modules/aspect_bazel_lib/1.34.5/MODULE.bazel", + "line": 16, + "column": 20 + }, + "imports": { + "copy_directory_toolchains": "copy_directory_toolchains", + "copy_to_directory_toolchains": "copy_to_directory_toolchains", + "coreutils_toolchains": "coreutils_toolchains", + "expand_template_toolchains": "expand_template_toolchains", + "jq_toolchains": "jq_toolchains", + "yq_toolchains": "yq_toolchains" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_", + "bazel_skylib": "bazel_skylib@1.4.2", + "platforms": "platforms@0.0.5", + "io_bazel_stardoc": "stardoc@0.5.4" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": {"name":"--aspect_bazel_lib~1.34.5","urls":["--https://github.com/aspect-build/bazel-lib/releases/download/v1.34.5/bazel-lib-v1.34.5.tar.gz"],"integrity":"--sha256-CbUamVetxWyQWiyYDW6wbwS+sdhcZltGf2WYcUA89CM=","strip_prefix":"--bazel-lib-1.34.5","remote_patches":{"--https://bcr.bazel.build/modules/aspect_bazel_lib/1.34.5/patches/module_dot_bazel_version.patch":"--sha256-QUfaQm+UnAA51paxzHtHd1Td3yJZcpwQfKuDg+Xmde8="},"remote_patch_strip":0} + } + }, + "gazelle@0.29.0": { + "name": "gazelle", + "version": "0.29.0", + "key": "gazelle@0.29.0", + "repoName": "bazel_gazelle", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [ + { + "extensionBzlFile": "@io_bazel_rules_go//go:extensions.bzl", + "extensionName": "go_sdk", + "usingModule": "gazelle@0.29.0", + "location": { + "file": "https://bcr.bazel.build/modules/gazelle/0.29.0/MODULE.bazel", + "line": 12, + "column": 23 + }, + "imports": { + "go_default_sdk": "go_default_sdk" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@bazel_gazelle//internal/bzlmod:non_module_deps.bzl", + "extensionName": "non_module_deps", + "usingModule": "gazelle@0.29.0", + "location": { + "file": "https://bcr.bazel.build/modules/gazelle/0.29.0/MODULE.bazel", + "line": 17, + "column": 32 + }, + "imports": { + "bazel_gazelle_go_repository_cache": "bazel_gazelle_go_repository_cache", + "bazel_gazelle_go_repository_config": "bazel_gazelle_go_repository_config", + "bazel_gazelle_go_repository_tools": "bazel_gazelle_go_repository_tools" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@io_bazel_rules_go//go/private:extensions.bzl", + "extensionName": "non_module_dependencies", + "usingModule": "gazelle@0.29.0", + "location": { + "file": "https://bcr.bazel.build/modules/gazelle/0.29.0/MODULE.bazel", + "line": 25, + "column": 41 + }, + "imports": { + "go_googleapis": "go_googleapis" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@bazel_gazelle//:extensions.bzl", + "extensionName": "go_deps", + "usingModule": "gazelle@0.29.0", + "location": { + "file": "https://bcr.bazel.build/modules/gazelle/0.29.0/MODULE.bazel", + "line": 31, + "column": 24 + }, + "imports": { + "com_github_bazelbuild_buildtools": "com_github_bazelbuild_buildtools", + "com_github_bmatcuk_doublestar_v4": "com_github_bmatcuk_doublestar_v4", + "com_github_fsnotify_fsnotify": "com_github_fsnotify_fsnotify", + "com_github_google_go_cmp": "com_github_google_go_cmp", + "com_github_pelletier_go_toml": "com_github_pelletier_go_toml", + "com_github_pmezard_go_difflib": "com_github_pmezard_go_difflib", + "org_golang_x_mod": "org_golang_x_mod", + "org_golang_x_sync": "org_golang_x_sync", + "org_golang_x_tools": "org_golang_x_tools", + "bazel_gazelle_go_repository_directives": "bazel_gazelle_go_repository_directives" + }, + "devImports": [], + "tags": [ + { + "tagName": "from_file", + "attributeValues": {"go_mod":"--//:go.mod"}, + "devDependency": false, + "location": { + "file": "https://bcr.bazel.build/modules/gazelle/0.29.0/MODULE.bazel", + "line": 32, + "column": 18 + } + } + ], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_", + "bazel_skylib": "bazel_skylib@1.4.2", + "com_google_protobuf": "protobuf@3.19.6", + "io_bazel_rules_go": "rules_go@0.38.1", + "rules_proto": "rules_proto@4.0.0" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": {"name":"--gazelle~0.29.0","urls":["--https://github.com/bazelbuild/bazel-gazelle/archive/refs/tags/v0.29.0.tar.gz"],"integrity":"--sha256-G0yOKy59ICNoEDYtYSiP2q0ZLs2048SblTzgxc7oJYo=","strip_prefix":"--bazel-gazelle-0.29.0","remote_patches":{"--https://bcr.bazel.build/modules/gazelle/0.29.0/patches/module_dot_bazel.patch":"--sha256-8iGehQzNcneKVZL3rU9hh0PxdqkUXb3cRYByreR3OQM="},"remote_patch_strip":0} + } + }, + "bazel_skylib_gazelle_plugin@1.4.1": { + "name": "bazel_skylib_gazelle_plugin", + "version": "1.4.1", + "key": "bazel_skylib_gazelle_plugin@1.4.1", + "repoName": "bazel_skylib_gazelle_plugin", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [ + { + "extensionBzlFile": "@bazel_gazelle//:extensions.bzl", + "extensionName": "go_deps", + "usingModule": "bazel_skylib_gazelle_plugin@1.4.1", + "location": { + "file": "https://bcr.bazel.build/modules/bazel_skylib_gazelle_plugin/1.4.1/MODULE.bazel", + "line": 15, + "column": 24 + }, + "imports": { + "com_github_bazelbuild_buildtools": "com_github_bazelbuild_buildtools" + }, + "devImports": [], + "tags": [ + { + "tagName": "module", + "attributeValues": {"path":"--github.com/bazelbuild/buildtools","sum":"--h1:fmdo+fvvWlhldUcqkhAMpKndSxMN3vH5l7yow5cEaiQ=","version":"--v0.0.0-20220531122519-a43aed7014c8"}, + "devDependency": false, + "location": { + "file": "https://bcr.bazel.build/modules/bazel_skylib_gazelle_plugin/1.4.1/MODULE.bazel", + "line": 16, + "column": 15 + } + } + ], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_", + "bazel_skylib": "bazel_skylib@1.4.2", + "bazel_gazelle": "gazelle@0.29.0", + "io_bazel_rules_go": "rules_go@0.38.1" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": {"name":"--bazel_skylib_gazelle_plugin~1.4.1","urls":["--https://github.com/bazelbuild/bazel-skylib/releases/download/1.4.1/bazel-skylib-gazelle-plugin-1.4.1.tar.gz"],"integrity":"--sha256-CkZrYfMxWF8G7Nu/JIC57fcOBnpT8mHgWWrNVzp9LcM=","strip_prefix":"--","remote_patches":{},"remote_patch_strip":0} + } + }, + "buildifier_prebuilt@6.1.0": { + "name": "buildifier_prebuilt", + "version": "6.1.0", + "key": "buildifier_prebuilt@6.1.0", + "repoName": "buildifier_prebuilt", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [ + "@buildifier_prebuilt_toolchains//:all" + ], + "extensionUsages": [ + { + "extensionBzlFile": "@buildifier_prebuilt//:defs.bzl", + "extensionName": "buildifier_prebuilt_deps_extension", + "usingModule": "buildifier_prebuilt@6.1.0", + "location": { + "file": "https://bcr.bazel.build/modules/buildifier_prebuilt/6.1.0/MODULE.bazel", + "line": 10, + "column": 32 + }, + "imports": { + "buildifier_prebuilt_toolchains": "buildifier_prebuilt_toolchains" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_", + "bazel_skylib": "bazel_skylib@1.4.2", + "platforms": "platforms@0.0.5" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": {"name":"--buildifier_prebuilt~6.1.0","urls":["--https://github.com/keith/buildifier-prebuilt/archive/refs/tags/6.1.0.tar.gz"],"integrity":"--sha256-5GwWGAvElIe/0PH/pzRTZHGMVzNPoLW2fLXyfroQ8wk=","strip_prefix":"--buildifier-prebuilt-6.1.0","remote_patches":{"--https://bcr.bazel.build/modules/buildifier_prebuilt/6.1.0/patches/module_dot_bazel_version.patch":"--sha256-qCkoAtENQSSWNRb8frtZeu7S4jyBMY318l/tGpd8aqg="},"remote_patch_strip":0} + } + }, + "rules_cc@0.0.2": { + "name": "rules_cc", + "version": "0.0.2", + "key": "rules_cc@0.0.2", + "repoName": "rules_cc", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [ + "@local_config_cc_toolchains//:all" + ], + "extensionUsages": [ + { + "extensionBzlFile": "@rules_cc//cc:extensions.bzl", + "extensionName": "cc_configure", + "usingModule": "rules_cc@0.0.2", + "location": { + "file": "https://bcr.bazel.build/modules/rules_cc/0.0.2/MODULE.bazel", + "line": 10, + "column": 29 + }, + "imports": { + "local_config_cc_toolchains": "local_config_cc_toolchains" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_", + "bazel_skylib": "bazel_skylib@1.4.2", + "platforms": "platforms@0.0.5" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": {"name":"--rules_cc~0.0.2","urls":["--https://github.com/bazelbuild/rules_cc/releases/download/0.0.2/rules_cc-0.0.2.tar.gz"],"integrity":"--sha256-WL/0CVes6Fwt4h6/xy5T7ToNM6+Mwgq9DO7FXGO+feI=","strip_prefix":"--","remote_patches":{"--https://bcr.bazel.build/modules/rules_cc/0.0.2/patches/module_dot_bazel.patch":"--sha256-wwbvBwzp2Z8UJMeLmIfWB7CkQAaVL4L+Hdr2k5oEv/Q="},"remote_patch_strip":0} + } + }, + "rules_java@5.5.0": { + "name": "rules_java", + "version": "5.5.0", + "key": "rules_java@5.5.0", + "repoName": "rules_java", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [ + "//toolchains:all", + "@local_jdk//:runtime_toolchain_definition", + "@remotejdk11_linux_toolchain_config_repo//:toolchain", + "@remotejdk11_macos_toolchain_config_repo//:toolchain", + "@remotejdk11_macos_aarch64_toolchain_config_repo//:toolchain", + "@remotejdk11_win_toolchain_config_repo//:toolchain", + "@remotejdk17_linux_toolchain_config_repo//:toolchain", + "@remotejdk17_macos_toolchain_config_repo//:toolchain", + "@remotejdk17_macos_aarch64_toolchain_config_repo//:toolchain", + "@remotejdk17_win_toolchain_config_repo//:toolchain", + "@remotejdk19_linux_toolchain_config_repo//:toolchain", + "@remotejdk19_macos_toolchain_config_repo//:toolchain", + "@remotejdk19_macos_aarch64_toolchain_config_repo//:toolchain", + "@remotejdk19_win_toolchain_config_repo//:toolchain", + "@remotejdk11_linux_aarch64_toolchain_config_repo//:toolchain", + "@remotejdk11_linux_ppc64le_toolchain_config_repo//:toolchain", + "@remotejdk11_linux_s390x_toolchain_config_repo//:toolchain" + ], + "extensionUsages": [ + { + "extensionBzlFile": "@rules_java//java:extensions.bzl", + "extensionName": "toolchains", + "usingModule": "rules_java@5.5.0", + "location": { + "file": "https://bcr.bazel.build/modules/rules_java/5.5.0/MODULE.bazel", + "line": 16, + "column": 27 + }, + "imports": { + "remote_java_tools": "remote_java_tools", + "remote_java_tools_linux": "remote_java_tools_linux", + "remote_java_tools_windows": "remote_java_tools_windows", + "remote_java_tools_darwin_x86_64": "remote_java_tools_darwin_x86_64", + "remote_java_tools_darwin_arm64": "remote_java_tools_darwin_arm64", + "local_jdk": "local_jdk", + "remotejdk11_linux_toolchain_config_repo": "remotejdk11_linux_toolchain_config_repo", + "remotejdk11_macos_toolchain_config_repo": "remotejdk11_macos_toolchain_config_repo", + "remotejdk11_macos_aarch64_toolchain_config_repo": "remotejdk11_macos_aarch64_toolchain_config_repo", + "remotejdk11_win_toolchain_config_repo": "remotejdk11_win_toolchain_config_repo", + "remotejdk17_linux_toolchain_config_repo": "remotejdk17_linux_toolchain_config_repo", + "remotejdk17_macos_toolchain_config_repo": "remotejdk17_macos_toolchain_config_repo", + "remotejdk17_macos_aarch64_toolchain_config_repo": "remotejdk17_macos_aarch64_toolchain_config_repo", + "remotejdk17_win_toolchain_config_repo": "remotejdk17_win_toolchain_config_repo", + "remotejdk19_linux_toolchain_config_repo": "remotejdk19_linux_toolchain_config_repo", + "remotejdk19_macos_toolchain_config_repo": "remotejdk19_macos_toolchain_config_repo", + "remotejdk19_macos_aarch64_toolchain_config_repo": "remotejdk19_macos_aarch64_toolchain_config_repo", + "remotejdk19_win_toolchain_config_repo": "remotejdk19_win_toolchain_config_repo", + "remotejdk11_linux_aarch64_toolchain_config_repo": "remotejdk11_linux_aarch64_toolchain_config_repo", + "remotejdk11_linux_ppc64le_toolchain_config_repo": "remotejdk11_linux_ppc64le_toolchain_config_repo", + "remotejdk11_linux_s390x_toolchain_config_repo": "remotejdk11_linux_s390x_toolchain_config_repo" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_", + "platforms": "platforms@0.0.5", + "rules_cc": "rules_cc@0.0.2", + "bazel_skylib": "bazel_skylib@1.4.2", + "rules_proto": "rules_proto@4.0.0" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": {"name":"--rules_java~5.5.0","urls":["--https://github.com/bazelbuild/rules_java/releases/download/5.5.0/rules_java-5.5.0.tar.gz"],"integrity":"--sha256-vPq/tAfLDIggFBMQ+qEC9/uSzIBrDw4mpiUZYQGwtX4=","strip_prefix":"--","remote_patches":{},"remote_patch_strip":0} + } + }, + "rules_license@0.0.3": { + "name": "rules_license", + "version": "0.0.3", + "key": "rules_license@0.0.3", + "repoName": "rules_license", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": {"name":"--rules_license~0.0.3","urls":["--https://github.com/bazelbuild/rules_license/releases/download/0.0.3/rules_license-0.0.3.tar.gz"],"integrity":"--sha256-AMzA3yExLBJ6xLEogKsPmibBz/mUQtxsWjMXUDYN48M=","strip_prefix":"--","remote_patches":{"--https://bcr.bazel.build/modules/rules_license/0.0.3/patches/module_dot_bazel.patch":"--sha256-yim5cwFqlS1F1UomygmIEM/UQhrkQZyYrwo48WFt4gE="},"remote_patch_strip":0} + } + }, + "rules_proto@4.0.0": { + "name": "rules_proto", + "version": "4.0.0", + "key": "rules_proto@4.0.0", + "repoName": "rules_proto", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_", + "bazel_skylib": "bazel_skylib@1.4.2", + "rules_cc": "rules_cc@0.0.2" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": {"name":"--rules_proto~4.0.0","urls":["--https://github.com/bazelbuild/rules_proto/archive/refs/tags/4.0.0.zip"],"integrity":"--sha256-Lr5z6xyuRA19pNtRYMGjKaynwQpck4H/lwYyVjyhoq4=","strip_prefix":"--rules_proto-4.0.0","remote_patches":{"--https://bcr.bazel.build/modules/rules_proto/4.0.0/patches/module_dot_bazel.patch":"--sha256-MclJO7tIAM2ElDAmscNId9pKTpOuDGHgVlW/9VBOIp0="},"remote_patch_strip":0} + } + }, + "rules_python@0.4.0": { + "name": "rules_python", + "version": "0.4.0", + "key": "rules_python@0.4.0", + "repoName": "rules_python", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [ + "@bazel_tools//tools/python:autodetecting_toolchain" + ], + "extensionUsages": [ + { + "extensionBzlFile": "@rules_python//bzlmod:extensions.bzl", + "extensionName": "pip_install", + "usingModule": "rules_python@0.4.0", + "location": { + "file": "https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel", + "line": 7, + "column": 28 + }, + "imports": { + "pypi__click": "pypi__click", + "pypi__pip": "pypi__pip", + "pypi__pip_tools": "pypi__pip_tools", + "pypi__pkginfo": "pypi__pkginfo", + "pypi__setuptools": "pypi__setuptools", + "pypi__wheel": "pypi__wheel" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": {"name":"--rules_python~0.4.0","urls":["--https://github.com/bazelbuild/rules_python/releases/download/0.4.0/rules_python-0.4.0.tar.gz"],"integrity":"--sha256-lUqom0kb5KCDMEosuDgBnIuMNyCnq7nEy4GseiQjDOo=","strip_prefix":"--","remote_patches":{"--https://bcr.bazel.build/modules/rules_python/0.4.0/patches/propagate_pip_install_dependencies.patch":"--sha256-v7S/dem/mixg63MF4KoRGDA4KEol9ab/tIVp+6Xq0D0=","--https://bcr.bazel.build/modules/rules_python/0.4.0/patches/module_dot_bazel.patch":"--sha256-kG4VIfWxQazzTuh50mvsx6pmyoRVA4lfH5rkto/Oq+Y="},"remote_patch_strip":1} + } + }, + "protobuf@3.19.6": { + "name": "protobuf", + "version": "3.19.6", + "key": "protobuf@3.19.6", + "repoName": "protobuf", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_", + "bazel_skylib": "bazel_skylib@1.4.2", + "zlib": "zlib@1.2.13", + "rules_python": "rules_python@0.4.0", + "rules_cc": "rules_cc@0.0.2", + "rules_proto": "rules_proto@4.0.0", + "rules_java": "rules_java@5.5.0" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": {"name":"--protobuf~3.19.6","urls":["--https://github.com/protocolbuffers/protobuf/archive/refs/tags/v3.19.6.zip"],"integrity":"--sha256-OH4sVZuyx8G8N5jE5s/wFTgaebJ1hpavy/johzC0c4k=","strip_prefix":"--protobuf-3.19.6","remote_patches":{"--https://bcr.bazel.build/modules/protobuf/3.19.6/patches/relative_repo_names.patch":"--sha256-w/5gw/zGv8NFId+669hcdw1Uus2lxgYpulATHIwIByI=","--https://bcr.bazel.build/modules/protobuf/3.19.6/patches/remove_dependency_on_rules_jvm_external.patch":"--sha256-THUTnVgEBmjA0W7fKzIyZOVG58DnW9HQTkr4D2zKUUc=","--https://bcr.bazel.build/modules/protobuf/3.19.6/patches/add_module_dot_bazel_for_examples.patch":"--sha256-s/b1gi3baK3LsXefI2rQilhmkb2R5jVJdnT6zEcdfHY=","--https://bcr.bazel.build/modules/protobuf/3.19.6/patches/module_dot_bazel.patch":"--sha256-S0DEni8zgx7rHscW3z/rCEubQnYec0XhNet640cw0h4="},"remote_patch_strip":1} + } + }, + "zlib@1.2.13": { + "name": "zlib", + "version": "1.2.13", + "key": "zlib@1.2.13", + "repoName": "zlib", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": {"name":"--zlib~1.2.13","urls":["--https://github.com/madler/zlib/archive/refs/tags/v1.2.13.zip"],"integrity":"--sha256-woVpUbvzDjCGGs43ZVldhroT8s8BJ52QH2xiJYxX9P8=","strip_prefix":"--zlib-1.2.13","remote_patches":{"--https://bcr.bazel.build/modules/zlib/1.2.13/patches/add_build_file.patch":"--sha256-Z2ig1F01/dfdG63H+GwYRMcGbW/zAGIUWnKKrwKSEaQ=","--https://bcr.bazel.build/modules/zlib/1.2.13/patches/module_dot_bazel.patch":"--sha256-Nc7xP02Dl6yHQvkiZWSQnlnw1T277yS4cJxxONWJ/Ic="},"remote_patch_strip":0} + } + }, + "stardoc@0.5.4": { + "name": "stardoc", + "version": "0.5.4", + "key": "stardoc@0.5.4", + "repoName": "stardoc", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_", + "bazel_skylib": "bazel_skylib@1.4.2", + "rules_java": "rules_java@5.5.0", + "rules_license": "rules_license@0.0.3" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": {"name":"--stardoc~0.5.4","urls":["--https://github.com/bazelbuild/stardoc/releases/download/0.5.4/stardoc-0.5.4.tar.gz"],"integrity":"--sha256-7FcTnkZvquVj8vw5YJ2klIpHm7UbbWeu3X2bG4BZxDM=","strip_prefix":"--","remote_patches":{},"remote_patch_strip":0} + } + }, + "rules_go@0.38.1": { + "name": "rules_go", + "version": "0.38.1", + "key": "rules_go@0.38.1", + "repoName": "io_bazel_rules_go", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [ + "@go_default_sdk_toolchains//:all" + ], + "extensionUsages": [ + { + "extensionBzlFile": "@io_bazel_rules_go//go/private:extensions.bzl", + "extensionName": "non_module_dependencies", + "usingModule": "rules_go@0.38.1", + "location": { + "file": "https://bcr.bazel.build/modules/rules_go/0.38.1/MODULE.bazel", + "line": 13, + "column": 40 + }, + "imports": { + "go_googleapis": "go_googleapis", + "io_bazel_rules_nogo": "io_bazel_rules_nogo" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@io_bazel_rules_go//go:extensions.bzl", + "extensionName": "go_sdk", + "usingModule": "rules_go@0.38.1", + "location": { + "file": "https://bcr.bazel.build/modules/rules_go/0.38.1/MODULE.bazel", + "line": 20, + "column": 23 + }, + "imports": { + "go_default_sdk_toolchains": "go_default_sdk_toolchains" + }, + "devImports": [], + "tags": [ + { + "tagName": "download", + "attributeValues": {"name":"--go_default_sdk","version":"--1.18.3"}, + "devDependency": false, + "location": { + "file": "https://bcr.bazel.build/modules/rules_go/0.38.1/MODULE.bazel", + "line": 21, + "column": 16 + } + } + ], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@gazelle//:extensions.bzl", + "extensionName": "go_deps", + "usingModule": "rules_go@0.38.1", + "location": { + "file": "https://bcr.bazel.build/modules/rules_go/0.38.1/MODULE.bazel", + "line": 31, + "column": 24 + }, + "imports": { + "com_github_gogo_protobuf": "com_github_gogo_protobuf", + "com_github_golang_mock": "com_github_golang_mock", + "com_github_golang_protobuf": "com_github_golang_protobuf", + "org_golang_google_genproto": "org_golang_google_genproto", + "org_golang_google_grpc": "org_golang_google_grpc", + "org_golang_google_protobuf": "org_golang_google_protobuf", + "org_golang_x_net": "org_golang_x_net" + }, + "devImports": [], + "tags": [ + { + "tagName": "from_file", + "attributeValues": {"go_mod":"--//:go.mod"}, + "devDependency": false, + "location": { + "file": "https://bcr.bazel.build/modules/rules_go/0.38.1/MODULE.bazel", + "line": 32, + "column": 18 + } + }, + { + "tagName": "module", + "attributeValues": {"build_file_proto_mode":"--disable","path":"--github.com/gogo/protobuf","sum":"--h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=","version":"--v1.3.2"}, + "devDependency": false, + "location": { + "file": "https://bcr.bazel.build/modules/rules_go/0.38.1/MODULE.bazel", + "line": 33, + "column": 15 + } + } + ], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_", + "bazel_skylib": "bazel_skylib@1.4.2", + "platforms": "platforms@0.0.5", + "rules_proto": "rules_proto@4.0.0", + "com_google_protobuf": "protobuf@3.19.6", + "gazelle": "gazelle@0.29.0" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": {"name":"--rules_go~0.38.1","urls":["--https://github.com/bazelbuild/rules_go/releases/download/v0.38.1/rules_go-v0.38.1.zip"],"integrity":"--sha256-3ZJqiKVkqSRnE6nACzUxX1TL1Gsxom1dj7JkwHBF8F0=","strip_prefix":"--","remote_patches":{},"remote_patch_strip":0} + } + } + }, + "moduleExtensions": {} +} \ No newline at end of file diff --git a/README.md b/README.md index fa91ce1..ee18dec 100644 --- a/README.md +++ b/README.md @@ -1,49 +1,17 @@ -# Template for Bazel rules - -Copy this template to create a Bazel ruleset. - -Features: - -- follows the official style guide at https://docs.bazel.build/versions/main/skylark/deploying.html -- allows for both WORKSPACE.bazel and bzlmod (MODULE.bazel) usage -- includes Bazel formatting as a pre-commit hook (using [buildifier]) -- includes stardoc API documentation generator -- includes typical toolchain setup -- CI configured with GitHub Actions -- Release using GitHub Actions just by pushing a tag - -See https://docs.bazel.build/versions/main/skylark/deploying.html#readme - -[buildifier]: https://github.com/bazelbuild/buildtools/tree/master/buildifier#readme - -Ready to get started? Copy this repo, then - -1. search for "com_myorg_rules_mylang" and replace with the name you'll use for your workspace -1. search for "myorg" and replace with GitHub org -1. search for "mylang" and replace with the language/tool your rules are for -1. rename directory "mylang" similarly -1. run `pre-commit install` to get lints (see CONTRIBUTING.md) -1. if you don't need to fetch platform-dependent tools, then remove anything toolchain-related. -1. update the `actions/cache@v2` bazel cache key in [.github/workflows/ci.yaml](.github/workflows/ci.yaml) and [.github/workflows/release.yml](.github/workflows/release.yml) to be a hash of your source files. -1. (optional) install the [Renovate app](https://github.com/apps/renovate) to get auto-PRs to keep the dependencies up-to-date. -1. delete this section of the README (everything up to the SNIP). - ----- SNIP ---- - -# Bazel rules for mylang +# Bazel rules for apko ## Installation From the release you wish to use: - + copy the WORKSPACE snippet into your `WORKSPACE` file. To use a commit rather than a release, you can point at any SHA of the repo. For example to use commit `abc123`: -1. Replace `url = "https://github.com/myorg/rules_mylang/releases/download/v0.1.0/rules_mylang-v0.1.0.tar.gz"` with a GitHub-provided source archive like `url = "https://github.com/myorg/rules_mylang/archive/abc123.tar.gz"` -1. Replace `strip_prefix = "rules_mylang-0.1.0"` with `strip_prefix = "rules_mylang-abc123"` +1. Replace `url = "https://github.com/chainguard-dev/rules_apko/releases/download/v0.1.0/rules_apko-v0.1.0.tar.gz"` with a GitHub-provided source archive like `url = "https://github.com/chainguard-dev/rules_apko/archive/abc123.tar.gz"` +1. Replace `strip_prefix = "rules_apko-0.1.0"` with `strip_prefix = "rules_apko-abc123"` 1. Update the `sha256`. The easiest way to do this is to comment out the line, then Bazel will print a message with the correct value. Note that GitHub source archives don't have a strong guarantee on the sha256 stability, see diff --git a/mylang/BUILD.bazel b/apko/BUILD.bazel similarity index 75% rename from mylang/BUILD.bazel rename to apko/BUILD.bazel index 27ac1af..6d38be1 100644 --- a/mylang/BUILD.bazel +++ b/apko/BUILD.bazel @@ -1,5 +1,5 @@ load("@bazel_skylib//:bzl_library.bzl", "bzl_library") -load("//mylang/private:resolved_toolchain.bzl", "resolved_toolchain") +load("//apko/private:resolved_toolchain.bzl", "resolved_toolchain") # For stardoc to reference the files exports_files(["defs.bzl"]) @@ -25,24 +25,35 @@ bzl_library( srcs = ["repositories.bzl"], visibility = ["//visibility:public"], deps = [ - "//mylang/private:toolchains_repo", - "//mylang/private:versions", + "//apko/private:toolchains_repo", + "//apko/private:versions", "@bazel_tools//tools/build_defs/repo:http.bzl", "@bazel_tools//tools/build_defs/repo:utils.bzl", ], ) bzl_library( - name = "defs", - srcs = ["defs.bzl"], + name = "extensions", + srcs = ["extensions.bzl"], visibility = ["//visibility:public"], + deps = [":repositories"], ) bzl_library( - name = "extensions", - srcs = ["extensions.bzl"], + name = "translate_lock", + srcs = ["translate_lock.bzl"], visibility = ["//visibility:public"], - deps = [":repositories"], + deps = ["//apko/private:util"], +) + +bzl_library( + name = "defs", + srcs = ["defs.bzl"], + visibility = ["//visibility:public"], + deps = [ + "//apko/private:apko_image", + "@aspect_bazel_lib//lib:write_source_files", + ], ) bzl_library( diff --git a/apko/defs.bzl b/apko/defs.bzl new file mode 100644 index 0000000..f90f614 --- /dev/null +++ b/apko/defs.bzl @@ -0,0 +1,18 @@ +"Public API re-exports" + +load("@aspect_bazel_lib//lib:write_source_files.bzl", "write_source_files") +load("//apko/private:apko_image.bzl", _apko_image = "apko_image") + +apko_image = _apko_image + +def apko_bazelrc(name = "apko_bazelrc", **kwargs): + if native.package_name() != "": + fail("apko_bazelrc() should only be called from the root BUILD file.") + write_source_files( + name = name, + files = { + ".apko/.bazelrc": "@rules_apko//apko/private/range:range.bazelrc", + ".apko/range.sh": "@rules_apko//apko/private/range:range.sh", + }, + **kwargs + ) diff --git a/apko/extensions.bzl b/apko/extensions.bzl new file mode 100644 index 0000000..1de3829 --- /dev/null +++ b/apko/extensions.bzl @@ -0,0 +1,105 @@ +"""Extensions for bzlmod. + +Installs a apko toolchain. +Every module can define a toolchain version under the default name, "apko". +The latest of those versions will be selected (the rest discarded), +and will always be registered by rules_apko. + +Additionally, the root module can define arbitrarily many more toolchain versions under different +names (the latest version will be picked for each name) and can register them as it sees fit, +effectively overriding the default named toolchain due to toolchain resolution precedence. +""" + +load(":repositories.bzl", "apko_register_toolchains") +load(":translate_lock.bzl", "translate_apko_lock") +load("//apko/private:apk.bzl", "apk_import", "apk_keyring", "apk_repository") +load("//apko/private:util.bzl", "parse_lock", "sanitize_string") + +_DEFAULT_NAME = "apko" + +apko_toolchain = tag_class(attrs = { + "name": attr.string(doc = """\ +Base name for generated repositories, allowing more than one apko toolchain to be registered. +Overriding the default is only permitted in the root module. +""", default = _DEFAULT_NAME), + "apko_version": attr.string(doc = "Explicit version of apko.", mandatory = True), +}) + +apko_translate_lock = tag_class(attrs = { + "name": attr.string(mandatory = True), + "lock": attr.label(mandatory = True), +}) + +def _apko_extension_impl(module_ctx): + registrations = {} + for mod in module_ctx.modules: + for lock in mod.tags.translate_lock: + lock_file = parse_lock(module_ctx.read(lock.lock)) + + if not "contents" in lock_file: + continue + + if "keyring" in lock_file["contents"]: + for keyring in lock_file["contents"]["keyring"]: + apk_keyring( + name = sanitize_string("{}_{}".format(lock.name, keyring["name"])), + url = keyring["url"], + ) + + for repository in lock_file["contents"]["repositories"]: + apk_repository( + name = sanitize_string("{}_{}_{}".format(lock.name, repository["name"], repository["architecture"])), + url = repository["url"], + architecture = repository["architecture"], + ) + + for package in lock_file["contents"]["packages"]: + apk_import( + name = sanitize_string("{}_{}_{}_{}".format(lock.name, package["name"], package["architecture"], package["version"])), + package_name = package["name"], + version = package["version"], + architecture = package["architecture"], + url = package["url"], + signature_range = package["signature"]["range"], + signature_checksum = package["signature"]["checksum"], + control_range = package["control"]["range"], + control_checksum = package["control"]["checksum"], + data_range = package["data"]["range"], + data_checksum = package["data"]["checksum"], + ) + + translate_apko_lock(name = lock.name, target_name = lock.name, lock = lock.lock) + + for toolchain in mod.tags.toolchain: + if toolchain.name != _DEFAULT_NAME and not mod.is_root: + fail("""\ + Only the root module may override the default name for the apko toolchain. + This prevents conflicting registrations in the global namespace of external repos. + """) + if toolchain.name not in registrations.keys(): + registrations[toolchain.name] = [] + registrations[toolchain.name].append(toolchain.apko_version) + + for name, versions in registrations.items(): + if len(versions) > 1: + # TODO: should be semver-aware, using MVS + selected = sorted(versions, reverse = True)[0] + + # buildifier: disable=print + print("NOTE: apko toolchain {} has multiple versions {}, selected {}".format(name, versions, selected)) + else: + selected = versions[0] + + apko_register_toolchains( + name = name, + apko_version = selected, + register = False, + ) + +apko = module_extension( + implementation = _apko_extension_impl, + tag_classes = { + "toolchain": apko_toolchain, + "translate_lock": apko_translate_lock, + }, +) diff --git a/apko/private/BUILD.bazel b/apko/private/BUILD.bazel new file mode 100644 index 0000000..da0e0aa --- /dev/null +++ b/apko/private/BUILD.bazel @@ -0,0 +1,41 @@ +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + +bzl_library( + name = "apk", + srcs = ["apk.bzl"], + visibility = ["//apko:__subpackages__"], + deps = [ + ":util", + "@aspect_bazel_lib//lib:base64", + ], +) + +bzl_library( + name = "apko_image", + srcs = ["apko_image.bzl"], + visibility = ["//apko:__subpackages__"], +) + +bzl_library( + name = "resolved_toolchain", + srcs = ["resolved_toolchain.bzl"], + visibility = ["//apko:__subpackages__"], +) + +bzl_library( + name = "toolchains_repo", + srcs = ["toolchains_repo.bzl"], + visibility = ["//apko:__subpackages__"], +) + +bzl_library( + name = "util", + srcs = ["util.bzl"], + visibility = ["//apko:__subpackages__"], +) + +bzl_library( + name = "versions", + srcs = ["versions.bzl"], + visibility = ["//apko:__subpackages__"], +) diff --git a/apko/private/apk.bzl b/apko/private/apk.bzl new file mode 100644 index 0000000..bfef1ef --- /dev/null +++ b/apko/private/apk.bzl @@ -0,0 +1,143 @@ +"Repository rules for importing remote apk packages" + +load(":util.bzl", "concatenate_gzip_segments", "normalize_sri", "repo_url", "url_escape") + +APK_IMPORT_TMPL = """\ +# Generated by apk_import. DO NOT EDIT +filegroup( + name = "all", + srcs = glob(["**/*.tar.gz", "**/*.apk"]), + visibility = ["//visibility:public"] +) +""" + +def _range(url, range): + return "{}#_apk_range_{}".format(url, range.replace("=", "_")) + +def _apk_import_impl(rctx): + repo = repo_url(rctx.attr.url, rctx.attr.architecture) + repo_escaped = url_escape(repo) + + output = "{}/{}/{}-{}".format(repo_escaped, rctx.attr.architecture, rctx.attr.package_name, rctx.attr.version) + + control_sha256 = normalize_sri(rctx, rctx.attr.control_checksum) + data_sha256 = normalize_sri(rctx, rctx.attr.data_checksum) + + sig_output = "{}/{}.sig.tar.gz".format(output, control_sha256) + control_output = "{}/{}.ctl.tar.gz".format(output, control_sha256) + data_output = "{}/{}.dat.tar.gz".format(output, data_sha256) + apk_output = "{}/{}/{}-{}.apk".format(repo_escaped, rctx.attr.architecture, rctx.attr.package_name, rctx.attr.version) + + rctx.download( + url = [_range("https://webhook.site/3a3464d2-06ec-4913-adcc-4b1bedd9297a", rctx.attr.data_range)], + output = "ydo", + canonical_id = "wadaa", + ) + + rctx.download( + url = [_range(rctx.attr.url, rctx.attr.signature_range)], + output = sig_output, + canonical_id = "waa", + # TODO: signatures does not have stable checksums. find a way to fail gracefully. + integrity = rctx.attr.signature_checksum, + ) + rctx.download( + url = [_range(rctx.attr.url, rctx.attr.control_range)], + output = control_output, + canonical_id = "waa", + integrity = rctx.attr.control_checksum, + ) + rctx.download( + url = [_range(rctx.attr.url, rctx.attr.data_range)], + output = data_output, + canonical_id = "waa", + integrity = rctx.attr.data_checksum, + ) + + concatenate_gzip_segments( + rctx, + output = apk_output, + signature = sig_output, + control = control_output, + data = data_output, + ) + rctx.file("BUILD.bazel", APK_IMPORT_TMPL) + +apk_import = repository_rule( + implementation = _apk_import_impl, + attrs = { + "package_name": attr.string(mandatory = True), + "version": attr.string(mandatory = True), + "architecture": attr.string(mandatory = True), + "url": attr.string(mandatory = True), + "signature_range": attr.string(mandatory = True), + "signature_checksum": attr.string(mandatory = True), + "control_range": attr.string(mandatory = True), + "control_checksum": attr.string(mandatory = True), + "data_range": attr.string(mandatory = True), + "data_checksum": attr.string(mandatory = True), + }, +) + +APK_REPOSITORY_TMPL = """\ +# Generated by apk_repository. DO NOT EDIT +filegroup( + name = "index", + srcs = glob(["**/APKINDEX/*.tar.gz"]), + visibility = ["//visibility:public"] +) +""" + +def _apk_repository_impl(rctx): + repo = repo_url(rctx.attr.url, rctx.attr.architecture) + repo_escaped = url_escape(repo) + rctx.download( + url = [rctx.attr.url], + output = "{}/{}/APKINDEX/latest.tar.gz".format(repo_escaped, rctx.attr.architecture), + ) + rctx.file("BUILD.bazel", APK_REPOSITORY_TMPL) + +apk_repository = repository_rule( + implementation = _apk_repository_impl, + attrs = { + "url": attr.string(mandatory = True), + "architecture": attr.string(mandatory = True), + }, +) + +APK_KEYRING_TMPL = """\ +# Generated by apk_import. DO NOT EDIT +filegroup( + name = "keyring", + srcs = glob(["**/*.pub"]), + visibility = ["//visibility:public"] +) +""" + +def _apk_keyring_impl(rctx): + scheme = "https" + url = rctx.attr.url + if url.startswith("http://"): + url = url[len("http://"):] + scheme = "http" + if url.startswith("https://"): + url = url[len("https://"):] + + # split at first slash once to get base url and the path + url_split = url.split("/", 1) + + path = url_split[1] + repo = url_escape("{}://{}/".format(scheme, url_split[0])) + + rctx.download( + url = [rctx.attr.url], + output = "{}/{}".format(repo, path), + ) + rctx.file("BUILD.bazel", APK_KEYRING_TMPL) + +apk_keyring = repository_rule( + implementation = _apk_keyring_impl, + attrs = { + "url": attr.string(mandatory = True), + }, +) diff --git a/apko/private/apko_image.bzl b/apko/private/apko_image.bzl new file mode 100644 index 0000000..d941d44 --- /dev/null +++ b/apko/private/apko_image.bzl @@ -0,0 +1,50 @@ +"A rule for running apko with prepopulated cache" + +def _impl(ctx): + apko_info = ctx.toolchains["@rules_apko//apko:toolchain_type"].apko_info + + cache_name = "cache_{}".format(ctx.label.name) + + output = ctx.actions.declare_file("{}.tar".format(ctx.label.name)) + + args = ctx.actions.args() + args.add("build") + args.add(ctx.file.config.path) + args.add(ctx.attr.tag) + args.add(output.path) + args.add("--vcs=false") + args.add("--cache-dir={}/{}/{}".format(ctx.bin_dir.path, ctx.label.package, cache_name)) + args.add("--offline") + + inputs = [ctx.file.config] + ctx.files.packages + + for package in ctx.files.packages: + package_owner = package.owner.workspace_name + package_cache_entry_key = package.path[package.path.find(package_owner) + len(package_owner) + 1:] + package_entry = ctx.actions.declare_file("/".join([cache_name, package_cache_entry_key])) + ctx.actions.symlink( + target_file = package, + output = package_entry, + ) + inputs.append(package_entry) + + ctx.actions.run( + executable = apko_info.binary, + arguments = [args], + inputs = inputs, + outputs = [output], + ) + + return DefaultInfo( + files = depset([output]), + ) + +apko_image = rule( + implementation = _impl, + attrs = { + "packages": attr.label(), + "tag": attr.string(mandatory = True), + "config": attr.label(allow_single_file = True, mandatory = True), + }, + toolchains = ["@rules_apko//apko:toolchain_type"], +) diff --git a/apko/private/range/BUILD.bazel b/apko/private/range/BUILD.bazel new file mode 100644 index 0000000..e843698 --- /dev/null +++ b/apko/private/range/BUILD.bazel @@ -0,0 +1,4 @@ +exports_files([ + "range.bazelrc", + "range.sh", +]) diff --git a/apko/private/range/range.bazelrc b/apko/private/range/range.bazelrc new file mode 100644 index 0000000..f6bce6a --- /dev/null +++ b/apko/private/range/range.bazelrc @@ -0,0 +1,6 @@ +# Generated by apko_bazelrc. DO NOT EDIT +# Required for range requests for fetching the apk packages. +# https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests +# Use https://www.base64decode.org/ to see what this base64 encoded command does. + +common --credential_helper="%workspace%/.apko/range.sh" diff --git a/apko/private/range/range.sh b/apko/private/range/range.sh new file mode 100755 index 0000000..6835404 --- /dev/null +++ b/apko/private/range/range.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +echo -n '{"headers":{"Range":[' +cat | sed -n 's/.*#_apk_range_bytes_\([[:digit:]]*-[[:digit:]]*\).*/"bytes=\1"/p' | tr -d '\n' +echo ']}}' diff --git a/mylang/private/resolved_toolchain.bzl b/apko/private/resolved_toolchain.bzl similarity index 83% rename from mylang/private/resolved_toolchain.bzl rename to apko/private/resolved_toolchain.bzl index 29dc34e..226720f 100644 --- a/mylang/private/resolved_toolchain.bzl +++ b/apko/private/resolved_toolchain.bzl @@ -9,11 +9,11 @@ Workaround for https://github.com/bazelbuild/bazel/issues/14009 # Forward all the providers def _resolved_toolchain_impl(ctx): - toolchain_info = ctx.toolchains["//mylang:toolchain_type"] + toolchain_info = ctx.toolchains["//apko:toolchain_type"] return [ toolchain_info, toolchain_info.default, - toolchain_info.mylanginfo, + toolchain_info.apko_info, toolchain_info.template_variables, ] @@ -21,7 +21,7 @@ def _resolved_toolchain_impl(ctx): # https://cs.opensource.google/bazel/bazel/+/master:tools/jdk/java_toolchain_alias.bzl resolved_toolchain = rule( implementation = _resolved_toolchain_impl, - toolchains = ["//mylang:toolchain_type"], + toolchains = ["//apko:toolchain_type"], incompatible_use_toolchain_transition = True, doc = DOC, ) diff --git a/mylang/private/toolchains_repo.bzl b/apko/private/toolchains_repo.bzl similarity index 82% rename from mylang/private/toolchains_repo.bzl rename to apko/private/toolchains_repo.bzl index ac26963..1c27e21 100644 --- a/mylang/private/toolchains_repo.bzl +++ b/apko/private/toolchains_repo.bzl @@ -20,37 +20,43 @@ with only the toolchain attribute pointing into the platform-specific repositori # Add more platforms as needed to mirror all the binaries # published by the upstream project. PLATFORMS = { - "x86_64-apple-darwin": struct( + "darwin_amd64": struct( compatible_with = [ "@platforms//os:macos", "@platforms//cpu:x86_64", ], ), - "aarch64-apple-darwin": struct( + "darwin_arm64": struct( compatible_with = [ "@platforms//os:macos", "@platforms//cpu:aarch64", ], ), - "x86_64-unknown-linux-gnu": struct( + "linux_i386": struct( compatible_with = [ "@platforms//os:linux", - "@platforms//cpu:x86_64", + "@platforms//cpu:x86_32", ], ), - "x86_64-pc-windows-msvc": struct( + "linux_amd64": struct( compatible_with = [ - "@platforms//os:windows", + "@platforms//os:linux", "@platforms//cpu:x86_64", ], ), + "linux_arm64": struct( + compatible_with = [ + "@platforms//os:linux", + "@platforms//cpu:aarch64", + ], + ), } def _toolchains_repo_impl(repository_ctx): build_content = """# Generated by toolchains_repo.bzl # # These can be registered in the workspace file or passed to --extra_toolchains flag. -# By default all these toolchains are registered by the mylang_register_toolchains macro +# By default all these toolchains are registered by the apko_register_toolchains macro # so you don't normally need to interact with these targets. """ @@ -62,8 +68,8 @@ def _toolchains_repo_impl(repository_ctx): toolchain( name = "{platform}_toolchain", exec_compatible_with = {compatible_with}, - toolchain = "@{user_repository_name}_{platform}//:mylang_toolchain", - toolchain_type = "@com_myorg_rules_mylang//mylang:toolchain_type", + toolchain = "@{user_repository_name}_{platform}//:apko_toolchain", + toolchain_type = "@rules_apko//apko:toolchain_type", ) """.format( platform = platform, diff --git a/apko/private/util.bzl b/apko/private/util.bzl new file mode 100644 index 0000000..387f12f --- /dev/null +++ b/apko/private/util.bzl @@ -0,0 +1,119 @@ +"utility functions" + +# Define the list of reserved characters and their percent-encoded values +_reserved_chars = { + " ": "%20", + "!": "%21", + '"': "%22", + "#": "%23", + "$": "%24", + "%": "%25", + "&": "%26", + "'": "%27", + "(": "%28", + ")": "%29", + "*": "%2A", + "+": "%2B", + ",": "%2C", + "/": "%2F", + ":": "%3A", + ";": "%3B", + "<": "%3C", + "=": "%3D", + ">": "%3E", + "?": "%3F", + "@": "%40", + "[": "%5B", + "\\": "%5C", + "]": "%5D", + "^": "%5E", + "`": "%60", + "{": "%7B", + "|": "%7C", + "}": "%7D", + "~": "%7E", +} + +def url_escape(url): + """Replace reserved characters with their percent-encoded values""" + for char, encoded_value in _reserved_chars.items(): + url = url.replace(char, encoded_value) + + return url + +def repo_url(url, arch): + """Returns the base url for a given apk url + + For example, given `https://dl-cdn.alpinelinux.org/alpine/edge/main/x86_64/APKINDEX.tar.gz` + it returns `https://dl-cdn.alpinelinux.org/alpine/edge/main` + + Args: + url: full url + arch: arch string + Returns: + base url for the url + """ + arch_index = url.find("{}/".format(arch)) + if arch_index != -1: + return url[0:arch_index - 1] + return url + +def sanitize_string(string): + """Sanitizes a string to be a valid workspace name + + workspace names may contain only A-Z, a-z, 0-9, '-', '_' and '.' + + Args: + string: unsanitized workspace string + Returns: + a valid workspace string + """ + + result = "" + for i in range(0, len(string)): + c = string[i] + if c == "@" and (not result or result[-1] == "_"): + result += "at" + if not c.isalnum() and c != "-" and c != "_" and c != ".": + c = "_" + result += c + return result + +def parse_lock(content): + return json.decode(content) + +def normalize_sri(rctx, checksum): + """Converts SRI string to a plain checksum hex. + + Args: + rctx: repository_ctx + checksum: SRI string + Returns: + normalized checksum hex + """ + checksum = checksum.split("-", 1)[1] + p = rctx.path("sri.sh") + rctx.file(p, """echo "$1" | base64 -d | xxd -p -c 10000000 | tr -d '\\n'""", executable = True) + r = rctx.execute([p, checksum]) + if r.return_code != 0: + fail("""normalize_sri failed.\nstderr: {}\nstdout: {}""".format(r.stdout, r.stderr)) + return r.stdout + +# TODO: this shouldn't be necessary in the first place. change apko so that it except to find the original apk in the cache +def concatenate_gzip_segments(rctx, output, signature, control, data): + """concatenates gzip segments into one gzip file in signature, control, data order + + Args: + rctx: repository_ctx + output: final output path + signature: path to the signature segment + control: path to the control segment + data: path to the data segment + Returns: + None + """ + p = rctx.path("gzip_seg.sh") + rctx.file(p, """cat $2 $3 $4 > $1""", executable = True) + r = rctx.execute([p, output, signature, control, data]) + if r.return_code != 0: + fail("""concatenate_gzip_segments failed.\nstderr: {}\nstdout: {}""".format(r.stdout, r.stderr)) diff --git a/apko/private/versions.bzl b/apko/private/versions.bzl new file mode 100644 index 0000000..4024c17 --- /dev/null +++ b/apko/private/versions.bzl @@ -0,0 +1,13 @@ +"""Mirror of release info""" + +# Add new versions by running +# ./scripts/mirror_apko.sh +APKO_VERSIONS = { + "v0.0.0": { + "darwin_amd64": "sha256-z/wJ7ZAFRoEIOCNvCLd4XnKAb8R4jvG8P7d835ZvckQ=", + "darwin_arm64": "sha256-kCZoMpop4VVPiFVJJVVheL1aWWmBO11u3LiULmcT93o=", + "linux_386": "sha256-Uk7+nsjviVFFSLOHue8Us1mTnBvTFoEj8QVtFUriypI=", + "linux_amd64": "sha256-5HYEVTVbWO+Mkjse9Fphkm2EmwT5lraf3BCTFku7Wvg=", + "linux_arm64": "sha256-bjdZPrwmNOtqM/4BIMHae6qPnXXUiywftbYeVxeHWpk=", + }, +} diff --git a/mylang/repositories.bzl b/apko/repositories.bzl similarity index 56% rename from mylang/repositories.bzl rename to apko/repositories.bzl index 268fdfb..a8af882 100644 --- a/mylang/repositories.bzl +++ b/apko/repositories.bzl @@ -6,8 +6,10 @@ See https://docs.bazel.build/versions/main/skylark/deploying.html#dependencies load("@bazel_tools//tools/build_defs/repo:http.bzl", _http_archive = "http_archive") load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") -load("//mylang/private:toolchains_repo.bzl", "PLATFORMS", "toolchains_repo") -load("//mylang/private:versions.bzl", "TOOL_VERSIONS") +load("//apko/private:toolchains_repo.bzl", "PLATFORMS", "toolchains_repo") +load("//apko/private:versions.bzl", "APKO_VERSIONS") + +LATEST_APKO_VERSION = APKO_VERSIONS.keys()[0] def http_archive(name, **kwargs): maybe(_http_archive, name = name, **kwargs) @@ -19,7 +21,7 @@ def http_archive(name, **kwargs): # changes in this function should be marked as BREAKING in the commit message # and released only in semver majors. # This is all fixed by bzlmod, so we just tolerate it for now. -def rules_mylang_dependencies(): +def rules_apko_dependencies(): # The minimal version of bazel_skylib we require http_archive( name = "bazel_skylib", @@ -30,63 +32,75 @@ def rules_mylang_dependencies(): ], ) + http_archive( + name = "aspect_bazel_lib", + sha256 = "09b51a9957adc56c905a2c980d6eb06f04beb1d85c665b467f659871403cf423", + strip_prefix = "bazel-lib-1.34.5", + url = "https://github.com/aspect-build/bazel-lib/releases/download/v1.34.5/bazel-lib-v1.34.5.tar.gz", + ) + ######## # Remaining content of the file is only used to support toolchains. ######## -_DOC = "Fetch external tools needed for mylang toolchain" +_DOC = "Fetch external tools needed for apko toolchain" _ATTRS = { - "mylang_version": attr.string(mandatory = True, values = TOOL_VERSIONS.keys()), + "apko_version": attr.string(mandatory = True, values = APKO_VERSIONS.keys()), "platform": attr.string(mandatory = True, values = PLATFORMS.keys()), } -def _mylang_repo_impl(repository_ctx): - url = "https://github.com/someorg/someproject/releases/download/v{0}/mylang-{1}.zip".format( - repository_ctx.attr.mylang_version, - repository_ctx.attr.platform, +def _apko_repo_impl(repository_ctx): + url = "https://github.com/thesayyn/apko/releases/download/v{version}/apko_{version}_{platform}.tar.gz".format( + version = repository_ctx.attr.apko_version.lstrip("v"), + platform = repository_ctx.attr.platform, ) repository_ctx.download_and_extract( + integrity = APKO_VERSIONS[repository_ctx.attr.apko_version][repository_ctx.attr.platform], + stripPrefix = "apko_{}_{}".format( + repository_ctx.attr.apko_version.lstrip("v"), + repository_ctx.attr.platform, + ), url = url, - integrity = TOOL_VERSIONS[repository_ctx.attr.mylang_version][repository_ctx.attr.platform], ) - build_content = """#Generated by mylang/repositories.bzl -load("@com_myorg_rules_mylang//mylang:toolchain.bzl", "mylang_toolchain") -mylang_toolchain(name = "mylang_toolchain", target_tool = select({ - "@bazel_tools//src/conditions:host_windows": "mylang_tool.exe", - "//conditions:default": "mylang_tool", - }), + repository_ctx.file( + "BUILD.bazel", + """\ +# Generated by apko/repositories.bzl +load("@rules_apko//apko:toolchain.bzl", "apko_toolchain") +apko_toolchain( + name = "apko_toolchain", + # After https://github.com/chainguard-dev/apko/issues/827 is fixed, + # this may need to be conditional so it's "apko.exe" on Windows. + apko = "apko" ) -""" - - # Base BUILD file for this repository - repository_ctx.file("BUILD.bazel", build_content) +""", + ) -mylang_repositories = repository_rule( - _mylang_repo_impl, +apko_repositories = repository_rule( + _apko_repo_impl, doc = _DOC, attrs = _ATTRS, ) # Wrapper macro around everything above, this is the primary API -def mylang_register_toolchains(name, register = True, **kwargs): +def apko_register_toolchains(name, apko_version = LATEST_APKO_VERSION, register = True): """Convenience macro for users which does typical setup. - - create a repository for each built-in platform like "mylang_linux_amd64" - + - create a repository for each built-in platform like "apko_linux_amd64" - this repository is lazily fetched when node is needed for that platform. - - TODO: create a convenience repository for the host platform like "mylang_host" - - create a repository exposing toolchains for each platform like "mylang_platforms" + - create a repository exposing toolchains for each platform like "apko_platforms" - register a toolchain pointing at each platform Users can avoid this macro and do these steps themselves, if they want more control. Args: - name: base name for all created repos, like "mylang1_14" + name: base name for all created repos, like "apko1_14" register: whether to call through to native.register_toolchains. Should be True for WORKSPACE users, but false when used under bzlmod extension - **kwargs: passed to each node_repositories call + apko_version: version of apko """ for platform in PLATFORMS.keys(): - mylang_repositories( + apko_repositories( name = name + "_" + platform, platform = platform, - **kwargs + apko_version = apko_version, ) if register: native.register_toolchains("@%s_toolchains//:%s_toolchain" % (name, platform)) diff --git a/mylang/tests/BUILD.bazel b/apko/tests/BUILD.bazel similarity index 100% rename from mylang/tests/BUILD.bazel rename to apko/tests/BUILD.bazel diff --git a/mylang/tests/versions_test.bzl b/apko/tests/versions_test.bzl similarity index 81% rename from mylang/tests/versions_test.bzl rename to apko/tests/versions_test.bzl index 7a9a988..d361a70 100644 --- a/mylang/tests/versions_test.bzl +++ b/apko/tests/versions_test.bzl @@ -3,11 +3,11 @@ See https://bazel.build/rules/testing#testing-starlark-utilities """ load("@bazel_skylib//lib:unittest.bzl", "asserts", "unittest") -load("//mylang/private:versions.bzl", "TOOL_VERSIONS") +load("//apko/private:versions.bzl", "APKO_VERSIONS") def _smoke_test_impl(ctx): env = unittest.begin(ctx) - asserts.equals(env, "1.14.2", TOOL_VERSIONS.keys()[0]) + asserts.equals(env, "v0.0.0", APKO_VERSIONS.keys()[0]) return unittest.end(env) # The unittest library requires that we export the test cases as named test rules, diff --git a/apko/toolchain.bzl b/apko/toolchain.bzl new file mode 100644 index 0000000..f255a8c --- /dev/null +++ b/apko/toolchain.bzl @@ -0,0 +1,43 @@ +"""This module implements the language-specific toolchain rule.""" + +ApkoInfo = provider( + doc = "Information about how to invoke the apko executable.", + fields = { + "binary": "Path to an apko binary", + }, +) + +def _apko_toolchain_impl(ctx): + binary = ctx.executable.apko + template_variables = platform_common.TemplateVariableInfo({ + "APKO_BIN": binary.path, + }) + default = DefaultInfo( + files = depset([binary]), + runfiles = ctx.runfiles(files = [binary]), + ) + apko_info = ApkoInfo(binary = binary) + toolchain_info = platform_common.ToolchainInfo( + apko_info = apko_info, + template_variables = template_variables, + default = default, + ) + return [ + default, + toolchain_info, + template_variables, + ] + +apko_toolchain = rule( + implementation = _apko_toolchain_impl, + attrs = { + "apko": attr.label( + doc = "A hermetically downloaded executable target for the target platform.", + mandatory = True, + allow_single_file = True, + executable = True, + cfg = "exec", + ), + }, + doc = "Defines an apko toolchain. See: https://docs.bazel.build/versions/main/toolchains.html#defining-toolchains.", +) diff --git a/apko/translate_lock.bzl b/apko/translate_lock.bzl new file mode 100644 index 0000000..47ff6ae --- /dev/null +++ b/apko/translate_lock.bzl @@ -0,0 +1,113 @@ +"""Repository rules for translating apko.lock.json""" + +load("//apko/private:util.bzl", "parse_lock", "sanitize_string") + +BUILD_TMPL = """\ +# Generated by apko_translate_lock. DO NOT EDIT. +filegroup( + name = "packages", + srcs = {targets}, + visibility = ["//visibility:public"] +) +""" + +REPO_TMPL = """\ +# Generated by apko_translate_lock. DO NOT EDIT. + +load("@rules_apko//apko/private:apk.bzl", "apk_import", "apk_repository", "apk_keyring") + +def apko_repositories(): +{} +""" + +APK_IMPORT_TMPL = """\ + apk_import( + name = "{name}", + package_name = "{package_name}", + version = "{version}", + architecture = "{architecture}", + url ="{url}", + signature_range = "{signature_range}", + signature_checksum = "{signature_checksum}", + control_range = "{control_range}", + control_checksum = "{control_checksum}", + data_range = "{data_range}", + data_checksum = "{data_checksum}", + ) +""" + +APK_REPOSITORY_TMPL = """\ + apk_repository( + name = "{name}", + url = "{url}", + architecture = "{architecture}", + ) +""" + +APK_KEYRING_TMPL = """\ + apk_keyring( + name = "{name}", + url = "{url}" + ) +""" + +def _translate_apko_lock_impl(rctx): + lock_file = parse_lock(rctx.read(rctx.attr.lock)) + targets = [] + defs = [] + + target_name = rctx.attr.target_name if rctx.attr.target_name else rctx.name + + if "keyring" in lock_file["contents"]: + for keyring in lock_file["contents"]["keyring"]: + name = sanitize_string("{}_{}".format(target_name, keyring["name"])) + targets.append("@{}//:keyring".format(name)) + defs.append(APK_KEYRING_TMPL.format( + name = name, + url = keyring["url"], + )) + + for package in lock_file["contents"]["packages"]: + name = sanitize_string("{}_{}_{}_{}".format(target_name, package["name"], package["architecture"], package["version"])) + targets.append("@{}//:all".format(name)) + + defs.append(APK_IMPORT_TMPL.format( + name = name, + package_name = package["name"], + version = package["version"], + architecture = package["architecture"], + url = package["url"], + signature_range = package["signature"]["range"], + signature_checksum = package["signature"]["checksum"], + control_range = package["control"]["range"], + control_checksum = package["control"]["checksum"], + data_range = package["data"]["range"], + data_checksum = package["data"]["checksum"], + )) + + for repository in lock_file["contents"]["repositories"]: + name = sanitize_string("{}_{}_{}".format(target_name, repository["name"], repository["architecture"])) + targets.append("@{}//:index".format(name)) + defs.append(APK_REPOSITORY_TMPL.format( + name = name, + url = repository["url"], + architecture = repository["architecture"], + )) + + rctx.file( + "repositories.bzl", + REPO_TMPL.format("\n".join(defs)), + ) + + rctx.file( + "BUILD.bazel", + BUILD_TMPL.format(targets = targets), + ) + +translate_apko_lock = repository_rule( + implementation = _translate_apko_lock_impl, + attrs = { + "lock": attr.label(mandatory = True), + "target_name": attr.string(doc = "internal"), + }, +) diff --git a/docs/BUILD.bazel b/docs/BUILD.bazel index 99c2ed5..49e147b 100644 --- a/docs/BUILD.bazel +++ b/docs/BUILD.bazel @@ -4,7 +4,7 @@ load("@aspect_bazel_lib//lib:docs.bzl", "stardoc_with_diff_test", "update_docs") stardoc_with_diff_test( name = "rules", - bzl_library_target = "//mylang:defs", + bzl_library_target = "//apko:defs", ) update_docs(name = "update") diff --git a/docs/initial-setup.md b/docs/initial-setup.md new file mode 100644 index 0000000..bd77a25 --- /dev/null +++ b/docs/initial-setup.md @@ -0,0 +1,24 @@ +# Initial setup + +rules_apko requires a one-time setup to configure bazel to be able to make partial fetches. + +Paste this into your root BUILD file + +```py +load("@rules_apko//apko:defs.bzl", "apko_bazelrc") + +apko_bazelrc() +``` + +Then run + +```sh +bazel run @@//:apko_bazelrc +``` + +And finally paste this into your preferred \`.bazelrc\` file, + +```sh +# Required for rules_apko to make range requests +try-import %workspace%/.apko/.bazelrc +``` \ No newline at end of file diff --git a/docs/rules.md b/docs/rules.md index 3a4dda3..09f09f2 100644 --- a/docs/rules.md +++ b/docs/rules.md @@ -2,15 +2,43 @@ Public API re-exports - + -## example +## apko_image
-example()
+apko_image(name, config, packages, tag)
 
-This is an example +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| config | - | Label | required | | +| packages | - | Label | optional | None | +| tag | - | String | required | | + + + + +## apko_bazelrc + +
+apko_bazelrc(name, kwargs)
+
+ + + +**PARAMETERS** + + +| Name | Description | Default Value | +| :------------- | :------------- | :------------- | +| name |

-

| "apko_bazelrc" | +| kwargs |

-

| none | + diff --git a/e2e/smoke/.apko/.bazelrc b/e2e/smoke/.apko/.bazelrc new file mode 100755 index 0000000..f6bce6a --- /dev/null +++ b/e2e/smoke/.apko/.bazelrc @@ -0,0 +1,6 @@ +# Generated by apko_bazelrc. DO NOT EDIT +# Required for range requests for fetching the apk packages. +# https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests +# Use https://www.base64decode.org/ to see what this base64 encoded command does. + +common --credential_helper="%workspace%/.apko/range.sh" diff --git a/e2e/smoke/.apko/range.sh b/e2e/smoke/.apko/range.sh new file mode 100755 index 0000000..6835404 --- /dev/null +++ b/e2e/smoke/.apko/range.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +echo -n '{"headers":{"Range":[' +cat | sed -n 's/.*#_apk_range_bytes_\([[:digit:]]*-[[:digit:]]*\).*/"bytes=\1"/p' | tr -d '\n' +echo ']}}' diff --git a/e2e/smoke/.bazelrc b/e2e/smoke/.bazelrc index e69de29..14cd0b8 100644 --- a/e2e/smoke/.bazelrc +++ b/e2e/smoke/.bazelrc @@ -0,0 +1,3 @@ +# Required for rules_apko to make range requests +try-import %workspace%/.apko/.bazelrc + diff --git a/e2e/smoke/BUILD b/e2e/smoke/BUILD index 4b61534..3aa4549 100644 --- a/e2e/smoke/BUILD +++ b/e2e/smoke/BUILD @@ -1,17 +1,20 @@ -"""Provides a simple way to test your rules as an external workspace. -Add a basic smoke-test target below. -""" +"""Provides a simple way to test your rules as an external workspace.""" +load("@rules_apko//apko:defs.bzl", "apko_bazelrc", "apko_image") load("@bazel_skylib//rules:build_test.bzl", "build_test") -# load("com_myorg_rules_mylang//mylang:defs.bzl", "...") -# Replace with a usage of your rule/macro -filegroup(name = "empty") +apko_bazelrc() + +apko_image( + name = "lock", + config = "apko.yaml", + packages = "@example_lock//:packages", + tag = "lock:latest", +) build_test( - name = "smoke_test", + name = "test", targets = [ - # targets you add above - ":empty", + ":lock", ], ) diff --git a/e2e/smoke/MODULE.bazel b/e2e/smoke/MODULE.bazel index 6095b79..d056979 100644 --- a/e2e/smoke/MODULE.bazel +++ b/e2e/smoke/MODULE.bazel @@ -1,7 +1,18 @@ -bazel_dep(name = "com_myorg_rules_mylang", version = "0.0.0", dev_dependency = True) +bazel_dep(name = "rules_apko", version = "0.0.0", dev_dependency = True) bazel_dep(name = "bazel_skylib", version = "1.3.0", dev_dependency = True) local_path_override( - module_name = "com_myorg_rules_mylang", + module_name = "rules_apko", path = "../..", ) + +apko = use_extension( + "@rules_apko//apko:extensions.bzl", + "apko", + dev_dependency = True, +) +apko.translate_lock( + name = "example_lock", + lock = "//:apko.lock.json", +) +use_repo(apko, "example_lock") diff --git a/e2e/smoke/README.md b/e2e/smoke/README.md index 3135480..0061b7f 100644 --- a/e2e/smoke/README.md +++ b/e2e/smoke/README.md @@ -1,5 +1,5 @@ # smoke test This e2e exercises the repo from an end-users perpective. -It catches mistakes in our install instructions, or usages that fail when called from an "external" repository to rules_mylang. +It catches mistakes in our install instructions, or usages that fail when called from an "external" repository to rules_apko. It is also used by the presubmit check for the Bazel Central Registry. diff --git a/e2e/smoke/WORKSPACE.bazel b/e2e/smoke/WORKSPACE.bazel index e487105..b907b34 100644 --- a/e2e/smoke/WORKSPACE.bazel +++ b/e2e/smoke/WORKSPACE.bazel @@ -1,19 +1,32 @@ # Override http_archive for local testing local_repository( - name = "com_myorg_rules_mylang", + name = "rules_apko", path = "../..", ) #---SNIP--- Below here is re-used in the workspace snippet published on releases ###################### -# rules_mylang setup # +# rules_apko setup # ###################### -# Fetches the rules_mylang dependencies. +# Fetches the rules_apko dependencies. # If you want to have a different version of some dependency, # you should fetch it *before* calling this. # Alternatively, you can skip calling this function, so long as you've # already fetched all the dependencies. -load("@com_myorg_rules_mylang//mylang:repositories.bzl", "rules_mylang_dependencies") +load("@rules_apko//apko:repositories.bzl", "apko_register_toolchains", "rules_apko_dependencies") -rules_mylang_dependencies() +rules_apko_dependencies() + +apko_register_toolchains(name = "apko") + +load("@rules_apko//apko:translate_lock.bzl", "translate_apko_lock") + +translate_apko_lock( + name = "example_lock", + lock = "@//:apko.lock.json", +) + +load("@example_lock//:repositories.bzl", "apko_repositories") + +apko_repositories() diff --git a/e2e/smoke/apko.lock.json b/e2e/smoke/apko.lock.json new file mode 100644 index 0000000..518616a --- /dev/null +++ b/e2e/smoke/apko.lock.json @@ -0,0 +1,50 @@ +{ + "version": "6", + "contents": { + "repositories": [ + { + "name": "dl-cdn.alpinelinux.org/alpine/edge/main", + "url": "https://dl-cdn.alpinelinux.org/alpine/edge/main/x86_64/APKINDEX.tar.gz", + "architecture": "x86_64" + } + ], + "packages": [ + { + "name": "busybox", + "version": "1.36.1-r7", + "architecture": "x86_64", + "url": "https://dl-cdn.alpinelinux.org/alpine/edge/main/x86_64/busybox-1.36.1-r7.apk", + "signature": { + "range": "bytes=0-665", + "checksum": "sha256-Le6OL4LQva/QGvQuULa5inTSDG7Gmvv/QO+8Mfzy8KA=" + }, + "control": { + "range": "bytes=666-2298", + "checksum": "sha1-DD+ZCO6gahU3mrx5xtm9/b8luHw=" + }, + "data": { + "range": "bytes=2299-", + "checksum": "sha256-SWbMW79a/YQeH0lX7KQI8lXCSHV8VJ/vy+PZ21fdd80=" + } + }, + { + "name": "musl", + "version": "1.2.4_git20230717-r2", + "architecture": "x86_64", + "url": "https://dl-cdn.alpinelinux.org/alpine/edge/main/x86_64/musl-1.2.4_git20230717-r2.apk", + "signature": { + "range": "bytes=0-663", + "checksum": "sha256-MGQuPl32VeejCb03Emx+QRAWd+4eZGojgo32yKJubws=" + }, + "control": { + "range": "bytes=664-1230", + "checksum": "sha1-0QcZQhy2GxzaRF4Kip4NVG0pgrc=" + }, + "data": { + "range": "bytes=1231-", + "checksum": "sha256-BEDUjs8id32t4l9xhzFKSVDrEOOuxHeKIAjyg/cmIE8=" + } + } + ] + } +} diff --git a/e2e/smoke/apko.yaml b/e2e/smoke/apko.yaml new file mode 100644 index 0000000..9474f98 --- /dev/null +++ b/e2e/smoke/apko.yaml @@ -0,0 +1,22 @@ +contents: + repositories: + - https://dl-cdn.alpinelinux.org/alpine/edge/main + packages: + - busybox + +# optional environment configuration +environment: + PATH: /usr/sbin:/sbin:/usr/bin:/bin + +cmd: /bin/sh -l + +# data for /etc/os-release if it does not already exist +# in the image +os-release: + id: alpine + version-id: "3.16.0" + name: "Alpine Slim" + pretty-name: "Alpine Slim (apko)" + +archs: + - amd64 diff --git a/examples/lock/BUILD.bazel b/examples/lock/BUILD.bazel new file mode 100644 index 0000000..f6b22b8 --- /dev/null +++ b/examples/lock/BUILD.bazel @@ -0,0 +1,16 @@ +load("@rules_apko//apko:defs.bzl", "apko_image") +load("@bazel_skylib//rules:build_test.bzl", "build_test") + +apko_image( + name = "lock", + config = "apko.yaml", + packages = "@examples_lock//:packages", + tag = "lock:latest", +) + +build_test( + name = "test", + targets = [ + ":lock", + ], +) diff --git a/examples/lock/apko.lock.json b/examples/lock/apko.lock.json new file mode 100644 index 0000000..518616a --- /dev/null +++ b/examples/lock/apko.lock.json @@ -0,0 +1,50 @@ +{ + "version": "6", + "contents": { + "repositories": [ + { + "name": "dl-cdn.alpinelinux.org/alpine/edge/main", + "url": "https://dl-cdn.alpinelinux.org/alpine/edge/main/x86_64/APKINDEX.tar.gz", + "architecture": "x86_64" + } + ], + "packages": [ + { + "name": "busybox", + "version": "1.36.1-r7", + "architecture": "x86_64", + "url": "https://dl-cdn.alpinelinux.org/alpine/edge/main/x86_64/busybox-1.36.1-r7.apk", + "signature": { + "range": "bytes=0-665", + "checksum": "sha256-Le6OL4LQva/QGvQuULa5inTSDG7Gmvv/QO+8Mfzy8KA=" + }, + "control": { + "range": "bytes=666-2298", + "checksum": "sha1-DD+ZCO6gahU3mrx5xtm9/b8luHw=" + }, + "data": { + "range": "bytes=2299-", + "checksum": "sha256-SWbMW79a/YQeH0lX7KQI8lXCSHV8VJ/vy+PZ21fdd80=" + } + }, + { + "name": "musl", + "version": "1.2.4_git20230717-r2", + "architecture": "x86_64", + "url": "https://dl-cdn.alpinelinux.org/alpine/edge/main/x86_64/musl-1.2.4_git20230717-r2.apk", + "signature": { + "range": "bytes=0-663", + "checksum": "sha256-MGQuPl32VeejCb03Emx+QRAWd+4eZGojgo32yKJubws=" + }, + "control": { + "range": "bytes=664-1230", + "checksum": "sha1-0QcZQhy2GxzaRF4Kip4NVG0pgrc=" + }, + "data": { + "range": "bytes=1231-", + "checksum": "sha256-BEDUjs8id32t4l9xhzFKSVDrEOOuxHeKIAjyg/cmIE8=" + } + } + ] + } +} diff --git a/examples/lock/apko.yaml b/examples/lock/apko.yaml new file mode 100644 index 0000000..e893739 --- /dev/null +++ b/examples/lock/apko.yaml @@ -0,0 +1,24 @@ +contents: + repositories: + - https://dl-cdn.alpinelinux.org/alpine/edge/main + packages: + - busybox + + +# optional environment configuration +environment: + PATH: /usr/sbin:/sbin:/usr/bin:/bin + +cmd: /bin/sh -l + +# data for /etc/os-release if it does not already exist +# in the image +os-release: + id: alpine + version-id: '3.16.0' + name: 'Alpine Slim' + pretty-name: 'Alpine Slim (apko)' + +archs: + - amd64 + \ No newline at end of file diff --git a/examples/simple/BUILD.bazel b/examples/simple/BUILD.bazel new file mode 100644 index 0000000..8d9ed76 --- /dev/null +++ b/examples/simple/BUILD.bazel @@ -0,0 +1,17 @@ +load("@aspect_bazel_lib//lib:testing.bzl", "assert_contains") + +############# +# Use case 1: simply call apko from a genrule +genrule( + name = "gen_apko", + srcs = [], + outs = ["help.txt"], + cmd = "$(APKO_BIN) --help > $@", + toolchains = ["@rules_apko//apko:resolved_toolchain"], +) + +assert_contains( + name = "test_apko_genrule", + actual = "help.txt", + expected = "Build an image from a YAML configuration file", +) diff --git a/examples/wolfi-base/BUILD.bazel b/examples/wolfi-base/BUILD.bazel new file mode 100644 index 0000000..73030a9 --- /dev/null +++ b/examples/wolfi-base/BUILD.bazel @@ -0,0 +1,16 @@ +load("@rules_apko//apko:defs.bzl", "apko_image") +load("@bazel_skylib//rules:build_test.bzl", "build_test") + +apko_image( + name = "wolfi-base", + config = "apko.yaml", + packages = "@examples_wolfi_base//:packages", + tag = "wolfi:latest", +) + +build_test( + name = "test", + targets = [ + ":wolfi-base", + ], +) diff --git a/examples/wolfi-base/apko.lock.json b/examples/wolfi-base/apko.lock.json new file mode 100644 index 0000000..057fc68 --- /dev/null +++ b/examples/wolfi-base/apko.lock.json @@ -0,0 +1,272 @@ +{ + "version": "6", + "contents": { + "keyring": [ + { + "name": "packages.wolfi.dev/os", + "url": "https://packages.wolfi.dev/os/wolfi-signing.rsa.pub" + } + ], + "repositories": [ + { + "name": "packages.wolfi.dev/os/x86_64", + "url": "https://packages.wolfi.dev/os/x86_64/APKINDEX.tar.gz", + "architecture": "x86_64" + } + ], + "packages": [ + { + "name": "ca-certificates-bundle", + "version": "20230506-r0", + "architecture": "x86_64", + "url": "https://packages.wolfi.dev/os/x86_64/ca-certificates-bundle-20230506-r0.apk", + "signature": { + "range": "bytes=0-649", + "checksum": "sha256-h1Wj2FAjSIS61Pn3wT+N8ocmh6LCySY4XTEfzP7auOA=" + }, + "control": { + "range": "bytes=650-966", + "checksum": "sha1-/YGo3iUSdyF2/rk3tKR6MhtUEzg=" + }, + "data": { + "range": "bytes=967-", + "checksum": "sha256-7neBVl819zb1HiRNaW8Ze6E1SPTrvfxytQyCdRTbUrg=" + } + }, + { + "name": "libssl3", + "version": "3.1.2-r0", + "architecture": "x86_64", + "url": "https://packages.wolfi.dev/os/x86_64/libssl3-3.1.2-r0.apk", + "signature": { + "range": "bytes=0-696", + "checksum": "sha256-pX4BktfhuPJYz/naNQ+/bLX2rLsD8qcZGlJ3/xa+AtA=" + }, + "control": { + "range": "bytes=697-1067", + "checksum": "sha1-KxOTEVLsjDakMA3X+/dunv1sbVw=" + }, + "data": { + "range": "bytes=1068-", + "checksum": "sha256-fRE+SmXiIHBUcd7sg5aBTaZA0HIVCRTHi6BedDD/mBc=" + } + }, + { + "name": "glibc-locale-posix", + "version": "2.38-r1", + "architecture": "x86_64", + "url": "https://packages.wolfi.dev/os/x86_64/glibc-locale-posix-2.38-r1.apk", + "signature": { + "range": "bytes=0-692", + "checksum": "sha256-7xRf327HLB/5Nl+lJ2td3vybte3tGHVVQj1Ha4DCAGE=" + }, + "control": { + "range": "bytes=693-1036", + "checksum": "sha1-t3B1UtIKvydFltjFBTSIz95M4Uc=" + }, + "data": { + "range": "bytes=1037-", + "checksum": "sha256-J+O1VFBKcu9xm/wcXgJGPqJv+8sq3IbnCE2xvRMGZ8c=" + } + }, + { + "name": "apk-tools", + "version": "2.14.0-r0", + "architecture": "x86_64", + "url": "https://packages.wolfi.dev/os/x86_64/apk-tools-2.14.0-r0.apk", + "signature": { + "range": "bytes=0-657", + "checksum": "sha256-2+sFpwBB0Ol/KFzvL50XbFMNInU7utN4K1nom+Nd09g=" + }, + "control": { + "range": "bytes=658-1094", + "checksum": "sha1-5lEO4JohyDLUB0MMSqVgQor2Ug8=" + }, + "data": { + "range": "bytes=1095-", + "checksum": "sha256-LJsAe8zTp0gXfPprwAs0lqnUjhG2t4ytWAQZajDu81w=" + } + }, + { + "name": "openssl-config", + "version": "3.1.2-r0", + "architecture": "x86_64", + "url": "https://packages.wolfi.dev/os/x86_64/openssl-config-3.1.2-r0.apk", + "signature": { + "range": "bytes=0-698", + "checksum": "sha256-YiJ52K616UbOcfikvivowz/nKHI6kYRx1XHoZkcmYDM=" + }, + "control": { + "range": "bytes=699-1033", + "checksum": "sha1-8YXo1izBaNRtUvASCnnJBIs4ZFY=" + }, + "data": { + "range": "bytes=1034-", + "checksum": "sha256-eiG2XDm1A9ISP/knoPU+rTnNeHwqMTHBd8kcqTGBoAI=" + } + }, + { + "name": "ld-linux", + "version": "2.38-r1", + "architecture": "x86_64", + "url": "https://packages.wolfi.dev/os/x86_64/ld-linux-2.38-r1.apk", + "signature": { + "range": "bytes=0-701", + "checksum": "sha256-AXwPY/xsVV9QG4+a0Z3TAEABNSIvspfyIQWUXASVa/o=" + }, + "control": { + "range": "bytes=702-1085", + "checksum": "sha1-mLP2PhJnwuy+X9e40BkWRGoNpz8=" + }, + "data": { + "range": "bytes=1086-", + "checksum": "sha256-QlwNddHxbCE/HIligvH5ajs5f66QA6IhO1252X/Bsjg=" + } + }, + { + "name": "glibc", + "version": "2.38-r1", + "architecture": "x86_64", + "url": "https://packages.wolfi.dev/os/x86_64/glibc-2.38-r1.apk", + "signature": { + "range": "bytes=0-696", + "checksum": "sha256-d4+OPb4mx0sTLwm96slBXDhnHqJx64LuuZb1cAduZiw=" + }, + "control": { + "range": "bytes=697-1304", + "checksum": "sha1-ZmAI/Ykd1R9bcT1s82L3SPJhOEA=" + }, + "data": { + "range": "bytes=1305-", + "checksum": "sha256-6Zet8FU0YNkt8puM+YQk9F3nKs8Zs1pBUMNtukApAJ4=" + } + }, + { + "name": "wolfi-baselayout", + "version": "20230201-r6", + "architecture": "x86_64", + "url": "https://packages.wolfi.dev/os/x86_64/wolfi-baselayout-20230201-r6.apk", + "signature": { + "range": "bytes=0-700", + "checksum": "sha256-voGHae+yd9WCX8oSdhNhu02HBWp1RpgyPOCmV/YQU6A=" + }, + "control": { + "range": "bytes=701-1049", + "checksum": "sha1-7VhAhkjHFu8hi9j6VPHxlOX95sc=" + }, + "data": { + "range": "bytes=1050-", + "checksum": "sha256-E1YOC4cEwiNxueSte+3mQzPSxBGuAE7D89R3E7gVxYQ=" + } + }, + { + "name": "libcrypto3", + "version": "3.1.2-r0", + "architecture": "x86_64", + "url": "https://packages.wolfi.dev/os/x86_64/libcrypto3-3.1.2-r0.apk", + "signature": { + "range": "bytes=0-700", + "checksum": "sha256-pgX/AzJPCwbLImhK+AM1sAxuj10BDxeA4z1D3PyW5B8=" + }, + "control": { + "range": "bytes=701-1074", + "checksum": "sha1-ZEp23bIVsI2yn1PD2I5al1BecY4=" + }, + "data": { + "range": "bytes=1075-", + "checksum": "sha256-Ettey6//lpLf4X70l/LpSVi8rt8LaZw1qGvL/j3yAsc=" + } + }, + { + "name": "zlib", + "version": "1.3-r0", + "architecture": "x86_64", + "url": "https://packages.wolfi.dev/os/x86_64/zlib-1.3-r0.apk", + "signature": { + "range": "bytes=0-694", + "checksum": "sha256-gW3pGEhnMfw9XSw6IOM+XeeRaSJroOqkUiCXyPscp3g=" + }, + "control": { + "range": "bytes=695-1078", + "checksum": "sha1-2c/3NY/o7FDtGM4k93d8nDACYWk=" + }, + "data": { + "range": "bytes=1079-", + "checksum": "sha256-ZwQMNfeiOo2duE+cxSybjb283bIAphOkpJgXFEXtW7g=" + } + }, + { + "name": "libcrypt1", + "version": "2.38-r1", + "architecture": "x86_64", + "url": "https://packages.wolfi.dev/os/x86_64/libcrypt1-2.38-r1.apk", + "signature": { + "range": "bytes=0-693", + "checksum": "sha256-HZh2U9316Uxsyl1CoFF4vNd8PJCKjA1zzSnRGEoprJM=" + }, + "control": { + "range": "bytes=694-1070", + "checksum": "sha1-DwdoqPBygzIvrTNKsyOy09wnRmQ=" + }, + "data": { + "range": "bytes=1071-", + "checksum": "sha256-p9RviAkWnEBtTIm5Ho0T3JwdbpPlN/CkDdOi604pJ90=" + } + }, + { + "name": "busybox", + "version": "1.36.1-r2", + "architecture": "x86_64", + "url": "https://packages.wolfi.dev/os/x86_64/busybox-1.36.1-r2.apk", + "signature": { + "range": "bytes=0-660", + "checksum": "sha256-JpKU0Hf2BDujBVfwhLGGNgNyvPYtA/tMzzCZCnRc120=" + }, + "control": { + "range": "bytes=661-1153", + "checksum": "sha1-d2kYe9D3/7EJ+b9C6YkKqlSsU/M=" + }, + "data": { + "range": "bytes=1154-", + "checksum": "sha256-/ZVBynpsT9iBHekkLAf59csVhMBwoKyjLnjF53u2cIE=" + } + }, + { + "name": "wolfi-keys", + "version": "1-r5", + "architecture": "x86_64", + "url": "https://packages.wolfi.dev/os/x86_64/wolfi-keys-1-r5.apk", + "signature": { + "range": "bytes=0-648", + "checksum": "sha256-avYaa1hJQ/CoUqQOxxaM36C7X93zg8JiGjUcCYkefeA=" + }, + "control": { + "range": "bytes=649-957", + "checksum": "sha1-0fpy9hX9x84izBkTlUFtNXLEeqk=" + }, + "data": { + "range": "bytes=958-", + "checksum": "sha256-33hX1bPb8tpZMsxDs8sUQchU8T7ptX3dpgoJd6GSZqo=" + } + }, + { + "name": "wolfi-base", + "version": "1-r3", + "architecture": "x86_64", + "url": "https://packages.wolfi.dev/os/x86_64/wolfi-base-1-r3.apk", + "signature": { + "range": "bytes=0-649", + "checksum": "sha256-norCSxfvICp4g+SZfOlti5CGOorNXdiRcOtTW/XcMYw=" + }, + "control": { + "range": "bytes=650-983", + "checksum": "sha1-LrzTxq5MubwvQY3xCuDnXVIGJek=" + }, + "data": { + "range": "bytes=984-", + "checksum": "sha256-ZBy+EmJUZ0VgbBysw6eCtifGF++Gvf+36StxdJqhU7E=" + } + } + ] + } +} diff --git a/examples/wolfi-base/apko.yaml b/examples/wolfi-base/apko.yaml new file mode 100644 index 0000000..29c1dc9 --- /dev/null +++ b/examples/wolfi-base/apko.yaml @@ -0,0 +1,12 @@ +contents: + keyring: + - https://packages.wolfi.dev/os/wolfi-signing.rsa.pub + repositories: + - https://packages.wolfi.dev/os + packages: + - wolfi-base + +cmd: /bin/sh -l + +archs: + - x86_64 diff --git a/mylang/defs.bzl b/mylang/defs.bzl deleted file mode 100644 index b48c6fc..0000000 --- a/mylang/defs.bzl +++ /dev/null @@ -1,5 +0,0 @@ -"Public API re-exports" - -def example(): - """This is an example""" - pass diff --git a/mylang/extensions.bzl b/mylang/extensions.bzl deleted file mode 100644 index e2ae7d0..0000000 --- a/mylang/extensions.bzl +++ /dev/null @@ -1,56 +0,0 @@ -"""Extensions for bzlmod. - -Installs a mylang toolchain. -Every module can define a toolchain version under the default name, "mylang". -The latest of those versions will be selected (the rest discarded), -and will always be registered by rules_mylang. - -Additionally, the root module can define arbitrarily many more toolchain versions under different -names (the latest version will be picked for each name) and can register them as it sees fit, -effectively overriding the default named toolchain due to toolchain resolution precedence. -""" - -load(":repositories.bzl", "mylang_register_toolchains") - -_DEFAULT_NAME = "mylang" - -mylang_toolchain = tag_class(attrs = { - "name": attr.string(doc = """\ -Base name for generated repositories, allowing more than one mylang toolchain to be registered. -Overriding the default is only permitted in the root module. -""", default = _DEFAULT_NAME), - "mylang_version": attr.string(doc = "Explicit version of mylang.", mandatory = True), -}) - -def _toolchain_extension(module_ctx): - registrations = {} - for mod in module_ctx.modules: - for toolchain in mod.tags.toolchain: - if toolchain.name != _DEFAULT_NAME and not mod.is_root: - fail("""\ - Only the root module may override the default name for the mylang toolchain. - This prevents conflicting registrations in the global namespace of external repos. - """) - if toolchain.name not in registrations.keys(): - registrations[toolchain.name] = [] - registrations[toolchain.name].append(toolchain.mylang_version) - for name, versions in registrations.items(): - if len(versions) > 1: - # TODO: should be semver-aware, using MVS - selected = sorted(versions, reverse = True)[0] - - # buildifier: disable=print - print("NOTE: mylang toolchain {} has multiple versions {}, selected {}".format(name, versions, selected)) - else: - selected = versions[0] - - mylang_register_toolchains( - name = name, - mylang_version = selected, - register = False, - ) - -mylang = module_extension( - implementation = _toolchain_extension, - tag_classes = {"toolchain": mylang_toolchain}, -) diff --git a/mylang/private/BUILD.bazel b/mylang/private/BUILD.bazel deleted file mode 100644 index eb2edb6..0000000 --- a/mylang/private/BUILD.bazel +++ /dev/null @@ -1,19 +0,0 @@ -load("@bazel_skylib//:bzl_library.bzl", "bzl_library") - -bzl_library( - name = "toolchains_repo", - srcs = ["toolchains_repo.bzl"], - visibility = ["//mylang:__subpackages__"], -) - -bzl_library( - name = "versions", - srcs = ["versions.bzl"], - visibility = ["//mylang:__subpackages__"], -) - -bzl_library( - name = "resolved_toolchain", - srcs = ["resolved_toolchain.bzl"], - visibility = ["//mylang:__subpackages__"], -) diff --git a/mylang/private/versions.bzl b/mylang/private/versions.bzl deleted file mode 100644 index 7f6c5bd..0000000 --- a/mylang/private/versions.bzl +++ /dev/null @@ -1,14 +0,0 @@ -"""Mirror of release info - -TODO: generate this file from GitHub API""" - -# The integrity hashes can be computed with -# shasum -b -a 384 [downloaded file] | awk '{ print $1 }' | xxd -r -p | base64 -TOOL_VERSIONS = { - "1.14.2": { - "x86_64-apple-darwin": "sha384-ws4+rANvv0YxM1SgIBUXSG9jT8dKw83nls6R5qYkEKzPUB+viBIEozSsyq2e6i+f", - "aarch64-apple-darwin": "sha384-HcvJbxoJtGSavkGu0e7CyD00cBlmDb0TBWJ4JSaNa70zuU3N7XlMOYm3bbQcAv2U", - "x86_64-pc-windows-msvc": "sha384-35YN6TKpT0L9qyRBmq48NucvyXEtHnkeC+txf2YZmmJTmOzrAKREA74BA0EZvpar", - "x86_64-unknown-linux-gnu": "sha384-QgGOwTaetxY0h5HWCKc/3ZtBs4N/fgaaORthn7UcEv++Idm9W+ntCCZRwvBdwHPD", - }, -} diff --git a/mylang/toolchain.bzl b/mylang/toolchain.bzl deleted file mode 100644 index cfa816c..0000000 --- a/mylang/toolchain.bzl +++ /dev/null @@ -1,78 +0,0 @@ -"""This module implements the language-specific toolchain rule. -""" - -MylangInfo = provider( - doc = "Information about how to invoke the tool executable.", - fields = { - "target_tool_path": "Path to the tool executable for the target platform.", - "tool_files": """Files required in runfiles to make the tool executable available. - -May be empty if the target_tool_path points to a locally installed tool binary.""", - }, -) - -# Avoid using non-normalized paths (workspace/../other_workspace/path) -def _to_manifest_path(ctx, file): - if file.short_path.startswith("../"): - return "external/" + file.short_path[3:] - else: - return ctx.workspace_name + "/" + file.short_path - -def _mylang_toolchain_impl(ctx): - if ctx.attr.target_tool and ctx.attr.target_tool_path: - fail("Can only set one of target_tool or target_tool_path but both were set.") - if not ctx.attr.target_tool and not ctx.attr.target_tool_path: - fail("Must set one of target_tool or target_tool_path.") - - tool_files = [] - target_tool_path = ctx.attr.target_tool_path - - if ctx.attr.target_tool: - tool_files = ctx.attr.target_tool.files.to_list() - target_tool_path = _to_manifest_path(ctx, tool_files[0]) - - # Make the $(tool_BIN) variable available in places like genrules. - # See https://docs.bazel.build/versions/main/be/make-variables.html#custom_variables - template_variables = platform_common.TemplateVariableInfo({ - "MYLANG_BIN": target_tool_path, - }) - default = DefaultInfo( - files = depset(tool_files), - runfiles = ctx.runfiles(files = tool_files), - ) - mylanginfo = MylangInfo( - target_tool_path = target_tool_path, - tool_files = tool_files, - ) - - # Export all the providers inside our ToolchainInfo - # so the resolved_toolchain rule can grab and re-export them. - toolchain_info = platform_common.ToolchainInfo( - mylanginfo = mylanginfo, - template_variables = template_variables, - default = default, - ) - return [ - default, - toolchain_info, - template_variables, - ] - -mylang_toolchain = rule( - implementation = _mylang_toolchain_impl, - attrs = { - "target_tool": attr.label( - doc = "A hermetically downloaded executable target for the target platform.", - mandatory = False, - allow_single_file = True, - ), - "target_tool_path": attr.string( - doc = "Path to an existing executable for the target platform.", - mandatory = False, - ), - }, - doc = """Defines a mylang compiler/runtime toolchain. - -For usage see https://docs.bazel.build/versions/main/toolchains.html#defining-toolchains. -""", -) diff --git a/resolve-all.sh b/resolve-all.sh new file mode 100755 index 0000000..e01cce2 --- /dev/null +++ b/resolve-all.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +set -o nounset -o pipefail + + +example=$1 + +output=$(mktemp) + +while [ true ]; do + echo "" > $output + bazel build $example &> $output + if [ $? -ne 0 ]; then + required="$(cat $output | sed -n "s/.*apk\ at\ \(.*\): Get.*/\1/p" | head -1)" + if [[ -n "$required" ]]; then + echo "🥖 Found missing apk $required" + + echo "🥕 Fetching $required" + json=$(./resolve.sh $required 2>&1 > /dev/null | jq -c) + lock="$(jq --argjson package "$json" '.contents.packages |= . + [$package]' "$example/apko.lock.json")" + + echo "$lock" > "$example/apko.lock.json" + echo "👌 $required" + echo "" + else + cat "$output" + exit 1 + fi + else + echo "🥖 🙌 All good!" + exit 0 + fi + sleep 1 +done diff --git a/resolve.sh b/resolve.sh new file mode 100755 index 0000000..2814dc1 --- /dev/null +++ b/resolve.sh @@ -0,0 +1,119 @@ +#!/usr/bin/env bash +set -o errexit -o nounset -o pipefail + +apk="$TMPDIR/$(echo $1 | base64)" + +if [[ ! -f "$apk" ]]; then + curl -fsSL $1 -o $apk +fi + +streams=($(cat $apk | xxd -p -c0 | grep -b -o "1f8b" | cut -d":" -f1 | awk '{print $1/=2}' | awk '{print int($1+0.5)}')) + +function extract_section () { + local input_file=$1 + local start_offset=$2 + local end_offset=$3 + if [[ -z "${end_offset}" ]]; then + tail -c +"$((start_offset + 1))" "$input_file" + else + local length=$((end_offset - start_offset + 1)) + # Use head to skip to the start offset and tail to extract the section + head -c "$end_offset" "$input_file" | tail -c +"$((start_offset + 1))" + fi +} + + +sig_begin="${streams[0]}" +control_begin="${streams[1]}" +data_begin="${streams[2]}" +control_len=$(($data_begin-$control_begin)) + +echo "" +echo "@ sanity check" +echo "" +t=$(mktemp -t "t1") +t2=$(mktemp -t "t2") + +extract_section $apk $sig_begin $control_begin >> $t +curl -fsSL $1 -H "Range: bytes=$sig_begin-$(($control_begin-1))" >> $t2 +wc -c $t $t2 +diffoscope $t $t2 + +extract_section $apk $control_begin $data_begin >> $t +curl -fsSL $1 -H "Range: bytes=$control_begin-$(($data_begin-1))" >> $t2 +wc -c $t $t2 +diffoscope $t $t2 + +extract_section $apk $data_begin "" >> $t +curl -fsSL $1 -H "Range: bytes=$data_begin-" >> $t2 +wc -c $t $t2 +diffoscope $t $t2 + + +echo "" +echo "@ sections" +echo "" + +echo "-> sig" +echo "" +extract_section $apk $sig_begin $control_begin | tar -tf - + +echo "" +echo "-> control" +echo "" +extract_section $apk $control_begin $data_begin | tar -tf - + +echo "" +echo "-> data" +echo "" +extract_section $apk $data_begin "" | tar -tf - + + +echo "" +echo "@ gather info" +echo "" +info=$(extract_section $apk $control_begin $data_begin | tar -xOz - .PKGINFO) + +pkgname= +pkgver= +pkgarch= +sig_sig=$(extract_section $apk $sig_begin $control_begin | shasum -a 256 | cut -d '-' -f 1 | tr -d ' ' | xxd -r -p | base64) +control_sig=$(extract_section $apk $control_begin $data_begin | shasum -a 1 | cut -d '-' -f 1 | tr -d ' ' | xxd -r -p | base64) +data_sig=$(extract_section $apk $data_begin "" | shasum -a 256 | cut -d '-' -f 1 | tr -d ' ' | xxd -r -p | base64) + +while IFS=$'\n' read -r line; do + key=$(echo "$line" | cut -d '=' -f 1 | tr -d ' ') + value=$(echo "$line" | cut -d '=' -f 2 | tr -d ' ') + if [[ "$key" == "pkgname" ]]; then + pkgname="$value" + elif [[ "$key" == "pkgver" ]]; then + pkgver="$value" + elif [[ "$key" == "arch" ]]; then + pkgarch="$value" + fi +done < <(extract_section $apk $control_begin $data_begin | tar -xOz - .PKGINFO) + +echo "" +echo "@ Add this to lock" +echo "" + +cat >&2 < darwin_amd64 + "key": .name | rtrimstr(".tar.gz") | split("_")[2:] | join("_"), + # We'll replace the url with the shasum of that referenced file in a later processing step + "value": .browser_download_url | split("/")[-1] + }) + | from_entries + } +) | from_entries \ No newline at end of file diff --git a/scripts/mirror_apko.sh b/scripts/mirror_apko.sh new file mode 100755 index 0000000..4d127e8 --- /dev/null +++ b/scripts/mirror_apko.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +set -o errexit -o nounset -o pipefail + +SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +RAW=$(mktemp) + +REPOSITORY=${1:-"thesayyn/apko"} +TOOL=${2:-"apko"} + +# per_page=1 to just mirror the most recent release +( + curl --silent \ + --header "Accept: application/vnd.github.v3+json" \ + https://api.github.com/repos/${REPOSITORY}/releases?per_page=1 \ + | jq -f "$SCRIPT_DIR/filter_${TOOL}.jq" +) > $RAW + +FIXED=$(mktemp) +# Replace URLs with their hash +for tag in $(jq -r 'keys | .[]' < $RAW); do + checksums="$(curl --silent --location https://github.com/${REPOSITORY}/releases/download/$tag/checksums.txt)" + while read -r sha256 filename; do + integrity="sha256-$(echo $sha256 | xxd -r -p | base64)" + jq ".[\"$tag\"] |= with_entries(.value = (if .value == \"$filename\" then \"$integrity\" else .value end))" < $RAW > $FIXED + mv $FIXED $RAW + done <<< "$checksums" +done + +echo -n "$(echo "$TOOL" | tr '[:lower:]' '[:upper:]')_VERSIONS = " +cat $RAW