Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Set license information for packages with rules_license #1118

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.18.1")
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.20.2/bazel-starlib.v0.20.2.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",
],
)
1 change: 1 addition & 0 deletions swiftpkg/bzlmod/swift_deps.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,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))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to confirm. The case when a name won't be present is the package declaration. Is that correct?


# 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 @@ -798,6 +798,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 @@ -850,6 +888,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 @@ -862,6 +918,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