Skip to content

Commit

Permalink
Allow rules_license metadata in bzlmod
Browse files Browse the repository at this point in the history
  • Loading branch information
AmeliasCode committed Dec 20, 2024
1 parent 89aec55 commit 61c4add
Show file tree
Hide file tree
Showing 12 changed files with 241 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .bazelci/presubmit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -846,6 +846,14 @@ tasks:
working_directory: examples/bzlmod/hello_world_no_cargo
build_targets:
- "//..."
bzlmod_rules_license_metadata:
name: rules_license_metadata with bzlmod
platform: ubuntu2004
working_directory: examples/bzlmod/rules_license_metadata
build_targets:
- "//..."
test_targets:
- "//..."
bzlmod_override_targets:
name: Override Targets bzlmod
platform: ubuntu2004
Expand Down
7 changes: 7 additions & 0 deletions crate_universe/extensions.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ _OPT_BOOL_VALUES = {
"on": True,
}

GENERATE_RULES_LICENSE_METADATA_ATTR = attr.bool(doc = "Generate rules_license metadata for third party crates", default = False)

def _get_or_insert(d, key, value):
if key not in d:
d[key] = value
Expand Down Expand Up @@ -78,6 +80,7 @@ def _generate_hub_and_spokes(*, module_ctx, cargo_bazel, cfg, annotations, cargo

rendering_config = json.decode(render_config(
regen_command = "Run 'cargo update [--workspace]'",
generate_rules_license_metadata = cfg.generate_rules_license_metadata,
))
config_file = tag_path.get_child("config.json")
module_ctx.file(
Expand Down Expand Up @@ -512,6 +515,8 @@ _from_cargo = tag_class(
"generate_build_scripts": CRATES_VENDOR_ATTRS["generate_build_scripts"],
"splicing_config": CRATES_VENDOR_ATTRS["splicing_config"],
"supported_platform_triples": CRATES_VENDOR_ATTRS["supported_platform_triples"],
} | {
"generate_rules_license_metadata": GENERATE_RULES_LICENSE_METADATA_ATTR,
},
)

Expand Down Expand Up @@ -653,6 +658,8 @@ _from_specs = tag_class(
"generate_build_scripts": CRATES_VENDOR_ATTRS["generate_build_scripts"],
"splicing_config": CRATES_VENDOR_ATTRS["splicing_config"],
"supported_platform_triples": CRATES_VENDOR_ATTRS["supported_platform_triples"],
} | {
"generate_rules_license_metadata": GENERATE_RULES_LICENSE_METADATA_ATTR,
},
)

Expand Down
12 changes: 12 additions & 0 deletions examples/bzlmod/rules_license_metadata/.bazelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Required on windows
common --enable_platform_specific_config
startup --windows_enable_symlinks
build:windows --enable_runfiles

build --experimental_enable_bzlmod

# This isn't currently the defaut in Bazel, but we enable it to test we'll be ready if/when it flips.
build --incompatible_disallow_empty_glob

# Required for cargo_build_script support before Bazel 7
build --incompatible_merge_fixed_and_default_shell_env
1 change: 1 addition & 0 deletions examples/bzlmod/rules_license_metadata/.bazelversion
2 changes: 2 additions & 0 deletions examples/bzlmod/rules_license_metadata/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/bazel-*
.DS_Store
50 changes: 50 additions & 0 deletions examples/bzlmod/rules_license_metadata/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
load("@crates//:defs.bzl", "all_crate_deps")
load("@crates_from_spec//:defs.bzl", all_crate_deps_from_spec = "all_crate_deps")
load("@rules_license//sample_reports:licenses_used.bzl", "licenses_used")
load("@rules_python//python:defs.bzl", "py_test")
load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_doc")

package(default_visibility = ["//visibility:public"])

rust_binary(
name = "all_crate_deps",
srcs = ["src/main.rs"],
deps = all_crate_deps(normal = True),
)

rust_binary(
name = "all_crate_deps_from_spec",
srcs = ["src/main.rs"],
deps = all_crate_deps_from_spec(normal = True),
)

rust_doc(
name = "all_crate_deps_doc",
crate = ":all_crate_deps",
)

licenses_used(
name = "licenses_used",
out = "license_info.json",
deps = [
":all_crate_deps",
],
)

licenses_used(
name = "licenses_used_from_spec",
out = "license_info_from_spec.json",
deps = [
":all_crate_deps_from_spec",
],
)

py_test(
name = "license_check_test",
srcs = ["license_check_test.py"],
data = [
":license_info.json",
":license_info_from_spec.json",
],
python_version = "PY3",
)
16 changes: 16 additions & 0 deletions examples/bzlmod/rules_license_metadata/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions examples/bzlmod/rules_license_metadata/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[workspace]
[package]
name = "all_crate_deps"
version = "0.0.0"
edition = "2021"
publish = false

[lib]
path = "fake.rs"

[dependencies]
anyhow = "1.0.79"
54 changes: 54 additions & 0 deletions examples/bzlmod/rules_license_metadata/MODULE.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"""bazelbuild/rules_rust - bzlmod example"""

module(
name = "rules_license_metadata_bzlmod_example",
version = "0.0.0",
)

bazel_dep(name = "platforms", version = "0.0.10")
bazel_dep(
name = "bazel_skylib",
version = "1.7.1",
)
bazel_dep(name = "rules_python", version = "1.0.0")
bazel_dep(name = "rules_license", version = "1.0.0")
bazel_dep(
name = "rules_rust",
version = "0.0.0",
)
local_path_override(
module_name = "rules_rust",
path = "../../..",
)

rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
rust.toolchain(edition = "2021")
use_repo(
rust,
"rust_toolchains",
)

register_toolchains("@rust_toolchains//:all")

crate = use_extension(
"@rules_rust//crate_universe:extensions.bzl",
"crate",
)
crate.from_cargo(
name = "crates",
cargo_lockfile = "//:Cargo.lock",
generate_rules_license_metadata = True,
manifests = ["//:Cargo.toml"],
)
use_repo(crate, "crates")

crate_from_spec = use_extension("@rules_rust//crate_universe:extensions.bzl", "crate")
crate_from_spec.spec(
package = "anyhow",
version = "1.0.79",
)
crate_from_spec.from_specs(
name = "crates_from_spec",
generate_rules_license_metadata = True,
)
use_repo(crate_from_spec, "crates_from_spec")
1 change: 1 addition & 0 deletions examples/bzlmod/rules_license_metadata/WORKSPACE.bzlmod
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Intentionally blank; enable strict mode for bzlmod
60 changes: 60 additions & 0 deletions examples/bzlmod/rules_license_metadata/license_check_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import json
import os
import codecs
import unittest

# Largely borrowed from rules_license:
# https://github.com/bazelbuild/rules_license/blob/main/examples/vndor/constant_gen/verify_licenses_test.py

APACHE_2_LICENSE_TARGET = "@rules_license~//licenses/spdx:Apache-2.0"
MIT_LICENSE_TARGET = "@rules_license~//licenses/spdx:MIT"

def load_licenses_info(info_path):
"""Loads the licenses_info() JSON format."""
with codecs.open(info_path, encoding="utf-8") as licenses_file:
return json.loads(licenses_file.read())

class LicenseCheckTest(unittest.TestCase):
def test_license_info(self):
self.check_license("license_info.json", "//:all_crate_deps")

def test_license_info_from_spec(self):
self.check_license("license_info_from_spec.json", "//:all_crate_deps_from_spec")


# Load the generated report and ensure that the data is as expected.
# Note: [email protected] is licensed under both Apache-2.0 and MIT, so we expect both to be present
# If this dependency is ever changed, you may need to update this test to reflect that
def check_license(self, file_name, top_level_target):
info = load_licenses_info(os.path.join(os.path.dirname(__file__), file_name))
self.assertEqual(len(info),1)
all_crate_deps = info[0]
self.assertEqual(all_crate_deps["top_level_target"], top_level_target)
self.assertEqual(len(all_crate_deps["dependencies"]), 3)

licenses = all_crate_deps["licenses"]

self.assertEqual(len(licenses), 1)

apache_found = False
mit_found = False
other_found = False
other_license_found = ""
for license_item in licenses:
for kind in license_item["license_kinds"]:
if kind["target"] == APACHE_2_LICENSE_TARGET:
apache_found = True
continue
if kind["target"] == MIT_LICENSE_TARGET:
mit_found = True
continue
else:
other_found = True
other_license_found = kind["target"]
continue
self.assertFalse(other_found, "Unexpected license found: (%s)." % other_license_found)
self.assertTrue(apache_found, "Apache-2.0 license not found.")
self.assertTrue(mit_found, "MIT license not found.")

if __name__ == "__main__":
unittest.main(verbosity=3)
18 changes: 18 additions & 0 deletions examples/bzlmod/rules_license_metadata/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2015 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.

fn main() -> anyhow::Result<()> {
println!("Hello, world!");
Ok(())
}

0 comments on commit 61c4add

Please sign in to comment.