Bazel在宏中组合多个规则

Bazel在宏中组合多个规则,bazel,Bazel,我的项目结构中有多个子模块,这些基本上是文件夹,它们本身也是项目 对于给定的python项目,每个项目都有子项目。我希望能够编写一个宏,可以创建一组对给定子项目采取的操作 基本上,在工作区内,有以下内容: load("@io_bazel_rules_python//:python/pip.bzl", "pip_import" ) pip_import( name = "foo", requirements = "@subprojectname//:requirements.t

我的项目结构中有多个子模块,这些基本上是文件夹,它们本身也是项目

对于给定的python项目,每个项目都有子项目。我希望能够编写一个宏,可以创建一组对给定子项目采取的操作

基本上,在工作区内,有以下内容:

load("@io_bazel_rules_python//:python/pip.bzl",
   "pip_import"
)

pip_import(
   name = "foo",
   requirements = "@subprojectname//:requirements.txt",
)

load("@foo//:requirements.bzl", "pip_install")
pip_install()
我想为多个子项目执行上述操作。但是,如果我将所有代码放入bzl文件中的函数中

pyrules.bzl

load("@io_bazel_rules_python//:python/pip.bzl",
   "pip_import"
)


def doit(name):
    pip_import(
       name = "foo",
       requirements = "@{repo}//:requirements.txt".format(repo=name)
    )

    load("@foo//:requirements.bzl", "pip_install")
    pip_install()
我无法使用第二个load命令,因为“load处的语法错误:预期表达式”。如果没有将多个bzl文件加载到父工作区中,是否还有其他方法来创建可重用的逻辑块

更新1。 评论要求提供有关工作流的更多信息。警告,对于Bazel在其他地方的使用方式,我有一个非标准布局,即不是monorepo。但它应该有一个类似的实际布局

项目安排如下:

projectname/
    WORKSPACE
    BUILD
    src/
       stuff
    submodule/ # < git modules that are checked out into folder
        subproject1/
            BUILD
            src/
                stuff
        subproject2/
            BUILD
            src/ 
                stuff
projectname/
工作空间
建造
src/
东西
子模块/#<签出到文件夹中的git模块
次级项目1/
建造
src/
东西
次级项目2/
建造
src/
东西
首先,我在工作区中加载了一个repository_规则,该规则查找子模块文件夹中的所有项目,并将它们添加为存储库。在子项目中,其中一些是python。我想加载它的requirements.txt文件。因此,总的问题是这些requirements.txt文件在哪里,并在其上进行pip安装。理想情况下,我希望子项目构建文件中的py_库定义知道子项目的需求文件存在依赖关系,但这可能并不重要,因为父构建文件是创建par_二进制文件等的唯一对象,因此只要pip_安装并设置依赖关系,项目本身应该是可用的

Bazel似乎不允许子项目像上面的pip_安装那样定义自己的存储库操作。我认为这是因为在构建文件中不能有存储库操作,并且子工作区文件似乎没有任何效果。因此,我不得不将其添加到父工作区文件中


如果它在父工作区中,我必须为我想要使用的每个子项目复制粘贴pip操作。然而,我更愿意只建立一个通用规则,它将定位需求文件并pip安装它们。但是,试图从中生成宏意味着我无法在其中使用load调用。所有pip操作似乎都需要与存储库操作交互,然后只需要从父工作区文件调用存储库操作

对于这种情况,似乎不存在任何合理的解决方案。然而,我认为重要的是要认识到,如果你愿意在内部支持,你所依赖的规则是可以修改的。我最终修改了rules_python存储库中的piptool.py,以便在一次调用中添加对多个requirements.txt文件的支持。然后将以下规则添加到我自己的内部使用的规则存储库中

#
# Python
#

def _pip_import_requirements_impl(repository_ctx):
  """Core implementation of pip_import."""
  # Add an empty top-level BUILD file.
  # This is because Bazel requires BUILD files along all paths accessed
  # via //this/sort/of:path and we wouldn't be able to load our generated
  # requirements.bzl without it.
  repository_ctx.file("BUILD", "")

  # To see the output, pass: quiet=False
  result = repository_ctx.execute([
    "python3", repository_ctx.path(repository_ctx.attr._script),
    "--name", repository_ctx.attr.name,
    "--input"
    ] +
    [repository_ctx.path(r) for r in repository_ctx.attr.requirements] +
    [
      "--output", repository_ctx.path("requirements.bzl"),
      "--directory", repository_ctx.path("")
    ],
  quiet = repository_ctx.attr.quiet)

  if result.return_code:
    fail("pip_import failed: %s (%s)" % (result.stdout, result.stderr))


pip_import_requirements = repository_rule(
  attrs = {
    "quiet" : attr.bool(default = False),
    "requirements": attr.label_list(
       allow_files = True,
       mandatory = True,
     ),
     "_script": attr.label(
       executable = True,
       default = Label("@io_bazel_rules_python//tools:piptool.par"),
       cfg = "host",
     ),
  },
  implementation = _pip_import_requirements_impl,
)
然后我可以在我的工作区中执行以下操作

pip_import_requirements(
  name = "py_requirements",
  requirements = [
    "@mycore//:requirements.txt",
    "@myother//:requirements.txt"
  ]
)

load(
    "@py_requirements//:requirements.bzl",
    "pip_install",
)

pip_install()
下面是我碰巧需要的任何构建文件。请注意,py_需求参考将始终适用于项目中的任何构建文件

load(
    "@py_requirements//:requirements.bzl",
    "all_requirements"
)

par_binary(
    name = "funkyserver",
    main = "src/main.py",
    srcs = glob(["src/**/*.py"]),
    deps = [
        "@mycore//:core",
        "@myother//:other"
    ] + all_requirements,
)
对于piptool.py。您需要使用RuleDeXyToeS.SH在RuleSyPython ReP.< /P>中重建PIPToo.Par。
diff --git a/rules_python/piptool.py b/rules_python/piptool.py
index f5d504a..ab520d8 100644
--- a/rules_python/piptool.py
+++ b/rules_python/piptool.py
@@ -87,7 +87,7 @@ def pip_main(argv):
 parser.add_argument('--name', action='store',
                     help=('The namespace of the import.'))

-parser.add_argument('--input', action='store',
+parser.add_argument('--input', action='store', nargs='+',
                     help=('The requirements.txt file to import.'))

 parser.add_argument('--output', action='store',
@@ -154,7 +154,8 @@ def main():
   args = parser.parse_args()

   # https://github.com/pypa/pip/blob/9.0.1/pip/__init__.py#L209
-  if pip_main(["wheel", "-w", args.directory, "-r", args.input]):
+  if pip_main(["wheel", "-w", args.directory] + [p for x in [
+      ('-r',  i) for i in args.input] for p in x]):
     sys.exit(1)

   # Enumerate the .whl files we downloaded.
@@ -219,7 +220,7 @@ def requirement(name):
   if name_key not in _requirements:
     fail("Could not find pip-provided dependency: '%s'" % name)
   return _requirements[name_key]
-""".format(input=args.input,
+""".format(input=" ".join(args.input),
            whl_libraries='\n'.join(map(whl_library, whls)) if whls else "pass",
            mappings=whl_targets))

您希望这个pyrules.bzl文件放在哪里?父工作区将引用它们吗?怎么说?说得好。我做了一个非常复杂的变通方法,动态创建bzl文件,然后将其添加为假存储库。这是我在启动时解决文件问题的唯一方法,而不必事先手动描述所有文件。我认为如果你能提供更多关于你心目中的流程的上下文(比如克隆后)会有所帮助。你能分享你对piptool.py的修改吗?或者更好,你能做一个PR吗?