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

pantsbuild / pants / 20632486505

01 Jan 2026 04:21AM UTC coverage: 43.231% (-37.1%) from 80.281%
20632486505

Pull #22962

github

web-flow
Merge 08d5c63b0 into f52ab6675
Pull Request #22962: Bump the gha-deps group across 1 directory with 6 updates

26122 of 60424 relevant lines covered (43.23%)

0.86 hits per line

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

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

5
import os
×
6
import re
×
7
from collections import defaultdict
×
8
from collections.abc import Mapping
×
9
from dataclasses import dataclass
×
10
from typing import DefaultDict
×
11

12
from pants.backend.codegen.protobuf.target_types import AllProtobufTargets, ProtobufSourceField
×
13
from pants.engine.addresses import Address
×
14
from pants.engine.fs import FileContent
×
15
from pants.engine.internals.graph import hydrate_sources
×
16
from pants.engine.intrinsics import get_digest_contents
×
17
from pants.engine.rules import collect_rules, concurrently, implicitly, rule
×
18
from pants.engine.target import HydrateSourcesRequest
×
19
from pants.jvm.dependency_inference.artifact_mapper import MutableTrieNode
×
20
from pants.jvm.dependency_inference.symbol_mapper import SymbolMap
×
21
from pants.jvm.subsystems import JvmSubsystem
×
22
from pants.jvm.target_types import JvmResolveField
×
23
from pants.util.ordered_set import OrderedSet
×
24

25
_ResolveName = str
×
26

27

28
@dataclass(frozen=True)
×
29
class FirstPartyProtobufJvmMappingRequest:
×
30
    capitalize_base_name: bool
×
31

32

33
@rule
×
34
async def map_first_party_protobuf_jvm_targets_to_symbols(
×
35
    request: FirstPartyProtobufJvmMappingRequest,
36
    all_protobuf_targets: AllProtobufTargets,
37
    jvm: JvmSubsystem,
38
) -> SymbolMap:
39
    sources = await concurrently(
×
40
        hydrate_sources(
41
            HydrateSourcesRequest(
42
                tgt[ProtobufSourceField],
43
                for_sources_types=(ProtobufSourceField,),
44
                enable_codegen=True,
45
            ),
46
            **implicitly(),
47
        )
48
        for tgt in all_protobuf_targets
49
    )
50

51
    all_contents = await concurrently(
×
52
        get_digest_contents(source.snapshot.digest) for source in sources
53
    )
54

55
    namespace_mapping: DefaultDict[tuple[_ResolveName, str], OrderedSet[Address]] = defaultdict(
×
56
        OrderedSet
57
    )
58
    for tgt, contents in zip(all_protobuf_targets, all_contents):
×
59
        if not contents:
×
60
            continue
×
61
        if len(contents) > 1:
×
62
            raise AssertionError(
×
63
                f"Protobuf target `{tgt.address}` mapped to more than one source file."
64
            )
65

66
        resolve = tgt[JvmResolveField].normalized_value(jvm)
×
67
        namespace = _determine_namespace(
×
68
            contents[0], capitalize_base_name=request.capitalize_base_name
69
        )
70
        namespace_mapping[(resolve, namespace)].add(tgt.address)
×
71

72
    mapping: Mapping[str, MutableTrieNode] = defaultdict(MutableTrieNode)
×
73
    for (resolve, namespace), addresses in namespace_mapping.items():
×
74
        mapping[resolve].insert(namespace, addresses, first_party=True, recursive=True)
×
75

76
    return SymbolMap((resolve, node.frozen()) for resolve, node in mapping.items())
×
77

78

79
# Determine generated Java/Scala package name
80
# * https://grpc.io/docs/languages/java/generated-code
81
# * https://scalapb.github.io/docs/generated-code
82
def _determine_namespace(file: FileContent, *, capitalize_base_name: bool) -> str:
×
83
    base_name, _, _ = os.path.basename(file.path).partition(".")
×
84
    base_name = base_name.capitalize() if capitalize_base_name else base_name
×
85
    package_definition = _parse_package_definition(file.content)
×
86
    return f"{package_definition}.{base_name}" if package_definition else base_name
×
87

88

89
_QUOTE_CHAR = r"(?:'|\")"
×
90
_JAVA_PACKAGE_OPTION_RE = re.compile(
×
91
    rf"^\s*option\s+java_package\s+=\s+{_QUOTE_CHAR}(.+){_QUOTE_CHAR};"
92
)
93
_PACKAGE_RE = re.compile(r"^\s*package\s+(.+);")
×
94

95

96
def _parse_package_definition(content_raw: bytes) -> str | None:
×
97
    content = content_raw.decode()
×
98
    for line in content.splitlines():
×
99
        m = _JAVA_PACKAGE_OPTION_RE.match(line)
×
100
        if m:
×
101
            return m.group(1)
×
102
        m = _PACKAGE_RE.match(line)
×
103
        if m:
×
104
            return m.group(1)
×
105
    return None
×
106

107

108
def rules():
×
109
    return collect_rules()
×
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