Brian Silverman | cc09f18 | 2022-03-09 15:40:20 -0800 | [diff] [blame] | 1 | //! A module for representations of starlark constructs |
| 2 | |
| 3 | mod glob; |
| 4 | mod label; |
| 5 | mod select; |
Adam Snaider | 1c095c9 | 2023-07-08 02:09:58 -0400 | [diff] [blame^] | 6 | mod serialize; |
| 7 | mod target_compatible_with; |
| 8 | |
| 9 | use std::collections::BTreeSet as Set; |
| 10 | |
| 11 | use serde::{Serialize, Serializer}; |
| 12 | use serde_starlark::Error as StarlarkError; |
Brian Silverman | cc09f18 | 2022-03-09 15:40:20 -0800 | [diff] [blame] | 13 | |
| 14 | pub use glob::*; |
| 15 | pub use label::*; |
| 16 | pub use select::*; |
Adam Snaider | 1c095c9 | 2023-07-08 02:09:58 -0400 | [diff] [blame^] | 17 | pub use target_compatible_with::*; |
Brian Silverman | cc09f18 | 2022-03-09 15:40:20 -0800 | [diff] [blame] | 18 | |
| 19 | pub type SelectStringList = SelectList<String>; |
| 20 | pub type SelectStringDict = SelectDict<String>; |
Adam Snaider | 1c095c9 | 2023-07-08 02:09:58 -0400 | [diff] [blame^] | 21 | |
| 22 | #[derive(Serialize)] |
| 23 | #[serde(untagged)] |
| 24 | pub enum Starlark { |
| 25 | Load(Load), |
| 26 | Package(Package), |
| 27 | ExportsFiles(ExportsFiles), |
| 28 | Filegroup(Filegroup), |
| 29 | Alias(Alias), |
| 30 | CargoBuildScript(CargoBuildScript), |
| 31 | #[serde(serialize_with = "serialize::rust_proc_macro")] |
| 32 | RustProcMacro(RustProcMacro), |
| 33 | #[serde(serialize_with = "serialize::rust_library")] |
| 34 | RustLibrary(RustLibrary), |
| 35 | #[serde(serialize_with = "serialize::rust_binary")] |
| 36 | RustBinary(RustBinary), |
| 37 | |
| 38 | #[serde(skip_serializing)] |
| 39 | Verbatim(String), |
| 40 | } |
| 41 | |
| 42 | pub struct Load { |
| 43 | pub bzl: String, |
| 44 | pub items: Set<String>, |
| 45 | } |
| 46 | |
| 47 | pub struct Package { |
| 48 | pub default_visibility: Set<String>, |
| 49 | } |
| 50 | |
| 51 | pub struct ExportsFiles { |
| 52 | pub paths: Set<String>, |
| 53 | pub globs: Glob, |
| 54 | } |
| 55 | |
| 56 | #[derive(Serialize)] |
| 57 | #[serde(rename = "filegroup")] |
| 58 | pub struct Filegroup { |
| 59 | pub name: String, |
| 60 | pub srcs: Glob, |
| 61 | } |
| 62 | |
| 63 | #[derive(Serialize)] |
| 64 | #[serde(rename = "alias")] |
| 65 | pub struct Alias { |
| 66 | pub name: String, |
| 67 | pub actual: String, |
| 68 | pub tags: Set<String>, |
| 69 | } |
| 70 | |
| 71 | #[derive(Serialize)] |
| 72 | #[serde(rename = "cargo_build_script")] |
| 73 | pub struct CargoBuildScript { |
| 74 | pub name: String, |
| 75 | #[serde( |
| 76 | skip_serializing_if = "SelectDict::is_empty", |
| 77 | serialize_with = "SelectDict::serialize_starlark" |
| 78 | )] |
| 79 | pub aliases: SelectDict<WithOriginalConfigurations<String>>, |
| 80 | #[serde( |
| 81 | skip_serializing_if = "SelectDict::is_empty", |
| 82 | serialize_with = "SelectDict::serialize_starlark" |
| 83 | )] |
| 84 | pub build_script_env: SelectDict<WithOriginalConfigurations<String>>, |
| 85 | #[serde(skip_serializing_if = "Data::is_empty")] |
| 86 | pub compile_data: Data, |
| 87 | #[serde( |
| 88 | skip_serializing_if = "SelectList::is_empty", |
| 89 | serialize_with = "SelectList::serialize_starlark" |
| 90 | )] |
| 91 | pub crate_features: SelectList<String>, |
| 92 | pub crate_name: String, |
| 93 | #[serde(skip_serializing_if = "Option::is_none")] |
| 94 | pub crate_root: Option<String>, |
| 95 | #[serde(skip_serializing_if = "Data::is_empty")] |
| 96 | pub data: Data, |
| 97 | #[serde( |
| 98 | skip_serializing_if = "SelectList::is_empty", |
| 99 | serialize_with = "SelectList::serialize_starlark" |
| 100 | )] |
| 101 | pub deps: SelectList<WithOriginalConfigurations<String>>, |
| 102 | pub edition: String, |
| 103 | #[serde(skip_serializing_if = "Option::is_none")] |
| 104 | pub linker_script: Option<String>, |
| 105 | #[serde(skip_serializing_if = "Option::is_none")] |
| 106 | pub links: Option<String>, |
| 107 | #[serde( |
| 108 | skip_serializing_if = "SelectList::is_empty", |
| 109 | serialize_with = "SelectList::serialize_starlark" |
| 110 | )] |
| 111 | pub proc_macro_deps: SelectList<WithOriginalConfigurations<String>>, |
| 112 | #[serde( |
| 113 | skip_serializing_if = "SelectDict::is_empty", |
| 114 | serialize_with = "SelectDict::serialize_starlark" |
| 115 | )] |
| 116 | pub rustc_env: SelectDict<WithOriginalConfigurations<String>>, |
| 117 | #[serde( |
| 118 | skip_serializing_if = "SelectList::is_empty", |
| 119 | serialize_with = "SelectList::serialize_starlark" |
| 120 | )] |
| 121 | pub rustc_env_files: SelectList<WithOriginalConfigurations<String>>, |
| 122 | #[serde( |
| 123 | skip_serializing_if = "SelectList::is_empty", |
| 124 | serialize_with = "SelectList::serialize_starlark" |
| 125 | )] |
| 126 | pub rustc_flags: SelectList<WithOriginalConfigurations<String>>, |
| 127 | pub srcs: Glob, |
| 128 | #[serde(skip_serializing_if = "Set::is_empty")] |
| 129 | pub tags: Set<String>, |
| 130 | #[serde( |
| 131 | skip_serializing_if = "SelectList::is_empty", |
| 132 | serialize_with = "SelectList::serialize_starlark" |
| 133 | )] |
| 134 | pub tools: SelectList<WithOriginalConfigurations<String>>, |
| 135 | #[serde(skip_serializing_if = "Set::is_empty")] |
| 136 | pub toolchains: Set<String>, |
| 137 | pub version: String, |
| 138 | pub visibility: Set<String>, |
| 139 | } |
| 140 | |
| 141 | #[derive(Serialize)] |
| 142 | pub struct RustProcMacro { |
| 143 | pub name: String, |
| 144 | #[serde( |
| 145 | skip_serializing_if = "SelectList::is_empty", |
| 146 | serialize_with = "SelectList::serialize_starlark" |
| 147 | )] |
| 148 | pub deps: SelectList<WithOriginalConfigurations<String>>, |
| 149 | #[serde( |
| 150 | skip_serializing_if = "SelectList::is_empty", |
| 151 | serialize_with = "SelectList::serialize_starlark" |
| 152 | )] |
| 153 | pub proc_macro_deps: SelectList<WithOriginalConfigurations<String>>, |
| 154 | #[serde( |
| 155 | skip_serializing_if = "SelectDict::is_empty", |
| 156 | serialize_with = "SelectDict::serialize_starlark" |
| 157 | )] |
| 158 | pub aliases: SelectDict<WithOriginalConfigurations<String>>, |
| 159 | #[serde(flatten)] |
| 160 | pub common: CommonAttrs, |
| 161 | } |
| 162 | |
| 163 | #[derive(Serialize)] |
| 164 | pub struct RustLibrary { |
| 165 | pub name: String, |
| 166 | #[serde( |
| 167 | skip_serializing_if = "SelectList::is_empty", |
| 168 | serialize_with = "SelectList::serialize_starlark" |
| 169 | )] |
| 170 | pub deps: SelectList<WithOriginalConfigurations<String>>, |
| 171 | #[serde( |
| 172 | skip_serializing_if = "SelectList::is_empty", |
| 173 | serialize_with = "SelectList::serialize_starlark" |
| 174 | )] |
| 175 | pub proc_macro_deps: SelectList<WithOriginalConfigurations<String>>, |
| 176 | #[serde( |
| 177 | skip_serializing_if = "SelectDict::is_empty", |
| 178 | serialize_with = "SelectDict::serialize_starlark" |
| 179 | )] |
| 180 | pub aliases: SelectDict<WithOriginalConfigurations<String>>, |
| 181 | #[serde(flatten)] |
| 182 | pub common: CommonAttrs, |
| 183 | #[serde(skip_serializing_if = "std::ops::Not::not")] |
| 184 | pub disable_pipelining: bool, |
| 185 | } |
| 186 | |
| 187 | #[derive(Serialize)] |
| 188 | pub struct RustBinary { |
| 189 | pub name: String, |
| 190 | #[serde( |
| 191 | skip_serializing_if = "SelectList::is_empty", |
| 192 | serialize_with = "SelectList::serialize_starlark" |
| 193 | )] |
| 194 | pub deps: SelectList<WithOriginalConfigurations<String>>, |
| 195 | #[serde( |
| 196 | skip_serializing_if = "SelectList::is_empty", |
| 197 | serialize_with = "SelectList::serialize_starlark" |
| 198 | )] |
| 199 | pub proc_macro_deps: SelectList<WithOriginalConfigurations<String>>, |
| 200 | #[serde( |
| 201 | skip_serializing_if = "SelectDict::is_empty", |
| 202 | serialize_with = "SelectDict::serialize_starlark" |
| 203 | )] |
| 204 | pub aliases: SelectDict<WithOriginalConfigurations<String>>, |
| 205 | #[serde(flatten)] |
| 206 | pub common: CommonAttrs, |
| 207 | } |
| 208 | |
| 209 | #[derive(Serialize)] |
| 210 | pub struct CommonAttrs { |
| 211 | #[serde(skip_serializing_if = "Data::is_empty")] |
| 212 | pub compile_data: Data, |
| 213 | #[serde( |
| 214 | skip_serializing_if = "SelectList::is_empty", |
| 215 | serialize_with = "SelectList::serialize_starlark" |
| 216 | )] |
| 217 | pub crate_features: SelectList<String>, |
| 218 | #[serde(skip_serializing_if = "Option::is_none")] |
| 219 | pub crate_root: Option<String>, |
| 220 | #[serde(skip_serializing_if = "Data::is_empty")] |
| 221 | pub data: Data, |
| 222 | pub edition: String, |
| 223 | #[serde(skip_serializing_if = "Option::is_none")] |
| 224 | pub linker_script: Option<String>, |
| 225 | #[serde( |
| 226 | skip_serializing_if = "SelectDict::is_empty", |
| 227 | serialize_with = "SelectDict::serialize_starlark" |
| 228 | )] |
| 229 | pub rustc_env: SelectDict<WithOriginalConfigurations<String>>, |
| 230 | #[serde( |
| 231 | skip_serializing_if = "SelectList::is_empty", |
| 232 | serialize_with = "SelectList::serialize_starlark" |
| 233 | )] |
| 234 | pub rustc_env_files: SelectList<WithOriginalConfigurations<String>>, |
| 235 | #[serde(skip_serializing_if = "Vec::is_empty")] |
| 236 | pub rustc_flags: Vec<String>, |
| 237 | pub srcs: Glob, |
| 238 | #[serde(skip_serializing_if = "Set::is_empty")] |
| 239 | pub tags: Set<String>, |
| 240 | #[serde( |
| 241 | serialize_with = "serialize_target_compatible_with", |
| 242 | skip_serializing_if = "Option::is_none" |
| 243 | )] |
| 244 | pub target_compatible_with: Option<TargetCompatibleWith>, |
| 245 | pub version: String, |
| 246 | } |
| 247 | |
| 248 | fn serialize_target_compatible_with<S>( |
| 249 | value: &Option<TargetCompatibleWith>, |
| 250 | serializer: S, |
| 251 | ) -> Result<S::Ok, S::Error> |
| 252 | where |
| 253 | S: Serializer, |
| 254 | { |
| 255 | // SAFETY: Option::is_none causes serialization to get skipped. |
| 256 | value.as_ref().unwrap().serialize_starlark(serializer) |
| 257 | } |
| 258 | |
| 259 | pub struct Data { |
| 260 | pub glob: Glob, |
| 261 | pub select: SelectList<WithOriginalConfigurations<String>>, |
| 262 | } |
| 263 | |
| 264 | impl Package { |
| 265 | pub fn default_visibility_public() -> Self { |
| 266 | let mut default_visibility = Set::new(); |
| 267 | default_visibility.insert("//visibility:public".to_owned()); |
| 268 | Package { default_visibility } |
| 269 | } |
| 270 | } |
| 271 | |
| 272 | pub fn serialize(starlark: &[Starlark]) -> Result<String, StarlarkError> { |
| 273 | let mut content = String::new(); |
| 274 | for call in starlark { |
| 275 | if !content.is_empty() { |
| 276 | content.push('\n'); |
| 277 | } |
| 278 | if let Starlark::Verbatim(comment) = call { |
| 279 | content.push_str(comment); |
| 280 | } else { |
| 281 | content.push_str(&serde_starlark::to_string(call)?); |
| 282 | } |
| 283 | } |
| 284 | Ok(content) |
| 285 | } |