Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I zip files in bazel

Tags:

zip

bazel

I have a set of files as part of the my repository. How do I produce a zip file out of those files in bazel. I found a rules for tar.gz etc. but cannot find a way how to achive a zip archive.

Found references mentioning zipper but couldn't figure out how to load it and use it. Can someone more experienced with bazel help?

like image 690
jaksky Avatar asked Dec 23 '22 21:12

jaksky


2 Answers

A basic pkg_zip rule was added to rules_pkg recently. Here is a basic usage example from the unit tests:

load("@rules_pkg//:pkg.bzl", "pkg_zip")

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

You can specify the paths using the extra rules in mappings.bzl. Here is the example given by the Bazel team:

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",
    ],
)
like image 135
Rohan Singh Avatar answered Feb 01 '23 06:02

Rohan Singh


The zipper utility is at @bazel_tools//tools/zip:zipper, this is its usage:

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.

So it can be used in a genrule like this:

$ 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

It can similarly be used in 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"},
)
like image 43
ahumesky Avatar answered Feb 01 '23 07:02

ahumesky