xref: /aosp_15_r20/external/bazelbuild-rules_python/python/private/repo_utils.bzl (revision 60517a1edbc8ecf509223e9af94a7adec7d736b8)
1*60517a1eSAndroid Build Coastguard Worker# Copyright 2024 The Bazel Authors. All rights reserved.
2*60517a1eSAndroid Build Coastguard Worker#
3*60517a1eSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
4*60517a1eSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
5*60517a1eSAndroid Build Coastguard Worker# You may obtain a copy of the License at
6*60517a1eSAndroid Build Coastguard Worker#
7*60517a1eSAndroid Build Coastguard Worker#    http://www.apache.org/licenses/LICENSE-2.0
8*60517a1eSAndroid Build Coastguard Worker#
9*60517a1eSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
10*60517a1eSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
11*60517a1eSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*60517a1eSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
13*60517a1eSAndroid Build Coastguard Worker# limitations under the License.
14*60517a1eSAndroid Build Coastguard Worker
15*60517a1eSAndroid Build Coastguard Worker"""Functionality shared only by repository rule phase code.
16*60517a1eSAndroid Build Coastguard Worker
17*60517a1eSAndroid Build Coastguard WorkerThis code should only be loaded and used during the repository phase.
18*60517a1eSAndroid Build Coastguard Worker"""
19*60517a1eSAndroid Build Coastguard Worker
20*60517a1eSAndroid Build Coastguard WorkerREPO_DEBUG_ENV_VAR = "RULES_PYTHON_REPO_DEBUG"
21*60517a1eSAndroid Build Coastguard WorkerREPO_VERBOSITY_ENV_VAR = "RULES_PYTHON_REPO_DEBUG_VERBOSITY"
22*60517a1eSAndroid Build Coastguard Worker
23*60517a1eSAndroid Build Coastguard Workerdef _is_repo_debug_enabled(mrctx):
24*60517a1eSAndroid Build Coastguard Worker    """Tells if debbugging output is requested during repo operatiosn.
25*60517a1eSAndroid Build Coastguard Worker
26*60517a1eSAndroid Build Coastguard Worker    Args:
27*60517a1eSAndroid Build Coastguard Worker        mrctx: repository_ctx or module_ctx object
28*60517a1eSAndroid Build Coastguard Worker
29*60517a1eSAndroid Build Coastguard Worker    Returns:
30*60517a1eSAndroid Build Coastguard Worker        True if enabled, False if not.
31*60517a1eSAndroid Build Coastguard Worker    """
32*60517a1eSAndroid Build Coastguard Worker    return _getenv(mrctx, REPO_DEBUG_ENV_VAR) == "1"
33*60517a1eSAndroid Build Coastguard Worker
34*60517a1eSAndroid Build Coastguard Workerdef _logger(mrctx, name = None):
35*60517a1eSAndroid Build Coastguard Worker    """Creates a logger instance for printing messages.
36*60517a1eSAndroid Build Coastguard Worker
37*60517a1eSAndroid Build Coastguard Worker    Args:
38*60517a1eSAndroid Build Coastguard Worker        mrctx: repository_ctx or module_ctx object. If the attribute
39*60517a1eSAndroid Build Coastguard Worker            `_rule_name` is present, it will be included in log messages.
40*60517a1eSAndroid Build Coastguard Worker        name: name for the logger. Optional for repository_ctx usage.
41*60517a1eSAndroid Build Coastguard Worker
42*60517a1eSAndroid Build Coastguard Worker    Returns:
43*60517a1eSAndroid Build Coastguard Worker        A struct with attributes logging: trace, debug, info, warn, fail.
44*60517a1eSAndroid Build Coastguard Worker    """
45*60517a1eSAndroid Build Coastguard Worker    if _is_repo_debug_enabled(mrctx):
46*60517a1eSAndroid Build Coastguard Worker        verbosity_level = "DEBUG"
47*60517a1eSAndroid Build Coastguard Worker    else:
48*60517a1eSAndroid Build Coastguard Worker        verbosity_level = "WARN"
49*60517a1eSAndroid Build Coastguard Worker
50*60517a1eSAndroid Build Coastguard Worker    env_var_verbosity = _getenv(mrctx, REPO_VERBOSITY_ENV_VAR)
51*60517a1eSAndroid Build Coastguard Worker    verbosity_level = env_var_verbosity or verbosity_level
52*60517a1eSAndroid Build Coastguard Worker
53*60517a1eSAndroid Build Coastguard Worker    verbosity = {
54*60517a1eSAndroid Build Coastguard Worker        "DEBUG": 2,
55*60517a1eSAndroid Build Coastguard Worker        "INFO": 1,
56*60517a1eSAndroid Build Coastguard Worker        "TRACE": 3,
57*60517a1eSAndroid Build Coastguard Worker    }.get(verbosity_level, 0)
58*60517a1eSAndroid Build Coastguard Worker
59*60517a1eSAndroid Build Coastguard Worker    if hasattr(mrctx, "attr"):
60*60517a1eSAndroid Build Coastguard Worker        rctx = mrctx  # This is `repository_ctx`.
61*60517a1eSAndroid Build Coastguard Worker        name = name or "{}(@@{})".format(getattr(rctx.attr, "_rule_name", "?"), rctx.name)
62*60517a1eSAndroid Build Coastguard Worker    elif not name:
63*60517a1eSAndroid Build Coastguard Worker        fail("The name has to be specified when using the logger with `module_ctx`")
64*60517a1eSAndroid Build Coastguard Worker
65*60517a1eSAndroid Build Coastguard Worker    def _log(enabled_on_verbosity, level, message_cb_or_str, printer = print):
66*60517a1eSAndroid Build Coastguard Worker        if verbosity < enabled_on_verbosity:
67*60517a1eSAndroid Build Coastguard Worker            return
68*60517a1eSAndroid Build Coastguard Worker
69*60517a1eSAndroid Build Coastguard Worker        if type(message_cb_or_str) == "string":
70*60517a1eSAndroid Build Coastguard Worker            message = message_cb_or_str
71*60517a1eSAndroid Build Coastguard Worker        else:
72*60517a1eSAndroid Build Coastguard Worker            message = message_cb_or_str()
73*60517a1eSAndroid Build Coastguard Worker
74*60517a1eSAndroid Build Coastguard Worker        # NOTE: printer may be the `fail` function.
75*60517a1eSAndroid Build Coastguard Worker        printer("\nrules_python:{} {}:".format(
76*60517a1eSAndroid Build Coastguard Worker            name,
77*60517a1eSAndroid Build Coastguard Worker            level.upper(),
78*60517a1eSAndroid Build Coastguard Worker        ), message)  # buildifier: disable=print
79*60517a1eSAndroid Build Coastguard Worker
80*60517a1eSAndroid Build Coastguard Worker    return struct(
81*60517a1eSAndroid Build Coastguard Worker        trace = lambda message_cb: _log(3, "TRACE", message_cb),
82*60517a1eSAndroid Build Coastguard Worker        debug = lambda message_cb: _log(2, "DEBUG", message_cb),
83*60517a1eSAndroid Build Coastguard Worker        info = lambda message_cb: _log(1, "INFO", message_cb),
84*60517a1eSAndroid Build Coastguard Worker        warn = lambda message_cb: _log(0, "WARNING", message_cb),
85*60517a1eSAndroid Build Coastguard Worker        fail = lambda message_cb: _log(-1, "FAIL", message_cb, fail),
86*60517a1eSAndroid Build Coastguard Worker    )
87*60517a1eSAndroid Build Coastguard Worker
88*60517a1eSAndroid Build Coastguard Workerdef _execute_internal(
89*60517a1eSAndroid Build Coastguard Worker        mrctx,
90*60517a1eSAndroid Build Coastguard Worker        *,
91*60517a1eSAndroid Build Coastguard Worker        op,
92*60517a1eSAndroid Build Coastguard Worker        fail_on_error = False,
93*60517a1eSAndroid Build Coastguard Worker        arguments,
94*60517a1eSAndroid Build Coastguard Worker        environment = {},
95*60517a1eSAndroid Build Coastguard Worker        logger = None,
96*60517a1eSAndroid Build Coastguard Worker        **kwargs):
97*60517a1eSAndroid Build Coastguard Worker    """Execute a subprocess with debugging instrumentation.
98*60517a1eSAndroid Build Coastguard Worker
99*60517a1eSAndroid Build Coastguard Worker    Args:
100*60517a1eSAndroid Build Coastguard Worker        mrctx: module_ctx or repository_ctx object
101*60517a1eSAndroid Build Coastguard Worker        op: string, brief description of the operation this command
102*60517a1eSAndroid Build Coastguard Worker            represents. Used to succintly describe it in logging and
103*60517a1eSAndroid Build Coastguard Worker            error messages.
104*60517a1eSAndroid Build Coastguard Worker        fail_on_error: bool, True if fail() should be called if the command
105*60517a1eSAndroid Build Coastguard Worker            fails (non-zero exit code), False if not.
106*60517a1eSAndroid Build Coastguard Worker        arguments: list of arguments; see module_ctx.execute#arguments or
107*60517a1eSAndroid Build Coastguard Worker            repository_ctx#arguments.
108*60517a1eSAndroid Build Coastguard Worker        environment: optional dict of the environment to run the command
109*60517a1eSAndroid Build Coastguard Worker            in; see module_ctx.execute#environment or
110*60517a1eSAndroid Build Coastguard Worker            repository_ctx.execute#environment.
111*60517a1eSAndroid Build Coastguard Worker        logger: optional `Logger` to use for logging execution details. Must be
112*60517a1eSAndroid Build Coastguard Worker            specified when using module_ctx. If not specified, a default will
113*60517a1eSAndroid Build Coastguard Worker            be created.
114*60517a1eSAndroid Build Coastguard Worker        **kwargs: additional kwargs to pass onto rctx.execute
115*60517a1eSAndroid Build Coastguard Worker
116*60517a1eSAndroid Build Coastguard Worker    Returns:
117*60517a1eSAndroid Build Coastguard Worker        exec_result object, see repository_ctx.execute return type.
118*60517a1eSAndroid Build Coastguard Worker    """
119*60517a1eSAndroid Build Coastguard Worker    if not logger and hasattr(mrctx, "attr"):
120*60517a1eSAndroid Build Coastguard Worker        rctx = mrctx
121*60517a1eSAndroid Build Coastguard Worker        logger = _logger(rctx)
122*60517a1eSAndroid Build Coastguard Worker    elif not logger:
123*60517a1eSAndroid Build Coastguard Worker        fail("logger must be specified when using 'module_ctx'")
124*60517a1eSAndroid Build Coastguard Worker
125*60517a1eSAndroid Build Coastguard Worker    logger.debug(lambda: (
126*60517a1eSAndroid Build Coastguard Worker        "repo.execute: {op}: start\n" +
127*60517a1eSAndroid Build Coastguard Worker        "  command: {cmd}\n" +
128*60517a1eSAndroid Build Coastguard Worker        "  working dir: {cwd}\n" +
129*60517a1eSAndroid Build Coastguard Worker        "  timeout: {timeout}\n" +
130*60517a1eSAndroid Build Coastguard Worker        "  environment:{env_str}\n"
131*60517a1eSAndroid Build Coastguard Worker    ).format(
132*60517a1eSAndroid Build Coastguard Worker        op = op,
133*60517a1eSAndroid Build Coastguard Worker        cmd = _args_to_str(arguments),
134*60517a1eSAndroid Build Coastguard Worker        cwd = _cwd_to_str(mrctx, kwargs),
135*60517a1eSAndroid Build Coastguard Worker        timeout = _timeout_to_str(kwargs),
136*60517a1eSAndroid Build Coastguard Worker        env_str = _env_to_str(environment),
137*60517a1eSAndroid Build Coastguard Worker    ))
138*60517a1eSAndroid Build Coastguard Worker
139*60517a1eSAndroid Build Coastguard Worker    mrctx.report_progress("Running {}".format(op))
140*60517a1eSAndroid Build Coastguard Worker    result = mrctx.execute(arguments, environment = environment, **kwargs)
141*60517a1eSAndroid Build Coastguard Worker
142*60517a1eSAndroid Build Coastguard Worker    if fail_on_error and result.return_code != 0:
143*60517a1eSAndroid Build Coastguard Worker        logger.fail((
144*60517a1eSAndroid Build Coastguard Worker            "repo.execute: {op}: end: failure:\n" +
145*60517a1eSAndroid Build Coastguard Worker            "  command: {cmd}\n" +
146*60517a1eSAndroid Build Coastguard Worker            "  return code: {return_code}\n" +
147*60517a1eSAndroid Build Coastguard Worker            "  working dir: {cwd}\n" +
148*60517a1eSAndroid Build Coastguard Worker            "  timeout: {timeout}\n" +
149*60517a1eSAndroid Build Coastguard Worker            "  environment:{env_str}\n" +
150*60517a1eSAndroid Build Coastguard Worker            "{output}"
151*60517a1eSAndroid Build Coastguard Worker        ).format(
152*60517a1eSAndroid Build Coastguard Worker            op = op,
153*60517a1eSAndroid Build Coastguard Worker            cmd = _args_to_str(arguments),
154*60517a1eSAndroid Build Coastguard Worker            return_code = result.return_code,
155*60517a1eSAndroid Build Coastguard Worker            cwd = _cwd_to_str(mrctx, kwargs),
156*60517a1eSAndroid Build Coastguard Worker            timeout = _timeout_to_str(kwargs),
157*60517a1eSAndroid Build Coastguard Worker            env_str = _env_to_str(environment),
158*60517a1eSAndroid Build Coastguard Worker            output = _outputs_to_str(result),
159*60517a1eSAndroid Build Coastguard Worker        ))
160*60517a1eSAndroid Build Coastguard Worker    elif _is_repo_debug_enabled(mrctx):
161*60517a1eSAndroid Build Coastguard Worker        logger.debug((
162*60517a1eSAndroid Build Coastguard Worker            "repo.execute: {op}: end: {status}\n" +
163*60517a1eSAndroid Build Coastguard Worker            "  return code: {return_code}\n" +
164*60517a1eSAndroid Build Coastguard Worker            "{output}"
165*60517a1eSAndroid Build Coastguard Worker        ).format(
166*60517a1eSAndroid Build Coastguard Worker            op = op,
167*60517a1eSAndroid Build Coastguard Worker            status = "success" if result.return_code == 0 else "failure",
168*60517a1eSAndroid Build Coastguard Worker            return_code = result.return_code,
169*60517a1eSAndroid Build Coastguard Worker            output = _outputs_to_str(result),
170*60517a1eSAndroid Build Coastguard Worker        ))
171*60517a1eSAndroid Build Coastguard Worker
172*60517a1eSAndroid Build Coastguard Worker    result_kwargs = {k: getattr(result, k) for k in dir(result)}
173*60517a1eSAndroid Build Coastguard Worker    return struct(
174*60517a1eSAndroid Build Coastguard Worker        describe_failure = lambda: _execute_describe_failure(
175*60517a1eSAndroid Build Coastguard Worker            op = op,
176*60517a1eSAndroid Build Coastguard Worker            arguments = arguments,
177*60517a1eSAndroid Build Coastguard Worker            result = result,
178*60517a1eSAndroid Build Coastguard Worker            mrctx = mrctx,
179*60517a1eSAndroid Build Coastguard Worker            kwargs = kwargs,
180*60517a1eSAndroid Build Coastguard Worker            environment = environment,
181*60517a1eSAndroid Build Coastguard Worker        ),
182*60517a1eSAndroid Build Coastguard Worker        **result_kwargs
183*60517a1eSAndroid Build Coastguard Worker    )
184*60517a1eSAndroid Build Coastguard Worker
185*60517a1eSAndroid Build Coastguard Workerdef _execute_unchecked(*args, **kwargs):
186*60517a1eSAndroid Build Coastguard Worker    """Execute a subprocess.
187*60517a1eSAndroid Build Coastguard Worker
188*60517a1eSAndroid Build Coastguard Worker    Additional information will be printed if debug output is enabled.
189*60517a1eSAndroid Build Coastguard Worker
190*60517a1eSAndroid Build Coastguard Worker    Args:
191*60517a1eSAndroid Build Coastguard Worker        *args: see _execute_internal
192*60517a1eSAndroid Build Coastguard Worker        **kwargs: see _execute_internal
193*60517a1eSAndroid Build Coastguard Worker
194*60517a1eSAndroid Build Coastguard Worker    Returns:
195*60517a1eSAndroid Build Coastguard Worker        exec_result object, see repository_ctx.execute return type.
196*60517a1eSAndroid Build Coastguard Worker    """
197*60517a1eSAndroid Build Coastguard Worker    return _execute_internal(fail_on_error = False, *args, **kwargs)
198*60517a1eSAndroid Build Coastguard Worker
199*60517a1eSAndroid Build Coastguard Workerdef _execute_checked(*args, **kwargs):
200*60517a1eSAndroid Build Coastguard Worker    """Execute a subprocess, failing for a non-zero exit code.
201*60517a1eSAndroid Build Coastguard Worker
202*60517a1eSAndroid Build Coastguard Worker    If the command fails, then fail() is called with detailed information
203*60517a1eSAndroid Build Coastguard Worker    about the command and its failure.
204*60517a1eSAndroid Build Coastguard Worker
205*60517a1eSAndroid Build Coastguard Worker    Args:
206*60517a1eSAndroid Build Coastguard Worker        *args: see _execute_internal
207*60517a1eSAndroid Build Coastguard Worker        **kwargs: see _execute_internal
208*60517a1eSAndroid Build Coastguard Worker
209*60517a1eSAndroid Build Coastguard Worker    Returns:
210*60517a1eSAndroid Build Coastguard Worker        exec_result object, see repository_ctx.execute return type.
211*60517a1eSAndroid Build Coastguard Worker    """
212*60517a1eSAndroid Build Coastguard Worker    return _execute_internal(fail_on_error = True, *args, **kwargs)
213*60517a1eSAndroid Build Coastguard Worker
214*60517a1eSAndroid Build Coastguard Workerdef _execute_checked_stdout(*args, **kwargs):
215*60517a1eSAndroid Build Coastguard Worker    """Calls execute_checked, but only returns the stdout value."""
216*60517a1eSAndroid Build Coastguard Worker    return _execute_checked(*args, **kwargs).stdout
217*60517a1eSAndroid Build Coastguard Worker
218*60517a1eSAndroid Build Coastguard Workerdef _execute_describe_failure(*, op, arguments, result, mrctx, kwargs, environment):
219*60517a1eSAndroid Build Coastguard Worker    return (
220*60517a1eSAndroid Build Coastguard Worker        "repo.execute: {op}: failure:\n" +
221*60517a1eSAndroid Build Coastguard Worker        "  command: {cmd}\n" +
222*60517a1eSAndroid Build Coastguard Worker        "  return code: {return_code}\n" +
223*60517a1eSAndroid Build Coastguard Worker        "  working dir: {cwd}\n" +
224*60517a1eSAndroid Build Coastguard Worker        "  timeout: {timeout}\n" +
225*60517a1eSAndroid Build Coastguard Worker        "  environment:{env_str}\n" +
226*60517a1eSAndroid Build Coastguard Worker        "{output}"
227*60517a1eSAndroid Build Coastguard Worker    ).format(
228*60517a1eSAndroid Build Coastguard Worker        op = op,
229*60517a1eSAndroid Build Coastguard Worker        cmd = _args_to_str(arguments),
230*60517a1eSAndroid Build Coastguard Worker        return_code = result.return_code,
231*60517a1eSAndroid Build Coastguard Worker        cwd = _cwd_to_str(mrctx, kwargs),
232*60517a1eSAndroid Build Coastguard Worker        timeout = _timeout_to_str(kwargs),
233*60517a1eSAndroid Build Coastguard Worker        env_str = _env_to_str(environment),
234*60517a1eSAndroid Build Coastguard Worker        output = _outputs_to_str(result),
235*60517a1eSAndroid Build Coastguard Worker    )
236*60517a1eSAndroid Build Coastguard Worker
237*60517a1eSAndroid Build Coastguard Workerdef _which_checked(mrctx, binary_name):
238*60517a1eSAndroid Build Coastguard Worker    """Tests to see if a binary exists, and otherwise fails with a message.
239*60517a1eSAndroid Build Coastguard Worker
240*60517a1eSAndroid Build Coastguard Worker    Args:
241*60517a1eSAndroid Build Coastguard Worker        binary_name: name of the binary to find.
242*60517a1eSAndroid Build Coastguard Worker        mrctx: module_ctx or repository_ctx.
243*60517a1eSAndroid Build Coastguard Worker
244*60517a1eSAndroid Build Coastguard Worker    Returns:
245*60517a1eSAndroid Build Coastguard Worker        mrctx.Path for the binary.
246*60517a1eSAndroid Build Coastguard Worker    """
247*60517a1eSAndroid Build Coastguard Worker    result = _which_unchecked(mrctx, binary_name)
248*60517a1eSAndroid Build Coastguard Worker    if result.binary == None:
249*60517a1eSAndroid Build Coastguard Worker        fail(result.describe_failure())
250*60517a1eSAndroid Build Coastguard Worker    return result.binary
251*60517a1eSAndroid Build Coastguard Worker
252*60517a1eSAndroid Build Coastguard Workerdef _which_unchecked(mrctx, binary_name):
253*60517a1eSAndroid Build Coastguard Worker    """Tests to see if a binary exists.
254*60517a1eSAndroid Build Coastguard Worker
255*60517a1eSAndroid Build Coastguard Worker    This is also watch the `PATH` environment variable.
256*60517a1eSAndroid Build Coastguard Worker
257*60517a1eSAndroid Build Coastguard Worker    Args:
258*60517a1eSAndroid Build Coastguard Worker        binary_name: name of the binary to find.
259*60517a1eSAndroid Build Coastguard Worker        mrctx: repository context.
260*60517a1eSAndroid Build Coastguard Worker
261*60517a1eSAndroid Build Coastguard Worker    Returns:
262*60517a1eSAndroid Build Coastguard Worker        `struct` with attributes:
263*60517a1eSAndroid Build Coastguard Worker        * `binary`: `repository_ctx.Path`
264*60517a1eSAndroid Build Coastguard Worker        * `describe_failure`: `Callable | None`; takes no args. If the
265*60517a1eSAndroid Build Coastguard Worker          binary couldn't be found, provides a detailed error description.
266*60517a1eSAndroid Build Coastguard Worker    """
267*60517a1eSAndroid Build Coastguard Worker    path = _getenv(mrctx, "PATH", "")
268*60517a1eSAndroid Build Coastguard Worker    binary = mrctx.which(binary_name)
269*60517a1eSAndroid Build Coastguard Worker    if binary:
270*60517a1eSAndroid Build Coastguard Worker        _watch(mrctx, binary)
271*60517a1eSAndroid Build Coastguard Worker        describe_failure = None
272*60517a1eSAndroid Build Coastguard Worker    else:
273*60517a1eSAndroid Build Coastguard Worker        describe_failure = lambda: _which_describe_failure(binary_name, path)
274*60517a1eSAndroid Build Coastguard Worker
275*60517a1eSAndroid Build Coastguard Worker    return struct(
276*60517a1eSAndroid Build Coastguard Worker        binary = binary,
277*60517a1eSAndroid Build Coastguard Worker        describe_failure = describe_failure,
278*60517a1eSAndroid Build Coastguard Worker    )
279*60517a1eSAndroid Build Coastguard Worker
280*60517a1eSAndroid Build Coastguard Workerdef _which_describe_failure(binary_name, path):
281*60517a1eSAndroid Build Coastguard Worker    return (
282*60517a1eSAndroid Build Coastguard Worker        "Unable to find the binary '{binary_name}' on PATH.\n" +
283*60517a1eSAndroid Build Coastguard Worker        "  PATH = {path}"
284*60517a1eSAndroid Build Coastguard Worker    ).format(
285*60517a1eSAndroid Build Coastguard Worker        binary_name = binary_name,
286*60517a1eSAndroid Build Coastguard Worker        path = path,
287*60517a1eSAndroid Build Coastguard Worker    )
288*60517a1eSAndroid Build Coastguard Worker
289*60517a1eSAndroid Build Coastguard Workerdef _getenv(mrctx, name, default = None):
290*60517a1eSAndroid Build Coastguard Worker    # Bazel 7+ API has (repository|module)_ctx.getenv
291*60517a1eSAndroid Build Coastguard Worker    return getattr(mrctx, "getenv", mrctx.os.environ.get)(name, default)
292*60517a1eSAndroid Build Coastguard Worker
293*60517a1eSAndroid Build Coastguard Workerdef _args_to_str(arguments):
294*60517a1eSAndroid Build Coastguard Worker    return " ".join([_arg_repr(a) for a in arguments])
295*60517a1eSAndroid Build Coastguard Worker
296*60517a1eSAndroid Build Coastguard Workerdef _arg_repr(value):
297*60517a1eSAndroid Build Coastguard Worker    if _arg_should_be_quoted(value):
298*60517a1eSAndroid Build Coastguard Worker        return repr(value)
299*60517a1eSAndroid Build Coastguard Worker    else:
300*60517a1eSAndroid Build Coastguard Worker        return str(value)
301*60517a1eSAndroid Build Coastguard Worker
302*60517a1eSAndroid Build Coastguard Worker_SPECIAL_SHELL_CHARS = [" ", "'", '"', "{", "$", "("]
303*60517a1eSAndroid Build Coastguard Worker
304*60517a1eSAndroid Build Coastguard Workerdef _arg_should_be_quoted(value):
305*60517a1eSAndroid Build Coastguard Worker    # `value` may be non-str, such as mrctx.path objects
306*60517a1eSAndroid Build Coastguard Worker    value_str = str(value)
307*60517a1eSAndroid Build Coastguard Worker    for char in _SPECIAL_SHELL_CHARS:
308*60517a1eSAndroid Build Coastguard Worker        if char in value_str:
309*60517a1eSAndroid Build Coastguard Worker            return True
310*60517a1eSAndroid Build Coastguard Worker    return False
311*60517a1eSAndroid Build Coastguard Worker
312*60517a1eSAndroid Build Coastguard Workerdef _cwd_to_str(mrctx, kwargs):
313*60517a1eSAndroid Build Coastguard Worker    cwd = kwargs.get("working_directory")
314*60517a1eSAndroid Build Coastguard Worker    if not cwd:
315*60517a1eSAndroid Build Coastguard Worker        cwd = "<default: {}>".format(mrctx.path(""))
316*60517a1eSAndroid Build Coastguard Worker    return cwd
317*60517a1eSAndroid Build Coastguard Worker
318*60517a1eSAndroid Build Coastguard Workerdef _env_to_str(environment):
319*60517a1eSAndroid Build Coastguard Worker    if not environment:
320*60517a1eSAndroid Build Coastguard Worker        env_str = " <default environment>"
321*60517a1eSAndroid Build Coastguard Worker    else:
322*60517a1eSAndroid Build Coastguard Worker        env_str = "\n".join(["{}={}".format(k, repr(v)) for k, v in environment.items()])
323*60517a1eSAndroid Build Coastguard Worker        env_str = "\n" + env_str
324*60517a1eSAndroid Build Coastguard Worker    return env_str
325*60517a1eSAndroid Build Coastguard Worker
326*60517a1eSAndroid Build Coastguard Workerdef _timeout_to_str(kwargs):
327*60517a1eSAndroid Build Coastguard Worker    return kwargs.get("timeout", "<default timeout>")
328*60517a1eSAndroid Build Coastguard Worker
329*60517a1eSAndroid Build Coastguard Workerdef _outputs_to_str(result):
330*60517a1eSAndroid Build Coastguard Worker    lines = []
331*60517a1eSAndroid Build Coastguard Worker    items = [
332*60517a1eSAndroid Build Coastguard Worker        ("stdout", result.stdout),
333*60517a1eSAndroid Build Coastguard Worker        ("stderr", result.stderr),
334*60517a1eSAndroid Build Coastguard Worker    ]
335*60517a1eSAndroid Build Coastguard Worker    for name, content in items:
336*60517a1eSAndroid Build Coastguard Worker        if content:
337*60517a1eSAndroid Build Coastguard Worker            lines.append("===== {} start =====".format(name))
338*60517a1eSAndroid Build Coastguard Worker
339*60517a1eSAndroid Build Coastguard Worker            # Prevent adding an extra new line, which makes the output look odd.
340*60517a1eSAndroid Build Coastguard Worker            if content.endswith("\n"):
341*60517a1eSAndroid Build Coastguard Worker                lines.append(content[:-1])
342*60517a1eSAndroid Build Coastguard Worker            else:
343*60517a1eSAndroid Build Coastguard Worker                lines.append(content)
344*60517a1eSAndroid Build Coastguard Worker            lines.append("===== {} end =====".format(name))
345*60517a1eSAndroid Build Coastguard Worker        else:
346*60517a1eSAndroid Build Coastguard Worker            lines.append("<{} empty>".format(name))
347*60517a1eSAndroid Build Coastguard Worker    return "\n".join(lines)
348*60517a1eSAndroid Build Coastguard Worker
349*60517a1eSAndroid Build Coastguard Worker# This includes the vendored _translate_cpu and _translate_os from
350*60517a1eSAndroid Build Coastguard Worker# @platforms//host:extension.bzl at version 0.0.9 so that we don't
351*60517a1eSAndroid Build Coastguard Worker# force the users to depend on it.
352*60517a1eSAndroid Build Coastguard Worker
353*60517a1eSAndroid Build Coastguard Workerdef _get_platforms_os_name(mrctx):
354*60517a1eSAndroid Build Coastguard Worker    """Return the name in @platforms//os for the host os.
355*60517a1eSAndroid Build Coastguard Worker
356*60517a1eSAndroid Build Coastguard Worker    Args:
357*60517a1eSAndroid Build Coastguard Worker        mrctx: module_ctx or repository_ctx.
358*60517a1eSAndroid Build Coastguard Worker
359*60517a1eSAndroid Build Coastguard Worker    Returns:
360*60517a1eSAndroid Build Coastguard Worker        `str`. The target name.
361*60517a1eSAndroid Build Coastguard Worker    """
362*60517a1eSAndroid Build Coastguard Worker    os = mrctx.os.name.lower()
363*60517a1eSAndroid Build Coastguard Worker
364*60517a1eSAndroid Build Coastguard Worker    if os.startswith("mac os"):
365*60517a1eSAndroid Build Coastguard Worker        return "osx"
366*60517a1eSAndroid Build Coastguard Worker    if os.startswith("freebsd"):
367*60517a1eSAndroid Build Coastguard Worker        return "freebsd"
368*60517a1eSAndroid Build Coastguard Worker    if os.startswith("openbsd"):
369*60517a1eSAndroid Build Coastguard Worker        return "openbsd"
370*60517a1eSAndroid Build Coastguard Worker    if os.startswith("linux"):
371*60517a1eSAndroid Build Coastguard Worker        return "linux"
372*60517a1eSAndroid Build Coastguard Worker    if os.startswith("windows"):
373*60517a1eSAndroid Build Coastguard Worker        return "windows"
374*60517a1eSAndroid Build Coastguard Worker    return os
375*60517a1eSAndroid Build Coastguard Worker
376*60517a1eSAndroid Build Coastguard Workerdef _get_platforms_cpu_name(mrctx):
377*60517a1eSAndroid Build Coastguard Worker    """Return the name in @platforms//cpu for the host arch.
378*60517a1eSAndroid Build Coastguard Worker
379*60517a1eSAndroid Build Coastguard Worker    Args:
380*60517a1eSAndroid Build Coastguard Worker        mrctx: module_ctx or repository_ctx.
381*60517a1eSAndroid Build Coastguard Worker
382*60517a1eSAndroid Build Coastguard Worker    Returns:
383*60517a1eSAndroid Build Coastguard Worker        `str`. The target name.
384*60517a1eSAndroid Build Coastguard Worker    """
385*60517a1eSAndroid Build Coastguard Worker    arch = mrctx.os.arch.lower()
386*60517a1eSAndroid Build Coastguard Worker    if arch in ["i386", "i486", "i586", "i686", "i786", "x86"]:
387*60517a1eSAndroid Build Coastguard Worker        return "x86_32"
388*60517a1eSAndroid Build Coastguard Worker    if arch in ["amd64", "x86_64", "x64"]:
389*60517a1eSAndroid Build Coastguard Worker        return "x86_64"
390*60517a1eSAndroid Build Coastguard Worker    if arch in ["ppc", "ppc64", "ppc64le"]:
391*60517a1eSAndroid Build Coastguard Worker        return "ppc"
392*60517a1eSAndroid Build Coastguard Worker    if arch in ["arm", "armv7l"]:
393*60517a1eSAndroid Build Coastguard Worker        return "arm"
394*60517a1eSAndroid Build Coastguard Worker    if arch in ["aarch64"]:
395*60517a1eSAndroid Build Coastguard Worker        return "aarch64"
396*60517a1eSAndroid Build Coastguard Worker    if arch in ["s390x", "s390"]:
397*60517a1eSAndroid Build Coastguard Worker        return "s390x"
398*60517a1eSAndroid Build Coastguard Worker    if arch in ["mips64el", "mips64"]:
399*60517a1eSAndroid Build Coastguard Worker        return "mips64"
400*60517a1eSAndroid Build Coastguard Worker    if arch in ["riscv64"]:
401*60517a1eSAndroid Build Coastguard Worker        return "riscv64"
402*60517a1eSAndroid Build Coastguard Worker    return arch
403*60517a1eSAndroid Build Coastguard Worker
404*60517a1eSAndroid Build Coastguard Worker# TODO: Remove after Bazel 6 support dropped
405*60517a1eSAndroid Build Coastguard Workerdef _watch(mrctx, *args, **kwargs):
406*60517a1eSAndroid Build Coastguard Worker    """Calls mrctx.watch, if available."""
407*60517a1eSAndroid Build Coastguard Worker    if not args and not kwargs:
408*60517a1eSAndroid Build Coastguard Worker        fail("'watch' needs at least a single argument.")
409*60517a1eSAndroid Build Coastguard Worker
410*60517a1eSAndroid Build Coastguard Worker    if hasattr(mrctx, "watch"):
411*60517a1eSAndroid Build Coastguard Worker        mrctx.watch(*args, **kwargs)
412*60517a1eSAndroid Build Coastguard Worker
413*60517a1eSAndroid Build Coastguard Worker# TODO: Remove after Bazel 6 support dropped
414*60517a1eSAndroid Build Coastguard Workerdef _watch_tree(mrctx, *args, **kwargs):
415*60517a1eSAndroid Build Coastguard Worker    """Calls mrctx.watch_tree, if available."""
416*60517a1eSAndroid Build Coastguard Worker    if not args and not kwargs:
417*60517a1eSAndroid Build Coastguard Worker        fail("'watch_tree' needs at least a single argument.")
418*60517a1eSAndroid Build Coastguard Worker
419*60517a1eSAndroid Build Coastguard Worker    if hasattr(mrctx, "watch_tree"):
420*60517a1eSAndroid Build Coastguard Worker        mrctx.watch_tree(*args, **kwargs)
421*60517a1eSAndroid Build Coastguard Worker
422*60517a1eSAndroid Build Coastguard Workerrepo_utils = struct(
423*60517a1eSAndroid Build Coastguard Worker    # keep sorted
424*60517a1eSAndroid Build Coastguard Worker    execute_checked = _execute_checked,
425*60517a1eSAndroid Build Coastguard Worker    execute_checked_stdout = _execute_checked_stdout,
426*60517a1eSAndroid Build Coastguard Worker    execute_unchecked = _execute_unchecked,
427*60517a1eSAndroid Build Coastguard Worker    get_platforms_cpu_name = _get_platforms_cpu_name,
428*60517a1eSAndroid Build Coastguard Worker    get_platforms_os_name = _get_platforms_os_name,
429*60517a1eSAndroid Build Coastguard Worker    getenv = _getenv,
430*60517a1eSAndroid Build Coastguard Worker    is_repo_debug_enabled = _is_repo_debug_enabled,
431*60517a1eSAndroid Build Coastguard Worker    logger = _logger,
432*60517a1eSAndroid Build Coastguard Worker    watch = _watch,
433*60517a1eSAndroid Build Coastguard Worker    watch_tree = _watch_tree,
434*60517a1eSAndroid Build Coastguard Worker    which_checked = _which_checked,
435*60517a1eSAndroid Build Coastguard Worker    which_unchecked = _which_unchecked,
436*60517a1eSAndroid Build Coastguard Worker)
437