Skip to content

Commit

Permalink
feat: set license information for packages with rules_license (#1118)
Browse files Browse the repository at this point in the history
Resolves #1092.

Signed-off-by: Brentley Jones <github@brentleyjones.com>
  • Loading branch information
brentleyjones authored Sep 27, 2024
1 parent 76b88dc commit 880db7f
Show file tree
Hide file tree
Showing 13 changed files with 261 additions and 6 deletions.
1 change: 1 addition & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module(

bazel_dep(name = "cgrindel_bazel_starlib", version = "0.21.0")
bazel_dep(name = "bazel_skylib", version = "1.4.2")
bazel_dep(name = "rules_license", version = "0.0.8")
bazel_dep(
name = "rules_go",
version = "0.47.0",
Expand Down
10 changes: 10 additions & 0 deletions deps.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,13 @@ def swift_bazel_dependencies():
"https://github.com/cgrindel/bazel-starlib/releases/download/v0.21.0/bazel-starlib.v0.21.0.tar.gz",
],
)

maybe(
http_archive,
name = "rules_license",
sha256 = "241b06f3097fd186ff468832150d6cc142247dc42a32aaefb56d0099895fd229",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_license/releases/download/0.0.8/rules_license-0.0.8.tar.gz",
"https://github.com/bazelbuild/rules_license/releases/download/0.0.8/rules_license-0.0.8.tar.gz",
],
)
3 changes: 2 additions & 1 deletion docs/repository_rules_overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Used to build a local Swift package.
<pre>
swift_package(<a href="#swift_package-name">name</a>, <a href="#swift_package-bazel_package_name">bazel_package_name</a>, <a href="#swift_package-branch">branch</a>, <a href="#swift_package-commit">commit</a>, <a href="#swift_package-dependencies_index">dependencies_index</a>, <a href="#swift_package-env">env</a>, <a href="#swift_package-init_submodules">init_submodules</a>,
<a href="#swift_package-patch_args">patch_args</a>, <a href="#swift_package-patch_cmds">patch_cmds</a>, <a href="#swift_package-patch_cmds_win">patch_cmds_win</a>, <a href="#swift_package-patch_tool">patch_tool</a>, <a href="#swift_package-patches">patches</a>, <a href="#swift_package-recursive_init_submodules">recursive_init_submodules</a>,
<a href="#swift_package-remote">remote</a>, <a href="#swift_package-repo_mapping">repo_mapping</a>, <a href="#swift_package-shallow_since">shallow_since</a>, <a href="#swift_package-tag">tag</a>, <a href="#swift_package-verbose">verbose</a>)
<a href="#swift_package-remote">remote</a>, <a href="#swift_package-repo_mapping">repo_mapping</a>, <a href="#swift_package-shallow_since">shallow_since</a>, <a href="#swift_package-tag">tag</a>, <a href="#swift_package-verbose">verbose</a>, <a href="#swift_package-version">version</a>)
</pre>

Used to download and build an external Swift package.
Expand Down Expand Up @@ -70,5 +70,6 @@ Used to download and build an external Swift package.
| <a id="swift_package-shallow_since"></a>shallow_since | an optional date, not after the specified commit; the argument is not allowed if a tag is specified (which allows cloning with depth 1). Setting such a date close to the specified commit allows for a more shallow clone of the repository, saving bandwidth and wall-clock time. | String | optional | `""` |
| <a id="swift_package-tag"></a>tag | tag in the remote repository to checked out. Precisely one of branch, tag, or commit must be specified. | String | optional | `""` |
| <a id="swift_package-verbose"></a>verbose | - | Boolean | optional | `False` |
| <a id="swift_package-version"></a>version | The resolved version of the package. | String | optional | `""` |


1 change: 1 addition & 0 deletions swiftpkg/bzlmod/swift_deps.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ def _declare_pkg_from_dependency(dep, config_pkg):
bazel_package_name = name,
commit = pin.state.revision,
remote = pin.location,
version = pin.state.version,
dependencies_index = None,
init_submodules = init_submodules,
recursive_init_submodules = recursive_init_submodules,
Expand Down
5 changes: 4 additions & 1 deletion swiftpkg/internal/build_decls.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ def _to_starlark_parts(decl, indent):
for c in decl.comments:
parts.append(scg.indent(indent, "{}\n".format(c)))
parts.append(scg.indent(indent, "{}(\n".format(decl.kind)))
parts.extend(scg.new_attr("name", decl.name, indent + 1))

# Name won't be set for `package` declarations
if decl.name:
parts.extend(scg.new_attr("name", decl.name, indent + 1))

# Sort the keys to ensure that we have a consistent output. It would be
# ideal to output them in a manner that matches Buildifier output rules.
Expand Down
15 changes: 14 additions & 1 deletion swiftpkg/internal/build_files.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ load(":build_decls.bzl", "build_decls")
load(":load_statements.bzl", "load_statements")
load(":starlark_codegen.bzl", scg = "starlark_codegen")

def _new(load_stmts = [], decls = []):
def _new(load_stmts = [], package_attrs = {}, decls = []):
"""Create a `struct` that represents the parts of a Bazel build file.
Args:
load_stmts: A `list` of load statement `struct` values as returned
by `load_statements.new`.
package_attrs: A `dict` of attributes to set on the `package`
declaration.
decls: A `list` of declaration `struct` values as returned by
`build_decls.new`.
Expand All @@ -19,6 +21,7 @@ def _new(load_stmts = [], decls = []):
"""
return struct(
load_stmts = load_stmts,
package_attrs = package_attrs,
decls = decls,
to_starlark_parts = _to_starlark_parts,
)
Expand All @@ -27,6 +30,13 @@ def _to_starlark_parts(build_file, indent):
parts = []
for load_stmt in build_file.load_stmts:
parts.extend([scg.with_indent(indent, load_stmt), "\n"])
if build_file.package_attrs:
package_decl = build_decls.new(
"package",
None,
attrs = build_file.package_attrs,
)
parts.extend(["\n", scg.with_indent(indent, package_decl), "\n"])
for decl in build_file.decls:
parts.extend(["\n", scg.with_indent(indent, decl), "\n"])
return parts
Expand All @@ -48,14 +58,17 @@ def _merge(*bld_files):
fail("Attempted to merge build files, but none were provided.")

load_stmts = []
package_attrs = {}
decls = []
for bf in bld_files:
load_stmts.extend(bf.load_stmts)
package_attrs |= bf.package_attrs
decls.extend(bf.decls)
load_stmts = load_statements.uniq(load_stmts)
decls = build_decls.uniq(decls)
return _new(
load_stmts = load_stmts,
package_attrs = package_attrs,
decls = decls,
)

Expand Down
22 changes: 21 additions & 1 deletion swiftpkg/internal/pkginfos.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,18 @@ def _new_from_parsed_json(
)
targets.append(target)

url = None
version = None
if hasattr(repository_ctx, "attr"):
# We only want to try to collect url and version when called from
# `swift_package`
url = getattr(repository_ctx.attr, "remote", None)
version = getattr(
repository_ctx.attr,
"version",
getattr(repository_ctx.attr, "commit", None),
)

return _new(
name = dump_manifest["name"],
path = pkg_path,
Expand All @@ -610,6 +622,8 @@ def _new_from_parsed_json(
dependencies = dependencies,
products = products,
targets = targets,
url = url,
version = version,
)

# MARK: - Swift Package
Expand All @@ -622,7 +636,9 @@ def _new(
platforms = [],
dependencies = [],
products = [],
targets = []):
targets = [],
url = None,
version = None):
"""Returns a `struct` representing information about a Swift package.
Args:
Expand All @@ -639,6 +655,8 @@ def _new(
`pkginfos.new_product()`.
targets: A `list` of target structs as created by
`pkginfos.new_target()`.
url: Optional. The url of the package (`string`).
version: Optional. The semantic version of the package (`string`).
Returns:
A `struct` representing information about a Swift package.
Expand All @@ -652,6 +670,8 @@ def _new(
dependencies = dependencies,
products = products,
targets = targets,
url = url,
version = version,
)

# MARK: - Platform
Expand Down
13 changes: 12 additions & 1 deletion swiftpkg/internal/repo_rules.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,19 @@ higher. Found version %s installed.\
def _gen_build_files(repository_ctx, pkg_ctx):
pkg_info = pkg_ctx.pkg_info

# Create Bazel declarations for the Swift package targets
bld_files = []

licenses = repository_files.find_license_files(repository_ctx)
bld_files.append(
# Pick the shortest name, in order to prefer `LICENSE` over
# `LICENSE.md`
swiftpkg_build_files.new_for_license(
pkg_info,
sorted(licenses, key = len)[0] if licenses else None,
),
)

# Create Bazel declarations for the Swift package targets
for target in pkg_info.targets:
# Unfortunately, Package.resolved does not contain test-only external
# dependencies. So, we need to skip generating test targets.
Expand Down
44 changes: 44 additions & 0 deletions swiftpkg/internal/repository_files.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,49 @@ def _path_exists(repository_ctx, path):
)
return exec_result.return_code == 0

def _find_license_files(repository_ctx):
"""Retrieves all license files at the root of the package.
Args:
repository_ctx: A `repository_ctx` instance.
Returns:
A `list` of path `string` values.
"""

find_args = [
"find",
# Follow symlinks and report on the actual files.
"-H",
"-L",
".",
# For GNU find, it is important for the global options (e.g. -maxdepth)
# to be specified BEFORE other options like -type. Also, GNU find does
# not support -depth <level>. So, we approximate it by using -mindepth
# and -maxdepth.
"-mindepth",
"1",
"-maxdepth",
"1",
"-type",
"f",
"(",
"-name",
"LICENSE",
"-o",
"-name",
"LICENSE.*",
")",
]

exec_result = repository_ctx.execute(find_args, quiet = True)
if exec_result.return_code != 0:
fail("Failed to find license files. stderr:\n%s" % exec_result.stderr)
return _process_find_results(
exec_result.stdout,
find_path = ".",
)

def _list_files_under(
repository_ctx,
path,
Expand Down Expand Up @@ -247,6 +290,7 @@ repository_files = struct(
exclude_paths = _exclude_paths,
file_type = _file_type,
find_and_delete_files = _find_and_delete_files,
find_license_files = _find_license_files,
is_directory = _is_directory,
list_directories_under = _list_directories_under,
list_files_under = _list_files_under,
Expand Down
2 changes: 1 addition & 1 deletion swiftpkg/internal/starlark_codegen.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ _single_indent_str = " "
# MARK: - Simple Type Detection

_simple_starlark_types = [
"None",
"NoneType",
"bool",
"int",
"string",
Expand Down
1 change: 1 addition & 0 deletions swiftpkg/internal/swift_package.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ _ALL_ATTRS = dicts.add(
_GIT_ATTRS,
repo_rules.env_attrs,
repo_rules.swift_attrs,
{"version": attr.string(doc = "The resolved version of the package.")},
)

swift_package = repository_rule(
Expand Down
57 changes: 57 additions & 0 deletions swiftpkg/internal/swiftpkg_build_files.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -835,6 +835,44 @@ Expected only one target for the macro product {name} but received {count}.\
],
)

# MARK: - License

def _new_for_license(pkg_info, license):
packageinfo_target_name = "package_info.rspm"
decls = [
build_decls.new(
rules_license_kinds.package_info,
packageinfo_target_name,
attrs = {
"package_name": pkg_info.name,
"package_url": pkg_info.url,
"package_version": pkg_info.version,
},
),
]
default_package_metadata = [":{}".format(packageinfo_target_name)]
load_stmts = [rules_license_package_info_load_stmt]

if license:
license_target_name = "license.rspm"
decls.append(
build_decls.new(
rules_license_kinds.license,
license_target_name,
attrs = {
"license_text": license,
},
),
)
load_stmts.append(rules_license_license_load_stmt)
default_package_metadata.insert(0, ":{}".format(license_target_name))

return build_files.new(
load_stmts = load_stmts,
package_attrs = {"default_package_metadata": default_package_metadata},
decls = decls,
)

# MARK: - Constants and API Definition

swift_location = "@build_bazel_rules_swift//swift:swift.bzl"
Expand Down Expand Up @@ -893,6 +931,24 @@ native_kinds = struct(
alias = "alias",
)

rules_license_license_location = "@rules_license//rules:license.bzl"
rules_license_package_info_location = "@rules_license//rules:package_info.bzl"

rules_license_kinds = struct(
license = "license",
package_info = "package_info",
)

rules_license_license_load_stmt = load_statements.new(
rules_license_license_location,
rules_license_kinds.license,
)

rules_license_package_info_load_stmt = load_statements.new(
rules_license_package_info_location,
rules_license_kinds.package_info,
)

skylib_build_test_location = "@bazel_skylib//rules:build_test.bzl"

skylib_kinds = struct(
Expand All @@ -905,6 +961,7 @@ skylib_build_test_load_stmt = load_statements.new(
)

swiftpkg_build_files = struct(
new_for_license = _new_for_license,
new_for_target = _new_for_target,
new_for_products = _new_for_products,
new_for_product = _new_for_product,
Expand Down
Loading

0 comments on commit 880db7f

Please sign in to comment.