• 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

91.67
/src/python/pants/jvm/goals/lockfile.py
1
# Copyright 2022 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3

4
from __future__ import annotations
11✔
5

6
from collections import defaultdict
11✔
7
from collections.abc import Coroutine, Mapping
11✔
8
from dataclasses import dataclass
11✔
9
from typing import Any
11✔
10

11
from pants.core.goals.generate_lockfiles import (
11✔
12
    DEFAULT_TOOL_LOCKFILE,
13
    GenerateLockfile,
14
    GenerateLockfileResult,
15
    GenerateLockfilesSubsystem,
16
    KnownUserResolveNames,
17
    KnownUserResolveNamesRequest,
18
    RequestedUserResolveNames,
19
    UserGenerateLockfiles,
20
)
21
from pants.core.goals.resolves import ExportableTool
11✔
22
from pants.engine.environment import EnvironmentName
11✔
23
from pants.engine.fs import CreateDigest, FileContent
11✔
24
from pants.engine.internals.selectors import concurrently
11✔
25
from pants.engine.intrinsics import create_digest
11✔
26
from pants.engine.rules import collect_rules, implicitly, rule
11✔
27
from pants.engine.target import AllTargets
11✔
28
from pants.engine.unions import UnionMembership, UnionRule, union
11✔
29
from pants.jvm.resolve import coursier_fetch
11✔
30
from pants.jvm.resolve.common import (
11✔
31
    ArtifactRequirement,
32
    ArtifactRequirements,
33
    GatherJvmCoordinatesRequest,
34
)
35
from pants.jvm.resolve.coursier_fetch import coursier_resolve_lockfile
11✔
36
from pants.jvm.resolve.jvm_tool import (
11✔
37
    GenerateJvmLockfileFromTool,
38
    JvmToolBase,
39
    gather_coordinates_for_jvm_lockfile,
40
)
41
from pants.jvm.resolve.lockfile_metadata import JVMLockfileMetadata
11✔
42
from pants.jvm.subsystems import JvmSubsystem
11✔
43
from pants.jvm.target_types import JvmArtifactResolveField, JvmResolveField
11✔
44
from pants.option.subsystem import _construct_subsystem
11✔
45
from pants.util.docutil import bin_name
11✔
46
from pants.util.logging import LogLevel
11✔
47
from pants.util.ordered_set import OrderedSet
11✔
48

49

50
@dataclass(frozen=True)
11✔
51
class GenerateJvmLockfile(GenerateLockfile):
11✔
52
    artifacts: ArtifactRequirements
11✔
53

54

55
@union(in_scope_types=[EnvironmentName])
11✔
56
@dataclass(frozen=True)
11✔
57
class ValidateJvmArtifactsForResolveRequest:
11✔
58
    """Hook for backends to validate the artifact requirements requested for a resolve.
59

60
    The main user is the Scala backend which will ensure scala-library is present in the resolve.
61
    """
62

63
    artifacts: ArtifactRequirements
11✔
64
    resolve_name: str
11✔
65

66

67
@dataclass(frozen=True)
11✔
68
class ValidateJvmArtifactsForResolveResult:
11✔
69
    """Sentinel type that represents that a backend is satisfied with the artifacts for a JVM
70
    resolve."""
71

72

73
@rule(polymorphic=True)
11✔
74
async def _validate_jvm_artifacts_for_resolve(
11✔
75
    req: ValidateJvmArtifactsForResolveRequest, env_name: EnvironmentName
76
) -> ValidateJvmArtifactsForResolveResult:
77
    raise NotImplementedError()
×
78

79

80
@rule(desc="Generate JVM lockfile", level=LogLevel.DEBUG)
11✔
81
async def generate_jvm_lockfile(
11✔
82
    request: GenerateJvmLockfile,
83
    generate_lockfiles_subsystem: GenerateLockfilesSubsystem,
84
) -> GenerateLockfileResult:
85
    resolved_lockfile = await coursier_resolve_lockfile(request.artifacts)
1✔
86
    regenerate_command = (
1✔
87
        generate_lockfiles_subsystem.custom_command or f"{bin_name()} generate-lockfiles"
88
    )
89

90
    resolved_lockfile_contents = resolved_lockfile.to_serialized()
1✔
91
    metadata = JVMLockfileMetadata.new(request.artifacts)
1✔
92
    resolved_lockfile_contents = metadata.add_header_to_lockfile(
1✔
93
        resolved_lockfile_contents,
94
        regenerate_command=regenerate_command,
95
        delimeter="#",
96
    )
97

98
    lockfile_digest = await create_digest(
1✔
99
        CreateDigest([FileContent(request.lockfile_dest, resolved_lockfile_contents)])
100
    )
101
    return GenerateLockfileResult(lockfile_digest, request.resolve_name, request.lockfile_dest)
1✔
102

103

104
class RequestedJVMUserResolveNames(RequestedUserResolveNames):
11✔
105
    pass
11✔
106

107

108
class KnownJVMUserResolveNamesRequest(KnownUserResolveNamesRequest):
11✔
109
    pass
11✔
110

111

112
@rule
11✔
113
async def determine_jvm_user_resolves(
11✔
114
    _: KnownJVMUserResolveNamesRequest,
115
    jvm_subsystem: JvmSubsystem,
116
    union_membership: UnionMembership,
117
) -> KnownUserResolveNames:
118
    jvm_tool_resolves = ExportableTool.filter_for_subclasses(union_membership, JvmToolBase)
×
119
    names = (*jvm_subsystem.resolves.keys(), *jvm_tool_resolves.keys())
×
120
    return KnownUserResolveNames(
×
121
        names=names,
122
        option_name=f"[{jvm_subsystem.options_scope}].resolves",
123
        requested_resolve_names_cls=RequestedJVMUserResolveNames,
124
    )
125

126

127
@dataclass(frozen=True)
11✔
128
class _ValidateJvmArtifactsRequest:
11✔
129
    artifacts: ArtifactRequirements
11✔
130
    resolve_name: str
11✔
131

132

133
@rule
11✔
134
async def validate_jvm_artifacts_for_resolve(
11✔
135
    request: _ValidateJvmArtifactsRequest,
136
    union_membership: UnionMembership,
137
    jvm_subsystem: JvmSubsystem,
138
) -> GenerateJvmLockfile:
139
    impls = union_membership.get(ValidateJvmArtifactsForResolveRequest)
1✔
140
    for impl in impls:
1✔
141
        validate_request = impl(artifacts=request.artifacts, resolve_name=request.resolve_name)
×
142
        _ = await _validate_jvm_artifacts_for_resolve(
×
143
            **implicitly({validate_request: ValidateJvmArtifactsForResolveRequest})
144
        )
145

146
    return GenerateJvmLockfile(
1✔
147
        artifacts=request.artifacts,
148
        resolve_name=request.resolve_name,
149
        lockfile_dest=jvm_subsystem.resolves[request.resolve_name],
150
        diff=False,
151
    )
152

153

154
@rule
11✔
155
async def setup_lockfile_request_from_tool(
11✔
156
    request: GenerateJvmLockfileFromTool,
157
) -> GenerateJvmLockfile:
158
    artifacts = await gather_coordinates_for_jvm_lockfile(
2✔
159
        GatherJvmCoordinatesRequest(request.artifact_inputs, request.artifact_option_name)
160
    )
161
    return GenerateJvmLockfile(
2✔
162
        artifacts=artifacts,
163
        resolve_name=request.resolve_name,
164
        lockfile_dest=(
165
            request.lockfile if request.lockfile != DEFAULT_TOOL_LOCKFILE else DEFAULT_TOOL_LOCKFILE
166
        ),
167
        diff=False,
168
    )
169

170

171
async def _plan_generate_lockfile(
11✔
172
    resolve, resolve_to_artifacts, tools
173
) -> Coroutine[Any, Any, GenerateJvmLockfile]:
174
    """Generate a JVM lockfile request for each requested resolve.
175

176
    This step also allows other backends to validate the proposed set of artifact requirements for
177
    each resolve.
178
    """
179
    if resolve in resolve_to_artifacts:
1✔
180
        return validate_jvm_artifacts_for_resolve(
1✔
181
            _ValidateJvmArtifactsRequest(
182
                artifacts=ArtifactRequirements(resolve_to_artifacts[resolve]),
183
                resolve_name=resolve,
184
            ),
185
            **implicitly(),
186
        )
187
    elif resolve in tools:
1✔
188
        tool_cls: type[JvmToolBase] = tools[resolve]
1✔
189
        tool = await _construct_subsystem(tool_cls)
1✔
190

191
        return setup_lockfile_request_from_tool(
1✔
192
            GenerateJvmLockfileFromTool.create(tool),
193
        )
194

195
    else:
196
        return validate_jvm_artifacts_for_resolve(
×
197
            _ValidateJvmArtifactsRequest(
198
                artifacts=ArtifactRequirements(()),
199
                resolve_name=resolve,
200
            ),
201
            **implicitly(),
202
        )
203

204

205
@rule
11✔
206
async def setup_user_lockfile_requests(
11✔
207
    requested: RequestedJVMUserResolveNames,
208
    all_targets: AllTargets,
209
    jvm_subsystem: JvmSubsystem,
210
    union_membership: UnionMembership,
211
) -> UserGenerateLockfiles:
212
    resolve_to_artifacts: Mapping[str, OrderedSet[ArtifactRequirement]] = defaultdict(OrderedSet)
1✔
213
    for tgt in sorted(all_targets, key=lambda t: t.address):
1✔
214
        if not tgt.has_field(JvmArtifactResolveField):
1✔
215
            continue
×
216
        artifact = ArtifactRequirement.from_jvm_artifact_target(tgt)
1✔
217
        resolve = tgt[JvmResolveField].normalized_value(jvm_subsystem)
1✔
218
        resolve_to_artifacts[resolve].add(artifact)
1✔
219

220
    tools = ExportableTool.filter_for_subclasses(union_membership, JvmToolBase)
1✔
221

222
    rule_calls: list[Coroutine[Any, Any, GenerateJvmLockfile]] = []
1✔
223
    for resolve in requested:
1✔
224
        rule_calls.append(await _plan_generate_lockfile(resolve, resolve_to_artifacts, tools))
1✔
225

226
    jvm_lockfile_requests = await concurrently(rule_calls)
1✔
227

228
    return UserGenerateLockfiles(jvm_lockfile_requests)
1✔
229

230

231
def rules():
11✔
232
    return (
11✔
233
        *collect_rules(),
234
        *coursier_fetch.rules(),
235
        UnionRule(GenerateLockfile, GenerateJvmLockfile),
236
        UnionRule(KnownUserResolveNamesRequest, KnownJVMUserResolveNamesRequest),
237
        UnionRule(RequestedUserResolveNames, RequestedJVMUserResolveNames),
238
    )
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