我该如何在Bazel中压缩文件?

5

我有一组文件作为我的代码库的一部分。如何在Bazel中将这些文件生成一个zip文件?我找到了关于tar.gz等的规则,但找不到实现zip归档的方法。

发现了提到zipper的参考资料,但无法弄清楚如何加载和使用它。有没有更有经验的Bazel用户可以帮忙?

2个回答

10
最近在rules_pkg中添加了基本的pkg_zip规则。以下是来自单元测试的基本用法示例:
load("@rules_pkg//:pkg.bzl", "pkg_zip")

pkg_zip(
    name = "test_zip_basic",
    srcs = [
        "testdata/hello.txt",
        "testdata/loremipsum.txt",
    ],
)

您可以使用 mappings.bzl 中的额外规则指定路径。以下是Bazel团队提供的示例链接:example

load("@rules_pkg//:mappings.bzl", "pkg_attributes", "pkg_filegroup", "pkg_files", "pkg_mkdirs", "strip_prefix")
load("@rules_pkg//:pkg.bzl", "pkg_tar", "pkg_zip")

# This is the top level BUILD for a hypothetical project Foo.  It has a client,
# a server, docs, and runtime directories needed by the server.
# We want to ship it for Linux, macOS, and Windows.
#
# This example shows various techniques for specifying how your source tree
# transforms into the installation tree. As such, it favors using a lot of
# distict features, at the expense of uniformity.

pkg_files(
    name = "share_doc",
    srcs = [
        "//docs",
    ],
    # Required, but why?: see #354
    strip_prefix = strip_prefix.from_pkg(),
    # Where it should be in the final package
    prefix = "usr/share/doc/foo",
)

pkg_filegroup(
    name = "manpages",
    srcs = [
        "//src/client:manpages",
        "//src/server:manpages",
    ],
    prefix = "/usr/share",
)


pkg_tar(
    name = "foo_tar",
    srcs = [
        "README.txt",
        ":manpages",
        ":share_doc",
        "//resources/l10n:all",
        "//src/client:arch",
        "//src/server:arch",
    ],
)

pkg_zip(
    name = "foo_zip",
    srcs = [
        "README.txt",
        ":manpages",
        ":share_doc",
        "//resources/l10n:all",
        "//src/client:arch",
        "//src/server:arch",
    ],
)

3
你有没有想过在创建Zip文件时如何保留目录路径?按照这个规则。 - Rushi patel
1
我也在想同样的问题@Rushipatel。你解决了吗? - Luke Gehorsam
是否可以独立于“name”属性指定输出名称? - Arash Outadi

7

zip工具位于@bazel_tools//tools/zip:zipper,以下是它的用法:

Usage: zipper [vxc[fC]] x.zip [-d exdir] [[zip_path1=]file1 ... [zip_pathn=]filen]
  v verbose - list all file in x.zip
  x extract - extract files in x.zip to current directory, or
       an optional directory relative to the current directory
       specified through -d option
  c create  - add files to x.zip
  f flatten - flatten files to use with create or extract operation
  C compress - compress files when using the create operation
x and c cannot be used in the same command-line.

For every file, a path in the zip can be specified. Examples:
  zipper c x.zip a/b/__init__.py= # Add an empty file at a/b/__init__.py
  zipper c x.zip a/b/main.py=foo/bar/bin.py # Add file foo/bar/bin.py at a/b/main.py

If the zip path is not specified, it is assumed to be the file path.

因此,它可以在genrule中像这样使用:

$ tree
.
├── BUILD
├── dir
│   ├── a
│   ├── b
│   └── c
└── WORKSPACE

1 directory, 5 files


$ cat BUILD
genrule(
  name = "gen_zip",
  srcs = glob(["dir/*"]),
  tools = ["@bazel_tools//tools/zip:zipper"],
  outs = ["files.zip"],
  cmd = "$(location @bazel_tools//tools/zip:zipper) c $@ $(SRCS)",
)


$ bazel build :files.zip
INFO: Analyzed target //:files.zip (7 packages loaded, 41 targets configured).
INFO: Found 1 target...
Target //:files.zip up-to-date:
  bazel-bin/files.zip
INFO: Elapsed time: 0.653s, Critical Path: 0.08s
INFO: 1 process: 1 linux-sandbox.
INFO: Build completed successfully, 2 total actions


$ unzip -l bazel-bin/files.zip
Archive:  bazel-bin/files.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  2010-01-01 00:00   dir/a
        0  2010-01-01 00:00   dir/b
        0  2010-01-01 00:00   dir/c
---------                     -------
        0                     3 files

它同样可以在 Starlark 中使用:

def _some_rule_impl(ctx):

  zipper_inputs = []
  zipper_args = ctx.actions.args()
  zipper_args.add("c", ctx.outputs.zip.path)
  ....
  ctx.actions.run(
    inputs = zipper_inputs,
    outputs = [ctx.outputs.zip],
    executable = ctx.executable._zipper,
    arguments = [zipper_args],
    progress_message = "Creating zip...",
    mnemonic = "zipper",
  )


some_rule = rule(
  implementation = _some_rule_impl,
  attrs = {
    "deps": attr.label_list(),
    "$zipper": attr.label(default = Label("@bazel_tools//tools/zip:zipper"), cfg = "host", executable=True),
  },
  outputs = {"zip": "%{name}.zip"},
)

谢谢,这非常有帮助。就我所理解的,zip文件包含绝对路径或仅文件名(当使用“flatten”选项时)。是否可以将输出写入zip文件中的特定文件夹?例如,如果想要文件结构/dir/subdir/a,并且想要一个zip文件包含subdir/a? - jaksky
1
我正在努力让它工作。如何使用列表并生成映射。我需要在Starlark中完成吗?我试图使用单独的genrule来创建所需的结构(路径),但显然它保留了绝对路径。 - jaksky
@ahumesky,这似乎不再起作用了,或者我漏掉了什么。 - Rushi patel
@ahumesky 当需要压缩的源文件数量很大时(参数列表过长),这会导致问题。在规则实现中有没有一种分批向现有zip文件中添加内容的方式呢? - yoonjesung
1
@yoonjesung 尽管在使用帮助文本中没有显示,但 zipper 似乎支持使用 @filename 的选项文件:https://github.com/bazelbuild/bazel/blob/19532fbd3ae369d756ec8aa37a74a2c453a4cce9/third_party/ijar/zip_main.cc#L435 - ahumesky
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接