xref: /aosp_15_r20/external/bazelbuild-rules_python/python/config_settings/transition.bzl (revision 60517a1edbc8ecf509223e9af94a7adec7d736b8)
1*60517a1eSAndroid Build Coastguard Worker# Copyright 2023 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"""The transition module contains the rule definitions to wrap py_binary and py_test and transition
16*60517a1eSAndroid Build Coastguard Workerthem to the desired target platform.
17*60517a1eSAndroid Build Coastguard Worker"""
18*60517a1eSAndroid Build Coastguard Worker
19*60517a1eSAndroid Build Coastguard Workerload("@bazel_skylib//lib:dicts.bzl", "dicts")
20*60517a1eSAndroid Build Coastguard Workerload("//python:py_binary.bzl", _py_binary = "py_binary")
21*60517a1eSAndroid Build Coastguard Workerload("//python:py_info.bzl", "PyInfo")
22*60517a1eSAndroid Build Coastguard Workerload("//python:py_runtime_info.bzl", "PyRuntimeInfo")
23*60517a1eSAndroid Build Coastguard Workerload("//python:py_test.bzl", _py_test = "py_test")
24*60517a1eSAndroid Build Coastguard Workerload("//python/config_settings/private:py_args.bzl", "py_args")
25*60517a1eSAndroid Build Coastguard Workerload("//python/private:reexports.bzl", "BuiltinPyInfo", "BuiltinPyRuntimeInfo")
26*60517a1eSAndroid Build Coastguard Worker
27*60517a1eSAndroid Build Coastguard Workerdef _transition_python_version_impl(_, attr):
28*60517a1eSAndroid Build Coastguard Worker    return {"//python/config_settings:python_version": str(attr.python_version)}
29*60517a1eSAndroid Build Coastguard Worker
30*60517a1eSAndroid Build Coastguard Worker_transition_python_version = transition(
31*60517a1eSAndroid Build Coastguard Worker    implementation = _transition_python_version_impl,
32*60517a1eSAndroid Build Coastguard Worker    inputs = [],
33*60517a1eSAndroid Build Coastguard Worker    outputs = ["//python/config_settings:python_version"],
34*60517a1eSAndroid Build Coastguard Worker)
35*60517a1eSAndroid Build Coastguard Worker
36*60517a1eSAndroid Build Coastguard Workerdef _transition_py_impl(ctx):
37*60517a1eSAndroid Build Coastguard Worker    target = ctx.attr.target
38*60517a1eSAndroid Build Coastguard Worker    windows_constraint = ctx.attr._windows_constraint[platform_common.ConstraintValueInfo]
39*60517a1eSAndroid Build Coastguard Worker    target_is_windows = ctx.target_platform_has_constraint(windows_constraint)
40*60517a1eSAndroid Build Coastguard Worker    executable = ctx.actions.declare_file(ctx.attr.name + (".exe" if target_is_windows else ""))
41*60517a1eSAndroid Build Coastguard Worker    ctx.actions.symlink(
42*60517a1eSAndroid Build Coastguard Worker        is_executable = True,
43*60517a1eSAndroid Build Coastguard Worker        output = executable,
44*60517a1eSAndroid Build Coastguard Worker        target_file = target[DefaultInfo].files_to_run.executable,
45*60517a1eSAndroid Build Coastguard Worker    )
46*60517a1eSAndroid Build Coastguard Worker    default_outputs = []
47*60517a1eSAndroid Build Coastguard Worker    if target_is_windows:
48*60517a1eSAndroid Build Coastguard Worker        # NOTE: Bazel 6 + host=linux + target=windows results in the .exe extension missing
49*60517a1eSAndroid Build Coastguard Worker        inner_bootstrap_path = _strip_suffix(target[DefaultInfo].files_to_run.executable.short_path, ".exe")
50*60517a1eSAndroid Build Coastguard Worker        inner_bootstrap = None
51*60517a1eSAndroid Build Coastguard Worker        inner_zip_file_path = inner_bootstrap_path + ".zip"
52*60517a1eSAndroid Build Coastguard Worker        inner_zip_file = None
53*60517a1eSAndroid Build Coastguard Worker        for file in target[DefaultInfo].files.to_list():
54*60517a1eSAndroid Build Coastguard Worker            if file.short_path == inner_bootstrap_path:
55*60517a1eSAndroid Build Coastguard Worker                inner_bootstrap = file
56*60517a1eSAndroid Build Coastguard Worker            elif file.short_path == inner_zip_file_path:
57*60517a1eSAndroid Build Coastguard Worker                inner_zip_file = file
58*60517a1eSAndroid Build Coastguard Worker
59*60517a1eSAndroid Build Coastguard Worker        # TODO: Use `fragments.py.build_python_zip` once Bazel 6 support is dropped.
60*60517a1eSAndroid Build Coastguard Worker        # Which file the Windows .exe looks for depends on the --build_python_zip file.
61*60517a1eSAndroid Build Coastguard Worker        # Bazel 7+ has APIs to know the effective value of that flag, but not Bazel 6.
62*60517a1eSAndroid Build Coastguard Worker        # To work around this, we treat the existence of a .zip in the default outputs
63*60517a1eSAndroid Build Coastguard Worker        # to mean --build_python_zip=true.
64*60517a1eSAndroid Build Coastguard Worker        if inner_zip_file:
65*60517a1eSAndroid Build Coastguard Worker            suffix = ".zip"
66*60517a1eSAndroid Build Coastguard Worker            underlying_launched_file = inner_zip_file
67*60517a1eSAndroid Build Coastguard Worker        else:
68*60517a1eSAndroid Build Coastguard Worker            suffix = ""
69*60517a1eSAndroid Build Coastguard Worker            underlying_launched_file = inner_bootstrap
70*60517a1eSAndroid Build Coastguard Worker
71*60517a1eSAndroid Build Coastguard Worker        if underlying_launched_file:
72*60517a1eSAndroid Build Coastguard Worker            launched_file_symlink = ctx.actions.declare_file(ctx.attr.name + suffix)
73*60517a1eSAndroid Build Coastguard Worker            ctx.actions.symlink(
74*60517a1eSAndroid Build Coastguard Worker                is_executable = True,
75*60517a1eSAndroid Build Coastguard Worker                output = launched_file_symlink,
76*60517a1eSAndroid Build Coastguard Worker                target_file = underlying_launched_file,
77*60517a1eSAndroid Build Coastguard Worker            )
78*60517a1eSAndroid Build Coastguard Worker            default_outputs.append(launched_file_symlink)
79*60517a1eSAndroid Build Coastguard Worker
80*60517a1eSAndroid Build Coastguard Worker    env = {}
81*60517a1eSAndroid Build Coastguard Worker    for k, v in ctx.attr.env.items():
82*60517a1eSAndroid Build Coastguard Worker        env[k] = ctx.expand_location(v)
83*60517a1eSAndroid Build Coastguard Worker
84*60517a1eSAndroid Build Coastguard Worker    providers = [
85*60517a1eSAndroid Build Coastguard Worker        DefaultInfo(
86*60517a1eSAndroid Build Coastguard Worker            executable = executable,
87*60517a1eSAndroid Build Coastguard Worker            files = depset(default_outputs, transitive = [target[DefaultInfo].files]),
88*60517a1eSAndroid Build Coastguard Worker            runfiles = ctx.runfiles(default_outputs).merge(target[DefaultInfo].default_runfiles),
89*60517a1eSAndroid Build Coastguard Worker        ),
90*60517a1eSAndroid Build Coastguard Worker        # Ensure that the binary we're wrapping is included in code coverage.
91*60517a1eSAndroid Build Coastguard Worker        coverage_common.instrumented_files_info(
92*60517a1eSAndroid Build Coastguard Worker            ctx,
93*60517a1eSAndroid Build Coastguard Worker            dependency_attributes = ["target"],
94*60517a1eSAndroid Build Coastguard Worker        ),
95*60517a1eSAndroid Build Coastguard Worker        target[OutputGroupInfo],
96*60517a1eSAndroid Build Coastguard Worker        # TODO(f0rmiga): testing.TestEnvironment is deprecated in favour of RunEnvironmentInfo but
97*60517a1eSAndroid Build Coastguard Worker        # RunEnvironmentInfo is not exposed in Bazel < 5.3.
98*60517a1eSAndroid Build Coastguard Worker        # https://github.com/bazelbuild/rules_python/issues/901
99*60517a1eSAndroid Build Coastguard Worker        # https://github.com/bazelbuild/bazel/commit/dbdfa07e92f99497be9c14265611ad2920161483
100*60517a1eSAndroid Build Coastguard Worker        testing.TestEnvironment(env),
101*60517a1eSAndroid Build Coastguard Worker    ]
102*60517a1eSAndroid Build Coastguard Worker    if PyInfo in target:
103*60517a1eSAndroid Build Coastguard Worker        providers.append(target[PyInfo])
104*60517a1eSAndroid Build Coastguard Worker    if BuiltinPyInfo in target and PyInfo != BuiltinPyInfo:
105*60517a1eSAndroid Build Coastguard Worker        providers.append(target[BuiltinPyInfo])
106*60517a1eSAndroid Build Coastguard Worker
107*60517a1eSAndroid Build Coastguard Worker    if PyRuntimeInfo in target:
108*60517a1eSAndroid Build Coastguard Worker        providers.append(target[PyRuntimeInfo])
109*60517a1eSAndroid Build Coastguard Worker    if BuiltinPyRuntimeInfo in target and PyRuntimeInfo != BuiltinPyRuntimeInfo:
110*60517a1eSAndroid Build Coastguard Worker        providers.append(target[BuiltinPyRuntimeInfo])
111*60517a1eSAndroid Build Coastguard Worker    return providers
112*60517a1eSAndroid Build Coastguard Worker
113*60517a1eSAndroid Build Coastguard Worker_COMMON_ATTRS = {
114*60517a1eSAndroid Build Coastguard Worker    "deps": attr.label_list(
115*60517a1eSAndroid Build Coastguard Worker        mandatory = False,
116*60517a1eSAndroid Build Coastguard Worker    ),
117*60517a1eSAndroid Build Coastguard Worker    "env": attr.string_dict(
118*60517a1eSAndroid Build Coastguard Worker        mandatory = False,
119*60517a1eSAndroid Build Coastguard Worker    ),
120*60517a1eSAndroid Build Coastguard Worker    "python_version": attr.string(
121*60517a1eSAndroid Build Coastguard Worker        mandatory = True,
122*60517a1eSAndroid Build Coastguard Worker    ),
123*60517a1eSAndroid Build Coastguard Worker    "srcs": attr.label_list(
124*60517a1eSAndroid Build Coastguard Worker        allow_files = True,
125*60517a1eSAndroid Build Coastguard Worker        mandatory = False,
126*60517a1eSAndroid Build Coastguard Worker    ),
127*60517a1eSAndroid Build Coastguard Worker    "target": attr.label(
128*60517a1eSAndroid Build Coastguard Worker        executable = True,
129*60517a1eSAndroid Build Coastguard Worker        cfg = "target",
130*60517a1eSAndroid Build Coastguard Worker        mandatory = True,
131*60517a1eSAndroid Build Coastguard Worker        providers = [PyInfo],
132*60517a1eSAndroid Build Coastguard Worker    ),
133*60517a1eSAndroid Build Coastguard Worker    # "tools" is a hack here. It should be "data" but "data" is not included by default in the
134*60517a1eSAndroid Build Coastguard Worker    # location expansion in the same way it is in the native Python rules. The difference on how
135*60517a1eSAndroid Build Coastguard Worker    # the Bazel deals with those special attributes differ on the LocationExpander, e.g.:
136*60517a1eSAndroid Build Coastguard Worker    # https://github.com/bazelbuild/bazel/blob/ce611646/src/main/java/com/google/devtools/build/lib/analysis/LocationExpander.java#L415-L429
137*60517a1eSAndroid Build Coastguard Worker    #
138*60517a1eSAndroid Build Coastguard Worker    # Since the default LocationExpander used by ctx.expand_location is not the same as the native
139*60517a1eSAndroid Build Coastguard Worker    # rules (it doesn't set "allowDataAttributeEntriesInLabel"), we use "tools" temporarily while a
140*60517a1eSAndroid Build Coastguard Worker    # proper fix in Bazel happens.
141*60517a1eSAndroid Build Coastguard Worker    #
142*60517a1eSAndroid Build Coastguard Worker    # A fix for this was proposed in https://github.com/bazelbuild/bazel/pull/16381.
143*60517a1eSAndroid Build Coastguard Worker    "tools": attr.label_list(
144*60517a1eSAndroid Build Coastguard Worker        allow_files = True,
145*60517a1eSAndroid Build Coastguard Worker        mandatory = False,
146*60517a1eSAndroid Build Coastguard Worker    ),
147*60517a1eSAndroid Build Coastguard Worker    # Required to Opt-in to the transitions feature.
148*60517a1eSAndroid Build Coastguard Worker    "_allowlist_function_transition": attr.label(
149*60517a1eSAndroid Build Coastguard Worker        default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
150*60517a1eSAndroid Build Coastguard Worker    ),
151*60517a1eSAndroid Build Coastguard Worker    "_windows_constraint": attr.label(
152*60517a1eSAndroid Build Coastguard Worker        default = "@platforms//os:windows",
153*60517a1eSAndroid Build Coastguard Worker    ),
154*60517a1eSAndroid Build Coastguard Worker}
155*60517a1eSAndroid Build Coastguard Worker
156*60517a1eSAndroid Build Coastguard Worker_PY_TEST_ATTRS = {
157*60517a1eSAndroid Build Coastguard Worker    # Magic attribute to help C++ coverage work. There's no
158*60517a1eSAndroid Build Coastguard Worker    # docs about this; see TestActionBuilder.java
159*60517a1eSAndroid Build Coastguard Worker    "_collect_cc_coverage": attr.label(
160*60517a1eSAndroid Build Coastguard Worker        default = "@bazel_tools//tools/test:collect_cc_coverage",
161*60517a1eSAndroid Build Coastguard Worker        executable = True,
162*60517a1eSAndroid Build Coastguard Worker        cfg = "exec",
163*60517a1eSAndroid Build Coastguard Worker    ),
164*60517a1eSAndroid Build Coastguard Worker    # Magic attribute to make coverage work. There's no
165*60517a1eSAndroid Build Coastguard Worker    # docs about this; see TestActionBuilder.java
166*60517a1eSAndroid Build Coastguard Worker    "_lcov_merger": attr.label(
167*60517a1eSAndroid Build Coastguard Worker        default = configuration_field(fragment = "coverage", name = "output_generator"),
168*60517a1eSAndroid Build Coastguard Worker        executable = True,
169*60517a1eSAndroid Build Coastguard Worker        cfg = "exec",
170*60517a1eSAndroid Build Coastguard Worker    ),
171*60517a1eSAndroid Build Coastguard Worker}
172*60517a1eSAndroid Build Coastguard Worker
173*60517a1eSAndroid Build Coastguard Worker_transition_py_binary = rule(
174*60517a1eSAndroid Build Coastguard Worker    _transition_py_impl,
175*60517a1eSAndroid Build Coastguard Worker    attrs = _COMMON_ATTRS | _PY_TEST_ATTRS,
176*60517a1eSAndroid Build Coastguard Worker    cfg = _transition_python_version,
177*60517a1eSAndroid Build Coastguard Worker    executable = True,
178*60517a1eSAndroid Build Coastguard Worker    fragments = ["py"],
179*60517a1eSAndroid Build Coastguard Worker)
180*60517a1eSAndroid Build Coastguard Worker
181*60517a1eSAndroid Build Coastguard Worker_transition_py_test = rule(
182*60517a1eSAndroid Build Coastguard Worker    _transition_py_impl,
183*60517a1eSAndroid Build Coastguard Worker    attrs = _COMMON_ATTRS | _PY_TEST_ATTRS,
184*60517a1eSAndroid Build Coastguard Worker    cfg = _transition_python_version,
185*60517a1eSAndroid Build Coastguard Worker    test = True,
186*60517a1eSAndroid Build Coastguard Worker    fragments = ["py"],
187*60517a1eSAndroid Build Coastguard Worker)
188*60517a1eSAndroid Build Coastguard Worker
189*60517a1eSAndroid Build Coastguard Workerdef _py_rule(rule_impl, transition_rule, name, python_version, **kwargs):
190*60517a1eSAndroid Build Coastguard Worker    pyargs = py_args(name, kwargs)
191*60517a1eSAndroid Build Coastguard Worker    args = pyargs["args"]
192*60517a1eSAndroid Build Coastguard Worker    data = pyargs["data"]
193*60517a1eSAndroid Build Coastguard Worker    env = pyargs["env"]
194*60517a1eSAndroid Build Coastguard Worker    srcs = pyargs["srcs"]
195*60517a1eSAndroid Build Coastguard Worker    deps = pyargs["deps"]
196*60517a1eSAndroid Build Coastguard Worker    main = pyargs["main"]
197*60517a1eSAndroid Build Coastguard Worker
198*60517a1eSAndroid Build Coastguard Worker    # Attributes common to all build rules.
199*60517a1eSAndroid Build Coastguard Worker    # https://bazel.build/reference/be/common-definitions#common-attributes
200*60517a1eSAndroid Build Coastguard Worker    compatible_with = kwargs.pop("compatible_with", None)
201*60517a1eSAndroid Build Coastguard Worker    deprecation = kwargs.pop("deprecation", None)
202*60517a1eSAndroid Build Coastguard Worker    exec_compatible_with = kwargs.pop("exec_compatible_with", None)
203*60517a1eSAndroid Build Coastguard Worker    exec_properties = kwargs.pop("exec_properties", None)
204*60517a1eSAndroid Build Coastguard Worker    features = kwargs.pop("features", None)
205*60517a1eSAndroid Build Coastguard Worker    restricted_to = kwargs.pop("restricted_to", None)
206*60517a1eSAndroid Build Coastguard Worker    tags = kwargs.pop("tags", None)
207*60517a1eSAndroid Build Coastguard Worker    target_compatible_with = kwargs.pop("target_compatible_with", None)
208*60517a1eSAndroid Build Coastguard Worker    testonly = kwargs.pop("testonly", None)
209*60517a1eSAndroid Build Coastguard Worker    toolchains = kwargs.pop("toolchains", None)
210*60517a1eSAndroid Build Coastguard Worker    visibility = kwargs.pop("visibility", None)
211*60517a1eSAndroid Build Coastguard Worker
212*60517a1eSAndroid Build Coastguard Worker    common_attrs = {
213*60517a1eSAndroid Build Coastguard Worker        "compatible_with": compatible_with,
214*60517a1eSAndroid Build Coastguard Worker        "deprecation": deprecation,
215*60517a1eSAndroid Build Coastguard Worker        "exec_compatible_with": exec_compatible_with,
216*60517a1eSAndroid Build Coastguard Worker        "exec_properties": exec_properties,
217*60517a1eSAndroid Build Coastguard Worker        "features": features,
218*60517a1eSAndroid Build Coastguard Worker        "restricted_to": restricted_to,
219*60517a1eSAndroid Build Coastguard Worker        "target_compatible_with": target_compatible_with,
220*60517a1eSAndroid Build Coastguard Worker        "testonly": testonly,
221*60517a1eSAndroid Build Coastguard Worker        "toolchains": toolchains,
222*60517a1eSAndroid Build Coastguard Worker    }
223*60517a1eSAndroid Build Coastguard Worker
224*60517a1eSAndroid Build Coastguard Worker    # Test-specific extra attributes.
225*60517a1eSAndroid Build Coastguard Worker    if "env_inherit" in kwargs:
226*60517a1eSAndroid Build Coastguard Worker        common_attrs["env_inherit"] = kwargs.pop("env_inherit")
227*60517a1eSAndroid Build Coastguard Worker    if "size" in kwargs:
228*60517a1eSAndroid Build Coastguard Worker        common_attrs["size"] = kwargs.pop("size")
229*60517a1eSAndroid Build Coastguard Worker    if "timeout" in kwargs:
230*60517a1eSAndroid Build Coastguard Worker        common_attrs["timeout"] = kwargs.pop("timeout")
231*60517a1eSAndroid Build Coastguard Worker    if "flaky" in kwargs:
232*60517a1eSAndroid Build Coastguard Worker        common_attrs["flaky"] = kwargs.pop("flaky")
233*60517a1eSAndroid Build Coastguard Worker    if "shard_count" in kwargs:
234*60517a1eSAndroid Build Coastguard Worker        common_attrs["shard_count"] = kwargs.pop("shard_count")
235*60517a1eSAndroid Build Coastguard Worker    if "local" in kwargs:
236*60517a1eSAndroid Build Coastguard Worker        common_attrs["local"] = kwargs.pop("local")
237*60517a1eSAndroid Build Coastguard Worker
238*60517a1eSAndroid Build Coastguard Worker    # Binary-specific extra attributes.
239*60517a1eSAndroid Build Coastguard Worker    if "output_licenses" in kwargs:
240*60517a1eSAndroid Build Coastguard Worker        common_attrs["output_licenses"] = kwargs.pop("output_licenses")
241*60517a1eSAndroid Build Coastguard Worker
242*60517a1eSAndroid Build Coastguard Worker    rule_impl(
243*60517a1eSAndroid Build Coastguard Worker        name = "_" + name,
244*60517a1eSAndroid Build Coastguard Worker        args = args,
245*60517a1eSAndroid Build Coastguard Worker        data = data,
246*60517a1eSAndroid Build Coastguard Worker        deps = deps,
247*60517a1eSAndroid Build Coastguard Worker        env = env,
248*60517a1eSAndroid Build Coastguard Worker        srcs = srcs,
249*60517a1eSAndroid Build Coastguard Worker        main = main,
250*60517a1eSAndroid Build Coastguard Worker        tags = ["manual"] + (tags if tags else []),
251*60517a1eSAndroid Build Coastguard Worker        visibility = ["//visibility:private"],
252*60517a1eSAndroid Build Coastguard Worker        **dicts.add(common_attrs, kwargs)
253*60517a1eSAndroid Build Coastguard Worker    )
254*60517a1eSAndroid Build Coastguard Worker
255*60517a1eSAndroid Build Coastguard Worker    return transition_rule(
256*60517a1eSAndroid Build Coastguard Worker        name = name,
257*60517a1eSAndroid Build Coastguard Worker        args = args,
258*60517a1eSAndroid Build Coastguard Worker        deps = deps,
259*60517a1eSAndroid Build Coastguard Worker        env = env,
260*60517a1eSAndroid Build Coastguard Worker        python_version = python_version,
261*60517a1eSAndroid Build Coastguard Worker        srcs = srcs,
262*60517a1eSAndroid Build Coastguard Worker        tags = tags,
263*60517a1eSAndroid Build Coastguard Worker        target = ":_" + name,
264*60517a1eSAndroid Build Coastguard Worker        tools = data,
265*60517a1eSAndroid Build Coastguard Worker        visibility = visibility,
266*60517a1eSAndroid Build Coastguard Worker        **common_attrs
267*60517a1eSAndroid Build Coastguard Worker    )
268*60517a1eSAndroid Build Coastguard Worker
269*60517a1eSAndroid Build Coastguard Workerdef py_binary(name, python_version, **kwargs):
270*60517a1eSAndroid Build Coastguard Worker    return _py_rule(_py_binary, _transition_py_binary, name, python_version, **kwargs)
271*60517a1eSAndroid Build Coastguard Worker
272*60517a1eSAndroid Build Coastguard Workerdef py_test(name, python_version, **kwargs):
273*60517a1eSAndroid Build Coastguard Worker    return _py_rule(_py_test, _transition_py_test, name, python_version, **kwargs)
274*60517a1eSAndroid Build Coastguard Worker
275*60517a1eSAndroid Build Coastguard Workerdef _strip_suffix(s, suffix):
276*60517a1eSAndroid Build Coastguard Worker    if s.endswith(suffix):
277*60517a1eSAndroid Build Coastguard Worker        return s[:-len(suffix)]
278*60517a1eSAndroid Build Coastguard Worker    else:
279*60517a1eSAndroid Build Coastguard Worker        return s
280