diff options
| author | Ulf Lilleengen <[email protected]> | 2025-08-15 09:39:32 +0200 |
|---|---|---|
| committer | Ulf Lilleengen <[email protected]> | 2025-08-25 19:44:50 +0200 |
| commit | 3d004734a2a1db07d0e990462bb3fd5f04d3c7a0 (patch) | |
| tree | 4b488338c85601b933996746e25c27d49c5d1ae2 /release/src | |
| parent | 6a347f1f09b0076af868dcd63d9139081c92172b (diff) | |
chore: cleanup
Diffstat (limited to 'release/src')
| -rw-r--r-- | release/src/main.rs | 184 | ||||
| -rw-r--r-- | release/src/types.rs | 33 |
2 files changed, 74 insertions, 143 deletions
diff --git a/release/src/main.rs b/release/src/main.rs index 38bb728a8..769611c78 100644 --- a/release/src/main.rs +++ b/release/src/main.rs | |||
| @@ -8,8 +8,10 @@ use clap::{Parser, Subcommand}; | |||
| 8 | use petgraph::graph::{Graph, NodeIndex}; | 8 | use petgraph::graph::{Graph, NodeIndex}; |
| 9 | use petgraph::visit::Bfs; | 9 | use petgraph::visit::Bfs; |
| 10 | use petgraph::{Directed, Direction}; | 10 | use petgraph::{Directed, Direction}; |
| 11 | use serde::Deserialize; | ||
| 12 | use toml_edit::{DocumentMut, Item, Value}; | 11 | use toml_edit::{DocumentMut, Item, Value}; |
| 12 | use types::*; | ||
| 13 | |||
| 14 | mod types; | ||
| 13 | 15 | ||
| 14 | /// Tool to traverse and operate on intra-repo Rust crate dependencies | 16 | /// Tool to traverse and operate on intra-repo Rust crate dependencies |
| 15 | #[derive(Parser, Debug)] | 17 | #[derive(Parser, Debug)] |
| @@ -58,41 +60,6 @@ enum Command { | |||
| 58 | }, | 60 | }, |
| 59 | } | 61 | } |
| 60 | 62 | ||
| 61 | #[derive(Debug, Subcommand, Clone, Copy, PartialEq)] | ||
| 62 | enum ReleaseKind { | ||
| 63 | Patch, | ||
| 64 | Minor, | ||
| 65 | } | ||
| 66 | |||
| 67 | #[derive(Debug, Deserialize)] | ||
| 68 | struct CargoToml { | ||
| 69 | package: Option<Package>, | ||
| 70 | dependencies: Option<Deps>, | ||
| 71 | } | ||
| 72 | |||
| 73 | #[derive(Debug, Deserialize)] | ||
| 74 | struct Package { | ||
| 75 | name: String, | ||
| 76 | version: Option<String>, | ||
| 77 | } | ||
| 78 | |||
| 79 | #[derive(Debug, Deserialize)] | ||
| 80 | #[serde(untagged)] | ||
| 81 | enum Dep { | ||
| 82 | Version(String), | ||
| 83 | DetailedTable(BTreeMap<String, toml::Value>), | ||
| 84 | } | ||
| 85 | |||
| 86 | type Deps = std::collections::BTreeMap<String, Dep>; | ||
| 87 | |||
| 88 | #[derive(Debug, Clone, Deserialize)] | ||
| 89 | struct CrateConfig { | ||
| 90 | features: Option<Vec<String>>, | ||
| 91 | target: Option<String>, | ||
| 92 | } | ||
| 93 | |||
| 94 | type ReleaseConfig = HashMap<String, CrateConfig>; | ||
| 95 | |||
| 96 | fn load_release_config(repo: &Path) -> ReleaseConfig { | 63 | fn load_release_config(repo: &Path) -> ReleaseConfig { |
| 97 | let config_path = repo.join("release/config.toml"); | 64 | let config_path = repo.join("release/config.toml"); |
| 98 | if !config_path.exists() { | 65 | if !config_path.exists() { |
| @@ -104,7 +71,7 @@ fn load_release_config(repo: &Path) -> ReleaseConfig { | |||
| 104 | 71 | ||
| 105 | fn update_version(c: &mut Crate, new_version: &str) -> Result<()> { | 72 | fn update_version(c: &mut Crate, new_version: &str) -> Result<()> { |
| 106 | let path = &c.path; | 73 | let path = &c.path; |
| 107 | c.id.version = new_version.to_string(); | 74 | c.version = new_version.to_string(); |
| 108 | let content = fs::read_to_string(&path)?; | 75 | let content = fs::read_to_string(&path)?; |
| 109 | let mut doc: DocumentMut = content.parse()?; | 76 | let mut doc: DocumentMut = content.parse()?; |
| 110 | for section in ["package"] { | 77 | for section in ["package"] { |
| @@ -123,7 +90,7 @@ fn update_versions(to_update: &Crate, dep: &CrateId, new_version: &str) -> Resul | |||
| 123 | let mut changed = false; | 90 | let mut changed = false; |
| 124 | for section in ["dependencies", "dev-dependencies", "build-dependencies"] { | 91 | for section in ["dependencies", "dev-dependencies", "build-dependencies"] { |
| 125 | if let Some(Item::Table(dep_table)) = doc.get_mut(section) { | 92 | if let Some(Item::Table(dep_table)) = doc.get_mut(section) { |
| 126 | if let Some(item) = dep_table.get_mut(&dep.name) { | 93 | if let Some(item) = dep_table.get_mut(&dep) { |
| 127 | match item { | 94 | match item { |
| 128 | // e.g., foo = "0.1.0" | 95 | // e.g., foo = "0.1.0" |
| 129 | Item::Value(Value::String(_)) => { | 96 | Item::Value(Value::String(_)) => { |
| @@ -145,38 +112,11 @@ fn update_versions(to_update: &Crate, dep: &CrateId, new_version: &str) -> Resul | |||
| 145 | 112 | ||
| 146 | if changed { | 113 | if changed { |
| 147 | fs::write(&path, doc.to_string())?; | 114 | fs::write(&path, doc.to_string())?; |
| 148 | println!("🔧 Updated {} to {} in {}", dep.name, new_version, path.display()); | 115 | println!("🔧 Updated {} to {} in {}", dep, new_version, path.display()); |
| 149 | } | 116 | } |
| 150 | Ok(()) | 117 | Ok(()) |
| 151 | } | 118 | } |
| 152 | 119 | ||
| 153 | #[derive(Debug, Clone)] | ||
| 154 | struct Crate { | ||
| 155 | id: CrateId, | ||
| 156 | path: PathBuf, | ||
| 157 | config: CrateConfig, | ||
| 158 | dependencies: Vec<CrateId>, | ||
| 159 | } | ||
| 160 | |||
| 161 | #[derive(Debug, Clone, PartialOrd, Ord)] | ||
| 162 | struct CrateId { | ||
| 163 | name: String, | ||
| 164 | version: String, | ||
| 165 | } | ||
| 166 | |||
| 167 | impl PartialEq for CrateId { | ||
| 168 | fn eq(&self, other: &CrateId) -> bool { | ||
| 169 | self.name == other.name | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | impl Eq for CrateId {} | ||
| 174 | impl std::hash::Hash for CrateId { | ||
| 175 | fn hash<H: std::hash::Hasher>(&self, state: &mut H) { | ||
| 176 | self.name.hash(state) | ||
| 177 | } | ||
| 178 | } | ||
| 179 | |||
| 180 | fn list_crates(path: &PathBuf) -> Result<BTreeMap<CrateId, Crate>> { | 120 | fn list_crates(path: &PathBuf) -> Result<BTreeMap<CrateId, Crate>> { |
| 181 | let d = std::fs::read_dir(path)?; | 121 | let d = std::fs::read_dir(path)?; |
| 182 | let release_config = load_release_config(path); | 122 | let release_config = load_release_config(path); |
| @@ -187,41 +127,24 @@ fn list_crates(path: &PathBuf) -> Result<BTreeMap<CrateId, Crate>> { | |||
| 187 | if entry.file_type()?.is_dir() && name.starts_with("embassy-") { | 127 | if entry.file_type()?.is_dir() && name.starts_with("embassy-") { |
| 188 | let entry = entry.path().join("Cargo.toml"); | 128 | let entry = entry.path().join("Cargo.toml"); |
| 189 | if entry.exists() { | 129 | if entry.exists() { |
| 190 | let content = fs::read_to_string(&entry).unwrap_or_else(|_| { | 130 | let content = fs::read_to_string(&entry)?; |
| 191 | panic!("Failed to read {:?}", entry); | 131 | let parsed: ParsedCrate = toml::from_str(&content)?; |
| 192 | }); | 132 | let id = parsed.package.name; |
| 193 | let parsed: CargoToml = toml::from_str(&content).unwrap_or_else(|e| { | ||
| 194 | panic!("Failed to parse {:?}: {}", entry, e); | ||
| 195 | }); | ||
| 196 | let p = parsed.package.unwrap(); | ||
| 197 | let id = CrateId { | ||
| 198 | name: p.name.clone(), | ||
| 199 | version: p.version.unwrap(), | ||
| 200 | }; | ||
| 201 | 133 | ||
| 202 | let mut dependencies = Vec::new(); | 134 | let mut dependencies = Vec::new(); |
| 203 | if let Some(deps) = parsed.dependencies { | 135 | for (k, _) in parsed.dependencies { |
| 204 | for (k, v) in deps { | 136 | if k.starts_with("embassy-") { |
| 205 | if k.starts_with("embassy-") { | 137 | dependencies.push(k); |
| 206 | dependencies.push(CrateId { | ||
| 207 | name: k, | ||
| 208 | version: match v { | ||
| 209 | Dep::Version(v) => v, | ||
| 210 | Dep::DetailedTable(table) => { | ||
| 211 | table.get("version").unwrap().as_str().unwrap().to_string() | ||
| 212 | } | ||
| 213 | }, | ||
| 214 | }); | ||
| 215 | } | ||
| 216 | } | 138 | } |
| 217 | } | 139 | } |
| 218 | 140 | ||
| 219 | let path = path.join(entry); | 141 | let path = path.join(entry); |
| 220 | if let Some(config) = release_config.get(&p.name) { | 142 | if let Some(config) = release_config.get(&id) { |
| 221 | crates.insert( | 143 | crates.insert( |
| 222 | id.clone(), | 144 | id.clone(), |
| 223 | Crate { | 145 | Crate { |
| 224 | id, | 146 | name: id, |
| 147 | version: parsed.package.version, | ||
| 225 | path, | 148 | path, |
| 226 | dependencies, | 149 | dependencies, |
| 227 | config: config.clone(), | 150 | config: config.clone(), |
| @@ -250,12 +173,12 @@ fn build_graph(crates: &BTreeMap<CrateId, Crate>) -> (Graph<CrateId, ()>, HashMa | |||
| 250 | }; | 173 | }; |
| 251 | 174 | ||
| 252 | for krate in crates.values() { | 175 | for krate in crates.values() { |
| 253 | get_or_insert_node(krate.id.clone(), &mut graph, &mut node_indices); | 176 | get_or_insert_node(krate.name.clone(), &mut graph, &mut node_indices); |
| 254 | } | 177 | } |
| 255 | 178 | ||
| 256 | for krate in crates.values() { | 179 | for krate in crates.values() { |
| 257 | // Insert crate node if not exists | 180 | // Insert crate node if not exists |
| 258 | let crate_idx = get_or_insert_node(krate.id.clone(), &mut graph, &mut node_indices); | 181 | let crate_idx = get_or_insert_node(krate.name.clone(), &mut graph, &mut node_indices); |
| 259 | 182 | ||
| 260 | // Insert dependencies and connect edges | 183 | // Insert dependencies and connect edges |
| 261 | for dep in krate.dependencies.iter() { | 184 | for dep in krate.dependencies.iter() { |
| @@ -270,14 +193,10 @@ fn build_graph(crates: &BTreeMap<CrateId, Crate>) -> (Graph<CrateId, ()>, HashMa | |||
| 270 | fn main() -> Result<()> { | 193 | fn main() -> Result<()> { |
| 271 | let args = Args::parse(); | 194 | let args = Args::parse(); |
| 272 | 195 | ||
| 273 | let root = args.repo.canonicalize()?; //.expect("Invalid root crate path"); | 196 | let root = args.repo.canonicalize()?; |
| 274 | let mut crates = list_crates(&root)?; | 197 | let mut crates = list_crates(&root)?; |
| 275 | //println!("Crates: {:?}", crates); | ||
| 276 | let (mut graph, indices) = build_graph(&crates); | 198 | let (mut graph, indices) = build_graph(&crates); |
| 277 | 199 | ||
| 278 | // use petgraph::dot::{Config, Dot}; | ||
| 279 | // println!("{:?}", Dot::with_config(&graph, &[Config::EdgeNoLabel])); | ||
| 280 | |||
| 281 | match args.command { | 200 | match args.command { |
| 282 | Command::List => { | 201 | Command::List => { |
| 283 | let ordered = petgraph::algo::toposort(&graph, None).unwrap(); | 202 | let ordered = petgraph::algo::toposort(&graph, None).unwrap(); |
| @@ -287,10 +206,11 @@ fn main() -> Result<()> { | |||
| 287 | let mut bfs = Bfs::new(&graph, *node); | 206 | let mut bfs = Bfs::new(&graph, *node); |
| 288 | while let Some(node) = bfs.next(&graph) { | 207 | while let Some(node) = bfs.next(&graph) { |
| 289 | let weight = graph.node_weight(node).unwrap(); | 208 | let weight = graph.node_weight(node).unwrap(); |
| 290 | if weight.name == start.name { | 209 | let c = crates.get(weight).unwrap(); |
| 291 | println!("+ {}-{}", weight.name, weight.version); | 210 | if weight == start { |
| 211 | println!("+ {}-{}", weight, c.version); | ||
| 292 | } else { | 212 | } else { |
| 293 | println!("|- {}-{}", weight.name, weight.version); | 213 | println!("|- {}-{}", weight, c.version); |
| 294 | } | 214 | } |
| 295 | } | 215 | } |
| 296 | println!(""); | 216 | println!(""); |
| @@ -298,62 +218,44 @@ fn main() -> Result<()> { | |||
| 298 | } | 218 | } |
| 299 | } | 219 | } |
| 300 | Command::Dependencies { crate_name } => { | 220 | Command::Dependencies { crate_name } => { |
| 301 | let idx = indices | 221 | let idx = indices.get(&crate_name).expect("unable to find crate in tree"); |
| 302 | .get(&CrateId { | ||
| 303 | name: crate_name.clone(), | ||
| 304 | version: "".to_string(), | ||
| 305 | }) | ||
| 306 | .expect("unable to find crate in tree"); | ||
| 307 | let mut bfs = Bfs::new(&graph, *idx); | 222 | let mut bfs = Bfs::new(&graph, *idx); |
| 308 | while let Some(node) = bfs.next(&graph) { | 223 | while let Some(node) = bfs.next(&graph) { |
| 309 | let weight = graph.node_weight(node).unwrap(); | 224 | let weight = graph.node_weight(node).unwrap(); |
| 310 | if weight.name == crate_name { | 225 | let crt = crates.get(weight).unwrap(); |
| 311 | println!("+ {}-{}", weight.name, weight.version); | 226 | if *weight == crate_name { |
| 227 | println!("+ {}-{}", weight, crt.version); | ||
| 312 | } else { | 228 | } else { |
| 313 | println!("|- {}-{}", weight.name, weight.version); | 229 | println!("|- {}-{}", weight, crt.version); |
| 314 | } | 230 | } |
| 315 | } | 231 | } |
| 316 | } | 232 | } |
| 317 | Command::Dependents { crate_name } => { | 233 | Command::Dependents { crate_name } => { |
| 318 | let idx = indices | 234 | let idx = indices.get(&crate_name).expect("unable to find crate in tree"); |
| 319 | .get(&CrateId { | 235 | let weight = graph.node_weight(*idx).unwrap(); |
| 320 | name: crate_name.clone(), | 236 | let crt = crates.get(weight).unwrap(); |
| 321 | version: "".to_string(), | 237 | println!("+ {}-{}", weight, crt.version); |
| 322 | }) | ||
| 323 | .expect("unable to find crate in tree"); | ||
| 324 | let node = graph.node_weight(*idx).unwrap(); | ||
| 325 | println!("+ {}-{}", node.name, node.version); | ||
| 326 | for parent in graph.neighbors_directed(*idx, Direction::Incoming) { | 238 | for parent in graph.neighbors_directed(*idx, Direction::Incoming) { |
| 327 | let weight = graph.node_weight(parent).unwrap(); | 239 | let weight = graph.node_weight(parent).unwrap(); |
| 328 | println!("|- {}-{}", weight.name, weight.version); | 240 | let crt = crates.get(weight).unwrap(); |
| 241 | println!("|- {}-{}", weight, crt.version); | ||
| 329 | } | 242 | } |
| 330 | } | 243 | } |
| 331 | Command::SemverCheck { crate_name } => { | 244 | Command::SemverCheck { crate_name } => { |
| 332 | let c = crates | 245 | let c = crates.get(&crate_name).unwrap(); |
| 333 | .get(&CrateId { | ||
| 334 | name: crate_name.to_string(), | ||
| 335 | version: "".to_string(), | ||
| 336 | }) | ||
| 337 | .unwrap(); | ||
| 338 | check_semver(&c)?; | 246 | check_semver(&c)?; |
| 339 | } | 247 | } |
| 340 | Command::PrepareRelease { crate_name } => { | 248 | Command::PrepareRelease { crate_name } => { |
| 341 | let start = indices | 249 | let start = indices.get(&crate_name).expect("unable to find crate in tree"); |
| 342 | .get(&CrateId { | ||
| 343 | name: crate_name.clone(), | ||
| 344 | version: "".to_string(), | ||
| 345 | }) | ||
| 346 | .expect("unable to find crate in tree"); | ||
| 347 | |||
| 348 | graph.reverse(); | 250 | graph.reverse(); |
| 349 | 251 | ||
| 350 | let mut bfs = Bfs::new(&graph, *start); | 252 | let mut bfs = Bfs::new(&graph, *start); |
| 351 | 253 | ||
| 352 | while let Some(node) = bfs.next(&graph) { | 254 | while let Some(node) = bfs.next(&graph) { |
| 353 | let weight = graph.node_weight(node).unwrap(); | 255 | let weight = graph.node_weight(node).unwrap(); |
| 354 | println!("Preparing {}", weight.name); | 256 | println!("Preparing {}", weight); |
| 355 | let mut c = crates.get_mut(weight).unwrap(); | 257 | let mut c = crates.get_mut(weight).unwrap(); |
| 356 | let ver = semver::Version::parse(&c.id.version)?; | 258 | let ver = semver::Version::parse(&c.version)?; |
| 357 | let newver = if let Err(_) = check_semver(&c) { | 259 | let newver = if let Err(_) = check_semver(&c) { |
| 358 | println!("Semver check failed, bumping minor!"); | 260 | println!("Semver check failed, bumping minor!"); |
| 359 | semver::Version::new(ver.major, ver.minor + 1, 0) | 261 | semver::Version::new(ver.major, ver.minor + 1, 0) |
| @@ -361,12 +263,7 @@ fn main() -> Result<()> { | |||
| 361 | semver::Version::new(ver.major, ver.minor, ver.patch + 1) | 263 | semver::Version::new(ver.major, ver.minor, ver.patch + 1) |
| 362 | }; | 264 | }; |
| 363 | 265 | ||
| 364 | println!( | 266 | println!("Updating {} from {} -> {}", weight, c.version, newver.to_string()); |
| 365 | "Updating {} from {} -> {}", | ||
| 366 | weight.name, | ||
| 367 | c.id.version, | ||
| 368 | newver.to_string() | ||
| 369 | ); | ||
| 370 | let newver = newver.to_string(); | 267 | let newver = newver.to_string(); |
| 371 | 268 | ||
| 372 | update_version(&mut c, &newver)?; | 269 | update_version(&mut c, &newver)?; |
| @@ -377,7 +274,7 @@ fn main() -> Result<()> { | |||
| 377 | while let Some(dep_node) = bfs.next(&graph) { | 274 | while let Some(dep_node) = bfs.next(&graph) { |
| 378 | let dep_weight = graph.node_weight(dep_node).unwrap(); | 275 | let dep_weight = graph.node_weight(dep_node).unwrap(); |
| 379 | let dep = crates.get(dep_weight).unwrap(); | 276 | let dep = crates.get(dep_weight).unwrap(); |
| 380 | update_versions(dep, &c.id, &newver)?; | 277 | update_versions(dep, &c.name, &newver)?; |
| 381 | } | 278 | } |
| 382 | 279 | ||
| 383 | // Update changelog | 280 | // Update changelog |
| @@ -394,7 +291,8 @@ fn main() -> Result<()> { | |||
| 394 | let mut bfs = Bfs::new(&graph, *start); | 291 | let mut bfs = Bfs::new(&graph, *start); |
| 395 | while let Some(node) = bfs.next(&graph) { | 292 | while let Some(node) = bfs.next(&graph) { |
| 396 | let weight = graph.node_weight(node).unwrap(); | 293 | let weight = graph.node_weight(node).unwrap(); |
| 397 | println!("git tag {}-v{}", weight.name, weight.version); | 294 | let c = crates.get(weight).unwrap(); |
| 295 | println!("git tag {}-v{}", weight, c.version); | ||
| 398 | } | 296 | } |
| 399 | 297 | ||
| 400 | println!(""); | 298 | println!(""); |
diff --git a/release/src/types.rs b/release/src/types.rs new file mode 100644 index 000000000..56a886e6f --- /dev/null +++ b/release/src/types.rs | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | use serde::Deserialize; | ||
| 2 | use std::collections::{BTreeMap, HashMap}; | ||
| 3 | use std::path::PathBuf; | ||
| 4 | |||
| 5 | #[derive(Debug, Deserialize)] | ||
| 6 | pub struct ParsedCrate { | ||
| 7 | pub package: ParsedPackage, | ||
| 8 | pub dependencies: BTreeMap<String, toml::Value>, | ||
| 9 | } | ||
| 10 | |||
| 11 | #[derive(Debug, Deserialize)] | ||
| 12 | pub struct ParsedPackage { | ||
| 13 | pub name: String, | ||
| 14 | pub version: String, | ||
| 15 | } | ||
| 16 | |||
| 17 | #[derive(Debug, Clone, Deserialize)] | ||
| 18 | pub struct CrateConfig { | ||
| 19 | pub features: Option<Vec<String>>, | ||
| 20 | pub target: Option<String>, | ||
| 21 | } | ||
| 22 | |||
| 23 | pub type ReleaseConfig = HashMap<String, CrateConfig>; | ||
| 24 | pub type CrateId = String; | ||
| 25 | |||
| 26 | #[derive(Debug, Clone)] | ||
| 27 | pub struct Crate { | ||
| 28 | pub name: String, | ||
| 29 | pub version: String, | ||
| 30 | pub path: PathBuf, | ||
| 31 | pub config: CrateConfig, | ||
| 32 | pub dependencies: Vec<CrateId>, | ||
| 33 | } | ||
