Skip to content
Merged
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
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);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I was thinking that the testing would just be in this file and cover the changes around here. Not necessarily a brand new test target. I think that'd get sufficient coverage of the functionality, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, I get it now. Good call. I have added that test.


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
12 changes: 6 additions & 6 deletions examples/crate_universe/using_cxx/Cargo.Bazel.lock

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

Loading