aboutsummaryrefslogtreecommitdiff
path: root/release/src
diff options
context:
space:
mode:
authorUlf Lilleengen <[email protected]>2025-08-15 09:39:32 +0200
committerUlf Lilleengen <[email protected]>2025-08-25 19:44:50 +0200
commit3d004734a2a1db07d0e990462bb3fd5f04d3c7a0 (patch)
tree4b488338c85601b933996746e25c27d49c5d1ae2 /release/src
parent6a347f1f09b0076af868dcd63d9139081c92172b (diff)
chore: cleanup
Diffstat (limited to 'release/src')
-rw-r--r--release/src/main.rs184
-rw-r--r--release/src/types.rs33
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};
8use petgraph::graph::{Graph, NodeIndex}; 8use petgraph::graph::{Graph, NodeIndex};
9use petgraph::visit::Bfs; 9use petgraph::visit::Bfs;
10use petgraph::{Directed, Direction}; 10use petgraph::{Directed, Direction};
11use serde::Deserialize;
12use toml_edit::{DocumentMut, Item, Value}; 11use toml_edit::{DocumentMut, Item, Value};
12use types::*;
13
14mod 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)]
62enum ReleaseKind {
63 Patch,
64 Minor,
65}
66
67#[derive(Debug, Deserialize)]
68struct CargoToml {
69 package: Option<Package>,
70 dependencies: Option<Deps>,
71}
72
73#[derive(Debug, Deserialize)]
74struct Package {
75 name: String,
76 version: Option<String>,
77}
78
79#[derive(Debug, Deserialize)]
80#[serde(untagged)]
81enum Dep {
82 Version(String),
83 DetailedTable(BTreeMap<String, toml::Value>),
84}
85
86type Deps = std::collections::BTreeMap<String, Dep>;
87
88#[derive(Debug, Clone, Deserialize)]
89struct CrateConfig {
90 features: Option<Vec<String>>,
91 target: Option<String>,
92}
93
94type ReleaseConfig = HashMap<String, CrateConfig>;
95
96fn load_release_config(repo: &Path) -> ReleaseConfig { 63fn 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
105fn update_version(c: &mut Crate, new_version: &str) -> Result<()> { 72fn 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)]
154struct Crate {
155 id: CrateId,
156 path: PathBuf,
157 config: CrateConfig,
158 dependencies: Vec<CrateId>,
159}
160
161#[derive(Debug, Clone, PartialOrd, Ord)]
162struct CrateId {
163 name: String,
164 version: String,
165}
166
167impl PartialEq for CrateId {
168 fn eq(&self, other: &CrateId) -> bool {
169 self.name == other.name
170 }
171}
172
173impl Eq for CrateId {}
174impl std::hash::Hash for CrateId {
175 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
176 self.name.hash(state)
177 }
178}
179
180fn list_crates(path: &PathBuf) -> Result<BTreeMap<CrateId, Crate>> { 120fn 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
270fn main() -> Result<()> { 193fn 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 @@
1use serde::Deserialize;
2use std::collections::{BTreeMap, HashMap};
3use std::path::PathBuf;
4
5#[derive(Debug, Deserialize)]
6pub struct ParsedCrate {
7 pub package: ParsedPackage,
8 pub dependencies: BTreeMap<String, toml::Value>,
9}
10
11#[derive(Debug, Deserialize)]
12pub struct ParsedPackage {
13 pub name: String,
14 pub version: String,
15}
16
17#[derive(Debug, Clone, Deserialize)]
18pub struct CrateConfig {
19 pub features: Option<Vec<String>>,
20 pub target: Option<String>,
21}
22
23pub type ReleaseConfig = HashMap<String, CrateConfig>;
24pub type CrateId = String;
25
26#[derive(Debug, Clone)]
27pub struct Crate {
28 pub name: String,
29 pub version: String,
30 pub path: PathBuf,
31 pub config: CrateConfig,
32 pub dependencies: Vec<CrateId>,
33}