1# Copyright (C) 2023 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
15load("@bazel_skylib//lib:paths.bzl", "paths")
16load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
17
18def _impl(ctx):
19    target = ctx.attr.target
20    device_name = ctx.attr._device_name[BuildSettingInfo].value
21    target = target.replace("$(DeviceName)", device_name)
22
23    if paths.normalize(target) != target:
24        fail("file path must be normalized: " + target)
25    if target.startswith("/") or target.startswith("../"):
26        fail("file path must not start with / or ../: " + target)
27
28    data = {
29        "target": target,
30        "depend_on_target": ctx.attr.depend_on_target,
31    }
32    if ctx.attr.implicit_deps:
33        data["implicit_deps"] = [d.replace("$(DeviceName)", device_name) for d in ctx.attr.implicit_deps]
34
35    device_name = ctx.attr._device_name[BuildSettingInfo].value
36
37    out = ctx.actions.declare_symlink(ctx.label.name)
38    ctx.actions.symlink(
39        output = out,
40        # the bazel_sandwich: prefix signals to the mixed build handler to treat this specially
41        target_path = "bazel_sandwich:" + json.encode(data),
42    )
43    return [
44        DefaultInfo(files = depset([out])),
45    ]
46
47_bazel_sandwich_imported_file = rule(
48    implementation = _impl,
49    attrs = {
50        "target": attr.string(
51            mandatory = True,
52            doc = "The target of the symlink. It's a path relative to the root of the output dir " +
53                  " to import. In this attribute, $(DeviceName) will be replaced with the device name " +
54                  "product variable.",
55        ),
56        "depend_on_target": attr.bool(
57            default = True,
58            doc = "Whether or not a dependency should be added from the symlink to the file it's " +
59                  "targeting. In most cases you want this to be true.",
60        ),
61        "implicit_deps": attr.string_list(
62            doc = "Paths to other make-generated files to use as implicit deps. This is useful " +
63                  "when you want to import a folder to bazel, you can add an implicit dep on a " +
64                  "stamp file that depends on all contents of the foler. In this attribute, " +
65                  "$(DeviceName) will be replaced with the device name product variable.",
66        ),
67        "_device_name": attr.label(
68            default = "//build/bazel/product_config:device_name",
69        ),
70    },
71)
72
73def bazel_sandwich_imported_file(target_compatible_with = [], **kwargs):
74    _bazel_sandwich_imported_file(
75        target_compatible_with = ["//build/bazel/platforms:mixed_builds"] + target_compatible_with,
76        **kwargs
77    )
78