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

pantsbuild / pants / 24457917360

15 Apr 2026 01:41PM UTC coverage: 78.644% (+8.4%) from 70.203%
24457917360

push

github

web-flow
upgrade to Trivy v0.69.2 (Cherry-pick of #23155) (#23257)

Update to Trivy v0.69.2. Prior releases were deleted as part of [an
attack they
suffered](https://github.com/aquasecurity/trivy/discussions/10265), so
our CI is broken while it is still references the prior version.

Co-authored-by: Tom Dyas <tom.dyas@gmail.com>

1 of 1 new or added line in 1 file covered. (100.0%)

1089 existing lines in 53 files now uncovered.

74199 of 94348 relevant lines covered (78.64%)

3.16 hits per line

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

69.23
/src/python/pants/init/options_initializer.py
1
# Copyright 2016 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3

4
from __future__ import annotations
11✔
5

6
import dataclasses
11✔
7
import importlib
11✔
8
import logging
11✔
9
import sys
11✔
10
from collections.abc import Iterator
11✔
11
from contextlib import contextmanager
11✔
12
from pathlib import Path
11✔
13

14
import pkg_resources
11✔
15

16
from pants.build_graph.build_configuration import BuildConfiguration
11✔
17
from pants.engine.env_vars import CompleteEnvironmentVars
11✔
18
from pants.engine.internals.native_engine import PyExecutor
11✔
19
from pants.engine.unions import UnionMembership
11✔
20
from pants.help.flag_error_help_printer import FlagErrorHelpPrinter
11✔
21
from pants.init.bootstrap_scheduler import BootstrapScheduler
11✔
22
from pants.init.engine_initializer import EngineInitializer
11✔
23
from pants.init.extension_loader import (
11✔
24
    load_backends_and_plugins,
25
    load_build_configuration_from_source,
26
)
27
from pants.init.plugin_resolver import PluginResolver
11✔
28
from pants.init.plugin_resolver import rules as plugin_resolver_rules
11✔
29
from pants.option.bootstrap_options import DynamicRemoteOptions
11✔
30
from pants.option.errors import UnknownFlagsError
11✔
31
from pants.option.options import Options
11✔
32
from pants.option.options_bootstrapper import OptionsBootstrapper
11✔
33
from pants.util.requirements import parse_requirements_file
11✔
34

35
logger = logging.getLogger(__name__)
11✔
36

37

38
def _initialize_build_configuration(
11✔
39
    plugin_resolver: PluginResolver,
40
    options_bootstrapper: OptionsBootstrapper,
41
    env: CompleteEnvironmentVars,
42
) -> BuildConfiguration:
43
    """Initialize a BuildConfiguration for the given OptionsBootstrapper.
44

45
    NB: This method:
46
      1. has the side effect of (idempotently) adding PYTHONPATH entries for this process
47
      2. is expensive to call, because it might resolve plugins from the network
48
    """
49

50
    bootstrap_options = options_bootstrapper.bootstrap_options.for_global_scope()
3✔
51

52
    # Add any extra paths to python path (e.g., for loading extra source backends).
53
    for path in bootstrap_options.pythonpath:
3✔
54
        if path not in sys.path:
×
55
            sys.path.append(path)
×
56
            pkg_resources.fixup_namespace_packages(path)
×
57

58
    # Resolve the actual Python code for any plugins. `sys.path` is modified as a side effect if
59
    # plugins were configured.
60
    backends_requirements = _collect_backends_requirements(bootstrap_options.backend_packages)
3✔
61
    plugin_resolver.resolve(options_bootstrapper, env, backends_requirements)
3✔
62

63
    # Load plugins and backends.
64
    return load_backends_and_plugins(
2✔
65
        bootstrap_options.plugins,
66
        bootstrap_options.backend_packages,
67
    )
68

69

70
def _collect_backends_requirements(backends: list[str]) -> list[str]:
11✔
71
    """Collects backend package dependencies, in case those are declared in an adjacent
72
    requirements.txt. Ignores any loading errors, assuming those will be later on handled by the
73
    backends loader.
74

75
    :param backends: An list of packages to load v2 backends requirements from.
76
    """
77
    requirements = []
3✔
78

79
    for backend_package in backends:
3✔
UNCOV
80
        try:
×
UNCOV
81
            backend_package_spec = importlib.util.find_spec(backend_package)
×
82
        except ModuleNotFoundError:
×
83
            continue
×
84

UNCOV
85
        if backend_package_spec is None:
×
86
            continue
×
87

UNCOV
88
        if backend_package_spec.origin is None:
×
UNCOV
89
            logger.warning(
×
90
                f"Can not check requirements for backend: '{backend_package}'. A __init__.py file is probably missing."
91
            )
UNCOV
92
            continue
×
93

94
        requirements_txt_file_path = Path(backend_package_spec.origin).parent.joinpath(
×
95
            "requirements.txt"
96
        )
97
        if requirements_txt_file_path.exists():
×
98
            content = requirements_txt_file_path.read_text()
×
99
            backend_package_requirements = [
×
100
                str(r)
101
                for r in parse_requirements_file(content, rel_path=str(requirements_txt_file_path))
102
            ]
103
            requirements.extend(backend_package_requirements)
×
104

105
    return requirements
3✔
106

107

108
def create_bootstrap_scheduler(
11✔
109
    options_bootstrapper: OptionsBootstrapper, executor: PyExecutor
110
) -> BootstrapScheduler:
111
    bc_builder = BuildConfiguration.Builder()
3✔
112
    # To load plugins, we only need access to the Python/PEX rules.
113
    load_build_configuration_from_source(bc_builder, ["pants.backend.python"])
3✔
114
    # And to plugin-loading-specific rules.
115
    bc_builder.register_rules("_dummy_for_bootstrapping_", plugin_resolver_rules())
3✔
116
    # We allow unrecognized options to defer any option error handling until post-bootstrap.
117
    bc_builder.allow_unknown_options()
3✔
118
    return BootstrapScheduler(
3✔
119
        EngineInitializer.setup_graph(
120
            options_bootstrapper.bootstrap_options.for_global_scope(),
121
            bc_builder.create(),
122
            DynamicRemoteOptions.disabled(),
123
            executor,
124
            is_bootstrap=True,
125
        ).scheduler
126
    )
127

128

129
class OptionsInitializer:
11✔
130
    """Initializes BuildConfiguration and Options instances given an OptionsBootstrapper.
131

132
    NB: Although this constructor takes an instance of the OptionsBootstrapper, it is
133
    used only to construct a "bootstrap" Scheduler: actual calls to resolve plugins use a
134
    per-request instance of the OptionsBootstrapper, which might request different plugins.
135

136
    TODO: We would eventually like to use the bootstrap Scheduler to construct the
137
    OptionsBootstrapper as well, but for now we do the opposite thing, and the Scheduler is
138
    used only to resolve plugins.
139
      see https://github.com/pantsbuild/pants/pull/11568
140
    """
141

142
    def __init__(
11✔
143
        self,
144
        options_bootstrapper: OptionsBootstrapper,
145
        executor: PyExecutor,
146
    ) -> None:
147
        self._bootstrap_scheduler = create_bootstrap_scheduler(options_bootstrapper, executor)
3✔
148
        self._plugin_resolver = PluginResolver(self._bootstrap_scheduler)
3✔
149

150
    def build_config(
11✔
151
        self,
152
        options_bootstrapper: OptionsBootstrapper,
153
        env: CompleteEnvironmentVars,
154
    ) -> BuildConfiguration:
155
        return _initialize_build_configuration(self._plugin_resolver, options_bootstrapper, env)
3✔
156

157
    def options(
11✔
158
        self,
159
        options_bootstrapper: OptionsBootstrapper,
160
        env: CompleteEnvironmentVars,
161
        build_config: BuildConfiguration,
162
        union_membership: UnionMembership,
163
        *,
164
        raise_: bool,
165
    ) -> Options:
166
        with self.handle_unknown_flags(options_bootstrapper, env, raise_=raise_):
2✔
167
            return options_bootstrapper.full_options(
2✔
168
                build_config.known_scope_infos, union_membership, build_config.allow_unknown_options
169
            )
170

171
    @contextmanager
11✔
172
    def handle_unknown_flags(
11✔
173
        self,
174
        options_bootstrapper: OptionsBootstrapper,
175
        env: CompleteEnvironmentVars,
176
        *,
177
        raise_: bool,
178
    ) -> Iterator[None]:
179
        """If there are any unknown flags, print "Did you mean?" and possibly error."""
180
        try:
2✔
181
            yield
2✔
182
        except UnknownFlagsError as err:
×
183
            build_config = _initialize_build_configuration(
×
184
                self._plugin_resolver, options_bootstrapper, env
185
            )
186
            # We need an options instance in order to get "did you mean" suggestions, but we know
187
            # there are bad flags in the args, so we generate options with no flags.
188
            no_arg_bootstrapper = dataclasses.replace(
×
189
                options_bootstrapper, args=("dummy_first_arg",)
190
            )
191
            options = no_arg_bootstrapper.full_options(
×
192
                build_config.known_scope_infos,
193
                union_membership=UnionMembership.empty(),
194
            )
195
            FlagErrorHelpPrinter(options).handle_unknown_flags(err)
×
196
            if raise_:
×
197
                raise err
×
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