Skip to content

Commit

Permalink
Add support for new subpackages module for working with native.subpac…
Browse files Browse the repository at this point in the history
…kages

This adds support for friendly APIs on top of the new native.subpackages
support added to Bazel.  This allows code to use subpackage, if the
Bazel version supports it, test for packages existing and construct
targets based on relative subackages.

This Pull requires support for 'loadingtest' has been added to the
'unittest' module.
  • Loading branch information
kkress committed Feb 11, 2022
1 parent c97581b commit c949462
Show file tree
Hide file tree
Showing 7 changed files with 279 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ s = shell.quote(p)
* [new_sets](docs/new_sets_doc.md)
* [shell](docs/shell_doc.md)
* [structs](docs/structs_doc.md)
* [subpackages](docs/subpackages_doc.md)
* [types](docs/types_doc.md)
* [unittest](docs/unittest_doc.md)
* [versions](docs/versions_doc.md)
Expand Down
7 changes: 7 additions & 0 deletions docs/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ stardoc(
deps = ["//lib:structs"],
)

stardoc(
name = "subpackages_docs",
out = "subpackages_doc_gen.md",
input = "//lib:subpackages.bzl",
deps = ["//lib:subpackages"],
)

stardoc(
name = "types_docs",
out = "types_doc_gen.md",
Expand Down
96 changes: 96 additions & 0 deletions docs/subpackages_doc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<!-- Generated with Stardoc: http://skydoc.bazel.build -->

Skylib module containing common functions for working with native.subpackages()


<a id="#subpackages.all"></a>

## subpackages.all

<pre>
subpackages.all(<a href="#subpackages.all-exclude">exclude</a>, <a href="#subpackages.all-allow_empty">allow_empty</a>, <a href="#subpackages.all-fully_qualified">fully_qualified</a>)
</pre>

List all direct subpackages of the current package regardless of directory depth.

The returned list contains all subpackages, but not subpackages of subpackages.

Example:
Assuming the following BUILD files exist:

BUILD
foo/BUILD
foo/sub/BUILD
bar/BUILD
baz/deep/dir/BUILD

If the current package is 'BUILD' all() will return ['//foo', '//bar',
'//baz/deep/dir']. //foo/sub is not included because it is a direct
subpackage of '//foo' not '//'

NOTE: fail()s if native.subpackages() is not supported.


**PARAMETERS**


| Name | Description | Default Value |
| :------------- | :------------- | :------------- |
| <a id="subpackages.all-exclude"></a>exclude | see native.subpackages(exclude) | <code>[]</code> |
| <a id="subpackages.all-allow_empty"></a>allow_empty | see native.subpackages(allow_empty) | <code>False</code> |
| <a id="subpackages.all-fully_qualified"></a>fully_qualified | It true return fully qualified Labels for subpackages, otherwise returns subpackage path relative to current package. | <code>True</code> |

**RETURNS**

A mutable sorted list containing all sub-packages of the current Bazel
package.


<a id="#subpackages.exists"></a>

## subpackages.exists

<pre>
subpackages.exists(<a href="#subpackages.exists-relative_path">relative_path</a>)
</pre>

Checks to see if relative_path is a direct subpackage of the current package.

Example:

BUILD
foo/BUILD
foo/sub/BUILD

If the current package is 'BUILD':
subpackages.exists("foo") == True
subpackages.exists("foo/sub") == False
subpackages.exists("bar") == False

NOTE: fail()s if native.subpackages() is not supported.


**PARAMETERS**


| Name | Description | Default Value |
| :------------- | :------------- | :------------- |
| <a id="subpackages.exists-relative_path"></a>relative_path | a path to a subpackage to test, must not be an absolute Label. | none |

**RETURNS**

True if 'relative_path' is a subpackage of the current package.


<a id="#subpackages.supported"></a>

## subpackages.supported

<pre>
subpackages.supported()
</pre>





5 changes: 5 additions & 0 deletions lib/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ bzl_library(
srcs = ["structs.bzl"],
)

bzl_library(
name = "subpackages",
srcs = ["subpackages.bzl"],
)

bzl_library(
name = "types",
srcs = ["types.bzl"],
Expand Down
96 changes: 96 additions & 0 deletions lib/subpackages.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Copyright 2022 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 common functions for working with native.subpackages()
"""
_SUBACKAGES_SUPPORTED = "subpackages" in dir(native)

def _supported():
return _SUBACKAGES_SUPPORTED

def _check_supported():
if not _SUBACKAGES_SUPPORTED:
fail("native.subpackages not supported.")

def _all(exclude = [], allow_empty = False, fully_qualified = True):
"""List all direct subpackages of the current package regardless of directory depth.
The returned list contains all subpackages, but not subpackages of subpackages.
Example:
Assuming the following BUILD files exist:
BUILD
foo/BUILD
foo/sub/BUILD
bar/BUILD
baz/deep/dir/BUILD
If the current package is 'BUILD' all() will return ['//foo', '//bar',
'//baz/deep/dir']. //foo/sub is not included because it is a direct
subpackage of '//foo' not '//'
NOTE: fail()s if native.subpackages() is not supported.
Args:
exclude: see native.subpackages(exclude)
allow_empty: see native.subpackages(allow_empty)
fully_qualified: It true return fully qualified Labels for subpackages,
otherwise returns subpackage path relative to current package.
Returns:
A mutable sorted list containing all sub-packages of the current Bazel
package.
"""
_check_supported()

subs = native.subpackages(include = ["**"], exclude = exclude, allow_empty = allow_empty)
if fully_qualified:
return [_fully_qualified(s) for s in subs]

return subs

def _fully_qualified(relative_path):
return "//%s/%s" % (native.package_name(), relative_path)

def _exists(relative_path):
"""Checks to see if relative_path is a direct subpackage of the current package.
Example:
BUILD
foo/BUILD
foo/sub/BUILD
If the current package is 'BUILD':
subpackages.exists("foo") == True
subpackages.exists("foo/sub") == False
subpackages.exists("bar") == False
NOTE: fail()s if native.subpackages() is not supported.
Args:
relative_path: a path to a subpackage to test, must not be an absolute Label.
Returns:
True if 'relative_path' is a subpackage of the current package.
"""
_check_supported()
return relative_path in native.subpackages(include = [relative_path], allow_empty = True)

subpackages = struct(
all = _all,
exists = _exists,
supported = _supported,
)
3 changes: 3 additions & 0 deletions tests/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ load(":paths_tests.bzl", "paths_test_suite")
load(":selects_tests.bzl", "selects_test_suite")
load(":shell_tests.bzl", "shell_args_test_gen", "shell_test_suite")
load(":structs_tests.bzl", "structs_test_suite")
load(":subpackages_tests.bzl", "subpackages_test_suite")
load(":types_tests.bzl", "types_test_suite")
load(":unittest_tests.bzl", "unittest_passing_tests_suite")
load(":versions_tests.bzl", "versions_test_suite")
Expand Down Expand Up @@ -37,6 +38,8 @@ shell_test_suite()

structs_test_suite()

subpackages_test_suite()

types_test_suite()

unittest_passing_tests_suite()
Expand Down
71 changes: 71 additions & 0 deletions tests/subpackages_tests.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Copyright 2022 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.

"""Unit tests for subpackages.bzl."""

load("//lib:subpackages.bzl", "subpackages")
load("//lib:unittest.bzl", "loadingtest")

def _all_test(env):
"""Unit tests for subpackages.all."""

all_pkgs = [
"copy_file",
"diff_test",
"select_file",
"write_file",
]

# Not all pkgs exist in all test environments.
if subpackages.exists("run_binary"):
all_pkgs.append("run_binary")

if subpackages.exists("native_binary"):
all_pkgs.append("native_binary")

# These exist in all cases
filtered_pkgs = [
"copy_file",
"select_file",
"write_file",
]

# test defaults
loadingtest.asserts(
env,
"all",
all_pkgs,
subpackages.all(fully_qualified = False),
)

# test exclusion
loadingtest.asserts(
env,
"all_w_exclude",
filtered_pkgs,
subpackages.all(exclude = ["diff_test", "run_binary", "native_binary"], fully_qualified = False),
)

def _exists_test(env):
"""Unit tests for subpackages.exists."""
loadingtest.asserts(env, "exists_yes", True, subpackages.exists("copy_file"))
loadingtest.asserts(env, "exists_no", False, subpackages.exists("never_existed"))

def subpackages_test_suite():
"""Creates the test targets and test suite for subpackages.bzl tests."""

if subpackages.supported():
env = loadingtest.make("subpackages")
_all_test(env)
_exists_test(env)

0 comments on commit c949462

Please sign in to comment.