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

pantsbuild / pants / 21552830208

31 Jan 2026 11:40PM UTC coverage: 80.277% (-0.05%) from 80.324%
21552830208

Pull #23062

github

web-flow
Merge 808a9786c into 2c4dcf9cf
Pull Request #23062: Remove support for Get

18 of 25 new or added lines in 4 files covered. (72.0%)

17119 existing lines in 541 files now uncovered.

78278 of 97510 relevant lines covered (80.28%)

3.36 hits per line

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

58.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
5✔
UNCOV
5
import logging
5✔
UNCOV
6
import shlex
5✔
UNCOV
7
from itertools import chain
5✔
UNCOV
8
from pathlib import Path
5✔
9

UNCOV
10
from pants.core.target_types import ResourcesFieldSet, ResourcesGeneratorFieldSet
5✔
UNCOV
11
from pants.core.util_rules import stripped_source_files
5✔
UNCOV
12
from pants.core.util_rules.source_files import SourceFilesRequest
5✔
UNCOV
13
from pants.core.util_rules.stripped_source_files import strip_source_roots
5✔
UNCOV
14
from pants.core.util_rules.system_binaries import BashBinary, TouchBinary, ZipBinary
5✔
UNCOV
15
from pants.engine.fs import MergeDigests
5✔
UNCOV
16
from pants.engine.internals.selectors import concurrently
5✔
UNCOV
17
from pants.engine.intrinsics import merge_digests
5✔
UNCOV
18
from pants.engine.process import Process, execute_process_or_raise
5✔
UNCOV
19
from pants.engine.rules import collect_rules, implicitly, rule
5✔
UNCOV
20
from pants.engine.target import SourcesField
5✔
UNCOV
21
from pants.engine.unions import UnionRule
5✔
UNCOV
22
from pants.jvm import compile
5✔
UNCOV
23
from pants.jvm.compile import (
5✔
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
5✔
UNCOV
34
from pants.jvm.subsystems import JvmSubsystem
5✔
UNCOV
35
from pants.util.logging import LogLevel
5✔
36

UNCOV
37
logger = logging.getLogger(__name__)
5✔
38

39

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

46

UNCOV
47
@rule(desc="Assemble resources")
5✔
UNCOV
48
async def assemble_resources_jar(
5✔
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():
5✔
UNCOV
148
    return [
5✔
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

© 2026 Coveralls, Inc