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

pantsbuild / pants / 25443604553

06 May 2026 03:05PM UTC coverage: 92.879% (-0.04%) from 92.915%
25443604553

push

github

web-flow
[pants_ng] Scaffolding for a pants_ng mode. (#23319)

In this mode the command line is parsed as an
NG invocation, and dispatched appropriately.

Of course at the moment there are no
implementations to dispatch to. That will follow.

This does expose a new option, `pants_ng` to users. 
There is a big warning not to set it, but we're not trying
to hide that we're working on a new thing, so I am
comfortable with this.

25 of 76 new or added lines in 9 files covered. (32.89%)

1294 existing lines in 76 files now uncovered.

92234 of 99306 relevant lines covered (92.88%)

4.05 hits per line

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

100.0
/src/python/pants/backend/go/util_rules/link.py
1
# Copyright 2021 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3
from __future__ import annotations
11✔
4

5
import textwrap
11✔
6
from dataclasses import dataclass
11✔
7

8
from pants.backend.go.subsystems.golang import GolangSubsystem
11✔
9
from pants.backend.go.util_rules import import_config
11✔
10
from pants.backend.go.util_rules.build_opts import GoBuildOptions
11✔
11
from pants.backend.go.util_rules.cgo_binaries import CGoBinaryPathRequest, find_cgo_binary_path
11✔
12
from pants.backend.go.util_rules.import_config import ImportConfigRequest, generate_import_config
11✔
13
from pants.backend.go.util_rules.link_defs import (
11✔
14
    ImplicitLinkerDependenciesHook,
15
    get_implicit_linker_dependencies,
16
)
17
from pants.backend.go.util_rules.sdk import GoSdkProcess, GoSdkToolIDRequest, compute_go_tool_id
11✔
18
from pants.core.util_rules.system_binaries import BashBinary, BinaryPathTest
11✔
19
from pants.engine.fs import CreateDigest, Digest, Directory, FileContent
11✔
20
from pants.engine.internals.native_engine import AddPrefix, MergeDigests
11✔
21
from pants.engine.internals.selectors import concurrently
11✔
22
from pants.engine.intrinsics import add_prefix, create_digest, merge_digests
11✔
23
from pants.engine.process import fallible_to_exec_result_or_raise
11✔
24
from pants.engine.rules import collect_rules, implicitly, rule
11✔
25
from pants.engine.unions import UnionMembership
11✔
26
from pants.util.frozendict import FrozenDict
11✔
27

28

29
@dataclass(frozen=True)
11✔
30
class LinkGoBinaryRequest:
11✔
31
    """Link a Go binary from package archives and an import configuration."""
32

33
    input_digest: Digest
11✔
34
    archives: tuple[str, ...]
11✔
35
    build_opts: GoBuildOptions
11✔
36
    import_paths_to_pkg_a_files: FrozenDict[str, str]
11✔
37
    output_filename: str
11✔
38
    description: str
11✔
39

40

41
@dataclass(frozen=True)
11✔
42
class LinkedGoBinary:
11✔
43
    """A linked Go binary stored in a `Digest`."""
44

45
    digest: Digest
11✔
46

47

48
@dataclass(frozen=True)
11✔
49
class LinkerSetup:
11✔
50
    digest: Digest
11✔
51
    extld_wrapper_path: str
11✔
52

53

54
@rule
11✔
55
async def setup_go_linker(
11✔
56
    bash: BashBinary, golang_subsystem: GolangSubsystem.EnvironmentAware
57
) -> LinkerSetup:
58
    extld_binary = await find_cgo_binary_path(
10✔
59
        CGoBinaryPathRequest(
60
            binary_name=golang_subsystem.external_linker_binary_name,
61
            binary_path_test=BinaryPathTest(["--version"]),
62
        ),
63
        **implicitly(),
64
    )
65

66
    extld_wrapper_path = "__pants_extld_wrapper__"
10✔
67
    digest = await create_digest(
10✔
68
        CreateDigest(
69
            [
70
                FileContent(
71
                    path=extld_wrapper_path,
72
                    content=textwrap.dedent(
73
                        f"""\
74
                        #!{bash.path}
75
                        args=("${{@//__PANTS_SANDBOX_ROOT__/$__PANTS_SANDBOX_ROOT__}}")
76
                        exec {extld_binary.path} "${{args[@]}}"
77
                        """
78
                    ).encode(),
79
                    is_executable=True,
80
                ),
81
            ]
82
        )
83
    )
84
    return LinkerSetup(digest, extld_wrapper_path)
10✔
85

86

87
@rule
11✔
88
async def link_go_binary(
11✔
89
    request: LinkGoBinaryRequest,
90
    linker_setup: LinkerSetup,
91
    union_membership: UnionMembership,
92
) -> LinkedGoBinary:
93
    implict_linker_deps_hooks = union_membership.get(ImplicitLinkerDependenciesHook)
10✔
94
    implicit_linker_deps = await concurrently(
10✔
95
        get_implicit_linker_dependencies(
96
            **implicitly({hook(build_opts=request.build_opts): ImplicitLinkerDependenciesHook})
97
        )
98
        for hook in implict_linker_deps_hooks
99
    )
100

101
    implicit_dep_digests = []
10✔
102
    import_paths_to_pkg_a_files = dict(request.import_paths_to_pkg_a_files)
10✔
103
    for implicit_linker_dep in implicit_linker_deps:
10✔
104
        for (
4✔
105
            dep_import_path,
106
            pkg_archive_path,
107
        ) in implicit_linker_dep.import_paths_to_pkg_a_files.items():
108
            if dep_import_path not in import_paths_to_pkg_a_files:
4✔
UNCOV
109
                import_paths_to_pkg_a_files[dep_import_path] = pkg_archive_path
1✔
UNCOV
110
                implicit_dep_digests.append(implicit_linker_dep.digest)
1✔
111

112
    link_tmp_dir = "link-tmp"
10✔
113
    link_tmp_dir_digest = await create_digest(CreateDigest([Directory(link_tmp_dir)]))
10✔
114

115
    link_tool_id, import_config = await concurrently(
10✔
116
        compute_go_tool_id(GoSdkToolIDRequest("link")),
117
        generate_import_config(
118
            ImportConfigRequest(
119
                FrozenDict(import_paths_to_pkg_a_files), build_opts=request.build_opts
120
            )
121
        ),
122
    )
123

124
    import_config_digest = await add_prefix(AddPrefix(import_config.digest, link_tmp_dir))
10✔
125

126
    input_digest = await merge_digests(
10✔
127
        MergeDigests(
128
            [
129
                request.input_digest,
130
                link_tmp_dir_digest,
131
                linker_setup.digest,
132
                import_config_digest,
133
                *implicit_dep_digests,
134
            ]
135
        )
136
    )
137

138
    maybe_race_arg = ["-race"] if request.build_opts.with_race_detector else []
10✔
139
    maybe_msan_arg = ["-msan"] if request.build_opts.with_msan else []
10✔
140
    maybe_asan_arg = ["-asan"] if request.build_opts.with_asan else []
10✔
141

142
    result = await fallible_to_exec_result_or_raise(
10✔
143
        **implicitly(
144
            GoSdkProcess(
145
                input_digest=input_digest,
146
                command=(
147
                    "tool",
148
                    "link",
149
                    # Put the linker's temporary directory into the input root.
150
                    "-tmpdir",
151
                    f"__PANTS_SANDBOX_ROOT__/{link_tmp_dir}",
152
                    # Force `go tool link` to use a wrapper script as the "external linker" so that the script can
153
                    # replace any instances of `__PANTS_SANDBOX_ROOT__` in the linker arguments. This also allows
154
                    # Pants to know which external linker is in use and invalidate this `Process` as needed.
155
                    "-extld",
156
                    f"__PANTS_SANDBOX_ROOT__/{linker_setup.extld_wrapper_path}",
157
                    *maybe_race_arg,
158
                    *maybe_msan_arg,
159
                    *maybe_asan_arg,
160
                    "-importcfg",
161
                    f"{link_tmp_dir}/{import_config.CONFIG_PATH}",
162
                    "-o",
163
                    request.output_filename,
164
                    "-buildmode=exe",  # seen in `go build -x` output
165
                    *request.build_opts.linker_flags,
166
                    *request.archives,
167
                ),
168
                env={
169
                    "__PANTS_GO_LINK_TOOL_ID": link_tool_id.tool_id,
170
                },
171
                description=f"Link Go binary: {request.output_filename}",
172
                output_files=(request.output_filename,),
173
                replace_sandbox_root_in_args=True,
174
            ),
175
        )
176
    )
177

178
    return LinkedGoBinary(result.output_digest)
10✔
179

180

181
def rules():
11✔
182
    return (
11✔
183
        *collect_rules(),
184
        *import_config.rules(),
185
    )
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