Skip to content

Commit

Permalink
Add a rule to create providers for subdirectories
Browse files Browse the repository at this point in the history
  • Loading branch information
matts1 committed Apr 21, 2024
1 parent 1aaae38 commit 741b682
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 0 deletions.
50 changes: 50 additions & 0 deletions rules/directories/subdirectory.bzl
@@ -0,0 +1,50 @@
# Copyright 2024 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Skylib module containing rules to create metadata about subdirectories."""

load(":providers.bzl", "DirectoryInfo")

visibility("public")

_DIR_NOT_FOUND = """{dir} does not contain a directory named {name}.
Instead, it contains the directories {children}."""

def _subdirectory_impl(ctx):
dir = ctx.attr.parent[DirectoryInfo]
if ctx.attr.path.startswith("/"):
fail("Invalid path. Path must be relative to the parent directory")

for dirname in ctx.attr.path.split("/"):
if dirname not in dir.directories:
fail(_DIR_NOT_FOUND.format(
dir = dir.source_path,
name = repr(dirname),
children = repr(sorted(dir.directories)),
))
dir = dir.directories[dirname]

return [
dir,
DefaultInfo(files = dir.transitive_files),
]

subdirectory = rule(
implementation = _subdirectory_impl,
attrs = {
"parent": attr.label(providers = [DirectoryInfo], mandatory = True),
"path": attr.string(mandatory = True),
},
provides = [DirectoryInfo],
)
20 changes: 20 additions & 0 deletions tests/directories/BUILD
Expand Up @@ -2,7 +2,9 @@ load("@rules_testing//lib:analysis_test.bzl", "analysis_test")
load(
":directory_test.bzl",
"directory_test",
"nonexistent_subdirectory_test",
"outside_testdata_test",
"subdirectory_test",
)

analysis_test(
Expand All @@ -28,3 +30,21 @@ analysis_test(
impl = outside_testdata_test,
target = "//tests/directories/testdata:outside_testdata",
)

analysis_test(
name = "subdirectory_test",
impl = subdirectory_test,
targets = {
"root": "//tests/directories/testdata:root",
"dir": "//tests/directories/testdata:dir",
"subdir": "//tests/directories/testdata:subdir",
"f2": "//tests/directories/testdata:f2_filegroup",
},
)

analysis_test(
name = "nonexistent_subdirectory_test",
expect_failure = True,
impl = nonexistent_subdirectory_test,
target = "//tests/directories/testdata:nonexistent_subdirectory",
)
28 changes: 28 additions & 0 deletions tests/directories/directory_test.bzl
Expand Up @@ -83,3 +83,31 @@ def directory_test(env, targets):
newdir.direct_files().contains_exactly([f3])
newdir.transitive_files().contains_exactly([f3]).in_order()
env.expect.that_str(newdir.actual.generated_path + "/f3").equals(f3.path)

_NONEXISTENT_ERR = """tests/directories/testdata does not contain a directory named "nonexistent".
Instead, it contains the directories ["dir", "newdir"]."""

# buildifier: disable=function-docstring
def nonexistent_subdirectory_test(env, target):
env.expect.that_target(target).failures().contains_exactly_predicates([
matching.contains(_NONEXISTENT_ERR),
])

# buildifier: disable=function-docstring
def subdirectory_test(env, targets):
f2 = targets.f2.files.to_list()[0]

root = targets.root[DirectoryInfo]
want_dir = root.directories["dir"]
want_subdir = want_dir.directories["subdir"]

# Use that_str because it supports equality checks. They're not strings.
env.expect.that_str(targets.dir[DirectoryInfo]).equals(want_dir)
env.expect.that_str(targets.subdir[DirectoryInfo]).equals(want_subdir)

env.expect.that_collection(
targets.dir.files.to_list(),
).contains_exactly([f2])
env.expect.that_collection(
targets.subdir.files.to_list(),
).contains_exactly([f2])
20 changes: 20 additions & 0 deletions tests/directories/testdata/BUILD
@@ -1,6 +1,7 @@
load("@rules_testing//lib:util.bzl", "util")
load("//rules:copy_file.bzl", "copy_file")
load("//rules/directories:directory.bzl", "directory")
load("//rules/directories:subdirectory.bzl", "subdirectory")

package(default_visibility = ["//tests/directories:__pkg__"])

Expand Down Expand Up @@ -36,3 +37,22 @@ filegroup(
name = "f2_filegroup",
srcs = ["dir/subdir/f2"],
)

subdirectory(
name = "dir",
parent = ":root",
path = "dir",
)

subdirectory(
name = "subdir",
parent = ":root",
path = "dir/subdir",
)

util.helper_target(
subdirectory,
name = "nonexistent_subdirectory",
parent = ":root",
path = "nonexistent",
)

0 comments on commit 741b682

Please sign in to comment.