• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pantsbuild / pants / 25259185675

02 May 2026 06:47PM UTC coverage: 92.141% (-0.8%) from 92.955%
25259185675

push

github

web-flow
Fix the dynamic UI. (#23306)

In #23114 we upgraded to indicatif 0.18.4,
which included a fix to respect TERM, and 
display nothing if it's unset.

Since we did not pass TERM through pantsd, the
dynamic ui is now not shown. 

This change fixes that, and also pass NO_COLOR
through, since indicatif inspects it too.

88773 of 96345 relevant lines covered (92.14%)

3.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

54.79
/src/python/pants/backend/codegen/protobuf/java/rules.py
1
# Copyright 2020 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3
from __future__ import annotations
1✔
4

5
from dataclasses import dataclass
1✔
6
from pathlib import PurePath
1✔
7

8
from pants.backend.codegen.protobuf import protoc
1✔
9
from pants.backend.codegen.protobuf.java import dependency_inference, symbol_mapper
1✔
10
from pants.backend.codegen.protobuf.java.subsystem import JavaProtobufGrpcSubsystem
1✔
11
from pants.backend.codegen.protobuf.protoc import Protoc
1✔
12
from pants.backend.codegen.protobuf.target_types import (
1✔
13
    ProtobufGrpcToggleField,
14
    ProtobufSourceField,
15
    ProtobufSourcesGeneratorTarget,
16
    ProtobufSourceTarget,
17
)
18
from pants.backend.experimental.java.register import rules as java_backend_rules
1✔
19
from pants.backend.java.target_types import JavaSourceField
1✔
20
from pants.core.goals.resolves import ExportableTool
1✔
21
from pants.core.util_rules.external_tool import download_external_tool
1✔
22
from pants.core.util_rules.source_files import SourceFilesRequest
1✔
23
from pants.core.util_rules.stripped_source_files import strip_source_roots
1✔
24
from pants.engine.fs import (
1✔
25
    AddPrefix,
26
    CreateDigest,
27
    Digest,
28
    Directory,
29
    FileEntry,
30
    MergeDigests,
31
    RemovePrefix,
32
)
33
from pants.engine.internals.graph import transitive_targets
1✔
34
from pants.engine.intrinsics import (
1✔
35
    create_digest,
36
    digest_to_snapshot,
37
    get_digest_entries,
38
    merge_digests,
39
    remove_prefix,
40
)
41
from pants.engine.platform import Platform
1✔
42
from pants.engine.process import Process, fallible_to_exec_result_or_raise
1✔
43
from pants.engine.rules import collect_rules, concurrently, implicitly, rule
1✔
44
from pants.engine.target import GeneratedSources, GenerateSourcesRequest, TransitiveTargetsRequest
1✔
45
from pants.engine.unions import UnionRule
1✔
46
from pants.jvm.resolve.coursier_fetch import ToolClasspathRequest, materialize_classpath_for_tool
1✔
47
from pants.jvm.resolve.jvm_tool import GenerateJvmLockfileFromTool
1✔
48
from pants.jvm.target_types import PrefixedJvmJdkField, PrefixedJvmResolveField
1✔
49
from pants.source.source_root import SourceRootRequest, get_source_root
1✔
50
from pants.util.logging import LogLevel
1✔
51

52

53
class GenerateJavaFromProtobufRequest(GenerateSourcesRequest):
1✔
54
    input = ProtobufSourceField
1✔
55
    output = JavaSourceField
1✔
56

57

58
@dataclass(frozen=True)
1✔
59
class ProtobufJavaGrpcPlugin:
1✔
60
    digest: Digest
1✔
61
    path: str
1✔
62

63

64
@rule
1✔
65
async def resolve_protobuf_java_grpc_plugin(
1✔
66
    platform: Platform,
67
    tool: JavaProtobufGrpcSubsystem,
68
) -> ProtobufJavaGrpcPlugin:
69
    lockfile_request = GenerateJvmLockfileFromTool.create(tool)
×
70
    classpath = await materialize_classpath_for_tool(
×
71
        ToolClasspathRequest(lockfile=lockfile_request)
72
    )
73

74
    # TODO: Improve `ToolClasspath` API so that the filenames corresponding to a coordinate are identified by a
75
    # mapping. Work-around the lack of such information by looking for a platform-specific string in the filenames
76
    # provided in the classpath.
77
    platform_part = {
×
78
        Platform.macos_arm64: "exe_osx-aarch_64",
79
        Platform.macos_x86_64: "exe_osx-x86_64",
80
        Platform.linux_arm64: "exe_linux-aarch_64",
81
        Platform.linux_x86_64: "exe_linux-x86_64",
82
    }[platform]
83

84
    classpath_entries = await get_digest_entries(classpath.digest)
×
85
    candidate_plugin_entries = []
×
86
    for classpath_entry in classpath_entries:
×
87
        if isinstance(classpath_entry, FileEntry):
×
88
            path = PurePath(classpath_entry.path)
×
89
            if platform_part in path.name:
×
90
                candidate_plugin_entries.append(classpath_entry)
×
91

92
    assert len(candidate_plugin_entries) == 1
×
93

94
    plugin_digest = await create_digest(
×
95
        CreateDigest(
96
            [
97
                FileEntry(
98
                    path="protoc-gen-grpc-java",
99
                    file_digest=candidate_plugin_entries[0].file_digest,
100
                    is_executable=True,
101
                )
102
            ]
103
        )
104
    )
105

106
    return ProtobufJavaGrpcPlugin(digest=plugin_digest, path="protoc-gen-grpc-java")
×
107

108

109
@rule(desc="Generate Java from Protobuf", level=LogLevel.DEBUG)
1✔
110
async def generate_java_from_protobuf(
1✔
111
    request: GenerateJavaFromProtobufRequest,
112
    protoc: Protoc,
113
    grpc_plugin: ProtobufJavaGrpcPlugin,  # TODO: Don't access grpc plugin unless gRPC codegen is enabled.
114
    platform: Platform,
115
) -> GeneratedSources:
116
    download_protoc_request = download_external_tool(protoc.get_request(platform))
×
117

118
    output_dir = "_generated_files"
×
119
    create_output_dir_request = create_digest(CreateDigest([Directory(output_dir)]))
×
120

121
    # Protoc needs all transitive dependencies on `protobuf_source` to work properly. It won't
122
    # actually generate those dependencies; it only needs to look at their .proto files to work
123
    # with imports.
124
    transitive_targets_for_protobuf_source = await transitive_targets(
×
125
        TransitiveTargetsRequest([request.protocol_target.address]), **implicitly()
126
    )
127

128
    # NB: By stripping the source roots, we avoid having to set the value `--proto_path`
129
    # for Protobuf imports to be discoverable.
130
    all_stripped_sources_request = strip_source_roots(
×
131
        **implicitly(
132
            SourceFilesRequest(
133
                tgt[ProtobufSourceField]
134
                for tgt in transitive_targets_for_protobuf_source.closure
135
                if tgt.has_field(ProtobufSourceField)
136
            )
137
        )
138
    )
139
    target_stripped_sources_request = strip_source_roots(
×
140
        **implicitly(SourceFilesRequest([request.protocol_target[ProtobufSourceField]]))
141
    )
142

143
    (
×
144
        downloaded_protoc_binary,
145
        empty_output_dir,
146
        all_sources_stripped,
147
        target_sources_stripped,
148
    ) = await concurrently(
149
        download_protoc_request,
150
        create_output_dir_request,
151
        all_stripped_sources_request,
152
        target_stripped_sources_request,
153
    )
154

155
    unmerged_digests = [
×
156
        all_sources_stripped.snapshot.digest,
157
        downloaded_protoc_binary.digest,
158
        empty_output_dir,
159
    ]
160
    input_digest = await merge_digests(MergeDigests(unmerged_digests))
×
161

162
    immutable_input_digests = {}
×
163
    if request.protocol_target.get(ProtobufGrpcToggleField).value:
×
164
        immutable_input_digests["__grpc"] = grpc_plugin.digest
×
165

166
    argv = [downloaded_protoc_binary.exe, "--java_out", output_dir]
×
167
    if request.protocol_target.get(ProtobufGrpcToggleField).value:
×
168
        argv.extend(
×
169
            [
170
                f"--plugin=protoc-gen-grpc-java=./__grpc/{grpc_plugin.path}",
171
                f"--grpc-java_out={output_dir}",
172
            ]
173
        )
174

175
    argv.extend(target_sources_stripped.snapshot.files)
×
176
    result = await fallible_to_exec_result_or_raise(
×
177
        **implicitly(
178
            Process(
179
                argv,
180
                input_digest=input_digest,
181
                immutable_input_digests=immutable_input_digests,
182
                description=f"Generating Java sources from {request.protocol_target.address}.",
183
                level=LogLevel.DEBUG,
184
                output_directories=(output_dir,),
185
            )
186
        )
187
    )
188

189
    normalized_digest, source_root = await concurrently(
×
190
        remove_prefix(RemovePrefix(result.output_digest, output_dir)),
191
        get_source_root(SourceRootRequest.for_target(request.protocol_target)),
192
    )
193

194
    source_root_restored = (
×
195
        await digest_to_snapshot(**implicitly(AddPrefix(normalized_digest, source_root.path)))
196
        if source_root.path != "."
197
        else await digest_to_snapshot(normalized_digest)
198
    )
199
    return GeneratedSources(source_root_restored)
×
200

201

202
def rules():
1✔
203
    return [
1✔
204
        *collect_rules(),
205
        *dependency_inference.rules(),
206
        *symbol_mapper.rules(),
207
        *protoc.rules(),
208
        UnionRule(GenerateSourcesRequest, GenerateJavaFromProtobufRequest),
209
        UnionRule(ExportableTool, JavaProtobufGrpcSubsystem),
210
        ProtobufSourceTarget.register_plugin_field(PrefixedJvmJdkField),
211
        ProtobufSourcesGeneratorTarget.register_plugin_field(PrefixedJvmJdkField),
212
        ProtobufSourceTarget.register_plugin_field(PrefixedJvmResolveField),
213
        ProtobufSourcesGeneratorTarget.register_plugin_field(PrefixedJvmResolveField),
214
        # Bring in the Java backend (since this backend compiles Java code) to avoid rule graph errors.
215
        # TODO: Figure out whether a subset of rules can be brought in to still avoid rule graph errors.
216
        *java_backend_rules(),
217
    ]
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc