• 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

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

5
from dataclasses import dataclass
12✔
6

7
from pants.backend.go.util_rules import cgo_binaries
12✔
8
from pants.backend.go.util_rules.cgo_binaries import CGoBinaryPathRequest, find_cgo_binary_path
12✔
9
from pants.backend.go.util_rules.cgo_security import (
12✔
10
    check_compiler_flags,
11
    check_linker_flags,
12
    safe_arg,
13
)
14
from pants.core.util_rules.system_binaries import BinaryPathTest
12✔
15
from pants.engine.internals.selectors import concurrently
12✔
16
from pants.engine.process import Process, fallible_to_exec_result_or_raise
12✔
17
from pants.engine.rules import collect_rules, implicitly, rule
12✔
18

19
# Adapted from the Go toolchain
20
#
21
# Original copyright:
22
#   // Copyright 2011 The Go Authors. All rights reserved.
23
#   // Use of this source code is governed by a BSD-style
24
#   // license that can be found in the LICENSE file.
25

26

27
@dataclass(frozen=True)
12✔
28
class CGoPkgConfigFlagsRequest:
12✔
29
    """Request resolution of pkg-config arguments into CFLAGS and LDFLAGS."""
30

31
    pkg_config_args: tuple[str, ...]
12✔
32

33

34
@dataclass(frozen=True)
12✔
35
class CGoPkgConfigFlagsResult:
12✔
36
    cflags: tuple[str, ...]
12✔
37
    ldflags: tuple[str, ...]
12✔
38

39

40
# _split_pkg_config_output parses the pkg-config output into a tuple of flags. This implements the algorithm from
41
# https://github.com/pkgconf/pkgconf/blob/master/libpkgconf/argvsplit.c
42
# See https://github.com/golang/go/blob/54182ff54a687272dd7632c3a963e036ce03cb7c/src/cmd/go/internal/work/exec.go#L1414-L1473
43
def _split_pkg_config_output(content: bytes) -> tuple[str, ...]:
12✔
UNCOV
44
    if not content:
1✔
UNCOV
45
        return ()
1✔
46

UNCOV
47
    flags: list[str] = []
1✔
UNCOV
48
    flag = bytearray()
1✔
UNCOV
49
    escaped = False
1✔
UNCOV
50
    quote = 0
1✔
UNCOV
51
    for c in content:
1✔
UNCOV
52
        if escaped:
1✔
UNCOV
53
            if quote != 0:
1✔
UNCOV
54
                if c not in b'$`"\\':
1✔
UNCOV
55
                    flag.extend(b"\\")
1✔
UNCOV
56
                flag.append(c)
1✔
57
            else:
UNCOV
58
                flag.append(c)
1✔
UNCOV
59
            escaped = False
1✔
UNCOV
60
        elif quote != 0:
1✔
UNCOV
61
            if c == quote:
1✔
UNCOV
62
                quote = 0
1✔
63
            else:
UNCOV
64
                if c == ord("\\"):
1✔
UNCOV
65
                    escaped = True
1✔
66
                else:
UNCOV
67
                    flag.append(c)
1✔
UNCOV
68
        elif c not in b" \t\n\v\f\r":
1✔
UNCOV
69
            if c == ord(b"\\"):
1✔
UNCOV
70
                escaped = True
1✔
UNCOV
71
            elif c in b"'\"":
1✔
UNCOV
72
                quote = c
1✔
73
            else:
UNCOV
74
                flag.append(c)
1✔
UNCOV
75
        elif len(flag) != 0:
1✔
UNCOV
76
            flags.append(flag.decode())
1✔
UNCOV
77
            flag = bytearray()
1✔
78

UNCOV
79
    if escaped:
1✔
80
        raise ValueError("broken character escaping in pkg-config output")
×
UNCOV
81
    if quote != 0:
1✔
82
        raise ValueError("unterminated quoted string in pkgconf output")
×
UNCOV
83
    elif len(flag) != 0:
1✔
UNCOV
84
        flags.append(flag.decode())
1✔
85

UNCOV
86
    return tuple(flags)
1✔
87

88

89
@rule
12✔
90
async def resolve_cgo_pkg_config_args(request: CGoPkgConfigFlagsRequest) -> CGoPkgConfigFlagsResult:
12✔
91
    if not request.pkg_config_args:
×
92
        return CGoPkgConfigFlagsResult(cflags=(), ldflags=())
×
93

94
    pkg_config_flags = []
×
95
    pkgs = []
×
96
    for arg in request.pkg_config_args:
×
97
        if arg == "--":
×
98
            # Skip the `--` separator as we will add our own later.
99
            pass
×
100
        elif arg.startswith("--"):
×
101
            pkg_config_flags.append(arg)
×
102
        else:
103
            pkgs.append(arg)
×
104

105
    for pkg in pkgs:
×
106
        if not safe_arg(pkg):
×
107
            raise ValueError(f"invalid pkg-config package name: {pkg}")
×
108

109
    pkg_config_path = await find_cgo_binary_path(
×
110
        CGoBinaryPathRequest(
111
            binary_name="pkg-config",
112
            binary_path_test=BinaryPathTest(["--version"]),
113
        ),
114
        **implicitly(),
115
    )
116

117
    cflags_result, ldflags_result = await concurrently(
×
118
        fallible_to_exec_result_or_raise(
119
            **implicitly(
120
                Process(
121
                    argv=[pkg_config_path.path, "--cflags", *pkg_config_flags, "--", *pkgs],
122
                    description=f"Run pkg-config for CFLAGS for packages: {pkgs}",
123
                )
124
            )
125
        ),
126
        fallible_to_exec_result_or_raise(
127
            **implicitly(
128
                Process(
129
                    argv=[pkg_config_path.path, "--libs", *pkg_config_flags, "--", *pkgs],
130
                    description=f"Run pkg-config for LDFLAGS for packages: {pkgs}",
131
                )
132
            )
133
        ),
134
    )
135

136
    cflags: tuple[str, ...] = ()
×
137
    if cflags_result.stdout:
×
138
        cflags = _split_pkg_config_output(cflags_result.stdout)
×
139
        check_compiler_flags(cflags, "pkg-config --cflags")
×
140

141
    ldflags: tuple[str, ...] = ()
×
142
    if ldflags_result.stdout:
×
143
        # NOTE: we don't attempt to parse quotes and unescapes here. pkg-config
144
        # is typically used within shell backticks, which treats quotes literally.
145
        ldflags = tuple(arg.decode() for arg in ldflags_result.stdout.split())
×
146
        check_linker_flags(ldflags, "pkg-config --libs")
×
147

148
    return CGoPkgConfigFlagsResult(cflags=cflags, ldflags=ldflags)
×
149

150

151
def rules():
12✔
152
    return (
11✔
153
        *collect_rules(),
154
        *cgo_binaries.rules(),
155
    )
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