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

pantsbuild / pants / 22285099215

22 Feb 2026 08:52PM UTC coverage: 75.854% (-17.1%) from 92.936%
22285099215

Pull #23121

github

web-flow
Merge c7299df9c into ba8359840
Pull Request #23121: fix issue with optional fields in dependency validator

28 of 29 new or added lines in 2 files covered. (96.55%)

11174 existing lines in 400 files now uncovered.

53694 of 70786 relevant lines covered (75.85%)

1.88 hits per line

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

92.0
/src/python/pants/backend/go/util_rules/assembly.py
1
# Copyright 2021 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3

4
from __future__ import annotations
4✔
5

6
import os.path
4✔
7
from collections.abc import Iterable
4✔
8
from dataclasses import dataclass
4✔
9
from pathlib import PurePath
4✔
10

11
from pants.backend.go.util_rules.goroot import GoRoot
4✔
12
from pants.backend.go.util_rules.sdk import GoSdkProcess, GoSdkToolIDRequest, compute_go_tool_id
4✔
13
from pants.engine.fs import CreateDigest, Digest, FileContent, MergeDigests
4✔
14
from pants.engine.intrinsics import create_digest, execute_process, merge_digests
4✔
15
from pants.engine.rules import collect_rules, concurrently, implicitly, rule
4✔
16

17

18
@dataclass(frozen=True)
4✔
19
class GenerateAssemblySymabisRequest:
4✔
20
    """Generate a `symabis` file with metadata about the assembly files for consumption by Go
21
    compiler.
22

23
    See https://github.com/bazelbuild/rules_go/issues/1893.
24
    """
25

26
    compilation_input: Digest
4✔
27
    s_files: tuple[str, ...]
4✔
28
    import_path: str
4✔
29
    dir_path: str
4✔
30
    extra_assembler_flags: tuple[str, ...]
4✔
31

32

33
@dataclass(frozen=True)
4✔
34
class GenerateAssemblySymabisResult:
4✔
35
    symabis_digest: Digest
4✔
36
    symabis_path: str
4✔
37

38

39
@dataclass(frozen=True)
4✔
40
class FallibleGenerateAssemblySymabisResult:
4✔
41
    result: GenerateAssemblySymabisResult | None
4✔
42
    exit_code: int = 0
4✔
43
    stdout: str | None = None
4✔
44
    stderr: str | None = None
4✔
45

46

47
@dataclass(frozen=True)
4✔
48
class AssembleGoAssemblyFilesRequest:
4✔
49
    """Assemble Go assembly files to object files."""
50

51
    input_digest: Digest
4✔
52
    s_files: tuple[str, ...]
4✔
53
    dir_path: str
4✔
54
    import_path: str
4✔
55
    extra_assembler_flags: tuple[str, ...]
4✔
56

57

58
@dataclass(frozen=True)
4✔
59
class AssembleGoAssemblyFilesResult:
4✔
60
    assembly_outputs: tuple[tuple[str, Digest], ...]
4✔
61

62

63
@dataclass(frozen=True)
4✔
64
class FallibleAssembleGoAssemblyFilesResult:
4✔
65
    result: AssembleGoAssemblyFilesResult | None
4✔
66
    exit_code: int = 0
4✔
67
    stdout: str | None = None
4✔
68
    stderr: str | None = None
4✔
69

70

71
# Adapted from https://github.com/golang/go/blob/cb07765045aed5104a3df31507564ac99e6ddce8/src/cmd/go/internal/work/gc.go#L358-L410
72
#
73
# Note: Architecture-specific flags have not been adapted nor the flags added when compiling Go SDK packages
74
# themselves.
75
def _asm_args(
4✔
76
    import_path: str, dir_path: str, goroot: GoRoot, extra_flags: Iterable[str]
77
) -> tuple[str, ...]:
78
    # On Go 1.19+, the import path must be supplied via the `-p` option to `go tool asm`.
79
    # See https://go.dev/doc/go1.19#assembler and
80
    # https://github.com/bazelbuild/rules_go/commit/cde7d7bc27a34547c014369790ddaa95b932d08d (Bazel rules_go).
81
    maybe_package_import_path_args = (
4✔
82
        ["-p", import_path] if goroot.is_compatible_version("1.19") else []
83
    )
84

85
    # Add special argument if assembling files in certain packages in the standard library.
86
    # See:
87
    # - https://github.com/golang/go/blob/245e95dfabd77f337373bf2d6bb47cd353ad8d74/src/cmd/go/internal/work/gc.go#L370-L372
88
    # - https://github.com/golang/go/blob/245e95dfabd77f337373bf2d6bb47cd353ad8d74/src/cmd/internal/objabi/path.go#L43-L67
89
    # From Go 1.22+ this flag has been removed, since we're already passing the package path, asm can make that determination,
90
    # and there's no need to pass the flag anymore.
91
    # See:
92
    # - https://cs.opensource.google/go/go/+/72946ae8674a295e7485982fe57c65c7142b2c14
93
    maybe_assembling_stdlib_runtime_args = (
4✔
94
        ["-compiling-runtime"]
95
        if not goroot.is_compatible_version("1.22")
96
        and (
97
            import_path in ("runtime", "reflect", "syscall", "internal/bytealg")
98
            or import_path.startswith("runtime/internal")
99
        )
100
        else []
101
    )
102

103
    return (
4✔
104
        *maybe_package_import_path_args,
105
        "-trimpath",
106
        "__PANTS_SANDBOX_ROOT__",
107
        "-I",
108
        f"__PANTS_SANDBOX_ROOT__/{dir_path}",
109
        # Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files.
110
        "-I",
111
        os.path.join(goroot.path, "pkg", "include"),
112
        "-D",
113
        f"GOOS_{goroot.goos}",
114
        "-D",
115
        f"GOARCH_{goroot.goarch}",
116
        *maybe_assembling_stdlib_runtime_args,
117
        *extra_flags,
118
    )
119

120

121
@rule
4✔
122
async def generate_go_assembly_symabisfile(
4✔
123
    request: GenerateAssemblySymabisRequest,
124
    goroot: GoRoot,
125
) -> FallibleGenerateAssemblySymabisResult:
126
    # From Go tooling comments:
127
    #
128
    #   Supply an empty go_asm.h as if the compiler had been run. -symabis parsing is lax enough
129
    #   that we don't need the actual definitions that would appear in go_asm.h.
130
    #
131
    # See https://go-review.googlesource.com/c/go/+/146999/8/src/cmd/go/internal/work/gc.go
132
    if os.path.isabs(request.dir_path):
4✔
133
        symabis_path = "symabis"
4✔
134
    else:
UNCOV
135
        symabis_path = os.path.join(request.dir_path, "symabis")
×
136
    go_asm_h_digest, asm_tool_id = await concurrently(
4✔
137
        create_digest(CreateDigest([FileContent("go_asm.h", b"")])),
138
        compute_go_tool_id(GoSdkToolIDRequest("asm")),
139
    )
140
    symabis_input_digest = await merge_digests(
4✔
141
        MergeDigests([request.compilation_input, go_asm_h_digest])
142
    )
143
    symabis_result = await execute_process(
4✔
144
        **implicitly(
145
            GoSdkProcess(
146
                input_digest=symabis_input_digest,
147
                command=(
148
                    "tool",
149
                    "asm",
150
                    *_asm_args(
151
                        import_path=request.import_path,
152
                        dir_path=request.dir_path,
153
                        goroot=goroot,
154
                        extra_flags=request.extra_assembler_flags,
155
                    ),
156
                    "-gensymabis",
157
                    "-o",
158
                    symabis_path,
159
                    "--",
160
                    *(str(PurePath(request.dir_path, s_file)) for s_file in request.s_files),
161
                ),
162
                env={
163
                    "__PANTS_GO_ASM_TOOL_ID": asm_tool_id.tool_id,
164
                },
165
                description=f"Generate symabis metadata for assembly files for {request.dir_path}",
166
                output_files=(symabis_path,),
167
                replace_sandbox_root_in_args=True,
168
            )
169
        )
170
    )
171
    if symabis_result.exit_code != 0:
4✔
UNCOV
172
        return FallibleGenerateAssemblySymabisResult(
×
173
            None, symabis_result.exit_code, symabis_result.stderr.decode("utf-8")
174
        )
175

176
    return FallibleGenerateAssemblySymabisResult(
4✔
177
        result=GenerateAssemblySymabisResult(
178
            symabis_digest=symabis_result.output_digest,
179
            symabis_path=symabis_path,
180
        ),
181
    )
182

183

184
@rule
4✔
185
async def assemble_go_assembly_files(
4✔
186
    request: AssembleGoAssemblyFilesRequest,
187
    goroot: GoRoot,
188
) -> FallibleAssembleGoAssemblyFilesResult:
189
    asm_tool_id = await compute_go_tool_id(GoSdkToolIDRequest("asm"))
4✔
190

191
    def obj_output_path(s_file: str) -> str:
4✔
192
        if os.path.isabs(request.dir_path):
4✔
193
            return str(PurePath(s_file).with_suffix(".o"))
4✔
194
        else:
UNCOV
195
            return str(request.dir_path / PurePath(s_file).with_suffix(".o"))
×
196

197
    assembly_results = await concurrently(
4✔
198
        execute_process(
199
            **implicitly(
200
                GoSdkProcess(
201
                    input_digest=request.input_digest,
202
                    command=(
203
                        "tool",
204
                        "asm",
205
                        *_asm_args(
206
                            import_path=request.import_path,
207
                            dir_path=request.dir_path,
208
                            goroot=goroot,
209
                            extra_flags=request.extra_assembler_flags,
210
                        ),
211
                        "-o",
212
                        obj_output_path(s_file),
213
                        str(os.path.normpath(PurePath(request.dir_path, s_file))),
214
                    ),
215
                    env={
216
                        "__PANTS_GO_ASM_TOOL_ID": asm_tool_id.tool_id,
217
                    },
218
                    description=f"Assemble {s_file} with Go",
219
                    output_files=(obj_output_path(s_file),),
220
                    replace_sandbox_root_in_args=True,
221
                )
222
            ),
223
        )
224
        for s_file in request.s_files
225
    )
226
    exit_code = max(result.exit_code for result in assembly_results)
4✔
227
    if exit_code != 0:
4✔
228
        stdout = "\n\n".join(
×
229
            result.stdout.decode("utf-8") for result in assembly_results if result.stdout
230
        )
231
        stderr = "\n\n".join(
×
232
            result.stderr.decode("utf-8") for result in assembly_results if result.stderr
233
        )
234
        return FallibleAssembleGoAssemblyFilesResult(None, exit_code, stdout, stderr)
×
235

236
    assembly_outputs = tuple(
4✔
237
        (obj_output_path(s_file), result.output_digest)
238
        for s_file, result in zip(request.s_files, assembly_results)
239
    )
240

241
    return FallibleAssembleGoAssemblyFilesResult(
4✔
242
        AssembleGoAssemblyFilesResult(
243
            assembly_outputs=assembly_outputs,
244
        )
245
    )
246

247

248
def rules():
4✔
249
    return collect_rules()
4✔
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