From 44f1c19219a30c5c5554899404cf9059d6d436bc Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot Date: Mon, 27 Jul 2026 08:40:34 +0930 Subject: [PATCH 1/3] dwell: fix import_cmd.rs compile error from Output::new signature change PR #29 added a 4th parameter (log_level) to Output::new but import_cmd.rs was written before that change and only passes 3 arguments. --- crates/dwell-cli/src/commands/import_cmd.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/dwell-cli/src/commands/import_cmd.rs b/crates/dwell-cli/src/commands/import_cmd.rs index 2671cfd..c5d68c4 100644 --- a/crates/dwell-cli/src/commands/import_cmd.rs +++ b/crates/dwell-cli/src/commands/import_cmd.rs @@ -34,7 +34,7 @@ pub fn run( all: bool, dry_run: bool, ) -> dwell_core::Result<()> { - let out = Output::new(cli.json, cli.verbose, cli.quiet); + let out = Output::new(cli.json, cli.verbose, cli.quiet, None); let source_dir = crate::commands::resolve_source(cli, None)?; out.title(&format!("Importing: {}", url)); @@ -330,3 +330,4 @@ fn collect_dir(src_dir: &Path, prefix: &str, candidates: &mut Vec Date: Mon, 27 Jul 2026 08:43:36 +0930 Subject: [PATCH 2/3] dwell: cargo fmt --- crates/dwell-cli/src/commands.rs | 6 +- crates/dwell-cli/src/commands/import_cmd.rs | 105 ++++++++++++++++---- crates/dwell-cli/src/main.rs | 17 +++- crates/dwell-cli/src/output.rs | 79 +++++++++++---- 4 files changed, 165 insertions(+), 42 deletions(-) diff --git a/crates/dwell-cli/src/commands.rs b/crates/dwell-cli/src/commands.rs index f553d98..d9217ab 100644 --- a/crates/dwell-cli/src/commands.rs +++ b/crates/dwell-cli/src/commands.rs @@ -5,8 +5,8 @@ mod apply; mod deploy; mod deps; mod diff; -mod init; mod import_cmd; +mod init; mod module_cmd; mod package; mod reset; @@ -79,7 +79,9 @@ pub fn run(cli: Cli) -> dwell_core::Result<()> { Ok(()) } crate::Commands::Module { action } => module_cmd::run(&cli_ref, &cfg, action), - crate::Commands::Import { url, all, dry_run } => import_cmd::run(&cli_ref, &cfg, url, all, dry_run), + crate::Commands::Import { url, all, dry_run } => { + import_cmd::run(&cli_ref, &cfg, url, all, dry_run) + } crate::Commands::Plugin { .. } => { eprintln!("Plugin management — Phase 4 (coming soon)"); Ok(()) diff --git a/crates/dwell-cli/src/commands/import_cmd.rs b/crates/dwell-cli/src/commands/import_cmd.rs index c5d68c4..31ad96d 100644 --- a/crates/dwell-cli/src/commands/import_cmd.rs +++ b/crates/dwell-cli/src/commands/import_cmd.rs @@ -1,28 +1,68 @@ -use std::path::Path; use std::fs; +use std::path::Path; use crate::commands::CliRef; use crate::output::Output; /// Known config directory names commonly found in dotfiles repos. const CONFIG_DIRS: &[&str] = &[ - "ags", "alacritty", "btop", "cava", "dunst", "fastfetch", "fish", - "foot", "gtk-2.0", "gtk-3.0", "gtk-4.0", "hypr", "i3", "k9s", - "kitty", "Kvantum", "mako", "mpd", "mpv", "neofetch", "nvim", - "oh-my-posh", "picom", "polybar", "qtile", "ranger", "rofi", - "starship", "sway", "swaylock", "tmux", "waybar", "wlogout", - "wofi", "xfce4", "yazi", "zathura", + "ags", + "alacritty", + "btop", + "cava", + "dunst", + "fastfetch", + "fish", + "foot", + "gtk-2.0", + "gtk-3.0", + "gtk-4.0", + "hypr", + "i3", + "k9s", + "kitty", + "Kvantum", + "mako", + "mpd", + "mpv", + "neofetch", + "nvim", + "oh-my-posh", + "picom", + "polybar", + "qtile", + "ranger", + "rofi", + "starship", + "sway", + "swaylock", + "tmux", + "waybar", + "wlogout", + "wofi", + "xfce4", + "yazi", + "zathura", ]; /// Directories to skip (wallpapers, backgrounds, large media, version control). const SKIP_DIRS: &[&str] = &[ - "backgrounds", "wallpapers", "wallpaper", "wall", "Pictures", - "Screenshots", "previews", ".git", ".github", ".previews", + "backgrounds", + "wallpapers", + "wallpaper", + "wall", + "Pictures", + "Screenshots", + "previews", + ".git", + ".github", + ".previews", ]; /// File patterns at repo root that look like home-relative dotfiles. fn is_home_dotfile(name: &str) -> bool { - name.starts_with('.') && !name.starts_with(".git") + name.starts_with('.') + && !name.starts_with(".git") && !name.starts_with(".github") && !name.starts_with(".previews") } @@ -40,7 +80,8 @@ pub fn run( out.title(&format!("Importing: {}", url)); // Extract repo name from URL - let repo_name = url.trim_end_matches(".git") + let repo_name = url + .trim_end_matches(".git") .split('/') .last() .unwrap_or("dotfiles") @@ -141,7 +182,9 @@ pub fn run( fs::remove_dir_all(&tmp_dir).ok(); // Summary - out.info(&format!("Run 'dwell apply' to deploy, or 'dwell diff' to preview")); + out.info(&format!( + "Run 'dwell apply' to deploy, or 'dwell diff' to preview" + )); Ok(()) } @@ -185,7 +228,12 @@ fn detect_structure(repo_root: &Path) -> RepoStructure { let has_dotfiles_dir = repo_root.join("dotfiles").is_dir(); - match (has_config_subdirs, has_home_configs_dir, has_dotfiles_dir, has_dotfiles_at_root) { + match ( + has_config_subdirs, + has_home_configs_dir, + has_dotfiles_dir, + has_dotfiles_at_root, + ) { (true, _, _, _) => RepoStructure::DirectConfig, (_, true, _, _) => RepoStructure::HomeConfigsDir, (_, _, true, _) => RepoStructure::DotfilesDir, @@ -202,9 +250,17 @@ fn detect_structure(repo_root: &Path) -> RepoStructure { } fn has_config_looking_dirs(repo_root: &Path) -> bool { - fs::read_dir(repo_root).ok().map(|entries| { - entries.filter_map(|e| e.ok()).filter(|e| e.file_type().map(|t| t.is_dir()).unwrap_or(false)).take(10).count() - }).unwrap_or(0) > 2 + fs::read_dir(repo_root) + .ok() + .map(|entries| { + entries + .filter_map(|e| e.ok()) + .filter(|e| e.file_type().map(|t| t.is_dir()).unwrap_or(false)) + .take(10) + .count() + }) + .unwrap_or(0) + > 2 } #[derive(Debug)] @@ -224,7 +280,11 @@ fn discover_files(repo_root: &Path, structure: &RepoStructure, _all: bool) -> Ve if dir_path.is_dir() { // Check for doubled dir: name/name/ let doubled = dir_path.join(dir); - let source_dir = if doubled.is_dir() { &doubled } else { &dir_path }; + let source_dir = if doubled.is_dir() { + &doubled + } else { + &dir_path + }; collect_dir(source_dir, &format!("dot_config/{}", dir), &mut candidates); } } @@ -237,7 +297,11 @@ fn discover_files(repo_root: &Path, structure: &RepoStructure, _all: bool) -> Ve && !SKIP_DIRS.contains(&name.as_str()) && !CONFIG_DIRS.contains(&name.as_str()) { - collect_dir(&entry.path(), &format!("dot_config/{}", name), &mut candidates); + collect_dir( + &entry.path(), + &format!("dot_config/{}", name), + &mut candidates, + ); } } } @@ -277,7 +341,9 @@ fn discover_files(repo_root: &Path, structure: &RepoStructure, _all: bool) -> Ve if let Ok(entries) = fs::read_dir(repo_root) { for entry in entries.flatten() { let name = entry.file_name().to_string_lossy().to_string(); - if entry.file_type().map(|t| t.is_file()).unwrap_or(false) && is_home_dotfile(&name) { + if entry.file_type().map(|t| t.is_file()).unwrap_or(false) + && is_home_dotfile(&name) + { // .zshrc → dot_zshrc let dwell_name = format!("dot_{}", &name[1..]); candidates.push(ImportCandidate { @@ -330,4 +396,3 @@ fn collect_dir(src_dir: &Path, prefix: &str, candidates: &mut Vec if cli.quiet { "error" } else { "warn" }, + 0 => { + if cli.quiet { + "error" + } else { + "warn" + } + } 1 => "info", 2 => "debug", _ => "trace", - }.to_string() + } + .to_string() }); // Configure tracing subscriber with optional file output @@ -371,7 +378,11 @@ fn main() { .append(true) .open(log_path) .unwrap_or_else(|e| { - eprintln!("dwell: warning: cannot open log file {}: {}", log_path.display(), e); + eprintln!( + "dwell: warning: cannot open log file {}: {}", + log_path.display(), + e + ); // Fallback to stderr using /dev/null as a dummy that won't matter std::fs::File::create("/dev/null").unwrap() }); diff --git a/crates/dwell-cli/src/output.rs b/crates/dwell-cli/src/output.rs index 7e9967a..eff34da 100644 --- a/crates/dwell-cli/src/output.rs +++ b/crates/dwell-cli/src/output.rs @@ -21,14 +21,25 @@ impl Output { _ => None, }) .unwrap_or_else(|| { - if quiet { 1 } else { 3u8.saturating_add(verbose).min(5) } + if quiet { + 1 + } else { + 3u8.saturating_add(verbose).min(5) + } }); - Output { json_mode, verbose, quiet, level } + Output { + json_mode, + verbose, + quiet, + level, + } } /// Debug — dim blue dot, only at -v or --log-level=debug pub fn debug(&self, msg: &str) { - if self.level < 4 { return; } + if self.level < 4 { + return; + } if self.json_mode { println!(r#"{{"level":"debug","message":"{}"}}"#, msg); } else { @@ -38,7 +49,9 @@ impl Output { /// Trace — dim magenta hash, only at -vv or --log-level=trace pub fn trace(&self, msg: &str) { - if self.level < 5 { return; } + if self.level < 5 { + return; + } if self.json_mode { println!(r#"{{"level":"trace","message":"{}"}}"#, msg); } else { @@ -48,7 +61,9 @@ impl Output { /// Section header — bright cyan, bold pub fn section(&self, msg: &str) { - if self.level < 3 { return; } + if self.level < 3 { + return; + } if self.json_mode { println!(r#"{{"level":"section","message":"{}"}}"#, msg); } else { @@ -58,7 +73,9 @@ impl Output { /// Info — blue arrow, dim message pub fn info(&self, msg: &str) { - if self.level < 3 { return; } + if self.level < 3 { + return; + } if self.json_mode { println!(r#"{{"level":"info","message":"{}"}}"#, msg); } else { @@ -68,7 +85,9 @@ impl Output { /// Success — green checkmark, green message pub fn success(&self, msg: &str) { - if self.level < 3 { return; } + if self.level < 3 { + return; + } if self.json_mode { println!(r#"{{"level":"success","message":"{}"}}"#, msg); } else { @@ -78,7 +97,9 @@ impl Output { /// Warning — yellow exclamation, yellow message pub fn warn(&self, msg: &str) { - if self.level < 2 { return; } + if self.level < 2 { + return; + } if self.json_mode { println!(r#"{{"level":"warn","message":"{}"}}"#, msg); } else { @@ -88,19 +109,30 @@ impl Output { /// Error — red X, red message pub fn error(&self, msg: &str) { - if self.level < 1 { return; } + if self.level < 1 { + return; + } if self.json_mode { println!(r#"{{"level":"error","message":"{}"}}"#, msg); } else { - eprintln!(" {} {}", style("✗").red().bright(), style(msg).red().bright()); + eprintln!( + " {} {}", + style("✗").red().bright(), + style(msg).red().bright() + ); } } /// Step indicator — bold magenta for phase numbers pub fn step(&self, phase: &str, msg: &str) { - if self.level < 3 { return; } + if self.level < 3 { + return; + } if self.json_mode { - println!(r#"{{"level":"step","phase":"{}","message":"{}"}}"#, phase, msg); + println!( + r#"{{"level":"step","phase":"{}","message":"{}"}}"#, + phase, msg + ); } else { eprintln!(" {} {}", style(phase).magenta().bright(), style(msg).bold()); } @@ -108,7 +140,9 @@ impl Output { /// Apply result — colored per action type pub fn apply_result(&self, result: &dwell_core::ApplyResult) { - if self.level < 3 { return; } + if self.level < 3 { + return; + } if self.json_mode { println!("{}", serde_json::to_string(result).unwrap_or_default()); return; @@ -125,13 +159,20 @@ impl Output { eprintln!(" {} {}", icon, path); } else { let err = result.error.as_deref().unwrap_or("unknown error"); - eprintln!(" {} {} — {}", style("✗").red().bright(), path, style(err).red().dim()); + eprintln!( + " {} {} — {}", + style("✗").red().bright(), + path, + style(err).red().dim() + ); } } /// Title bar — prominent header with surrounding lines pub fn title(&self, msg: &str) { - if self.level < 3 { return; } + if self.level < 3 { + return; + } if self.json_mode { println!(r#"{{"level":"title","message":"{}"}}"#, msg); } else { @@ -144,7 +185,9 @@ impl Output { /// Colored key-value pair pub fn kv(&self, key: &str, value: &str) { - if self.level < 4 { return; } + if self.level < 4 { + return; + } if self.json_mode { println!(r#"{{"level":"kv","key":"{}","value":"{}"}}"#, key, value); } else { @@ -154,7 +197,9 @@ impl Output { /// File path — underlined for emphasis pub fn path(&self, path: &str) { - if self.level < 3 { return; } + if self.level < 3 { + return; + } if self.json_mode { println!(r#"{{"level":"path","path":"{}"}}"#, path); } else { From 7c961758089ff1260c6f98d3fd7a220f1537079a Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot Date: Mon, 27 Jul 2026 08:46:09 +0930 Subject: [PATCH 3/3] dwell: fix clippy warnings in import_cmd.rs --- crates/dwell-cli/src/commands/import_cmd.rs | 24 +++++++++------------ 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/crates/dwell-cli/src/commands/import_cmd.rs b/crates/dwell-cli/src/commands/import_cmd.rs index 31ad96d..1c19333 100644 --- a/crates/dwell-cli/src/commands/import_cmd.rs +++ b/crates/dwell-cli/src/commands/import_cmd.rs @@ -83,7 +83,7 @@ pub fn run( let repo_name = url .trim_end_matches(".git") .split('/') - .last() + .next_back() .unwrap_or("dotfiles") .to_string(); @@ -93,7 +93,7 @@ pub fn run( fs::remove_dir_all(&tmp_dir).ok(); } - out.info(&format!("Cloning into temporary directory...")); + out.info("Cloning into temporary directory..."); let status = std::process::Command::new("git") .args(["clone", "--depth", "1", &url, tmp_dir.to_str().unwrap()]) .status() @@ -139,14 +139,12 @@ pub fn run( let src = tmp_dir.join(&c.repo_path); let dst = source_dir.join(&c.dwell_path); - if dst.exists() { - if !all { - out.info(&format!("Skipping existing: {}", &c.dwell_path)); - skipped += 1; - continue; - } - // When --all, overwrite + if dst.exists() && !all { + out.info(&format!("Skipping existing: {}", c.dwell_path)); + skipped += 1; + continue; } + // When --all, overwrite if let Some(parent) = dst.parent() { fs::create_dir_all(parent).ok(); @@ -155,12 +153,12 @@ pub fn run( match fs::copy(&src, &dst) { Ok(_) => { if cli.verbose > 0 { - out.success(&format!(" {}", &c.dwell_path)); + out.success(&format!(" {}", c.dwell_path)); } copied += 1; } Err(e) => { - out.warn(&format!(" Failed: {}: {}", &c.dwell_path, e)); + out.warn(&format!(" Failed: {}: {}", c.dwell_path, e)); } } } @@ -182,9 +180,7 @@ pub fn run( fs::remove_dir_all(&tmp_dir).ok(); // Summary - out.info(&format!( - "Run 'dwell apply' to deploy, or 'dwell diff' to preview" - )); + out.info("Run 'dwell apply' to deploy, or 'dwell diff' to preview"); Ok(()) }