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

pantsbuild / pants / 19015773527

02 Nov 2025 05:33PM UTC coverage: 17.872% (-62.4%) from 80.3%
19015773527

Pull #22816

github

web-flow
Merge a12d75757 into 6c024e162
Pull Request #22816: Update Pants internal Python to 3.14

4 of 5 new or added lines in 3 files covered. (80.0%)

28452 existing lines in 683 files now uncovered.

9831 of 55007 relevant lines covered (17.87%)

0.18 hits per line

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

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

UNCOV
4
import itertools
×
UNCOV
5
import logging
×
UNCOV
6
import shlex
×
UNCOV
7
from itertools import chain
×
UNCOV
8
from pathlib import Path
×
9

UNCOV
10
from pants.core.target_types import ResourcesFieldSet, ResourcesGeneratorFieldSet
×
UNCOV
11
from pants.core.util_rules import stripped_source_files
×
UNCOV
12
from pants.core.util_rules.source_files import SourceFilesRequest
×
UNCOV
13
from pants.core.util_rules.stripped_source_files import strip_source_roots
×
UNCOV
14
from pants.core.util_rules.system_binaries import BashBinary, TouchBinary, ZipBinary
×
UNCOV
15
from pants.engine.fs import MergeDigests
×
UNCOV
16
from pants.engine.internals.selectors import concurrently
×
UNCOV
17
from pants.engine.intrinsics import merge_digests
×
UNCOV
18
from pants.engine.process import Process, execute_process_or_raise
×
UNCOV
19
from pants.engine.rules import collect_rules, implicitly, rule
×
UNCOV
20
from pants.engine.target import SourcesField
×
UNCOV
21
from pants.engine.unions import UnionRule
×
UNCOV
22
from pants.jvm import compile
×
UNCOV
23
from pants.jvm.compile import (
×
24
    ClasspathDependenciesRequest,
25
    ClasspathEntry,
26
    ClasspathEntryRequest,
27
    ClasspathEntryRequests,
28
    CompileResult,
29
    FallibleClasspathEntries,
30
    FallibleClasspathEntry,
31
    compile_classpath_entries,
32
)
UNCOV
33
from pants.jvm.strip_jar.strip_jar import StripJarRequest, strip_jar
×
UNCOV
34
from pants.jvm.subsystems import JvmSubsystem
×
UNCOV
35
from pants.util.logging import LogLevel
×
36

UNCOV
37
logger = logging.getLogger(__name__)
×
38

39

UNCOV
40
class JvmResourcesRequest(ClasspathEntryRequest):
×
UNCOV
41
    field_sets = (
×
42
        ResourcesFieldSet,
43
        ResourcesGeneratorFieldSet,
44
    )
45

46

UNCOV
47
@rule(desc="Assemble resources")
×
UNCOV
48
async def assemble_resources_jar(
×
49
    zip: ZipBinary,
50
    bash: BashBinary,
51
    touch: TouchBinary,
52
    jvm: JvmSubsystem,
53
    request: JvmResourcesRequest,
54
) -> FallibleClasspathEntry:
55
    # Request the component's direct dependency classpath, and additionally any prerequisite.
56
    # Filter out any dependencies that are generated by our current target so that each resource
57
    # only appears in a single input JAR.
58
    # NOTE: Generated dependencies will have the same dependencies as the current target, so we
59
    # don't need to inspect those dependencies.
60
    optional_prereq_request = [*((request.prerequisite,) if request.prerequisite else ())]
×
61
    fallibles = await concurrently(
×
62
        compile_classpath_entries(ClasspathEntryRequests(optional_prereq_request)),
63
        compile_classpath_entries(
64
            **implicitly(ClasspathDependenciesRequest(request, ignore_generated=True))
65
        ),
66
    )
67
    direct_dependency_classpath_entries = FallibleClasspathEntries(
×
68
        itertools.chain(*fallibles)
69
    ).if_all_succeeded()
70

71
    if direct_dependency_classpath_entries is None:
×
72
        return FallibleClasspathEntry(
×
73
            description=str(request.component),
74
            result=CompileResult.DEPENDENCY_FAILED,
75
            output=None,
76
            exit_code=1,
77
        )
78

79
    source_files = await strip_source_roots(
×
80
        **implicitly(
81
            SourceFilesRequest([tgt.get(SourcesField) for tgt in request.component.members])
82
        )
83
    )
84

85
    output_filename = f"{request.component.representative.address.path_safe_spec}.resources.jar"
×
86
    output_files = [output_filename]
×
87

88
    # #16231: Valid JAR files need the directories of each resource file as well as the files
89
    # themselves.
90

91
    paths = {Path(filename) for filename in source_files.snapshot.files}
×
92
    directories = {parent for path in paths for parent in path.parents}
×
93
    input_files = {str(path) for path in chain(paths, directories)}
×
94

95
    resources_jar_input_digest = source_files.snapshot.digest
×
96

97
    input_filenames = shlex.join(sorted(input_files))
×
98

99
    resources_jar_result = await execute_process_or_raise(
×
100
        **implicitly(
101
            Process(
102
                argv=[
103
                    bash.path,
104
                    "-c",
105
                    " ".join(
106
                        [
107
                            "TZ=UTC",
108
                            touch.path,
109
                            "-t 198001010000.00",
110
                            input_filenames,
111
                            "&&",
112
                            "TZ=UTC",
113
                            zip.path,
114
                            "-oX",
115
                            output_filename,
116
                            input_filenames,
117
                        ]
118
                    ),
119
                ],
120
                description=f"Build resources JAR for {request.component}",
121
                input_digest=resources_jar_input_digest,
122
                output_files=output_files,
123
                level=LogLevel.DEBUG,
124
            )
125
        )
126
    )
127

128
    output_digest = resources_jar_result.output_digest
×
129
    if jvm.reproducible_jars:
×
130
        output_digest = await strip_jar(
×
131
            **implicitly(StripJarRequest(output_digest, tuple(output_files)))
132
        )
133

134
    cpe = ClasspathEntry(output_digest, output_files, [])
×
135

136
    merged_cpe_digest = await merge_digests(
×
137
        MergeDigests(chain((cpe.digest,), (i.digest for i in direct_dependency_classpath_entries)))
138
    )
139

140
    merged_cpe = ClasspathEntry.merge(
×
141
        digest=merged_cpe_digest, entries=[cpe, *direct_dependency_classpath_entries]
142
    )
143

144
    return FallibleClasspathEntry(output_filename, CompileResult.SUCCEEDED, merged_cpe, 0)
×
145

146

UNCOV
147
def rules():
×
UNCOV
148
    return [
×
149
        *collect_rules(),
150
        *compile.rules(),
151
        *stripped_source_files.rules(),
152
        UnionRule(ClasspathEntryRequest, JvmResourcesRequest),
153
    ]
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

© 2025 Coveralls, Inc