diff --git a/BUILD.bazel b/BUILD.bazel index e1ddbac..4dc6414 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -1,3 +1,5 @@ +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + filegroup( name = "bzl_files", srcs = glob(["*.bzl"]) + [ @@ -9,3 +11,23 @@ filegroup( ) exports_files(["features.bzl"]) + +bzl_library( + name = "features", + srcs = ["features.bzl"], + visibility = ["//visibility:public"], + deps = [ + "//private:util", + "@bazel_features_globals//:globals", + ], +) + +bzl_library( + name = "deps", + srcs = ["deps.bzl"], + deps = [ + "//private:repos", + "@bazel_tools//tools/build_defs/repo:http.bzl", + "@bazel_tools//tools/build_defs/repo:utils.bzl", + ], +) diff --git a/MODULE.bazel b/MODULE.bazel index 61225ca..e34cddc 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -3,6 +3,14 @@ module( version = "0.0.0", ) -version = use_extension("//private:extensions.bzl", "version_extension") +bazel_dep(name = "bazel_skylib", version = "1.5.0") + +bazel_dep( + name = "stardoc", + version = "0.6.2", + dev_dependency = True, + repo_name = "io_bazel_stardoc", +) +version = use_extension("//private:extensions.bzl", "version_extension") use_repo(version, "bazel_features_globals", "bazel_features_version") diff --git a/WORKSPACE.bazel b/WORKSPACE.bazel index af29461..8325169 100644 --- a/WORKSPACE.bazel +++ b/WORKSPACE.bazel @@ -3,3 +3,38 @@ workspace(name = "bazel_features") load(":deps.bzl", "bazel_features_deps") bazel_features_deps() + +load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") + +bazel_skylib_workspace() + +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +http_archive( + name = "io_bazel_stardoc", + sha256 = "62bd2e60216b7a6fec3ac79341aa201e0956477e7c8f6ccc286f279ad1d96432", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/stardoc/releases/download/0.6.2/stardoc-0.6.2.tar.gz", + "https://github.com/bazelbuild/stardoc/releases/download/0.6.2/stardoc-0.6.2.tar.gz", + ], +) + +load("@io_bazel_stardoc//:setup.bzl", "stardoc_repositories") + +stardoc_repositories() + +load("@rules_jvm_external//:repositories.bzl", "rules_jvm_external_deps") + +rules_jvm_external_deps() + +load("@rules_jvm_external//:setup.bzl", "rules_jvm_external_setup") + +rules_jvm_external_setup() + +load("@io_bazel_stardoc//:deps.bzl", "stardoc_external_deps") + +stardoc_external_deps() + +load("@stardoc_maven//:defs.bzl", stardoc_pinned_maven_install = "pinned_maven_install") + +stardoc_pinned_maven_install() diff --git a/deps.bzl b/deps.bzl index 766638d..3ed76e1 100644 --- a/deps.bzl +++ b/deps.bzl @@ -1,10 +1,15 @@ -load("//private:version_repo.bzl", "version_repo") -load("//private:globals.bzl", "GLOBALS") -load("//private:globals_repo.bzl", "globals_repo") +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") +load("//private:repos.bzl", "bazel_features_repos") def bazel_features_deps(): - version_repo(name = "bazel_features_version") - globals_repo( - name = "bazel_features_globals", - globals = GLOBALS, + bazel_features_repos() + maybe( + http_archive, + name = "bazel_skylib", + sha256 = "cd55a062e763b9349921f0f5db8c3933288dc8ba4f76dd9416aac68acee3cb94", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.5.0/bazel-skylib-1.5.0.tar.gz", + "https://github.com/bazelbuild/bazel-skylib/releases/download/1.5.0/bazel-skylib-1.5.0.tar.gz", + ], ) diff --git a/features.bzl b/features.bzl index b314d17..6a9490c 100644 --- a/features.bzl +++ b/features.bzl @@ -26,16 +26,14 @@ _external_deps = struct( # Whether repository_ctx#download has the block parameter, allowing parallel downloads (#19674) download_has_block_param = ge("7.1.0"), # Whether repository_ctx#download has the headers parameter, allowing arbitrary headers (#17829) - download_has_headers_param = ge("7.1.0") + download_has_headers_param = ge("7.1.0"), ) _flags = struct( # This flag was renamed in https://github.com/bazelbuild/bazel/pull/18313 allow_unresolved_symlinks = ( - "allow_unresolved_symlinks" - if ge("7.0.0-pre.20230628.2") - else "experimental_allow_unresolved_symlinks" - ) + "allow_unresolved_symlinks" if ge("7.0.0-pre.20230628.2") else "experimental_allow_unresolved_symlinks" + ), ) _rules = struct( diff --git a/private/BUILD.bazel b/private/BUILD.bazel index a61edcc..7cdf03d 100644 --- a/private/BUILD.bazel +++ b/private/BUILD.bazel @@ -1,5 +1,63 @@ +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + filegroup( name = "bzl_files", srcs = glob(["*.bzl"]), visibility = ["//visibility:public"], ) + +bzl_library( + name = "parse", + srcs = ["parse.bzl"], +) + +bzl_library( + name = "util", + srcs = ["util.bzl"], + visibility = ["//:__subpackages__"], + deps = [ + ":parse", + "@bazel_features_version//:version", + ], +) + +bzl_library( + name = "globals", + srcs = ["globals.bzl"], + visibility = ["//:__subpackages__"], +) + +bzl_library( + name = "globals_repo", + srcs = ["globals_repo.bzl"], + visibility = ["//:__subpackages__"], + deps = [ + ":parse", + ], +) + +bzl_library( + name = "version_repo", + srcs = ["version_repo.bzl"], + visibility = ["//:__subpackages__"], +) + +bzl_library( + name = "repos", + srcs = ["repos.bzl"], + visibility = ["//:__subpackages__"], + deps = [ + ":globals", + ":globals_repo", + ":version_repo", + ], +) + +bzl_library( + name = "extensions", + srcs = ["extensions.bzl"], + visibility = ["//:__subpackages__"], + deps = [ + ":repos", + ], +) diff --git a/private/extensions.bzl b/private/extensions.bzl index 84040d0..7314d9f 100644 --- a/private/extensions.bzl +++ b/private/extensions.bzl @@ -1,8 +1,6 @@ -load("//:deps.bzl", "bazel_features_deps") -load(":version_repo.bzl", "version_repo") -load(":globals_repo.bzl", "globals_repo") +load("//private:repos.bzl", "bazel_features_repos") -def _version_extension_impl(mctx): - bazel_features_deps() +def _version_extension_impl(_): + bazel_features_repos() version_extension = module_extension(_version_extension_impl) diff --git a/private/globals_repo.bzl b/private/globals_repo.bzl index 9487c80..fcadfb2 100644 --- a/private/globals_repo.bzl +++ b/private/globals_repo.bzl @@ -1,7 +1,21 @@ load("//private:parse.bzl", "parse_version") def _globals_repo_impl(rctx): - rctx.file("BUILD.bazel", "exports_files([\"globals.bzl\"])") + rctx.file( + "BUILD.bazel", + """\ +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + +exports_files(["globals.bzl"]) + +# This keeps stardoc happy if globals.bzl is pulled into a repository. +bzl_library( + name = "globals", + srcs = ["globals.bzl"], + visibility = ["//visibility:public"], +) +""", + ) bazel_version = parse_version(native.bazel_version) diff --git a/private/repos.bzl b/private/repos.bzl new file mode 100644 index 0000000..525452d --- /dev/null +++ b/private/repos.bzl @@ -0,0 +1,10 @@ +load(":globals.bzl", "GLOBALS") +load(":globals_repo.bzl", "globals_repo") +load(":version_repo.bzl", "version_repo") + +def bazel_features_repos(): + version_repo(name = "bazel_features_version") + globals_repo( + name = "bazel_features_globals", + globals = GLOBALS, + ) diff --git a/private/version_repo.bzl b/private/version_repo.bzl index 105aea8..4cee444 100644 --- a/private/version_repo.bzl +++ b/private/version_repo.bzl @@ -1,5 +1,18 @@ def _version_repo_impl(rctx): - rctx.file("BUILD.bazel", "exports_files([\"version.bzl\"])") + rctx.file( + "BUILD.bazel", + """ +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + +exports_files(["version.bzl"]) + +bzl_library( + name = "version", + srcs = ["version.bzl"], + visibility = ["//visibility:public"], +) +""", + ) rctx.file("version.bzl", "version = '" + native.bazel_version + "'") version_repo = repository_rule( diff --git a/test/BUILD.bazel b/test/BUILD.bazel index e3c572c..520ec56 100644 --- a/test/BUILD.bazel +++ b/test/BUILD.bazel @@ -1,3 +1,10 @@ +load(":bzl_test.bzl", "bzl_test") load(":test.bzl", "run_test") run_test(name = "tests") + +bzl_test( + name = "features_bzl_test", + src = "features_bzl_macro.bzl", + deps = ["//:features"], +) diff --git a/test/bzl_test.bzl b/test/bzl_test.bzl new file mode 100644 index 0000000..42dc4da --- /dev/null +++ b/test/bzl_test.bzl @@ -0,0 +1,42 @@ +"""Macro for Ensuring Starlark Dependencies are Specified Properly""" + +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") +load("@io_bazel_stardoc//stardoc:stardoc.bzl", "stardoc") + +def bzl_test(name, src, deps): + """Provides build-time assurances that `bzl_library` declarations exist and are referenced properly. + + This macro relies upon Stardoc's ability to traverse `bzl_library` + dependencies. If a Starlark dependency is loaded, but not specified as a + dependency, the Stardoc utility will fail with a reasonably helpful error + message. Interestingly, the Stardoc utility does not apply the same rigor + to files that are directly specifed to it. + + Another point worth metioning is that the `src` file cannot be generated + for this macro to work. If one tries to use a generated file, the `input` + for the `stardoc` rule will resolve to the label for the generated file + which will cause the Stardoc utility to not find the file. Specifying the + input in different ways (i.e. filename vs target name) did not seem to + affect this behavior. + + Args: + name: The name of the build target. + src: A non-generated Starlark file that loads the `bzl_library` that is + being checked. + deps: A `list` of deps for the Starlark file. + + Returns: + """ + macro_lib_name = name + "_macro_lib" + bzl_library( + name = macro_lib_name, + srcs = [src], + deps = deps, + ) + + stardoc( + name = name, + out = macro_lib_name + ".md_", + input = src, + deps = [macro_lib_name], + ) diff --git a/test/features_bzl_macro.bzl b/test/features_bzl_macro.bzl new file mode 100644 index 0000000..9d2e3ce --- /dev/null +++ b/test/features_bzl_macro.bzl @@ -0,0 +1,16 @@ +"""Macro used with bzl_test + +For more information, please see `bzl_test.bzl`. +""" + +load("//:features.bzl", "bazel_features") + +def macro_with_doc(name): + """This macro does nothing. + + Args: + name: A `string` value. + """ + if name == None: + return None + return bazel_features