1# Copyright 2021 The Bazel Go Rules 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 15load( 16 "//go/private:providers.bzl", 17 "GoArchive", 18 "GoStdLib", 19) 20load( 21 "@bazel_skylib//lib:paths.bzl", 22 "paths", 23) 24 25GoPkgInfo = provider() 26 27DEPS_ATTRS = [ 28 "deps", 29 "embed", 30] 31 32PROTO_COMPILER_ATTRS = [ 33 "compiler", 34 "compilers", 35 "library", 36] 37 38def bazel_supports_canonical_label_literals(): 39 return str(Label("//:bogus")).startswith("@@") 40 41def is_file_external(f): 42 return f.owner.workspace_root != "" 43 44def file_path(f): 45 prefix = "__BAZEL_WORKSPACE__" 46 if not f.is_source: 47 prefix = "__BAZEL_EXECROOT__" 48 elif is_file_external(f): 49 prefix = "__BAZEL_OUTPUT_BASE__" 50 return paths.join(prefix, f.path) 51 52def _go_archive_to_pkg(archive): 53 return struct( 54 ID = str(archive.data.label), 55 PkgPath = archive.data.importpath, 56 ExportFile = file_path(archive.data.export_file), 57 GoFiles = [ 58 file_path(src) 59 for src in archive.data.orig_srcs 60 if src.path.endswith(".go") 61 ], 62 CompiledGoFiles = [ 63 file_path(src) 64 for src in archive.data.srcs 65 if src.path.endswith(".go") 66 ], 67 OtherFiles = [ 68 file_path(src) 69 for src in archive.data.orig_srcs 70 if not src.path.endswith(".go") 71 ], 72 Imports = { 73 pkg.data.importpath: str(pkg.data.label) 74 for pkg in archive.direct 75 }, 76 ) 77 78def make_pkg_json(ctx, name, pkg_info): 79 pkg_json_file = ctx.actions.declare_file(name + ".pkg.json") 80 ctx.actions.write(pkg_json_file, content = pkg_info.to_json()) 81 return pkg_json_file 82 83def _go_pkg_info_aspect_impl(target, ctx): 84 # Fetch the stdlib JSON file from the inner most target 85 stdlib_json_file = None 86 87 transitive_json_files = [] 88 transitive_export_files = [] 89 transitive_compiled_go_files = [] 90 91 for attr in DEPS_ATTRS + PROTO_COMPILER_ATTRS: 92 deps = getattr(ctx.rule.attr, attr, []) or [] 93 94 # Some attrs are not iterable, ensure that deps is always iterable. 95 if type(deps) != type([]): 96 deps = [deps] 97 98 for dep in deps: 99 if GoPkgInfo in dep: 100 pkg_info = dep[GoPkgInfo] 101 transitive_json_files.append(pkg_info.pkg_json_files) 102 transitive_compiled_go_files.append(pkg_info.compiled_go_files) 103 transitive_export_files.append(pkg_info.export_files) 104 105 # Fetch the stdlib json from the first dependency 106 if not stdlib_json_file: 107 stdlib_json_file = pkg_info.stdlib_json_file 108 109 pkg_json_files = [] 110 compiled_go_files = [] 111 export_files = [] 112 113 if GoArchive in target: 114 archive = target[GoArchive] 115 compiled_go_files.extend(archive.source.srcs) 116 export_files.append(archive.data.export_file) 117 pkg = _go_archive_to_pkg(archive) 118 pkg_json_files.append(make_pkg_json(ctx, archive.data.name, pkg)) 119 120 if ctx.rule.kind == "go_test": 121 for dep_archive in archive.direct: 122 # find the archive containing the test sources 123 if archive.data.label == dep_archive.data.label: 124 pkg = _go_archive_to_pkg(dep_archive) 125 pkg_json_files.append(make_pkg_json(ctx, dep_archive.data.name, pkg)) 126 compiled_go_files.extend(dep_archive.source.srcs) 127 export_files.append(dep_archive.data.export_file) 128 break 129 130 # If there was no stdlib json in any dependencies, fetch it from the 131 # current go_ node. 132 if not stdlib_json_file: 133 stdlib_json_file = ctx.attr._go_stdlib[GoStdLib]._list_json 134 135 pkg_info = GoPkgInfo( 136 stdlib_json_file = stdlib_json_file, 137 pkg_json_files = depset( 138 direct = pkg_json_files, 139 transitive = transitive_json_files, 140 ), 141 compiled_go_files = depset( 142 direct = compiled_go_files, 143 transitive = transitive_compiled_go_files, 144 ), 145 export_files = depset( 146 direct = export_files, 147 transitive = transitive_export_files, 148 ), 149 ) 150 151 return [ 152 pkg_info, 153 OutputGroupInfo( 154 go_pkg_driver_json_file = pkg_info.pkg_json_files, 155 go_pkg_driver_srcs = pkg_info.compiled_go_files, 156 go_pkg_driver_export_file = pkg_info.export_files, 157 go_pkg_driver_stdlib_json_file = depset([pkg_info.stdlib_json_file] if pkg_info.stdlib_json_file else []), 158 ), 159 ] 160 161go_pkg_info_aspect = aspect( 162 implementation = _go_pkg_info_aspect_impl, 163 attr_aspects = DEPS_ATTRS + PROTO_COMPILER_ATTRS, 164 attrs = { 165 "_go_stdlib": attr.label( 166 default = "//:stdlib", 167 ), 168 }, 169) 170