Skip to main content

max / makenotwork

sando: clear clippy lints from toolchain drift (rust 1.95) Mechanical only, no behavior change: collapse nested ifs, simplify boolean expressions, first-line .next() instead of a break-once loop, sort_by_key(Reverse), slice::from_ref in tests, doc-list indent. Keeps the workspace gate green under the newer clippy. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-06-19 01:05 UTC
Commit: 294d309a26e6f407e4291f6366430cb406fa9d75
Parent: c106137
8 files changed, +49 insertions, -56 deletions
@@ -4,8 +4,7 @@
4 4 //! - `file:///abs/path/to/dump.sql.gz` — local copy (dev).
5 5 //! - `rsync://host/module/path` — rsync daemon protocol.
6 6 //! - `ssh://user@host[:port]/path/file.sql.gz` — rsync-over-ssh. Used to pull
7 - //! prod backups from
8 - //! `backup-puller@alpha-west-1`.
7 + //! prod backups from `backup-puller@alpha-west-1`.
9 8 //!
10 9 //! The fetch is command-driven: the operator triggers it via /backup/fetch, it
11 10 //! is not implicit in promote. That keeps the slowest, most failure-prone step
@@ -45,11 +45,10 @@ pub async fn run(
45 45 // deploy branch so a just-pushed sha is locally resolvable. A fetch
46 46 // failure is non-fatal — the sha may already be present from a prior
47 47 // fetch or a direct push; the presence check below is the real gate.
48 - if let Some(upstream) = topo.repo.upstream.as_deref() {
49 - if let Err(e) = git::fetch_upstream(&bare, upstream, &topo.repo.branch).await {
48 + if let Some(upstream) = topo.repo.upstream.as_deref()
49 + && let Err(e) = git::fetch_upstream(&bare, upstream, &topo.repo.branch).await {
50 50 tracing::warn!(error = %e, upstream, "upstream fetch failed; proceeding with current bare-repo state");
51 51 }
52 - }
53 52 anyhow::ensure!(
54 53 git::sha_present(&bare, sha.as_str()).await?,
55 54 "sha {} not present in bare repo {} after fetch — push the commit to the upstream remote first",
@@ -32,11 +32,10 @@ pub fn classify_cargo_test(stdout: &[u8], stderr: &[u8]) -> GateFailure {
32 32 // Expect "P passed; F failed; ..."
33 33 for piece in rest.split(';') {
34 34 let p = piece.trim();
35 - if let Some(num_str) = p.strip_suffix(" failed") {
36 - if let Ok(n) = num_str.parse::<u32>() {
35 + if let Some(num_str) = p.strip_suffix(" failed")
36 + && let Ok(n) = num_str.parse::<u32>() {
37 37 failed_count = n;
38 38 }
39 - }
40 39 }
41 40 break;
42 41 }
@@ -45,14 +44,13 @@ pub fn classify_cargo_test(stdout: &[u8], stderr: &[u8]) -> GateFailure {
45 44 // libtest prints "failures:\n foo::bar" near the end too. Grab
46 45 // the first one for the summary line.
47 46 if let Some(idx) = stdout_s.find("\nfailures:\n") {
48 - for line in stdout_s[idx + 11..].lines() {
47 + // The "failures:" block repeats — once with stdout per failure, once as
48 + // a plain name list. Either way the first non-empty line is a candidate.
49 + if let Some(line) = stdout_s[idx + 11..].lines().next() {
49 50 let trimmed = line.trim();
50 - if trimmed.is_empty() { break; }
51 - // The "failures:" block repeats — once with stdout per
52 - // failure, once as a plain name list. Either way the first
53 - // non-empty line is a candidate.
54 - first_failed = Some(trimmed.to_string());
55 - break;
51 + if !trimmed.is_empty() {
52 + first_failed = Some(trimmed.to_string());
53 + }
56 54 }
57 55 }
58 56
@@ -286,7 +284,7 @@ fn combined_tail_for_classifier(stdout: &[u8], stderr: &[u8]) -> String {
286 284 let mut joined = Vec::with_capacity(stdout.len() + stderr.len() + 32);
287 285 joined.extend_from_slice(b"==== stdout ====\n");
288 286 joined.extend_from_slice(stdout);
289 - if !stdout.last().is_some_and(|b| *b == b'\n') { joined.push(b'\n'); }
287 + if stdout.last().is_none_or(|b| *b != b'\n') { joined.push(b'\n'); }
290 288 joined.extend_from_slice(b"==== stderr ====\n");
291 289 joined.extend_from_slice(stderr);
292 290 let s = String::from_utf8_lossy(&joined);
@@ -64,32 +64,6 @@ pub struct ReleaseEntry {
64 64 fn default_bin_names() -> Vec<String> { vec!["server".into()] }
65 65 fn default_logs_root() -> PathBuf { PathBuf::from("/srv/sando/logs") }
66 66
67 - #[cfg(test)]
68 - mod tests {
69 - use super::*;
70 -
71 - const MINIMAL: &str = r#"
72 - listen = "127.0.0.1:7766"
73 - db_path = "./sando.db"
74 - topology_path = "../sando.toml"
75 - workdir = "./work"
76 - release_root = "./releases"
77 - "#;
78 -
79 - #[test]
80 - fn cargo_target_dir_parses_when_present() {
81 - let raw = format!("{MINIMAL}\ncargo_target_dir = \"/srv/sando/cargo-target\"\n");
82 - let cfg: Config = toml::from_str(&raw).unwrap();
83 - assert_eq!(cfg.cargo_target_dir.as_deref(), Some(std::path::Path::new("/srv/sando/cargo-target")));
84 - }
85 -
86 - #[test]
87 - fn cargo_target_dir_defaults_to_none() {
88 - let cfg: Config = toml::from_str(MINIMAL).unwrap();
89 - assert!(cfg.cargo_target_dir.is_none(), "omitting it keeps the per-worktree target/");
90 - }
91 - }
92 -
93 67 impl Config {
94 68 /// Primary binary — the one the systemd unit's ExecStart points at.
95 69 pub fn primary_bin(&self) -> &str {
@@ -119,3 +93,29 @@ impl Config {
119 93 }
120 94 }
121 95 }
96 +
97 + #[cfg(test)]
98 + mod tests {
99 + use super::*;
100 +
101 + const MINIMAL: &str = r#"
102 + listen = "127.0.0.1:7766"
103 + db_path = "./sando.db"
104 + topology_path = "../sando.toml"
105 + workdir = "./work"
106 + release_root = "./releases"
107 + "#;
108 +
109 + #[test]
110 + fn cargo_target_dir_parses_when_present() {
111 + let raw = format!("{MINIMAL}\ncargo_target_dir = \"/srv/sando/cargo-target\"\n");
112 + let cfg: Config = toml::from_str(&raw).unwrap();
113 + assert_eq!(cfg.cargo_target_dir.as_deref(), Some(std::path::Path::new("/srv/sando/cargo-target")));
114 + }
115 +
116 + #[test]
117 + fn cargo_target_dir_defaults_to_none() {
118 + let cfg: Config = toml::from_str(MINIMAL).unwrap();
119 + assert!(cfg.cargo_target_dir.is_none(), "omitting it keeps the per-worktree target/");
120 + }
121 + }
@@ -231,7 +231,7 @@ async fn gc_local_releases(release_root: &Path) -> Result<()> {
231 231 let meta = entry.metadata().await?;
232 232 entries.push((entry.path(), meta.modified()?));
233 233 }
234 - entries.sort_by(|a, b| b.1.cmp(&a.1));
234 + entries.sort_by_key(|e| std::cmp::Reverse(e.1));
235 235 for (path, _) in entries.into_iter().skip(RELEASES_TO_KEEP) {
236 236 if let Err(e) = tokio::fs::remove_dir_all(&path).await {
237 237 tracing::warn!(path = %path.display(), error = %e, "gc: rm failed");
@@ -311,9 +311,9 @@ mod tests {
311 311 let release_root = root.join("rr");
312 312 tokio::fs::create_dir_all(&release_root).await.unwrap();
313 313
314 - deploy_local(&release_root, &"0.1.0".parse().unwrap(), &[bin.clone()]).await.unwrap();
314 + deploy_local(&release_root, &"0.1.0".parse().unwrap(), std::slice::from_ref(&bin)).await.unwrap();
315 315 tokio::fs::write(&bin, b"V2").await.unwrap();
316 - deploy_local(&release_root, &"0.2.0".parse().unwrap(), &[bin.clone()]).await.unwrap();
316 + deploy_local(&release_root, &"0.2.0".parse().unwrap(), std::slice::from_ref(&bin)).await.unwrap();
317 317
318 318 assert!(release_root.join("releases/0.1.0/server").exists());
319 319 assert!(release_root.join("releases/0.2.0/server").exists());
@@ -717,7 +717,7 @@ async fn persist_gate_log(ctx: &GateCtx, gate_kind: GateKind, stdout: &[u8], std
717 717 let mut body = Vec::with_capacity(stdout.len() + stderr.len() + 64);
718 718 body.extend_from_slice(b"==== stdout ====\n");
719 719 body.extend_from_slice(stdout);
720 - if !stdout.last().is_some_and(|b| *b == b'\n') {
720 + if stdout.last().is_none_or(|b| *b != b'\n') {
721 721 body.push(b'\n');
722 722 }
723 723 body.extend_from_slice(b"==== stderr ====\n");
@@ -45,12 +45,11 @@ impl LiveLog {
45 45 /// watching live still see the chunk.
46 46 pub async fn write_chunk(&mut self, bytes: &[u8]) {
47 47 if bytes.is_empty() { return; }
48 - if let Some(f) = self.file.as_mut() {
49 - if let Err(e) = f.write_all(bytes).await {
48 + if let Some(f) = self.file.as_mut()
49 + && let Err(e) = f.write_all(bytes).await {
50 50 tracing::warn!(error = %e, path = %self.path.display(), "live log write failed");
51 51 self.file = None;
52 52 }
53 - }
54 53 let text = String::from_utf8_lossy(bytes).into_owned();
55 54 events::emit(&self.events, Event::GateLogChunk {
56 55 run_id: self.run_id,
@@ -62,11 +61,10 @@ impl LiveLog {
62 61
63 62 /// Flush and close the file. Best-effort: errors are logged.
64 63 pub async fn close(mut self) {
65 - if let Some(mut f) = self.file.take() {
66 - if let Err(e) = f.flush().await {
64 + if let Some(mut f) = self.file.take()
65 + && let Err(e) = f.flush().await {
67 66 tracing::warn!(error = %e, path = %self.path.display(), "live log flush failed");
68 67 }
69 - }
70 68 }
71 69
72 70 pub fn run_id(&self) -> GateRunId { self.run_id }
@@ -86,12 +84,11 @@ impl ops_exec::LogSink for LiveLog {
86 84 }
87 85
88 86 async fn open_for_append(path: &Path) -> Option<File> {
89 - if let Some(parent) = path.parent() {
90 - if let Err(e) = tokio::fs::create_dir_all(parent).await {
87 + if let Some(parent) = path.parent()
88 + && let Err(e) = tokio::fs::create_dir_all(parent).await {
91 89 tracing::warn!(error = %e, dir = %parent.display(), "could not create gate log dir");
92 90 return None;
93 91 }
94 - }
95 92 match tokio::fs::OpenOptions::new()
96 93 .create(true)
97 94 .append(true)
@@ -27,7 +27,7 @@ async fn main() -> Result<()> {
27 27 git::ensure_bare_repo(Path::new(&topo.repo.bare_path)).await?;
28 28 let pool = db::connect(&cfg.db_path).await?;
29 29 db::migrate(&pool).await?;
30 - sync::sync(&pool, &*topo).await?;
30 + sync::sync(&pool, &topo).await?;
31 31 tracing::info!(tiers = topo.tiers.len(), bare = %topo.repo.bare_path, "topology synced");
32 32
33 33 let prom = metrics::init();