xref: /aosp_15_r20/bootable/libbootloader/gbl/readme.bzl (revision 5225e6b173e52d2efc6bcf950c27374fd72adabc)
1# Copyright (C) 2024 The Android Open Source Project
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"""
16Action that verifies all EFI protocols used by GBL are explicitly listed in README.md
17"""
18
19load("@rules_rust//rust/private:providers.bzl", "CrateInfo")
20
21def _readme_test_rule_impl(ctx):
22    shell_script = """
23while [[ $# -gt 0 ]]; do
24  case $1 in
25    --in)
26      INPUT=$2
27      shift
28      shift
29      ;;
30    --out)
31      OUTPUT=$2
32      shift
33      shift
34      ;;
35    --readme)
36      README=$2
37      shift
38      shift
39      ;;
40    *)
41      echo "Unexpected argument: $1"
42      exit 1
43      ;;
44  esac
45done
46
47if [ ! -f $README ]; then
48  echo "README file doesn't exist: ${README}"
49  exit 1
50fi
51
52ALL_INPUTS=$(echo ${INPUT} | sed 's/,/ /g')
53
54# Look for protocols in the source code that do not exist in the documentation.
55# The protocol name we match on here is the Rust struct name.
56DOCLESS_PROTOCOLS=""
57PROTOCOLS=($(grep -hE 'impl ProtocolInfo for .* \\{' ${ALL_INPUTS} | awk '{print $4}' | sort))
58for P in ${PROTOCOLS[@]}
59do
60  grep -Lq $P ${README} || DOCLESS_PROTOCOLS+="\n\t$P"
61done
62
63if [ ! -z "${DOCLESS_PROTOCOLS}" ]; then
64  echo -e "Missing documentation for protocol(s):$DOCLESS_PROTOCOLS"
65  exit 1
66fi
67
68# Look for protocols in the documentation that are not in the source, to try to
69# prevent stale docs referring to protocols we are no longer using.
70# Here we're matching on words ending in "Protocol", except "Protocol" itself.
71UNUSED_PROTOCOLS=""
72README_PROTOCOLS=($(grep -P " ?[^ ]+Protocol$" ${README} | awk '{print $NF}' | sort | uniq))
73for P in ${README_PROTOCOLS[@]}
74do
75  grep -qhE "impl ProtocolInfo for $P" ${ALL_INPUTS} || UNUSED_PROTOCOLS+="\n\t$P"
76done
77
78if [ ! -z "${UNUSED_PROTOCOLS}" ]; then
79  echo -e "Unused protocol(s) found in documentation:$UNUSED_PROTOCOLS"
80  exit 1
81fi
82
83touch $OUTPUT
84"""
85
86    out_file = ctx.actions.declare_file("%s.script" % ctx.attr.name)
87    in_files = [s for d in ctx.attr.deps for s in d[CrateInfo].srcs.to_list()]
88    readme = ctx.attr.readme
89    args = ctx.actions.args()
90    args.add_joined(
91        "--in",
92        in_files,
93        join_with = ",",
94    )
95    args.add(
96        "--out",
97        out_file,
98    )
99    args.add(
100        "--readme",
101        readme[DefaultInfo].files.to_list()[0],
102    )
103    ctx.actions.run_shell(
104        inputs = in_files + readme[DefaultInfo].files.to_list(),
105        outputs = [out_file],
106        arguments = [args],
107        command = shell_script,
108    )
109    return [DefaultInfo(executable = out_file)]
110
111readme_test = rule(
112    implementation = _readme_test_rule_impl,
113    attrs = {
114        "deps": attr.label_list(
115            providers = [CrateInfo],
116        ),
117        "readme": attr.label(
118            allow_single_file = [".md"],
119        ),
120    },
121    test = True,
122)
123