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)
View as plain text