Skip to content

Commit 6574e34

Browse files
authored
feat: gazelle manifest exclude_patterns (#917)
* feat: exclude_patterns for gazelle manifest Signed-off-by: Thulio Ferraz Assis <[email protected]> * feat: force gazelle manifest update on logic change Signed-off-by: Thulio Ferraz Assis <[email protected]> Signed-off-by: Thulio Ferraz Assis <[email protected]>
1 parent d170eb9 commit 6574e34

File tree

16 files changed

+295
-107
lines changed

16 files changed

+295
-107
lines changed

examples/build_file_generation/BUILD

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,23 @@ load("@rules_python//gazelle:def.bzl", "GAZELLE_PYTHON_RUNTIME_DEPS")
44
load("@rules_python//gazelle/manifest:defs.bzl", "gazelle_python_manifest")
55
load("@rules_python//gazelle/modules_mapping:def.bzl", "modules_mapping")
66
load("@rules_python//python:defs.bzl", "py_binary", "py_library")
7+
load("@rules_python//python:pip.bzl", "compile_pip_requirements")
8+
9+
compile_pip_requirements(
10+
name = "requirements",
11+
extra_args = ["--allow-unsafe"],
12+
requirements_in = "requirements.txt",
13+
requirements_txt = "requirements_lock.txt",
14+
)
715

816
# This rule fetches the metadata for python packages we depend on. That data is
917
# required for the gazelle_python_manifest rule to update our manifest file.
1018
modules_mapping(
1119
name = "modules_map",
20+
exclude_patterns = [
21+
"^_|(\\._)+", # This is the default.
22+
"(\\.tests)+", # Add a custom one to get rid of the psutil tests.
23+
],
1224
wheels = all_whl_requirements,
1325
)
1426

examples/build_file_generation/gazelle_python.yaml

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,14 @@
66
manifest:
77
modules_mapping:
88
certifi: certifi
9-
certifi.__init__: certifi
10-
certifi.__main__: certifi
119
certifi.core: certifi
1210
chardet: chardet
13-
chardet.__init__: chardet
1411
chardet.big5freq: chardet
1512
chardet.big5prober: chardet
1613
chardet.chardistribution: chardet
1714
chardet.charsetgroupprober: chardet
1815
chardet.charsetprober: chardet
1916
chardet.cli: chardet
20-
chardet.cli.__init__: chardet
2117
chardet.cli.chardetect: chardet
2218
chardet.codingstatemachine: chardet
2319
chardet.compat: chardet
@@ -53,18 +49,15 @@ manifest:
5349
chardet.utf8prober: chardet
5450
chardet.version: chardet
5551
idna: idna
56-
idna.__init__: idna
5752
idna.codec: idna
5853
idna.compat: idna
5954
idna.core: idna
6055
idna.idnadata: idna
6156
idna.intranges: idna
6257
idna.package_data: idna
6358
idna.uts46data: idna
59+
psutil: psutil
6460
requests: requests
65-
requests.__init__: requests
66-
requests.__version__: requests
67-
requests._internal_utils: requests
6861
requests.adapters: requests
6962
requests.api: requests
7063
requests.auth: requests
@@ -81,18 +74,9 @@ manifest:
8174
requests.structures: requests
8275
requests.utils: requests
8376
urllib3: urllib3
84-
urllib3.__init__: urllib3
85-
urllib3._collections: urllib3
86-
urllib3._version: urllib3
8777
urllib3.connection: urllib3
8878
urllib3.connectionpool: urllib3
8979
urllib3.contrib: urllib3
90-
urllib3.contrib.__init__: urllib3
91-
urllib3.contrib._appengine_environ: urllib3
92-
urllib3.contrib._securetransport: urllib3
93-
urllib3.contrib._securetransport.__init__: urllib3
94-
urllib3.contrib._securetransport.bindings: urllib3
95-
urllib3.contrib._securetransport.low_level: urllib3
9680
urllib3.contrib.appengine: urllib3
9781
urllib3.contrib.ntlmpool: urllib3
9882
urllib3.contrib.pyopenssl: urllib3
@@ -102,19 +86,14 @@ manifest:
10286
urllib3.fields: urllib3
10387
urllib3.filepost: urllib3
10488
urllib3.packages: urllib3
105-
urllib3.packages.__init__: urllib3
10689
urllib3.packages.backports: urllib3
107-
urllib3.packages.backports.__init__: urllib3
10890
urllib3.packages.backports.makefile: urllib3
10991
urllib3.packages.six: urllib3
11092
urllib3.packages.ssl_match_hostname: urllib3
111-
urllib3.packages.ssl_match_hostname.__init__: urllib3
112-
urllib3.packages.ssl_match_hostname._implementation: urllib3
11393
urllib3.poolmanager: urllib3
11494
urllib3.request: urllib3
11595
urllib3.response: urllib3
11696
urllib3.util: urllib3
117-
urllib3.util.__init__: urllib3
11897
urllib3.util.connection: urllib3
11998
urllib3.util.proxy: urllib3
12099
urllib3.util.queue: urllib3
@@ -129,4 +108,4 @@ manifest:
129108
pip_repository:
130109
name: pip
131110
incremental: true
132-
integrity: 4b3eed2cb51741419e11bd12a4533f285d059fda8029deaf6fedfe0fcda1b782
111+
integrity: 91adaddb7e2d3eb7234e78979ff40b666101ab4df91c62659b954cc9376c2f86
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
requests==2.25.1
2+
psutil==5.9.4

examples/build_file_generation/requirements_lock.txt

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# This file is autogenerated by pip-compile with python 3.9
33
# To update, run:
44
#
5-
# pip-compile --generate-hashes --output-file=requirements_lock.txt requirements.txt
5+
# bazel run //:requirements.update
66
#
77
certifi==2020.12.5 \
88
--hash=sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c \
@@ -16,10 +16,26 @@ idna==2.10 \
1616
--hash=sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6 \
1717
--hash=sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0
1818
# via requests
19+
psutil==5.9.4 \
20+
--hash=sha256:149555f59a69b33f056ba1c4eb22bb7bf24332ce631c44a319cec09f876aaeff \
21+
--hash=sha256:16653106f3b59386ffe10e0bad3bb6299e169d5327d3f187614b1cb8f24cf2e1 \
22+
--hash=sha256:3d7f9739eb435d4b1338944abe23f49584bde5395f27487d2ee25ad9a8774a62 \
23+
--hash=sha256:3ff89f9b835100a825b14c2808a106b6fdcc4b15483141482a12c725e7f78549 \
24+
--hash=sha256:54c0d3d8e0078b7666984e11b12b88af2db11d11249a8ac8920dd5ef68a66e08 \
25+
--hash=sha256:54d5b184728298f2ca8567bf83c422b706200bcbbfafdc06718264f9393cfeb7 \
26+
--hash=sha256:6001c809253a29599bc0dfd5179d9f8a5779f9dffea1da0f13c53ee568115e1e \
27+
--hash=sha256:68908971daf802203f3d37e78d3f8831b6d1014864d7a85937941bb35f09aefe \
28+
--hash=sha256:6b92c532979bafc2df23ddc785ed116fced1f492ad90a6830cf24f4d1ea27d24 \
29+
--hash=sha256:852dd5d9f8a47169fe62fd4a971aa07859476c2ba22c2254d4a1baa4e10b95ad \
30+
--hash=sha256:9120cd39dca5c5e1c54b59a41d205023d436799b1c8c4d3ff71af18535728e94 \
31+
--hash=sha256:c1ca331af862803a42677c120aff8a814a804e09832f166f226bfd22b56feee8 \
32+
--hash=sha256:efeae04f9516907be44904cc7ce08defb6b665128992a56957abc9b61dca94b7 \
33+
--hash=sha256:fd8522436a6ada7b4aad6638662966de0d61d241cb821239b2ae7013d41a43d4
34+
# via -r ./requirements.txt
1935
requests==2.25.1 \
2036
--hash=sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804 \
2137
--hash=sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e
22-
# via -r requirements.txt
38+
# via -r ./requirements.txt
2339
urllib3==1.26.5 \
2440
--hash=sha256:753a0374df26658f99d826cfe40394a686d05985786d946fbe4165b5148f5a7c \
2541
--hash=sha256:a7acd0977125325f516bda9735fa7142b909a8d01e8b2e4c8108d0984e6e0098

gazelle/manifest/defs.bzl

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
for updating and testing the Gazelle manifest file.
33
"""
44

5-
load("@io_bazel_rules_go//go:def.bzl", "go_binary")
5+
load("@io_bazel_rules_go//go:def.bzl", "GoSource", "go_binary")
66

77
def gazelle_python_manifest(
88
name,
@@ -38,7 +38,11 @@ def gazelle_python_manifest(
3838
update_target = "{}.update".format(name)
3939
update_target_label = "//{}:{}".format(native.package_name(), update_target)
4040

41+
manifest_generator_hash = Label("//gazelle/manifest/generate:generate_lib_sources_hash")
42+
4143
update_args = [
44+
"--manifest-generator-hash",
45+
"$(rootpath {})".format(manifest_generator_hash),
4246
"--requirements",
4347
"$(rootpath {})".format(requirements),
4448
"--pip-repository-name",
@@ -55,11 +59,12 @@ def gazelle_python_manifest(
5559

5660
go_binary(
5761
name = update_target,
58-
embed = ["@rules_python//gazelle/manifest/generate:generate_lib"],
62+
embed = [Label("//gazelle/manifest/generate:generate_lib")],
5963
data = [
6064
manifest,
6165
modules_mapping,
6266
requirements,
67+
manifest_generator_hash,
6368
],
6469
args = update_args,
6570
visibility = ["//visibility:private"],
@@ -70,21 +75,23 @@ def gazelle_python_manifest(
7075

7176
go_binary(
7277
name = test_binary,
73-
embed = ["@rules_python//gazelle/manifest/test:test_lib"],
78+
embed = [Label("//gazelle/manifest/test:test_lib")],
7479
visibility = ["//visibility:private"],
7580
)
7681

7782
native.sh_test(
7883
name = "{}.test".format(name),
79-
srcs = ["@rules_python//gazelle/manifest/test:run.sh"],
84+
srcs = [Label("//gazelle/manifest/test:run.sh")],
8085
data = [
8186
":{}".format(test_binary),
8287
manifest,
8388
requirements,
89+
manifest_generator_hash,
8490
],
8591
env = {
8692
"_TEST_BINARY": "$(rootpath :{})".format(test_binary),
8793
"_TEST_MANIFEST": "$(rootpath {})".format(manifest),
94+
"_TEST_MANIFEST_GENERATOR_HASH": "$(rootpath {})".format(manifest_generator_hash),
8895
"_TEST_REQUIREMENTS": "$(rootpath {})".format(requirements),
8996
},
9097
visibility = ["//visibility:private"],
@@ -97,3 +104,56 @@ def gazelle_python_manifest(
97104
tags = ["manual"],
98105
visibility = ["//visibility:public"],
99106
)
107+
108+
# buildifier: disable=provider-params
109+
AllSourcesInfo = provider(fields = {"all_srcs": "All sources collected from the target and dependencies."})
110+
111+
_rules_python_workspace = Label("//:WORKSPACE")
112+
113+
def _get_all_sources_impl(target, ctx):
114+
is_rules_python = target.label.workspace_name == _rules_python_workspace.workspace_name
115+
if not is_rules_python:
116+
# Avoid adding third-party dependency files to the checksum of the srcs.
117+
return AllSourcesInfo(all_srcs = depset())
118+
srcs = depset(
119+
target[GoSource].orig_srcs,
120+
transitive = [dep[AllSourcesInfo].all_srcs for dep in ctx.rule.attr.deps],
121+
)
122+
return [AllSourcesInfo(all_srcs = srcs)]
123+
124+
_get_all_sources = aspect(
125+
implementation = _get_all_sources_impl,
126+
attr_aspects = ["deps"],
127+
)
128+
129+
def _sources_hash_impl(ctx):
130+
all_srcs = ctx.attr.go_library[AllSourcesInfo].all_srcs
131+
hash_file = ctx.actions.declare_file(ctx.attr.name + ".hash")
132+
args = ctx.actions.args()
133+
args.add(hash_file)
134+
args.add_all(all_srcs)
135+
ctx.actions.run(
136+
outputs = [hash_file],
137+
inputs = all_srcs,
138+
arguments = [args],
139+
executable = ctx.executable._hasher,
140+
)
141+
return [DefaultInfo(
142+
files = depset([hash_file]),
143+
runfiles = ctx.runfiles([hash_file]),
144+
)]
145+
146+
sources_hash = rule(
147+
_sources_hash_impl,
148+
attrs = {
149+
"go_library": attr.label(
150+
aspects = [_get_all_sources],
151+
providers = [GoSource],
152+
),
153+
"_hasher": attr.label(
154+
cfg = "exec",
155+
default = Label("//gazelle/manifest/hasher"),
156+
executable = True,
157+
),
158+
},
159+
)

gazelle/manifest/generate/BUILD.bazel

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
2+
load("//gazelle/manifest:defs.bzl", "sources_hash")
23

34
go_library(
45
name = "generate_lib",
@@ -8,6 +9,12 @@ go_library(
89
deps = ["//gazelle/manifest"],
910
)
1011

12+
sources_hash(
13+
name = "generate_lib_sources_hash",
14+
go_library = ":generate_lib",
15+
visibility = ["//visibility:public"],
16+
)
17+
1118
go_binary(
1219
name = "generate",
1320
embed = [":generate_lib"],

gazelle/manifest/generate/generate.go

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,19 @@ func init() {
2424
}
2525

2626
func main() {
27+
var manifestGeneratorHashPath string
2728
var requirementsPath string
2829
var pipRepositoryName string
2930
var pipRepositoryIncremental bool
3031
var modulesMappingPath string
3132
var outputPath string
3233
var updateTarget string
34+
flag.StringVar(
35+
&manifestGeneratorHashPath,
36+
"manifest-generator-hash",
37+
"",
38+
"The file containing the hash for the source code of the manifest generator."+
39+
"This is important to force manifest updates when the generator logic changes.")
3340
flag.StringVar(
3441
&requirementsPath,
3542
"requirements",
@@ -92,7 +99,13 @@ func main() {
9299
Incremental: pipRepositoryIncremental,
93100
},
94101
})
95-
if err := writeOutput(outputPath, header, manifestFile, requirementsPath); err != nil {
102+
if err := writeOutput(
103+
outputPath,
104+
header,
105+
manifestFile,
106+
manifestGeneratorHashPath,
107+
requirementsPath,
108+
); err != nil {
96109
log.Fatalf("ERROR: %v\n", err)
97110
}
98111
}
@@ -129,6 +142,7 @@ func writeOutput(
129142
outputPath string,
130143
header string,
131144
manifestFile *manifest.File,
145+
manifestGeneratorHashPath string,
132146
requirementsPath string,
133147
) error {
134148
stat, err := os.Stat(outputPath)
@@ -146,7 +160,19 @@ func writeOutput(
146160
return fmt.Errorf("failed to write output: %w", err)
147161
}
148162

149-
if err := manifestFile.Encode(outputFile, requirementsPath); err != nil {
163+
manifestGeneratorHash, err := os.Open(manifestGeneratorHashPath)
164+
if err != nil {
165+
return fmt.Errorf("failed to write output: %w", err)
166+
}
167+
defer manifestGeneratorHash.Close()
168+
169+
requirements, err := os.Open(requirementsPath)
170+
if err != nil {
171+
return fmt.Errorf("failed to write output: %w", err)
172+
}
173+
defer requirements.Close()
174+
175+
if err := manifestFile.Encode(outputFile, manifestGeneratorHash, requirements); err != nil {
150176
return fmt.Errorf("failed to write output: %w", err)
151177
}
152178

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
2+
3+
go_library(
4+
name = "hasher_lib",
5+
srcs = ["main.go"],
6+
importpath = "github.com/bazelbuild/rules_python/gazelle/manifest/hasher",
7+
visibility = ["//visibility:private"],
8+
)
9+
10+
go_binary(
11+
name = "hasher",
12+
embed = [":hasher_lib"],
13+
visibility = ["//visibility:public"],
14+
)

gazelle/manifest/hasher/main.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package main
2+
3+
import (
4+
"crypto/sha256"
5+
"io"
6+
"log"
7+
"os"
8+
)
9+
10+
func main() {
11+
h := sha256.New()
12+
out, err := os.Create(os.Args[1])
13+
if err != nil {
14+
log.Fatal(err)
15+
}
16+
defer out.Close()
17+
for _, filename := range os.Args[2:] {
18+
f, err := os.Open(filename)
19+
if err != nil {
20+
log.Fatal(err)
21+
}
22+
defer f.Close()
23+
if _, err := io.Copy(h, f); err != nil {
24+
log.Fatal(err)
25+
}
26+
}
27+
if _, err := out.Write(h.Sum(nil)); err != nil {
28+
log.Fatal(err)
29+
}
30+
}

0 commit comments

Comments
 (0)