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

pantsbuild / pants / 18517631058

15 Oct 2025 04:18AM UTC coverage: 69.207% (-11.1%) from 80.267%
18517631058

Pull #22745

github

web-flow
Merge 642a76ca1 into 99919310e
Pull Request #22745: [windows] Add windows support in the stdio crate.

53815 of 77759 relevant lines covered (69.21%)

2.42 hits per line

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

0.0
/src/python/pants/backend/kotlin/compile/kotlinc_plugins.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
×
5

6
from collections.abc import Iterable, Iterator
×
7
from dataclasses import dataclass
×
8

9
from pants.backend.kotlin.subsystems.kotlinc import KotlincSubsystem
×
10
from pants.backend.kotlin.target_types import (
×
11
    KotlincConsumedPluginIdsField,
12
    KotlincPluginArgsField,
13
    KotlincPluginArtifactField,
14
    KotlincPluginIdField,
15
)
16
from pants.build_graph.address import AddressInput
×
17
from pants.engine.addresses import Addresses
×
18
from pants.engine.internals.build_files import resolve_address
×
19
from pants.engine.internals.graph import resolve_coarsened_targets as coarsened_targets_get
×
20
from pants.engine.internals.graph import resolve_targets
×
21
from pants.engine.internals.native_engine import MergeDigests
×
22
from pants.engine.intrinsics import merge_digests
×
23
from pants.engine.rules import collect_rules, concurrently, implicitly, rule
×
24
from pants.engine.target import AllTargets, Target, Targets
×
25
from pants.jvm.compile import ClasspathEntry, FallibleClasspathEntry
×
26
from pants.jvm.goals import lockfile
×
27
from pants.jvm.resolve.coursier_fetch import CoursierFetchRequest, fetch_with_coursier
×
28
from pants.jvm.resolve.jvm_tool import rules as jvm_tool_rules
×
29
from pants.jvm.resolve.key import CoursierResolveKey
×
30
from pants.jvm.subsystems import JvmSubsystem
×
31
from pants.jvm.target_types import JvmResolveField
×
32
from pants.util.frozendict import FrozenDict
×
33

34

35
@dataclass(frozen=True)
×
36
class KotlincPluginsForTargetWithoutResolveRequest:
×
37
    target: Target
×
38

39

40
@dataclass(frozen=True)
×
41
class KotlincPluginsForTargetRequest:
×
42
    target: Target
×
43
    resolve_name: str
×
44

45

46
@dataclass(frozen=True)
×
47
class KotlincPluginTargetsForTarget:
×
48
    plugins: Targets
×
49
    artifacts: Targets
×
50

51

52
@dataclass(frozen=True)
×
53
class KotlincPluginsRequest:
×
54
    plugins: Targets
×
55
    artifacts: Targets
×
56
    resolve: CoursierResolveKey
×
57

58
    @classmethod
×
59
    def from_target_plugins(
×
60
        cls,
61
        seq: Iterable[KotlincPluginTargetsForTarget],
62
        resolve: CoursierResolveKey,
63
    ) -> KotlincPluginsRequest:
64
        plugins: set[Target] = set()
×
65
        artifacts: set[Target] = set()
×
66

67
        for spft in seq:
×
68
            plugins.update(spft.plugins)
×
69
            artifacts.update(spft.artifacts)
×
70

71
        return KotlincPluginsRequest(Targets(plugins), Targets(artifacts), resolve)
×
72

73

74
@dataclass(frozen=True)
×
75
class KotlincPlugins:
×
76
    ids: tuple[str, ...]
×
77
    classpath: ClasspathEntry
×
78
    plugin_args: FrozenDict[str, tuple[str, ...]]
×
79

80
    def args(self, prefix: str | None = None) -> Iterator[str]:
×
81
        p = f"{prefix}/" if prefix else ""
×
82
        for kotlinc_plugin_path in self.classpath.filenames:
×
83
            yield f"-Xplugin={p}{kotlinc_plugin_path}"
×
84
        for id in self.ids:
×
85
            for arg in self.plugin_args.get(id, ()):
×
86
                yield "-P"
×
87
                yield f"plugin:{id}:{arg}"
×
88

89

90
class AllKotlincPluginTargets(Targets):
×
91
    pass
×
92

93

94
@rule
×
95
async def all_kotlinc_plugin_targets(targets: AllTargets) -> AllKotlincPluginTargets:
×
96
    return AllKotlincPluginTargets(
×
97
        tgt
98
        for tgt in targets
99
        if tgt.has_fields(
100
            (KotlincPluginArtifactField, KotlincPluginIdField, KotlincPluginArgsField)
101
        )
102
    )
103

104

105
@rule
×
106
async def add_resolve_name_to_plugin_request(
×
107
    request: KotlincPluginsForTargetWithoutResolveRequest, jvm: JvmSubsystem
108
) -> KotlincPluginsForTargetRequest:
109
    return KotlincPluginsForTargetRequest(
×
110
        request.target, request.target[JvmResolveField].normalized_value(jvm)
111
    )
112

113

114
@rule
×
115
async def resolve_kotlinc_plugins_for_target(
×
116
    request: KotlincPluginsForTargetRequest,
117
    all_kotlinc_plugins: AllKotlincPluginTargets,
118
    jvm: JvmSubsystem,
119
    kotlinc: KotlincSubsystem,
120
) -> KotlincPluginTargetsForTarget:
121
    target = request.target
×
122
    resolve = request.resolve_name
×
123

124
    plugin_ids = target.get(KotlincConsumedPluginIdsField).value
×
125
    if plugin_ids is None:
×
126
        plugin_names_by_resolve = kotlinc.parsed_default_plugins()
×
127
        plugin_ids = tuple(plugin_names_by_resolve.get(resolve, ()))
×
128

129
    candidate_plugins = []
×
130
    for plugin in all_kotlinc_plugins:
×
131
        if _plugin_id(plugin) not in plugin_ids:
×
132
            continue
×
133
        candidate_plugins.append(plugin)
×
134

135
    address_inputs: list[AddressInput] = [
×
136
        plugin[KotlincPluginArtifactField].to_address_input() for plugin in candidate_plugins
137
    ]
138
    artifact_addresses = await concurrently(
×
139
        resolve_address(**implicitly({address_input: AddressInput}))
140
        for address_input in address_inputs
141
    )
142
    candidate_artifacts = await resolve_targets(**implicitly(Addresses(artifact_addresses)))
×
143

144
    plugins: dict[str, tuple[Target, Target]] = {}  # Maps plugin ID to relevant JVM artifact
×
145
    for plugin, artifact in zip(candidate_plugins, candidate_artifacts):
×
146
        if artifact[JvmResolveField].normalized_value(jvm) != resolve:
×
147
            continue
×
148

149
        plugins[_plugin_id(plugin)] = (plugin, artifact)
×
150

151
    for plugin_id in plugin_ids:
×
152
        if plugin_id not in plugins:
×
153
            raise Exception(
×
154
                f"Could not find `kotlinc` plugin `{plugin_id}` in resolve `{resolve}` "
155
                f"for target {request.target}"
156
            )
157

158
    plugin_targets, artifact_targets = zip(*plugins.values()) if plugins else ((), ())
×
159
    return KotlincPluginTargetsForTarget(Targets(plugin_targets), Targets(artifact_targets))
×
160

161

162
def _plugin_id(target: Target) -> str:
×
163
    plugin_id = target[KotlincPluginIdField].value
×
164
    if not plugin_id:
×
165
        plugin_id = target.address.target_name
×
166
    return plugin_id
×
167

168

169
@rule
×
170
async def fetch_kotlinc_plugins(request: KotlincPluginsRequest) -> KotlincPlugins:
×
171
    # Fetch all the artifacts
172
    coarsened_targets = await coarsened_targets_get(
×
173
        **implicitly(Addresses(target.address for target in request.artifacts))
174
    )
175
    fallible_artifacts = await concurrently(
×
176
        fetch_with_coursier(CoursierFetchRequest(ct, resolve=request.resolve))
177
        for ct in coarsened_targets
178
    )
179

180
    artifacts = FallibleClasspathEntry.if_all_succeeded(fallible_artifacts)
×
181
    if artifacts is None:
×
182
        failed = [i for i in fallible_artifacts if i.exit_code != 0]
×
183
        raise Exception(f"Fetching local kotlinc plugins failed: {failed}")
×
184

185
    entries = list(ClasspathEntry.closure(artifacts))
×
186
    merged_classpath_digest = await merge_digests(MergeDigests(entry.digest for entry in entries))
×
187
    merged = ClasspathEntry.merge(merged_classpath_digest, entries)
×
188

189
    ids = tuple(_plugin_id(target) for target in request.plugins)
×
190

191
    plugin_args = FrozenDict(
×
192
        {
193
            _plugin_id(plugin): tuple(plugin[KotlincPluginArgsField].value or [])
194
            for plugin in request.plugins
195
        }
196
    )
197

198
    return KotlincPlugins(ids=ids, classpath=merged, plugin_args=plugin_args)
×
199

200

201
def rules():
×
202
    return (
×
203
        *collect_rules(),
204
        *jvm_tool_rules(),
205
        *lockfile.rules(),
206
    )
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