Skip to content

Commit

Permalink
Merge branch 'main' into toolchains
Browse files Browse the repository at this point in the history
  • Loading branch information
krasimirgg authored Aug 25, 2023
2 parents fecb02a + 7f40480 commit 0fdc6b5
Show file tree
Hide file tree
Showing 13 changed files with 283 additions and 65 deletions.
5 changes: 5 additions & 0 deletions crate_universe/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ version = "0.9.0"
authors = [
"Andre Brisco - [email protected]",
]
categories = ["development-tools"]
description = "A collection of tools which use Cargo to generate build targets for Bazel"
edition = "2021"
keywords = ["bazel"]
license = "Apache-2.0"
repository = "https://github.com/bazelbuild/rules_rust"

[features]
cargo = []
Expand Down
87 changes: 85 additions & 2 deletions crate_universe/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ pub enum Checksumish {
},
}

#[derive(Debug, Default, Deserialize, Serialize, Clone)]
#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq)]
pub struct CrateAnnotations {
/// Which subset of the crate's bins should get produced as `rust_binary` targets.
pub gen_binaries: Option<GenBinaries>,
Expand Down Expand Up @@ -335,6 +335,89 @@ impl Sum for CrateAnnotations {
}
}

/// A subset of `crate.annotation` that we allow packages to define in their
/// free-form Cargo.toml metadata.
///
/// ```toml
/// [package.metadata.bazel]
/// additive_build_file_contents = """
/// ...
/// """
/// data = ["font.woff2"]
/// extra_aliased_targets = { ... }
/// gen_build_script = false
/// ```
///
/// These are considered default values which apply if the Bazel workspace does
/// not specify a different value for the same annotation in their
/// crates_repository attributes.
#[derive(Debug, Deserialize)]
pub struct AnnotationsProvidedByPackage {
pub gen_build_script: Option<bool>,
pub data: Option<BTreeSet<String>>,
pub data_glob: Option<BTreeSet<String>>,
pub compile_data: Option<BTreeSet<String>>,
pub compile_data_glob: Option<BTreeSet<String>>,
pub rustc_env: Option<BTreeMap<String, String>>,
pub rustc_env_files: Option<BTreeSet<String>>,
pub rustc_flags: Option<Vec<String>>,
pub build_script_env: Option<BTreeMap<String, String>>,
pub build_script_rustc_env: Option<BTreeMap<String, String>>,
pub additive_build_file_content: Option<String>,
pub extra_aliased_targets: Option<BTreeMap<String, String>>,
}

impl CrateAnnotations {
pub fn apply_defaults_from_package_metadata(&mut self, pkg_metadata: &serde_json::Value) {
#[deny(unused_variables)]
let AnnotationsProvidedByPackage {
gen_build_script,
data,
data_glob,
compile_data,
compile_data_glob,
rustc_env,
rustc_env_files,
rustc_flags,
build_script_env,
build_script_rustc_env,
additive_build_file_content,
extra_aliased_targets,
} = match AnnotationsProvidedByPackage::deserialize(&pkg_metadata["bazel"]) {
Ok(annotations) => annotations,
// Ignore bad annotations. The set of supported annotations evolves
// over time across different versions of crate_universe, and we
// don't want a library to be impossible to import into Bazel for
// having old or broken annotations. The Bazel workspace can specify
// its own correct annotations.
Err(_) => return,
};

fn default<T>(workspace_value: &mut Option<T>, default_value: Option<T>) {
if workspace_value.is_none() {
*workspace_value = default_value;
}
}

default(&mut self.gen_build_script, gen_build_script);
default(&mut self.gen_build_script, gen_build_script);
default(&mut self.data, data);
default(&mut self.data_glob, data_glob);
default(&mut self.compile_data, compile_data);
default(&mut self.compile_data_glob, compile_data_glob);
default(&mut self.rustc_env, rustc_env);
default(&mut self.rustc_env_files, rustc_env_files);
default(&mut self.rustc_flags, rustc_flags);
default(&mut self.build_script_env, build_script_env);
default(&mut self.build_script_rustc_env, build_script_rustc_env);
default(
&mut self.additive_build_file_content,
additive_build_file_content,
);
default(&mut self.extra_aliased_targets, extra_aliased_targets);
}
}

/// A unique identifier for Crates
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct CrateId {
Expand Down Expand Up @@ -444,7 +527,7 @@ impl std::fmt::Display for CrateId {
}
}

#[derive(Debug, Hash, Clone)]
#[derive(Debug, Hash, Clone, PartialEq)]
pub enum GenBinaries {
All,
Some(BTreeSet<String>),
Expand Down
52 changes: 46 additions & 6 deletions crate_universe/src/metadata/metadata_annotation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ impl Annotations {
.packages
.iter()
.filter_map(|(pkg_id, pkg)| {
let extras: Vec<CrateAnnotations> = config
let mut crate_extra: CrateAnnotations = config
.annotations
.iter()
.filter(|(id, _)| id.matches(pkg))
Expand All @@ -395,18 +395,20 @@ impl Annotations {
extra
})
.cloned()
.collect();
.sum();

if !extras.is_empty() {
crate_extra.apply_defaults_from_package_metadata(&pkg.metadata);

if crate_extra == CrateAnnotations::default() {
None
} else {
Some((
CrateId::new(pkg.name.clone(), pkg.version.to_string()),
PairredExtras {
package_id: pkg_id.clone(),
crate_extra: extras.into_iter().sum(),
crate_extra,
},
))
} else {
None
}
})
.collect();
Expand Down Expand Up @@ -560,4 +562,42 @@ mod test {
assert!(result_str.contains("Unused annotations were provided. Please remove them"));
assert!(result_str.contains("mock-crate"));
}

#[test]
fn defaults_from_package_metadata() {
let crate_id = CrateId::new("has_package_metadata".to_owned(), "0.0.0".to_owned());
let annotations = CrateAnnotations {
rustc_env: Some({
let mut rustc_env = BTreeMap::new();
rustc_env.insert("BAR".to_owned(), "bar is set".to_owned());
rustc_env
}),
..CrateAnnotations::default()
};

let mut config = Config::default();
config
.annotations
.insert(crate_id.clone(), annotations.clone());

// Combine the above annotations with default values provided by the
// crate author in package metadata.
let combined_annotations = Annotations::new(
test::metadata::has_package_metadata(),
test::lockfile::has_package_metadata(),
config,
)
.unwrap();

let extras = &combined_annotations.pairred_extras[&crate_id].crate_extra;
let expected = CrateAnnotations {
// This comes from has_package_metadata's [package.metadata.bazel].
additive_build_file_content: Some("genrule(**kwargs)\n".to_owned()),
// The package metadata defines a default rustc_env containing FOO,
// but it is superseded by a rustc_env annotation containing only
// BAR. These dictionaries are intentionally not merged together.
..annotations
};
assert_eq!(*extras, expected);
}
}
16 changes: 16 additions & 0 deletions crate_universe/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,14 @@ pub mod metadata {
)))
.unwrap()
}

pub fn has_package_metadata() -> cargo_metadata::Metadata {
serde_json::from_str(include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/test_data/metadata/has_package_metadata/metadata.json"
)))
.unwrap()
}
}

pub mod lockfile {
Expand Down Expand Up @@ -174,4 +182,12 @@ pub mod lockfile {
)))
.unwrap()
}

pub fn has_package_metadata() -> cargo_lock::Lockfile {
cargo_lock::Lockfile::from_str(include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/test_data/metadata/has_package_metadata/Cargo.lock"
)))
.unwrap()
}
}

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

15 changes: 15 additions & 0 deletions crate_universe/test_data/metadata/has_package_metadata/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "has_package_metadata"
version = "0.0.0"
edition = "2021"

# Required to satisfy cargo but no `lib.rs` is expected to
# exist within test data.
[lib]
path = "lib.rs"

[package.metadata.bazel]
additive_build_file_content = """
genrule(**kwargs)
"""
rustc_env = { "FOO" = "foo is set" }

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

29 changes: 4 additions & 25 deletions examples/crate_universe/WORKSPACE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -277,35 +277,14 @@ no_cargo_crate_repositories()

crates_repository(
name = "using_cxx",
annotations = {
# CXX provides a header file that should be used in C++ sources that depend on cxx.
"cxx": [
crate.annotation(
additive_build_file_content = """
# This file is included in the BUILD for the cxx crate, to export its header
# file for C++ code to depend on.
cc_library(
name = "cxx_cc",
visibility = ["//visibility:public"],
hdrs = ["include/cxx.h"],
srcs = ["src/cxx.cc"],
includes = ["include"],
linkstatic = True,
)
""",
extra_aliased_targets = {"cxx_cc": "cxx_cc"},
gen_build_script = False,
),
],
},
cargo_lockfile = "//using_cxx:Cargo.Bazel.lock",
# `generator` is not necessary in official releases.
# See load satement for `cargo_bazel_bootstrap`.
generator = "@cargo_bazel_bootstrap//:cargo-bazel",
lockfile = "//using_cxx:cargo-bazel-lock.json",
packages = {
"cxx": crate.spec(
version = "1.0.0",
version = "1.0.105",
),
},
splicing_config = splicing_config(
Expand Down Expand Up @@ -341,10 +320,10 @@ rust_binary(
),
)
""",
sha256 = "df13eece12ed9e7bd4fb071a6af4c44421bb9024d339d029f5333bcdaca00000",
strip_prefix = "cxxbridge-cmd-1.0.100",
sha256 = "0b3eea393dbcbc1e875302846de4e4f9a31bf2e57ad3657bc83d61d00293b0fe",
strip_prefix = "cxxbridge-cmd-1.0.105",
type = "tar.gz",
urls = ["https://crates.io/api/v1/crates/cxxbridge-cmd/1.0.100/download"],
urls = ["https://crates.io/api/v1/crates/cxxbridge-cmd/1.0.105/download"],
)

crates_repository(
Expand Down
Loading

0 comments on commit 0fdc6b5

Please sign in to comment.