1pub mod ast;
14pub mod render;
15
16pub use ast::{StarlarkValue, StarlarkStmt, KwArg};
17pub use render::render_file;
18
19use gen_types::{Manifest, Package};
20
21#[must_use]
25pub fn render_build_bazel(manifest: &Manifest) -> String {
26 let mut stmts: Vec<StarlarkStmt> = Vec::new();
27 stmts.push(StarlarkStmt::Load {
28 module: "@rules_rust//rust:defs.bzl".to_string(),
29 symbols: vec!["rust_library".into(), "rust_binary".into()],
30 });
31 for pkg in &manifest.packages {
32 stmts.push(StarlarkStmt::Call {
33 func: "rust_library".to_string(),
34 args: rust_library_args(pkg),
35 });
36 }
37 render::render_file(&stmts)
38}
39
40#[must_use]
45pub fn render_module_bazel(manifest: &Manifest) -> String {
46 let mut stmts: Vec<StarlarkStmt> = Vec::new();
47 let module_name = manifest
48 .packages
49 .first()
50 .map(|p| p.name.clone())
51 .unwrap_or_else(|| "workspace".to_string());
52 let module_version = manifest
53 .packages
54 .first()
55 .map(|p| p.version.to_string())
56 .unwrap_or_else(|| "0.1.0".to_string());
57 stmts.push(StarlarkStmt::Call {
58 func: "module".to_string(),
59 args: vec![
60 KwArg::str("name", &module_name),
61 KwArg::str("version", &module_version),
62 ],
63 });
64 stmts.push(StarlarkStmt::Assign {
65 name: "rust".to_string(),
66 value: StarlarkValue::Call {
67 func: "use_extension".to_string(),
68 args: vec![
69 KwArg::positional(StarlarkValue::str("@rules_rust//rust:extensions.bzl")),
70 KwArg::positional(StarlarkValue::str("rust")),
71 ],
72 },
73 });
74 stmts.push(StarlarkStmt::Call {
75 func: "use_repo".to_string(),
76 args: vec![
77 KwArg::positional(StarlarkValue::Ident("rust".to_string())),
78 KwArg::positional(StarlarkValue::str("rust_toolchains")),
79 ],
80 });
81 render::render_file(&stmts)
82}
83
84fn rust_library_args(pkg: &Package) -> Vec<KwArg> {
85 vec![
86 KwArg::str("name", &pkg.name),
87 KwArg::positional_named(
88 "srcs",
89 StarlarkValue::Call {
90 func: "glob".to_string(),
91 args: vec![KwArg::positional(StarlarkValue::List(vec![
92 StarlarkValue::str("src/**/*.rs"),
93 ]))],
94 },
95 ),
96 KwArg::str("edition", "2021"),
97 KwArg::positional_named(
98 "deps",
99 StarlarkValue::List(
100 pkg.dependencies
101 .iter()
102 .map(|d| StarlarkValue::str(format!("@crate_index//:{}", d.name)))
103 .collect(),
104 ),
105 ),
106 KwArg::positional_named(
107 "visibility",
108 StarlarkValue::List(vec![StarlarkValue::str("//visibility:public")]),
109 ),
110 ]
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116 use gen_types::*;
117
118 fn demo() -> Manifest {
119 let p = Package {
120 name: "demo".into(),
121 version: Version::new(0, 1, 0),
122 source: PackageSource::Path { path: ".".into() },
123 registry: Registry::CratesIo,
124 dependencies: vec![Dependency {
125 name: "serde".into(),
126 constraint: VersionConstraint::from_spec(ConstraintSpec::Caret(Version::new(1, 0, 0))),
127 kind: DependencyKind::Direct,
128 features_enabled: vec![],
129 default_features: true,
130 target_predicate: None,
131 source_override: None,
132 }],
133 features: vec![],
134 build_steps: vec![],
135 license: None,
136 description: None,
137 authors: vec![],
138 homepage: None,
139 repository: None,
140 };
141 Manifest::new("/x", Workspace::single_package("/x", "cargo"), vec![p], None)
142 }
143
144 #[test]
145 fn renders_build_bazel_with_rust_library() {
146 let s = render_build_bazel(&demo());
147 assert!(s.contains("load(\"@rules_rust//rust:defs.bzl\""));
148 assert!(s.contains("rust_library("));
149 assert!(s.contains("name = \"demo\""));
150 assert!(s.contains("@crate_index//:serde"));
151 }
152
153 #[test]
154 fn renders_module_bazel_with_module_call_and_use_extension() {
155 let s = render_module_bazel(&demo());
156 assert!(s.contains("module(name = \"demo\""));
157 assert!(s.contains("rust = use_extension("));
158 assert!(s.contains("use_repo(rust"));
159 }
160
161 #[test]
162 fn renderer_is_deterministic() {
163 let m = demo();
164 let a = render_build_bazel(&m);
165 let b = render_build_bazel(&m);
166 assert_eq!(a, b);
167 }
168}