0

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

这是我想传递命令行值的规则。

  • 在使用加载规则时,这可以在实践中完成吗?
  • 可以访问 .bazel 文件的规则字段中的构建设置值,还是只能访问 Starlark 配置?
  • 有没有办法有效地“子类化”加载的规则而无需访问已发布的实现?如果_impl是公开的,似乎我可以用我自己的实现来包装它,并传递标志。

我对 Bazel 有点陌生,并且仍在寻找正确的方法来概念化这些东西。任何指导表示赞赏!

当前方法

后端/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",
)

后端/rules.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
4

1 回答 1

1

rules_docker有类似的东西repository_file,而且tag_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.

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

于 2022-02-01T20:10:28.063 回答