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"""This module is used to construct the config settings in the BUILD file in this same package. 16*60517a1eSAndroid Build Coastguard Worker""" 17*60517a1eSAndroid Build Coastguard Worker 18*60517a1eSAndroid Build Coastguard Workerload("@bazel_skylib//lib:selects.bzl", "selects") 19*60517a1eSAndroid Build Coastguard Workerload("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") 20*60517a1eSAndroid Build Coastguard Workerload(":semver.bzl", "semver") 21*60517a1eSAndroid Build Coastguard Worker 22*60517a1eSAndroid Build Coastguard Worker_PYTHON_VERSION_FLAG = Label("//python/config_settings:python_version") 23*60517a1eSAndroid Build Coastguard Worker_PYTHON_VERSION_MAJOR_MINOR_FLAG = Label("//python/config_settings:_python_version_major_minor") 24*60517a1eSAndroid Build Coastguard Worker 25*60517a1eSAndroid Build Coastguard Workerdef construct_config_settings(*, name, versions, minor_mapping): # buildifier: disable=function-docstring 26*60517a1eSAndroid Build Coastguard Worker """Create a 'python_version' config flag and construct all config settings used in rules_python. 27*60517a1eSAndroid Build Coastguard Worker 28*60517a1eSAndroid Build Coastguard Worker This mainly includes the targets that are used in the toolchain and pip hub 29*60517a1eSAndroid Build Coastguard Worker repositories that only match on the 'python_version' flag values. 30*60517a1eSAndroid Build Coastguard Worker 31*60517a1eSAndroid Build Coastguard Worker Args: 32*60517a1eSAndroid Build Coastguard Worker name: {type}`str` A dummy name value that is no-op for now. 33*60517a1eSAndroid Build Coastguard Worker versions: {type}`list[str]` A list of versions to build constraint settings for. 34*60517a1eSAndroid Build Coastguard Worker minor_mapping: {type}`dict[str, str]` A mapping from `X.Y` to `X.Y.Z` python versions. 35*60517a1eSAndroid Build Coastguard Worker """ 36*60517a1eSAndroid Build Coastguard Worker _ = name # @unused 37*60517a1eSAndroid Build Coastguard Worker _python_version_flag( 38*60517a1eSAndroid Build Coastguard Worker name = _PYTHON_VERSION_FLAG.name, 39*60517a1eSAndroid Build Coastguard Worker # TODO: The default here should somehow match the MODULE config. Until 40*60517a1eSAndroid Build Coastguard Worker # then, use the empty string to indicate an unknown version. This 41*60517a1eSAndroid Build Coastguard Worker # also prevents version-unaware targets from inadvertently matching 42*60517a1eSAndroid Build Coastguard Worker # a select condition when they shouldn't. 43*60517a1eSAndroid Build Coastguard Worker build_setting_default = "", 44*60517a1eSAndroid Build Coastguard Worker visibility = ["//visibility:public"], 45*60517a1eSAndroid Build Coastguard Worker ) 46*60517a1eSAndroid Build Coastguard Worker 47*60517a1eSAndroid Build Coastguard Worker _python_version_major_minor_flag( 48*60517a1eSAndroid Build Coastguard Worker name = _PYTHON_VERSION_MAJOR_MINOR_FLAG.name, 49*60517a1eSAndroid Build Coastguard Worker build_setting_default = "", 50*60517a1eSAndroid Build Coastguard Worker visibility = ["//visibility:public"], 51*60517a1eSAndroid Build Coastguard Worker ) 52*60517a1eSAndroid Build Coastguard Worker 53*60517a1eSAndroid Build Coastguard Worker native.config_setting( 54*60517a1eSAndroid Build Coastguard Worker name = "is_python_version_unset", 55*60517a1eSAndroid Build Coastguard Worker flag_values = {_PYTHON_VERSION_FLAG: ""}, 56*60517a1eSAndroid Build Coastguard Worker visibility = ["//visibility:public"], 57*60517a1eSAndroid Build Coastguard Worker ) 58*60517a1eSAndroid Build Coastguard Worker 59*60517a1eSAndroid Build Coastguard Worker _reverse_minor_mapping = {full: minor for minor, full in minor_mapping.items()} 60*60517a1eSAndroid Build Coastguard Worker for version in versions: 61*60517a1eSAndroid Build Coastguard Worker minor_version = _reverse_minor_mapping.get(version) 62*60517a1eSAndroid Build Coastguard Worker if not minor_version: 63*60517a1eSAndroid Build Coastguard Worker native.config_setting( 64*60517a1eSAndroid Build Coastguard Worker name = "is_python_{}".format(version), 65*60517a1eSAndroid Build Coastguard Worker flag_values = {":python_version": version}, 66*60517a1eSAndroid Build Coastguard Worker visibility = ["//visibility:public"], 67*60517a1eSAndroid Build Coastguard Worker ) 68*60517a1eSAndroid Build Coastguard Worker continue 69*60517a1eSAndroid Build Coastguard Worker 70*60517a1eSAndroid Build Coastguard Worker # Also need to match the minor version when using 71*60517a1eSAndroid Build Coastguard Worker name = "is_python_{}".format(version) 72*60517a1eSAndroid Build Coastguard Worker native.config_setting( 73*60517a1eSAndroid Build Coastguard Worker name = "_" + name, 74*60517a1eSAndroid Build Coastguard Worker flag_values = {":python_version": version}, 75*60517a1eSAndroid Build Coastguard Worker visibility = ["//visibility:public"], 76*60517a1eSAndroid Build Coastguard Worker ) 77*60517a1eSAndroid Build Coastguard Worker 78*60517a1eSAndroid Build Coastguard Worker # An alias pointing to an underscore-prefixed config_setting_group 79*60517a1eSAndroid Build Coastguard Worker # is used because config_setting_group creates 80*60517a1eSAndroid Build Coastguard Worker # `is_{version}_N` targets, which are easily confused with the 81*60517a1eSAndroid Build Coastguard Worker # `is_{minor}.{micro}` (dot) targets. 82*60517a1eSAndroid Build Coastguard Worker selects.config_setting_group( 83*60517a1eSAndroid Build Coastguard Worker name = "_{}_group".format(name), 84*60517a1eSAndroid Build Coastguard Worker match_any = [ 85*60517a1eSAndroid Build Coastguard Worker ":_is_python_{}".format(version), 86*60517a1eSAndroid Build Coastguard Worker ":is_python_{}".format(minor_version), 87*60517a1eSAndroid Build Coastguard Worker ], 88*60517a1eSAndroid Build Coastguard Worker visibility = ["//visibility:private"], 89*60517a1eSAndroid Build Coastguard Worker ) 90*60517a1eSAndroid Build Coastguard Worker native.alias( 91*60517a1eSAndroid Build Coastguard Worker name = name, 92*60517a1eSAndroid Build Coastguard Worker actual = "_{}_group".format(name), 93*60517a1eSAndroid Build Coastguard Worker visibility = ["//visibility:public"], 94*60517a1eSAndroid Build Coastguard Worker ) 95*60517a1eSAndroid Build Coastguard Worker 96*60517a1eSAndroid Build Coastguard Worker # This matches the raw flag value, e.g. --//python/config_settings:python_version=3.8 97*60517a1eSAndroid Build Coastguard Worker # It's private because matching the concept of e.g. "3.8" value is done 98*60517a1eSAndroid Build Coastguard Worker # using the `is_python_X.Y` config setting group, which is aware of the 99*60517a1eSAndroid Build Coastguard Worker # minor versions that could match instead. 100*60517a1eSAndroid Build Coastguard Worker for minor in minor_mapping.keys(): 101*60517a1eSAndroid Build Coastguard Worker native.config_setting( 102*60517a1eSAndroid Build Coastguard Worker name = "is_python_{}".format(minor), 103*60517a1eSAndroid Build Coastguard Worker flag_values = {_PYTHON_VERSION_MAJOR_MINOR_FLAG: minor}, 104*60517a1eSAndroid Build Coastguard Worker visibility = ["//visibility:public"], 105*60517a1eSAndroid Build Coastguard Worker ) 106*60517a1eSAndroid Build Coastguard Worker 107*60517a1eSAndroid Build Coastguard Workerdef _python_version_flag_impl(ctx): 108*60517a1eSAndroid Build Coastguard Worker value = ctx.build_setting_value 109*60517a1eSAndroid Build Coastguard Worker return [ 110*60517a1eSAndroid Build Coastguard Worker # BuildSettingInfo is the original provider returned, so continue to 111*60517a1eSAndroid Build Coastguard Worker # return it for compatibility 112*60517a1eSAndroid Build Coastguard Worker BuildSettingInfo(value = value), 113*60517a1eSAndroid Build Coastguard Worker # FeatureFlagInfo is returned so that config_setting respects the value 114*60517a1eSAndroid Build Coastguard Worker # as returned by this rule instead of as originally seen on the command 115*60517a1eSAndroid Build Coastguard Worker # line. 116*60517a1eSAndroid Build Coastguard Worker # It is also for Google compatibility, which expects the FeatureFlagInfo 117*60517a1eSAndroid Build Coastguard Worker # provider. 118*60517a1eSAndroid Build Coastguard Worker config_common.FeatureFlagInfo(value = value), 119*60517a1eSAndroid Build Coastguard Worker ] 120*60517a1eSAndroid Build Coastguard Worker 121*60517a1eSAndroid Build Coastguard Worker_python_version_flag = rule( 122*60517a1eSAndroid Build Coastguard Worker implementation = _python_version_flag_impl, 123*60517a1eSAndroid Build Coastguard Worker build_setting = config.string(flag = True), 124*60517a1eSAndroid Build Coastguard Worker attrs = {}, 125*60517a1eSAndroid Build Coastguard Worker) 126*60517a1eSAndroid Build Coastguard Worker 127*60517a1eSAndroid Build Coastguard Workerdef _python_version_major_minor_flag_impl(ctx): 128*60517a1eSAndroid Build Coastguard Worker input = ctx.attr._python_version_flag[config_common.FeatureFlagInfo].value 129*60517a1eSAndroid Build Coastguard Worker if input: 130*60517a1eSAndroid Build Coastguard Worker version = semver(input) 131*60517a1eSAndroid Build Coastguard Worker value = "{}.{}".format(version.major, version.minor) 132*60517a1eSAndroid Build Coastguard Worker else: 133*60517a1eSAndroid Build Coastguard Worker value = "" 134*60517a1eSAndroid Build Coastguard Worker 135*60517a1eSAndroid Build Coastguard Worker return [config_common.FeatureFlagInfo(value = value)] 136*60517a1eSAndroid Build Coastguard Worker 137*60517a1eSAndroid Build Coastguard Worker_python_version_major_minor_flag = rule( 138*60517a1eSAndroid Build Coastguard Worker implementation = _python_version_major_minor_flag_impl, 139*60517a1eSAndroid Build Coastguard Worker build_setting = config.string(flag = False), 140*60517a1eSAndroid Build Coastguard Worker attrs = { 141*60517a1eSAndroid Build Coastguard Worker "_python_version_flag": attr.label( 142*60517a1eSAndroid Build Coastguard Worker default = _PYTHON_VERSION_FLAG, 143*60517a1eSAndroid Build Coastguard Worker ), 144*60517a1eSAndroid Build Coastguard Worker }, 145*60517a1eSAndroid Build Coastguard Worker) 146