blob: 914d9c9e92d037a67b2264521d5ec8896f96393c [file] [view] [edit]
# rules_pkg — Claude Code guide
rules_pkg is a set of Bazel rules for building distribution packages (tar, zip, deb, rpm, …).
The core abstraction is a set of package-format-agnostic mapping rules (`pkg_files`,
`pkg_filegroup`, `pkg_mkdirs`, `pkg_mklink`) that describe *what* goes where in a package;
format-specific rules (`pkg_tar`, `pkg_zip`, `pkg_deb`, `pkg_rpm`) consume those descriptions.
## Repository layout
```
pkg/ Runtime rules and providers (shipped in the distribution)
mappings.bzl pkg_files, pkg_filegroup, pkg_mkdirs, pkg_mklink
providers.bzl PackageVariablesInfo and other providers
private/ Internal implementation helpers (not public API)
util.bzl substitute_package_variables, setup_output_files, …
deb/ pkg_deb implementation
tar/ pkg_tar implementation
zip/ pkg_zip implementation
tests/ All tests (not shipped)
mappings/ Analysis tests for pkg_files / pkg_filegroup
tar/ Tests for pkg_tar
deb/ Tests for pkg_deb
rpm/ Tests for pkg_rpm
zip/ Tests for pkg_zip
examples/ Runnable examples (tested in CI)
docs/ Generated reference docs (do not edit by hand)
distro/ Rules to build the distribution tarball
```
Top-level `.bzl` shims (`mappings.bzl`, `pkg.bzl`, etc.) are backward-compatibility
re-exports of the files inside `pkg/`.
## Code style
### Starlark / BUILD files — always run buildifier after editing
After editing any `.bzl` or `BUILD` file, run:
```
buildifier --lint=fix <FILE>
```
buildifier enforces load ordering, argument sorting, and other canonical style.
It will reorder loads alphabetically; let it.
### Starlark conventions
- All public rule attributes must have a `doc =` string.
- Use `substitute_package_variables(ctx, value)` (from `//pkg/private:util.bzl`)
to expand `$(VAR)` make-variable syntax in string attributes.
The rule must also declare a `package_variables` attribute typed
`attr.label(providers = [PackageVariablesInfo])`.
- Prefer solutions that work for all package formats (via `pkg_files`/`pkg_filegroup`)
over format-specific additions.
- Actions must not write quoted strings directly to command lines write paths to
an intermediate file instead.
### Python
- Python 3 only; no Python 2 support.
- Always import with full paths from the workspace root.
- No new third-party package dependencies standard library only.
### General
- No files should have trailing whitespace.
- Try to keep lines under 100 characters long.
## Testing
**All features and bug fixes must have tests.**
### Mappings (pkg_files / pkg_filegroup)
Tests live in `tests/mappings/mappings_test.bzl` and are registered via the
`mappings_analysis_tests()` macro called from `tests/mappings/BUILD`.
- Use `pkg_files_contents_test` (defined in `mappings_test.bzl`) to assert
expected destination paths from a `pkg_files` target.
- Use `pkg_filegroup_contents_test` to compare a `pkg_filegroup` output against
reference `pkg_files` / `pkg_mkdirs` / `pkg_mklink` targets.
- Use `generic_negative_test` for targets that are expected to fail analysis.
- Add new test names to the `pkg_files_analysis_tests` test suite list at the
bottom of `mappings_analysis_tests()`.
Run them with:
```
bazel test //tests/mappings/...
```
### package_variables / make-variable substitution
The sample naming rule used across tests is `my_package_naming` in
`tests/my_package_name.bzl`. Load it as:
```python
load("//tests:my_package_name.bzl", "my_package_naming")
```
Create an instance, then wire it to the `package_variables` attribute of
the rule under test. Example:
```python
my_package_naming(name = "my_vars", label = "linux_x86_64", tags = ["manual"])
pkg_files(
name = "my_files",
srcs = [...],
prefix = "usr/lib/$(label)",
package_variables = ":my_vars",
tags = ["manual"],
)
```
### Format-specific tests
```
bazel test //tests/tar/...
bazel test //tests/deb/...
bazel test //tests/zip/...
bazel test //tests/rpm/... # may require rpm toolchain
```
### Running everything
```
bazel test //tests/...
```
## Regenerating docs
After any feature change, regenerate the reference docs before committing:
```
bazel build //doc_build:reference
cp bazel-bin/doc_build/reference.md docs/latest.md
```
Do **not** `git commit` yet that is a separate step the user will handle.
## Common patterns
### Adding package_variables support to an attribute
1. Import `PackageVariablesInfo` from `//pkg:providers.bzl` and
`substitute_package_variables` from `//pkg/private:util.bzl`.
2. Add to the rule attrs:
```python
"package_variables": attr.label(
doc = """See [Common Attributes](#package_variables)""",
providers = [PackageVariablesInfo],
),
```
3. In the implementation, call substitution at the top before using the value:
```python
prefix = substitute_package_variables(ctx, ctx.attr.prefix)
```
4. Use the substituted local variable everywhere instead of `ctx.attr.prefix`.
5. Run `buildifier --lint=fix` on the modified file.
6. Add analysis tests in the appropriate test file.