Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions examples/build_file_generation/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ modules_mapping(
# the manifest doesn't need to be updated
gazelle_python_manifest(
name = "gazelle_python_manifest",
modules_mapping = ":modules_map",
pip_repository_name = "pip",
# NOTE: We can pass a list just like in `bzlmod_build_file_generation` example
# but we keep a single target here for regression testing.
requirements = "//:requirements_lock.txt",
lockfiles = "//:requirements_lock.txt",
modules_mapping = ":modules_map",
pip_repository_name = "pip",
)

# Our gazelle target points to the python gazelle binary.
Expand Down
11 changes: 8 additions & 3 deletions gazelle/docs/installation_and_usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,16 +113,21 @@ gazelle_python_manifest(
# python libraries are loaded in BUILD files.
pip_repository_name = "pip",

# This should point to wherever we declare our python dependencies
# (the same as what we passed to the modules_mapping rule in WORKSPACE)
# This should point to the lockfile for our Python dependencies.
# This argument is optional. If provided, the `.test` target is very
# fast because it just has to check an integrity field. If not provided,
# the integrity field is not added to the manifest which can help avoid
# merge conflicts in large repos.
requirements = "//:requirements_lock.txt",
# `lockfiles` accepts one file or a list, including a `uv.lock` file.
lockfiles = "//:uv.lock",
)
```

:::{versionchanged} VERSION_NEXT_FEATURE
The `requirements` argument is deprecated in favor of `lockfiles`, which can
refer to any dependency lockfile, including `uv.lock`.
:::

Finally, you create a target that you'll invoke to run the Gazelle tool
with the `rules_python` extension included. This typically goes in your root
`/BUILD.bazel` file:
Expand Down
54 changes: 37 additions & 17 deletions gazelle/manifest/defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,28 @@ load("@rules_python//python:defs.bzl", "py_binary")
def gazelle_python_manifest(
name,
modules_mapping,
requirements = [],
requirements = None,
lockfiles = [],
pip_repository_name = "",
pip_deps_repository_name = "",
manifest = ":gazelle_python.yaml",
**kwargs):
"""A macro for defining the updating and testing targets for the Gazelle manifest file.

:::{versionchanged} VERSION_NEXT_FEATURE
The `requirements` argument is deprecated in favor of `lockfiles`, which
can refer to any dependency lockfile, including `uv.lock`.
:::

Args:
name: the name used as a base for the targets.
modules_mapping: the target for the generated modules_mapping.json file.
requirements: the target for the requirements.txt file or a list of
requirements files that will be concatenated before passing on to
the manifest generator. If unset, no integrity field is added to the
manifest, meaning testing it is just as expensive as generating it,
but modifying it is much less likely to result in a merge conflict.
requirements: deprecated. Use lockfiles instead.
lockfiles: the target for a lockfile or a list of lockfiles that will be
concatenated before passing on to the manifest generator. If unset,
no integrity field is added to the manifest, meaning testing it is
just as expensive as generating it, but modifying it is much less
likely to result in a merge conflict.
pip_repository_name: the name of the pip_install or pip_repository target.
pip_deps_repository_name: deprecated - the old {bzl:obj}`pip_parse` target name.
manifest: the Gazelle manifest file.
Expand All @@ -57,6 +64,20 @@ def gazelle_python_manifest(
# This is a temporary check while pip_deps_repository_name exists as deprecated.
fail("pip_repository_name must be set in //{}:{}".format(native.package_name(), name))

if requirements != None:
if lockfiles:
fail("only one of requirements or lockfiles may be set in //{}:{}".format(
native.package_name(),
name,
))

# buildifier: disable=print
print("DEPRECATED requirements in //{}:{}. Please use lockfiles instead.".format(
native.package_name(),
name,
))
lockfiles = requirements

test_target = "{}.test".format(name)
update_target = "{}.update".format(name)
update_target_label = "//{}:{}".format(native.package_name(), update_target)
Expand All @@ -66,20 +87,19 @@ def gazelle_python_manifest(
manifest_generator = Label("//manifest/generate:generate")
manifest_generator_hash = Label("//manifest/generate:generate_lib_sources_hash")

if requirements and type(requirements) == "list":
# This runs if requirements is a list or is unset (default value is empty list)
if lockfiles and type(lockfiles) == "list":
native.genrule(
name = name + "_requirements_gen",
srcs = sorted(requirements),
outs = [name + "_requirements.txt"],
name = name + "_lockfiles_gen",
srcs = sorted(lockfiles),
outs = [name + "_lockfiles.txt"],
cmd_bash = "cat $(SRCS) > $@",
cmd_bat = "type $(SRCS) > $@",
)
requirements = name + "_requirements_gen"
lockfiles = name + "_lockfiles_gen"

update_args = [
"--manifest-generator-hash=$(execpath {})".format(manifest_generator_hash),
"--requirements=$(execpath {})".format(requirements) if requirements else "--requirements=",
"--requirements=$(execpath {})".format(lockfiles) if lockfiles else "--requirements=",
"--pip-repository-name={}".format(pip_repository_name),
"--modules-mapping=$(execpath {})".format(modules_mapping),
"--output=$(execpath {})".format(generated_manifest),
Expand All @@ -94,7 +114,7 @@ def gazelle_python_manifest(
srcs = [
modules_mapping,
manifest_generator_hash,
] + ([requirements] if requirements else []),
] + ([lockfiles] if lockfiles else []),
tags = ["manual"],
)

Expand All @@ -114,12 +134,12 @@ def gazelle_python_manifest(
**{k: v for k, v in kwargs.items() if k != "tags"}
)

if requirements:
if lockfiles:
attrs = {
"env": {
"_TEST_MANIFEST": "$(rlocationpath {})".format(manifest),
"_TEST_MANIFEST_GENERATOR_HASH": "$(rlocationpath {})".format(manifest_generator_hash),
"_TEST_REQUIREMENTS": "$(rlocationpath {})".format(requirements),
"_TEST_REQUIREMENTS": "$(rlocationpath {})".format(lockfiles),
},
"size": "small",
}
Expand All @@ -128,7 +148,7 @@ def gazelle_python_manifest(
srcs = [Label("//manifest/test:test.go")],
data = [
manifest,
requirements,
lockfiles,
manifest_generator_hash,
],
rundir = ".",
Expand Down
2 changes: 2 additions & 0 deletions news/4111.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
(gazelle) Deprecate the `requirements` argument of `gazelle_python_manifest`
in favor of the format-agnostic `lockfiles` argument, which supports `uv.lock`.