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

pantsbuild / pants / 19152966480

06 Nov 2025 11:25PM UTC coverage: 80.312% (+0.01%) from 80.3%
19152966480

Pull #22862

github

web-flow
Merge cfed30043 into 1de08017a
Pull Request #22862: [pants-ng] Initial implementation of contextual config

78065 of 97202 relevant lines covered (80.31%)

3.36 hits per line

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

67.69
/src/python/pants/backend/nfpm/rules.py
1
# Copyright 2023 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3

4
from __future__ import annotations
3✔
5

6
from collections.abc import Iterable
3✔
7
from dataclasses import dataclass
3✔
8

9
from pants.backend.nfpm.field_sets import (
3✔
10
    NfpmApkPackageFieldSet,
11
    NfpmArchlinuxPackageFieldSet,
12
    NfpmDebPackageFieldSet,
13
    NfpmPackageFieldSet,
14
    NfpmRpmPackageFieldSet,
15
)
16
from pants.backend.nfpm.field_sets import rules as field_sets_rules
3✔
17
from pants.backend.nfpm.subsystem import NfpmSubsystem
3✔
18
from pants.backend.nfpm.util_rules.contents import rules as contents_rules
3✔
19
from pants.backend.nfpm.util_rules.generate_config import (
3✔
20
    NfpmPackageConfigRequest,
21
    generate_nfpm_yaml,
22
)
23
from pants.backend.nfpm.util_rules.generate_config import rules as generate_config_rules
3✔
24
from pants.backend.nfpm.util_rules.inject_config import rules as inject_config_rules
3✔
25
from pants.backend.nfpm.util_rules.sandbox import (
3✔
26
    NfpmContentSandboxRequest,
27
    populate_nfpm_content_sandbox,
28
)
29
from pants.backend.nfpm.util_rules.sandbox import rules as sandbox_rules
3✔
30
from pants.core.goals import package
3✔
31
from pants.core.goals.package import BuiltPackage, BuiltPackageArtifact
3✔
32
from pants.core.util_rules.external_tool import download_external_tool
3✔
33
from pants.engine.fs import CreateDigest, Directory, MergeDigests
3✔
34
from pants.engine.internals.native_engine import AddPrefix, RemovePrefix
3✔
35
from pants.engine.internals.selectors import concurrently
3✔
36
from pants.engine.intrinsics import create_digest, digest_to_snapshot, merge_digests, remove_prefix
3✔
37
from pants.engine.platform import Platform
3✔
38
from pants.engine.process import Process, execute_process_or_raise
3✔
39
from pants.engine.rules import Rule, collect_rules, implicitly, rule
3✔
40
from pants.engine.unions import UnionRule
3✔
41
from pants.util.logging import LogLevel
3✔
42

43

44
@dataclass(frozen=True)
3✔
45
class BuiltNfpmPackageArtifact(BuiltPackageArtifact):
3✔
46
    packager: str = ""
3✔
47

48
    @classmethod
3✔
49
    def create(cls, relpath: str, packager: str) -> BuiltNfpmPackageArtifact:
3✔
50
        return cls(
×
51
            relpath=relpath,
52
            packager=packager,
53
            extra_log_lines=(f"Built {packager} package with nFPM: {relpath}",),
54
        )
55

56

57
@dataclass(frozen=True)
3✔
58
class NfpmPackageRequest:
3✔
59
    field_set: NfpmPackageFieldSet
3✔
60

61

62
@rule(level=LogLevel.INFO)
3✔
63
async def package_nfpm_package(
3✔
64
    request: NfpmPackageRequest,
65
    nfpm_subsystem: NfpmSubsystem,
66
    platform: Platform,
67
) -> BuiltPackage:
68
    output_dir = "__out"
×
69

70
    field_set = request.field_set
×
71

72
    nfpm_content_sandbox = await populate_nfpm_content_sandbox(
×
73
        NfpmContentSandboxRequest(field_set), **implicitly()
74
    )
75

76
    nfpm_config, downloaded_tool, output_dir_digest = await concurrently(
×
77
        generate_nfpm_yaml(
78
            NfpmPackageConfigRequest(field_set, nfpm_content_sandbox.digest), **implicitly()
79
        ),
80
        download_external_tool(nfpm_subsystem.get_request(platform)),
81
        create_digest(CreateDigest([Directory(output_dir)])),
82
    )
83

84
    sandbox_digest = await merge_digests(
×
85
        MergeDigests(
86
            (
87
                nfpm_content_sandbox.digest,
88
                nfpm_config.digest,
89
                downloaded_tool.digest,
90
                output_dir_digest,
91
            )
92
        )
93
    )
94

95
    result = await execute_process_or_raise(
×
96
        **implicitly(
97
            Process(
98
                argv=(
99
                    downloaded_tool.exe,
100
                    "package",  # or "pkg" or "p"
101
                    # use default config file: nfpm.yaml
102
                    "--packager",  # or "-p"
103
                    field_set.packager,
104
                    "--target",  # or "-t"
105
                    output_dir,
106
                ),
107
                description=f"Creating {field_set.packager} package with nFPM: {field_set.address}",
108
                input_digest=sandbox_digest,
109
                output_directories=(output_dir,),
110
            )
111
        ),
112
    )
113

114
    # The final directory that should contain the package artifact.
115
    # The package artifact itself will use the conventional filename generated by nFPM.
116
    output_path = field_set.output_path.value_or_default(file_ending=None)
×
117

118
    stripped_digest = await remove_prefix(RemovePrefix(result.output_digest, output_dir))
×
119
    final_snapshot = await digest_to_snapshot(**implicitly(AddPrefix(stripped_digest, output_path)))
×
120

121
    # nFPM creates only 1 file (any signature gets embedded in the package file).
122
    assert len(final_snapshot.files) == 1
×
123
    conventional_file_name = final_snapshot.files[0]
×
124

125
    return BuiltPackage(
×
126
        final_snapshot.digest,
127
        artifacts=(BuiltNfpmPackageArtifact.create(conventional_file_name, field_set.packager),),
128
    )
129

130

131
@rule
3✔
132
async def package_nfpm_apk_package(field_set: NfpmApkPackageFieldSet) -> BuiltPackage:
3✔
133
    built_package: BuiltPackage = await package_nfpm_package(
×
134
        NfpmPackageRequest(field_set), **implicitly()
135
    )
136
    return built_package
×
137

138

139
@rule
3✔
140
async def package_nfpm_archlinux_package(field_set: NfpmArchlinuxPackageFieldSet) -> BuiltPackage:
3✔
141
    built_package: BuiltPackage = await package_nfpm_package(
×
142
        NfpmPackageRequest(field_set), **implicitly()
143
    )
144
    return built_package
×
145

146

147
@rule
3✔
148
async def package_nfpm_deb_package(field_set: NfpmDebPackageFieldSet) -> BuiltPackage:
3✔
149
    built_package: BuiltPackage = await package_nfpm_package(
×
150
        NfpmPackageRequest(field_set), **implicitly()
151
    )
152
    return built_package
×
153

154

155
@rule
3✔
156
async def package_nfpm_rpm_package(field_set: NfpmRpmPackageFieldSet) -> BuiltPackage:
3✔
157
    built_package: BuiltPackage = await package_nfpm_package(
×
158
        NfpmPackageRequest(field_set), **implicitly()
159
    )
160
    return built_package
×
161

162

163
def rules() -> Iterable[Rule | UnionRule]:
3✔
164
    return [
3✔
165
        *package.rules(),
166
        *field_sets_rules(),
167
        *inject_config_rules(),
168
        *generate_config_rules(),
169
        *sandbox_rules(),
170
        *contents_rules(),
171
        *collect_rules(),
172
    ]
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