如何将用户定义的生成设置传递到现有的Bazel规则



我想从--define标志迁移出去,并根据以下内容构建设置:https://docs.bazel.build/versions/5.0.0/skylark/config.html

以下是我想要传递命令行值的规则。

  • 在使用加载的规则时,可以在实践中做到这一点吗
  • 一个人可以访问.bazel文件的规则字段中的构建设置值吗?还是它们只能访问Starlark配置
  • 有没有一种方法可以有效地";子类";一个加载的规则,却无法访问已发布的实现?如果_impl是公共的,那么我似乎可以用自己的实现来包装它,并将标志传递给它

我对Bazel有点陌生,但仍在寻找将这些东西概念化的正确方法。感谢您的指导!

当前方法

backend/BUILD.bazel:

load("@io_bazel_rules_docker//container:container.bzl", "container_image", "container_push")
# container_image :run_server definition
container_push(
name = "push_server",
format = "Docker",
image = ":run_server",
registry = "gcr.io",
repository = "$(PROJECT_ID)/chat/server",
tag = "$(CONTAINER_TAG)",
)

然后我运行:

bazel run 
--platforms=@io_bazel_rules_go//go/toolchain:linux_amd64 
--define PROJECT_ID=$(gcloud config get-value project) 
--define CONTAINER_TAG=some_feature_branch 
-- //backend:push_server

我尝试过的

的一些变体

load("//backend:rules.bzl", "gcr_container_push")
load("@bazel_skylib//rules:common_settings.bzl", "string_flag")
load("@io_bazel_rules_docker//container:container.bzl", "container_image")
string_flag(
name = "container_tag",
build_setting_default = "latest",
visibility = ["//visibility:public"],
)
string_flag(
name = "project_id",
build_setting_default = "",
visibility = ["//visibility:public"],
)
# container_image :run_server definition
gcr_container_push(
name = "push_server",
image = ":run_server", 
path = "chat/server",
)

后端/规则.bzl:

load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
load("@bazel_skylib//lib:paths.bzl", "paths")
load("@io_bazel_rules_docker//container:container.bzl", "container_push")
def _gcr_container_push_impl(ctx):
project_id = ctx.attr._project_id[BuildSettingInfo].value
if len(project_id) == 0:
fail("Please provide a GCP project ID via --//backend:project_id=<PROJECT ID>.")
container_push(
name = ctx.label.name,
format = "Docker",
image = ctx.attr.image,
registry = "gcr.io",
repository = paths.join(project_id, ctx.attr.path),
tag = ctx.attr._container_tag[BuildSettingInfo].value,
)
_gcr_container_push_attrs = {
"image": attr.label(
allow_single_file = [".tar"],
mandatory = True,
doc = "The label of the image to push.",
),
"path": attr.string(
mandatory = True,
doc = "The name of the image within the repository. Ex. gcr.io/project_id/<PATH>:tag.",
),
"_container_tag": attr.label(default = Label("//backend:container_tag")),
"_project_id": attr.label(default = Label("//backend:project_id")),
}
gcr_container_push = rule(
implementation = _gcr_container_push_impl,
attrs = _gcr_container_push_attrs,
executable = True,
)

然后我运行:

bazel run 
--platforms=@io_bazel_rules_go//go/toolchain:linux_amd64 
--//backend:project_id=ggx-prototype 
-- //backend:push_server  

哪个返回:

Error in container_push_: 'container_push_' can only be called during the loading phase

rules_docker具有类似于repository_filetag_file的属性来处理这类事情。您可以根据需要生成这些文件,包括使用用户定义标志的自定义规则。我会这样做:

def gcr_container_push(name, image, path, **kwargs):
if 'tag' in kwargs or 'repository' in kwargs:
fail('Not allowed to set these')
_gcr_container_repository(
name = name + '_repository',
visibility = ['//visibility:private'],
path = path,
)
_gcr_container_tag(
name = name + '_tag',
visibility = ['//visibility:private'],
path = path,
)
container_push(
name = name,
format = 'Docker',
image = image,
registry = 'gcr.io',
repository = '',
repository_file = ':%s_repository' % name,
tag_file = ':%s_tag' % name,
**kwargs
)
def _gcr_container_repository_impl(ctx):
project_id = ctx.attr._project_id[BuildSettingInfo].value
if len(project_id) == 0:
fail("Please provide a GCP project ID via --//backend:project_id=<PROJECT ID>.")
output = ctx.actions.declare_file(ctx.label.name + '_file')
ctx.actions.write(output, paths.join(project_id, ctx.attr.path))
return [DefaultInfo(files = depset([output]))]
_gcr_container_repository = rule(
impl = _gcr_container_repository_impl,
attrs = {
"path": attr.string(mandatory = True),
"_project_id": attr.label(default = Label("//backend:project_id")),
},
)
def _gcr_container_tag_impl(ctx):
output = ctx.actions.declare_file(ctx.label.name + '_file')
ctx.actions.write(output, ctx.attr._container_tag[BuildSettingInfo].value)
return [DefaultInfo(files = depset([output]))]
_gcr_container_tag = rule(
impl = _gcr_container_tag_impl,
attrs = {
"path": attr.string(mandatory = True),
"_container_tag": attr.label(default = Label("//backend:container_tag")),
},
)

您的尝试是将规则和宏混合在一起。规则具有属性,而_impl vs宏可以使用其他规则。我的方法使用自定义规则来生成文件,并使用宏将这些规则绑定到container_push

您的问题的一般答案是,这需要修改规则以基于用户定义的标志执行新类型的替换。我可以看到用allow_multiple = True配置的某种--@rules_docker//flags:docker_info=MY_PROJECT=foo会被替换,但它肯定需要修改规则。封装_impl将是一件棘手的事情,因为您必须介入并更改一些操作。

最新更新