Базель объединяет несколько правил в макрос - PullRequest
0 голосов
/ 09 мая 2018

В структуре моего проекта есть несколько подмодулей, это, по сути, папки, которые также являются проектами в рамках своих собственных прав.

Для данного проекта 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()

Я не могу использовать вторую команду загрузки из-за «синтаксической ошибки при« нагрузке »: ожидаемое выражение». Если у вас нет нескольких bzl-файлов, которые загружаются в родительский WORKSPACE, есть ли другой способ создать повторно используемые куски логики?

Обновление 1. Комментарии просили больше информации о рабочем процессе. Предупреждение, у меня есть нестандартный макет того, как Bazel, кажется, используется в другом месте, где не монорепо. Но это должно прийти к аналогичной практической планировке.

Проекты размечены как:

projectname/
    WORKSPACE
    BUILD
    src/
       stuff
    submodule/ # < git modules that are checked out into folder
        subproject1/
            BUILD
            src/
                stuff
        subproject2/
            BUILD
            src/ 
                stuff

Во-первых, у меня есть repository_rule, который загружается в WORKSPACE, который находит все проекты в папке субмодулей и добавляет их в качестве репозиториев. В рамках подпроекта некоторые из них являются Python. Я хотел бы загрузить его файлы require.txt. Отсюда и общий вопрос о том, где находятся эти файлы needs.txt и как их установить. В идеале я хотел бы, чтобы определения py_library в файлах BUILD подпроектов знали, что существует зависимость от файла требований подпроекта, но это, вероятно, не имеет значения, поскольку родительский файл BUILD - это единственное, что создает par_binaries и т. Д., поэтому до тех пор, пока происходит установка pip_install и установка зависимостей, сам проект должен быть пригодным для использования.

Bazel не позволяет дочернему проекту определять свои собственные действия с репозиторием, как описано выше pip_install. Я предполагаю, что это потому, что вы не можете выполнять действия с репозиторием в файле BUILD, а дочерние файлы WORKSPACE, похоже, не имеют никакого эффекта. Поэтому мне пришлось добавить это в родительский файл WORKSPACE.

Если он находится в родительском рабочем пространстве, я должен скопировать и вставить действия pip для каждого из подпроектов, которые я хочу использовать. Тем не менее, я бы предпочел просто установить общее правило, которое бы находило файл требований и устанавливал их в pip. Попытка сделать макрос из этого, однако, означает, что я не могу использовать вызов загрузки внутри него. Кажется, что все действия pip должны взаимодействовать с действиями с хранилищем, которые затем должны вызываться только из родительского файла WORKSPACE.

1 Ответ

0 голосов
/ 23 мая 2018

Не похоже, что существует разумное решение для этого сценария. Тем не менее, я думаю, что важно понимать, что правила, от которых вы зависите, могут быть изменены, если вы хотите поддержать их внутренне. Я закончил тем, что изменил piptool.py в репозитории rules_python, чтобы добавить поддержку нескольких файлов require.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()

И следующее в любом файле BUILD, который мне нужен. Обратите внимание, что ссылка py_requirements всегда будет доступна для любого файла BUILD в проекте.

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. Вам нужно будет перестроить piptool.par с помощью update_tools.sh в репозитории rules_python.

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))
...