1# Copyright 2023 The Bazel Authors. All rights reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"" 16 17load("//python/private:text_util.bzl", "render") 18load( 19 ":render_pkg_aliases.bzl", 20 "render_multiplatform_pkg_aliases", 21 "whl_alias", 22) 23 24_BUILD_FILE_CONTENTS = """\ 25package(default_visibility = ["//visibility:public"]) 26 27# Ensure the `requirements.bzl` source can be accessed by stardoc, since users load() from it 28exports_files(["requirements.bzl"]) 29""" 30 31def _impl(rctx): 32 bzl_packages = rctx.attr.packages or rctx.attr.whl_map.keys() 33 aliases = render_multiplatform_pkg_aliases( 34 aliases = { 35 key: [whl_alias(**v) for v in json.decode(values)] 36 for key, values in rctx.attr.whl_map.items() 37 }, 38 default_version = rctx.attr.default_version, 39 default_config_setting = "//_config:is_python_" + rctx.attr.default_version, 40 requirement_cycles = rctx.attr.groups, 41 ) 42 for path, contents in aliases.items(): 43 rctx.file(path, contents) 44 45 # NOTE: we are using the canonical name with the double '@' in order to 46 # always uniquely identify a repository, as the labels are being passed as 47 # a string and the resolution of the label happens at the call-site of the 48 # `requirement`, et al. macros. 49 macro_tmpl = "@@{name}//{{}}:{{}}".format(name = rctx.attr.name) 50 51 rctx.file("BUILD.bazel", _BUILD_FILE_CONTENTS) 52 rctx.template("requirements.bzl", rctx.attr._template, substitutions = { 53 "%%ALL_DATA_REQUIREMENTS%%": render.list([ 54 macro_tmpl.format(p, "data") 55 for p in bzl_packages 56 ]), 57 "%%ALL_REQUIREMENTS%%": render.list([ 58 macro_tmpl.format(p, "pkg") 59 for p in bzl_packages 60 ]), 61 "%%ALL_WHL_REQUIREMENTS_BY_PACKAGE%%": render.dict({ 62 p: macro_tmpl.format(p, "whl") 63 for p in bzl_packages 64 }), 65 "%%MACRO_TMPL%%": macro_tmpl, 66 }) 67 68hub_repository = repository_rule( 69 attrs = { 70 "default_version": attr.string( 71 mandatory = True, 72 doc = """\ 73This is the default python version in the format of X.Y. This should match 74what is setup by the 'python' extension using the 'is_default = True' 75setting.""", 76 ), 77 "groups": attr.string_list_dict( 78 mandatory = False, 79 ), 80 "packages": attr.string_list( 81 mandatory = False, 82 doc = """\ 83The list of packages that will be exposed via all_*requirements macros. Defaults to whl_map keys. 84""", 85 ), 86 "repo_name": attr.string( 87 mandatory = True, 88 doc = "The apparent name of the repo. This is needed because in bzlmod, the name attribute becomes the canonical name.", 89 ), 90 "whl_map": attr.string_dict( 91 mandatory = True, 92 doc = """\ 93The wheel map where values are json.encoded strings of the whl_map constructed 94in the pip.parse tag class. 95""", 96 ), 97 "_template": attr.label( 98 default = ":requirements.bzl.tmpl.bzlmod", 99 ), 100 }, 101 doc = """A rule for bzlmod mulitple pip repository creation. PRIVATE USE ONLY.""", 102 implementation = _impl, 103) 104