From 833ea447480f9d481d18de4b6b15915c0e5e6775 Mon Sep 17 00:00:00 2001 From: Eric Ratliff Date: Wed, 18 Feb 2026 17:59:17 -0600 Subject: [PATCH] Cleaned up old commands and updated menus --- Cargo.lock | 68 +-------- Cargo.toml | 5 +- src/board/mod.rs | 240 +++++++++++++++++++++++++++---- src/commands/build.rs | 305 ---------------------------------------- src/commands/mod.rs | 4 +- src/commands/monitor.rs | 167 ---------------------- src/commands/new.rs | 85 +++++++---- src/commands/setup.rs | 15 +- src/main.rs | 95 +------------ src/project/config.rs | 9 +- 10 files changed, 287 insertions(+), 706 deletions(-) delete mode 100644 src/commands/build.rs delete mode 100644 src/commands/monitor.rs diff --git a/Cargo.lock b/Cargo.lock index 04178eb..adb7283 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "aho-corasick" @@ -69,7 +69,6 @@ dependencies = [ "assert_cmd", "clap", "colored", - "ctrlc", "dirs", "home", "include_dir", @@ -115,15 +114,6 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" -[[package]] -name = "block2" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" -dependencies = [ - "objc2", -] - [[package]] name = "bstr" version = "1.12.1" @@ -141,12 +131,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - [[package]] name = "clap" version = "4.5.58" @@ -203,17 +187,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "ctrlc" -version = "3.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0b1fab2ae45819af2d0731d60f2afe17227ebb1a1538a236da84c93e9a60162" -dependencies = [ - "dispatch2", - "nix", - "windows-sys 0.61.2", -] - [[package]] name = "difflib" version = "0.4.0" @@ -241,18 +214,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "dispatch2" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" -dependencies = [ - "bitflags", - "block2", - "libc", - "objc2", -] - [[package]] name = "either" version = "1.15.0" @@ -415,18 +376,6 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" -[[package]] -name = "nix" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225e7cfe711e0ba79a68baeddb2982723e4235247aefce1482f2f16c27865b66" -dependencies = [ - "bitflags", - "cfg-if", - "cfg_aliases", - "libc", -] - [[package]] name = "normalize-line-endings" version = "0.3.0" @@ -442,21 +391,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "objc2" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" -dependencies = [ - "objc2-encode", -] - -[[package]] -name = "objc2-encode" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" - [[package]] name = "once_cell" version = "1.21.3" diff --git a/Cargo.toml b/Cargo.toml index 05bf241..9e0081e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,9 +40,6 @@ colored = "2.1" which = "5.0" home = "=0.5.9" -# Signal handling -ctrlc = "3.4" - [dev-dependencies] tempfile = "3.13" assert_cmd = "2.0" @@ -52,4 +49,4 @@ predicates = "3.1" opt-level = 3 lto = true codegen-units = 1 -strip = true +strip = true \ No newline at end of file diff --git a/src/board/mod.rs b/src/board/mod.rs index 0d36aa8..092c0f3 100644 --- a/src/board/mod.rs +++ b/src/board/mod.rs @@ -13,6 +13,22 @@ pub struct PortInfo { pub fqbn: String, } +impl PortInfo { + /// Returns true if this looks like a USB serial port rather than a + /// legacy motherboard COM port. + pub fn is_usb(&self) -> bool { + // arduino-cli labels USB ports "Serial Port (USB)" + if self.protocol.contains("USB") { + return true; + } + // Unix: ttyUSB* and ttyACM* are always USB + if self.port_name.contains("ttyUSB") || self.port_name.contains("ttyACM") { + return true; + } + false + } +} + /// JSON schema for `arduino-cli board list --format json` #[derive(Debug, Deserialize)] struct BoardListOutput { @@ -160,6 +176,36 @@ fn list_ports_fallback() -> Vec { result } +/// Pick the best default port from a list. Returns the index into the +/// slice, or None if the list is empty. +/// +/// Priority: +/// 1. A port with a recognized board (non-empty FQBN) +/// 2. A USB serial port (skip legacy motherboard COM ports) +/// 3. First port in the list +pub fn pick_default_port(ports: &[PortInfo]) -> Option { + if ports.is_empty() { + return None; + } + + // Prefer a port with a recognized FQBN + for (i, p) in ports.iter().enumerate() { + if !p.fqbn.is_empty() { + return Some(i); + } + } + + // Prefer a USB port over a legacy serial port + for (i, p) in ports.iter().enumerate() { + if p.is_usb() { + return Some(i); + } + } + + // Fall back to the first port + Some(0) +} + /// Auto-detect a single serial port. pub fn auto_detect_port() -> Result { let ports = list_ports(); @@ -171,35 +217,23 @@ pub fn auto_detect_port() -> Result { ); } - if ports.len() == 1 { - return Ok(ports[0].port_name.clone()); - } + let idx = pick_default_port(&ports).unwrap_or(0); - eprintln!("{}", "Multiple serial ports detected:".yellow()); - for p in &ports { - eprintln!(" {} ({})", p.port_name, p.board_name); - } - - // Prefer a port with a recognized board - for p in &ports { - if !p.fqbn.is_empty() { - eprintln!( - "{}", - format!( - "Auto-selected {} ({}). Use -p to override.", - p.port_name, p.board_name - ).yellow() - ); - return Ok(p.port_name.clone()); + if ports.len() > 1 { + eprintln!("{}", "Multiple serial ports detected:".yellow()); + for p in &ports { + eprintln!(" {} ({})", p.port_name, p.board_name); } + eprintln!( + "{}", + format!( + "Auto-selected {}. Use -p to override.", + ports[idx].port_name + ).yellow() + ); } - let selected = ports[0].port_name.clone(); - eprintln!( - "{}", - format!("Auto-selected {}. Use -p to override.", selected).yellow() - ); - Ok(selected) + Ok(ports[idx].port_name.clone()) } /// Print detailed port information. @@ -219,8 +253,18 @@ pub fn print_port_details(ports: &[PortInfo]) { return; } - for port in ports { - println!(" {}", port.port_name.green().bold()); + let default_idx = pick_default_port(ports); + + for (i, port) in ports.iter().enumerate() { + let is_default = default_idx == Some(i); + + if is_default { + print!(" {}", port.port_name.green().bold()); + println!(" {}", "<-- default".bright_green()); + } else { + println!(" {}", port.port_name.green().bold()); + } + println!(" Board: {}", port.board_name); if !port.fqbn.is_empty() { println!(" FQBN: {}", port.fqbn); @@ -254,6 +298,44 @@ pub fn print_port_details(ports: &[PortInfo]) { println!(); } + + // Only show override tip when there are multiple ports + if ports.len() > 1 { + if let Some(idx) = default_idx { + println!( + " Anvil will use {} when no port is specified.", + ports[idx].port_name.bright_white() + ); + println!(); + println!( + " {}", + "To select a different port, edit .anvil.toml in your project:" + .bright_white() + ); + println!(); + println!( + " {}", + "[monitor]".bright_cyan() + ); + println!( + " {}", + format!("port = \"{}\"", ports[idx].port_name).bright_cyan() + ); + println!(); + if cfg!(target_os = "windows") { + println!( + " Or pass it directly to the project scripts: {}", + format!("upload.bat -p {}", ports[idx].port_name).bright_cyan() + ); + } else { + println!( + " Or pass it directly to the project scripts: {}", + format!("./upload.sh -p {}", ports[idx].port_name).bright_cyan() + ); + } + println!(); + } + } } /// Find arduino-cli in PATH or in ~/.anvil/bin. @@ -342,4 +424,106 @@ mod tests { let boards = dp.matching_boards.as_ref().unwrap(); assert_eq!(boards[0].name, "Arduino Uno"); } -} + + #[test] + fn test_is_usb_from_protocol_label() { + let usb = PortInfo { + port_name: "COM3".to_string(), + protocol: "Serial Port (USB)".to_string(), + board_name: "Unknown".to_string(), + fqbn: String::new(), + }; + assert!(usb.is_usb()); + + let legacy = PortInfo { + port_name: "COM1".to_string(), + protocol: "Serial Port".to_string(), + board_name: "Unknown".to_string(), + fqbn: String::new(), + }; + assert!(!legacy.is_usb()); + } + + #[test] + fn test_is_usb_from_device_name() { + let usb = PortInfo { + port_name: "/dev/ttyUSB0".to_string(), + protocol: "serial".to_string(), + board_name: "Unknown".to_string(), + fqbn: String::new(), + }; + assert!(usb.is_usb()); + + let acm = PortInfo { + port_name: "/dev/ttyACM0".to_string(), + protocol: "serial".to_string(), + board_name: "Unknown".to_string(), + fqbn: String::new(), + }; + assert!(acm.is_usb()); + } + + #[test] + fn test_pick_default_prefers_fqbn() { + let ports = vec![ + PortInfo { + port_name: "COM1".to_string(), + protocol: "Serial Port".to_string(), + board_name: "Unknown".to_string(), + fqbn: String::new(), + }, + PortInfo { + port_name: "COM3".to_string(), + protocol: "Serial Port (USB)".to_string(), + board_name: "Arduino Uno".to_string(), + fqbn: "arduino:avr:uno".to_string(), + }, + ]; + assert_eq!(pick_default_port(&ports), Some(1)); + } + + #[test] + fn test_pick_default_prefers_usb_over_legacy() { + let ports = vec![ + PortInfo { + port_name: "COM1".to_string(), + protocol: "Serial Port".to_string(), + board_name: "Unknown".to_string(), + fqbn: String::new(), + }, + PortInfo { + port_name: "COM3".to_string(), + protocol: "Serial Port (USB)".to_string(), + board_name: "Unknown".to_string(), + fqbn: String::new(), + }, + PortInfo { + port_name: "COM4".to_string(), + protocol: "Serial Port (USB)".to_string(), + board_name: "Unknown".to_string(), + fqbn: String::new(), + }, + ]; + // Should skip COM1 and pick COM3 (first USB port) + assert_eq!(pick_default_port(&ports), Some(1)); + } + + #[test] + fn test_pick_default_empty() { + let ports: Vec = vec![]; + assert_eq!(pick_default_port(&ports), None); + } + + #[test] + fn test_pick_default_single() { + let ports = vec![ + PortInfo { + port_name: "COM1".to_string(), + protocol: "Serial Port".to_string(), + board_name: "Unknown".to_string(), + fqbn: String::new(), + }, + ]; + assert_eq!(pick_default_port(&ports), Some(0)); + } +} \ No newline at end of file diff --git a/src/commands/build.rs b/src/commands/build.rs deleted file mode 100644 index 74da099..0000000 --- a/src/commands/build.rs +++ /dev/null @@ -1,305 +0,0 @@ -use anyhow::{Result, bail, Context}; -use colored::*; -use std::path::{Path, PathBuf}; -use std::process::Command; - -use crate::board; -use crate::project::config::{ProjectConfig, build_cache_dir}; - -/// Full build: compile + upload (+ optional monitor). -pub fn run_build( - sketch: &str, - verify_only: bool, - do_monitor: bool, - do_clean: bool, - verbose: bool, - port: Option<&str>, - baud: Option, - fqbn_override: Option<&str>, -) -> Result<()> { - let sketch_path = resolve_sketch(sketch)?; - let sketch_name = sketch_name(&sketch_path)?; - let project_root = ProjectConfig::find_project_root(&sketch_path) - .ok(); - - // Load project config if available, otherwise use defaults - let config = match &project_root { - Some(root) => ProjectConfig::load(root)?, - None => { - eprintln!( - "{}", - "No .anvil.toml found; using default settings.".yellow() - ); - ProjectConfig::default() - } - }; - - let fqbn = fqbn_override.unwrap_or(&config.build.fqbn); - let monitor_baud = baud.unwrap_or(config.monitor.baud); - - println!("Sketch: {}", sketch_name.bright_white().bold()); - println!("Board: {}", fqbn.bright_white()); - - // Locate arduino-cli - let cli = board::find_arduino_cli() - .context("arduino-cli not found. Run: anvil setup")?; - - // Verify AVR core - if !board::is_avr_core_installed(&cli) { - bail!("arduino:avr core not installed. Run: anvil setup"); - } - - // Build cache directory - let cache_dir = build_cache_dir()?.join(&sketch_name); - - // Clean if requested - if do_clean && cache_dir.exists() { - println!("{}", "Cleaning build cache...".bright_yellow()); - std::fs::remove_dir_all(&cache_dir)?; - println!(" {} Cache cleared.", "ok".green()); - } - - // Compile - println!("{}", "Compiling...".bright_yellow()); - std::fs::create_dir_all(&cache_dir)?; - - let mut compile_args: Vec = vec![ - "compile".to_string(), - "--fqbn".to_string(), - fqbn.to_string(), - "--build-path".to_string(), - cache_dir.display().to_string(), - "--warnings".to_string(), - config.build.warnings.clone(), - ]; - - if verbose { - compile_args.push("--verbose".to_string()); - } - - // Inject project-level build flags (include paths, -Werror, etc.) - if let Some(ref root) = project_root { - let extra = config.extra_flags_string(root); - if !extra.is_empty() { - compile_args.push("--build-property".to_string()); - compile_args.push(format!("build.extra_flags={}", extra)); - } - } - - compile_args.push(sketch_path.display().to_string()); - - let status = Command::new(&cli) - .args(&compile_args) - .status() - .context("Failed to execute arduino-cli compile")?; - - if !status.success() { - bail!("Compilation failed."); - } - println!(" {} Compile succeeded.", "ok".green()); - - // Report binary size - report_binary_size(&cache_dir, &sketch_name); - - // Verify-only: stop here - if verify_only { - println!(); - println!(" {} Verify-only mode. Done.", "ok".green()); - return Ok(()); - } - - // Upload - let port = match port { - Some(p) => p.to_string(), - None => match &config.monitor.port { - Some(p) => p.clone(), - None => board::auto_detect_port()?, - }, - }; - - upload_to_board(&cli, fqbn, &port, &cache_dir, verbose)?; - - // Monitor - if do_monitor { - println!(); - println!( - "Opening serial monitor on {} at {} baud...", - port.bright_white(), - monitor_baud - ); - println!("Press Ctrl+C to exit."); - println!(); - - let _ = Command::new(&cli) - .args([ - "monitor", - "-p", &port, - "-c", &format!("baudrate={}", monitor_baud), - ]) - .status(); - } else { - println!(); - println!("To open serial monitor:"); - println!( - " anvil monitor -p {} -b {}", - port, monitor_baud - ); - } - - Ok(()) -} - -/// Upload cached build artifacts without recompiling. -pub fn run_upload_only( - sketch: &str, - port: Option<&str>, - verbose: bool, - fqbn_override: Option<&str>, -) -> Result<()> { - let sketch_path = resolve_sketch(sketch)?; - let sketch_name = sketch_name(&sketch_path)?; - let project_root = ProjectConfig::find_project_root(&sketch_path) - .ok(); - - let config = match &project_root { - Some(root) => ProjectConfig::load(root)?, - None => ProjectConfig::default(), - }; - - let fqbn = fqbn_override.unwrap_or(&config.build.fqbn); - - // Verify cached build exists - let cache_dir = build_cache_dir()?.join(&sketch_name); - if !cache_dir.exists() { - bail!( - "No cached build found for '{}'.\n\ - Run a compile first: anvil build --verify {}", - sketch_name, - sketch - ); - } - - let hex_name = format!("{}.ino.hex", sketch_name); - if !cache_dir.join(&hex_name).exists() { - bail!( - "Build cache exists but no .hex file found.\n\ - Try a clean rebuild: anvil build --clean {}", - sketch - ); - } - - println!(" {} Using cached build.", "ok".green()); - report_binary_size(&cache_dir, &sketch_name); - - let cli = board::find_arduino_cli() - .context("arduino-cli not found. Run: anvil setup")?; - - let port = match port { - Some(p) => p.to_string(), - None => match &config.monitor.port { - Some(p) => p.clone(), - None => board::auto_detect_port()?, - }, - }; - - upload_to_board(&cli, fqbn, &port, &cache_dir, verbose)?; - - Ok(()) -} - -/// Upload compiled artifacts to the board. -fn upload_to_board( - cli: &Path, - fqbn: &str, - port: &str, - input_dir: &Path, - verbose: bool, -) -> Result<()> { - println!( - "Uploading to {}...", - port.bright_white().bold() - ); - - let mut upload_args = vec![ - "upload".to_string(), - "--fqbn".to_string(), - fqbn.to_string(), - "--port".to_string(), - port.to_string(), - "--input-dir".to_string(), - input_dir.display().to_string(), - ]; - - if verbose { - upload_args.push("--verbose".to_string()); - } - - let status = Command::new(cli) - .args(&upload_args) - .status() - .context("Failed to execute arduino-cli upload")?; - - if !status.success() { - bail!( - "Upload failed. Run with --verbose for details.\n\ - Also try: anvil devices" - ); - } - - println!(" {} Upload complete!", "ok".green()); - Ok(()) -} - -/// Resolve sketch argument to an absolute path. -fn resolve_sketch(sketch: &str) -> Result { - let path = PathBuf::from(sketch); - let abs = if path.is_absolute() { - path - } else { - std::env::current_dir()?.join(&path) - }; - - // Canonicalize if it exists - let resolved = if abs.exists() { - abs.canonicalize().unwrap_or(abs) - } else { - abs - }; - - if !resolved.is_dir() { - bail!("Not a directory: {}", resolved.display()); - } - - Ok(resolved) -} - -/// Extract the sketch name from a path (basename of the directory). -fn sketch_name(sketch_path: &Path) -> Result { - let name = sketch_path - .file_name() - .context("Could not determine sketch name")? - .to_string_lossy() - .to_string(); - Ok(name) -} - -/// Report binary size using avr-size if available. -fn report_binary_size(cache_dir: &Path, sketch_name: &str) { - let elf_name = format!("{}.ino.elf", sketch_name); - let elf_path = cache_dir.join(&elf_name); - - if !elf_path.exists() { - return; - } - - if which::which("avr-size").is_err() { - return; - } - - println!(); - let _ = Command::new("avr-size") - .args(["--mcu=atmega328p", "-C"]) - .arg(&elf_path) - .status(); - println!(); -} diff --git a/src/commands/mod.rs b/src/commands/mod.rs index d016a5a..884cbcb 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -1,6 +1,4 @@ pub mod new; pub mod doctor; pub mod setup; -pub mod devices; -pub mod build; -pub mod monitor; +pub mod devices; \ No newline at end of file diff --git a/src/commands/monitor.rs b/src/commands/monitor.rs deleted file mode 100644 index e1d420a..0000000 --- a/src/commands/monitor.rs +++ /dev/null @@ -1,167 +0,0 @@ -use anyhow::{Result, Context}; -use colored::*; -use std::process::Command; -use std::time::Duration; -use std::thread; - -use crate::board; - -const DEFAULT_BAUD: u32 = 115200; - -pub fn run_monitor( - port: Option<&str>, - baud: Option, - watch: bool, -) -> Result<()> { - let cli = board::find_arduino_cli() - .context("arduino-cli not found. Run: anvil setup")?; - - let baud = baud.unwrap_or(DEFAULT_BAUD); - - if watch { - run_watch(&cli, port, baud) - } else { - run_single(&cli, port, baud) - } -} - -/// Open serial monitor once. -fn run_single( - cli: &std::path::Path, - port: Option<&str>, - baud: u32, -) -> Result<()> { - let port = match port { - Some(p) => p.to_string(), - None => board::auto_detect_port()?, - }; - - println!( - "Opening serial monitor on {} at {} baud...", - port.bright_white().bold(), - baud - ); - println!("Press Ctrl+C to exit."); - println!(); - - let status = Command::new(cli) - .args([ - "monitor", - "-p", &port, - "-c", &format!("baudrate={}", baud), - ]) - .status() - .context("Failed to start serial monitor")?; - - if !status.success() { - anyhow::bail!("Serial monitor exited with error."); - } - - Ok(()) -} - -/// Persistent watch mode: reconnect after upload/reset/replug. -fn run_watch( - cli: &std::path::Path, - port_hint: Option<&str>, - baud: u32, -) -> Result<()> { - let port = match port_hint { - Some(p) => p.to_string(), - None => { - match board::auto_detect_port() { - Ok(p) => p, - Err(_) => { - let default = default_port(); - println!( - "No port detected yet. Waiting for {}...", - default - ); - default - } - } - } - }; - - println!( - "Persistent monitor on {} at {} baud", - port.bright_white().bold(), - baud - ); - println!("Reconnects automatically after upload / reset / replug."); - println!("Press Ctrl+C to exit."); - println!(); - - let running = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(true)); - let r = running.clone(); - let _ = ctrlc::set_handler(move || { - r.store(false, std::sync::atomic::Ordering::Relaxed); - }); - - while running.load(std::sync::atomic::Ordering::Relaxed) { - if !port_exists(&port) { - println!( - "{}", - format!("--- Waiting for {} ...", port).bright_black() - ); - while !port_exists(&port) - && running.load(std::sync::atomic::Ordering::Relaxed) - { - thread::sleep(Duration::from_millis(500)); - } - - if !running.load(std::sync::atomic::Ordering::Relaxed) { - break; - } - - // Settle time - thread::sleep(Duration::from_secs(1)); - println!("{}", format!("--- {} connected ---", port).green()); - } - - let _ = Command::new(cli.as_os_str()) - .args([ - "monitor", - "-p", &port, - "-c", &format!("baudrate={}", baud), - ]) - .status(); - - if !running.load(std::sync::atomic::Ordering::Relaxed) { - break; - } - - println!( - "{}", - format!("--- {} disconnected ---", port).yellow() - ); - thread::sleep(Duration::from_millis(500)); - } - - println!(); - println!("Monitor stopped."); - Ok(()) -} - -fn port_exists(port: &str) -> bool { - #[cfg(unix)] - { - std::path::Path::new(port).exists() - } - - #[cfg(windows)] - { - // On Windows, check if the port appears in current device list - board::list_ports() - .iter() - .any(|p| p.port_name == port) - } -} - -fn default_port() -> String { - if cfg!(target_os = "windows") { - "COM3".to_string() - } else { - "/dev/ttyUSB0".to_string() - } -} diff --git a/src/commands/new.rs b/src/commands/new.rs index 250168b..aa05a42 100644 --- a/src/commands/new.rs +++ b/src/commands/new.rs @@ -201,32 +201,63 @@ fn print_next_steps(project_name: &str) { " 1. {}", format!("cd {}", project_name).bright_cyan() ); - println!( - " 2. Compile: {}", - "./build.sh".bright_cyan() - ); - println!( - " 3. Upload to board: {}", - "./upload.sh".bright_cyan() - ); - println!( - " 4. Upload + monitor: {}", - "./upload.sh --monitor".bright_cyan() - ); - println!( - " 5. Serial monitor: {}", - "./monitor.sh".bright_cyan() - ); - println!( - " 6. Run host tests: {}", - "./test/run_tests.sh".bright_cyan() - ); - println!(); - println!( - " {}", - "On Windows: build.bat, upload.bat, monitor.bat, test\\run_tests.bat" - .bright_black() - ); + + if cfg!(target_os = "windows") { + println!( + " 2. Compile: {}", + "build.bat".bright_cyan() + ); + println!( + " 3. Upload to board: {}", + "upload.bat".bright_cyan() + ); + println!( + " 4. Upload + monitor: {}", + "upload.bat --monitor".bright_cyan() + ); + println!( + " 5. Serial monitor: {}", + "monitor.bat".bright_cyan() + ); + println!( + " 6. Run host tests: {}", + "test\\run_tests.bat".bright_cyan() + ); + println!(); + println!( + " {}", + "On Linux/macOS: ./build.sh, ./upload.sh, ./monitor.sh" + .bright_black() + ); + } else { + println!( + " 2. Compile: {}", + "./build.sh".bright_cyan() + ); + println!( + " 3. Upload to board: {}", + "./upload.sh".bright_cyan() + ); + println!( + " 4. Upload + monitor: {}", + "./upload.sh --monitor".bright_cyan() + ); + println!( + " 5. Serial monitor: {}", + "./monitor.sh".bright_cyan() + ); + println!( + " 6. Run host tests: {}", + "./test/run_tests.sh".bright_cyan() + ); + println!(); + println!( + " {}", + "On Windows: build.bat, upload.bat, monitor.bat, test\\run_tests.bat" + .bright_black() + ); + } + println!( " {}", "System check: anvil doctor | Port scan: anvil devices" @@ -267,4 +298,4 @@ mod tests { let long_name = "a".repeat(51); assert!(validate_project_name(&long_name).is_err()); } -} +} \ No newline at end of file diff --git a/src/commands/setup.rs b/src/commands/setup.rs index 1f07359..be333ab 100644 --- a/src/commands/setup.rs +++ b/src/commands/setup.rs @@ -139,10 +139,17 @@ pub fn run_setup() -> Result<()> { println!(" 1. Plug in your RedBoard"); println!(" 2. {}", "anvil devices".bright_cyan()); println!(" 3. {}", "anvil new blink".bright_cyan()); - println!( - " 4. {}", - "cd blink && anvil build blink".bright_cyan() - ); + if cfg!(target_os = "windows") { + println!( + " 4. {}", + "cd blink && build.bat".bright_cyan() + ); + } else { + println!( + " 4. {}", + "cd blink && ./build.sh".bright_cyan() + ); + } println!(); Ok(()) diff --git a/src/main.rs b/src/main.rs index 48d52fe..30a2710 100644 --- a/src/main.rs +++ b/src/main.rs @@ -44,73 +44,6 @@ enum Commands { /// List connected boards and serial ports Devices, - - /// Compile a sketch (and optionally upload) - Build { - /// Path to sketch directory - sketch: String, - - /// Compile only -- do not upload - #[arg(long)] - verify: bool, - - /// Open serial monitor after upload - #[arg(long)] - monitor: bool, - - /// Delete cached build artifacts first - #[arg(long)] - clean: bool, - - /// Show full compiler output - #[arg(long)] - verbose: bool, - - /// Serial port (auto-detected if omitted) - #[arg(short, long)] - port: Option, - - /// Serial monitor baud rate - #[arg(short, long)] - baud: Option, - - /// Override Fully Qualified Board Name - #[arg(long)] - fqbn: Option, - }, - - /// Upload cached build artifacts (no recompile) - Upload { - /// Path to sketch directory - sketch: String, - - /// Serial port (auto-detected if omitted) - #[arg(short, long)] - port: Option, - - /// Show full avrdude output - #[arg(long)] - verbose: bool, - - /// Override Fully Qualified Board Name - #[arg(long)] - fqbn: Option, - }, - - /// Open serial monitor - Monitor { - /// Serial port (auto-detected if omitted) - #[arg(short, long)] - port: Option, - - /// Baud rate (default: from project config or 115200) - #[arg(short, long)] - baud: Option, - - /// Persistent mode: reconnect after upload/reset/replug - #[arg(long)] - watch: bool, - }, } fn main() -> Result<()> { @@ -133,7 +66,7 @@ fn main() -> Result<()> { } else { anyhow::bail!( "Project name required.\n\ - Usage: anvil new \n\ + Usage: anvil new \n\ List templates: anvil new --list-templates" ); } @@ -147,30 +80,6 @@ fn main() -> Result<()> { Commands::Devices => { commands::devices::scan_devices() } - Commands::Build { - sketch, verify, monitor, clean, verbose, - port, baud, fqbn, - } => { - commands::build::run_build( - &sketch, verify, monitor, clean, verbose, - port.as_deref(), baud, fqbn.as_deref(), - ) - } - Commands::Upload { sketch, port, verbose, fqbn } => { - commands::build::run_upload_only( - &sketch, - port.as_deref(), - verbose, - fqbn.as_deref(), - ) - } - Commands::Monitor { port, baud, watch } => { - commands::monitor::run_monitor( - port.as_deref(), - baud, - watch, - ) - } } } @@ -193,4 +102,4 @@ fn print_banner() { .bright_cyan() ); println!(); -} +} \ No newline at end of file diff --git a/src/project/config.rs b/src/project/config.rs index cb0614d..8691edf 100644 --- a/src/project/config.rs +++ b/src/project/config.rs @@ -146,13 +146,6 @@ pub fn anvil_home() -> Result { Ok(anvil_dir) } -/// Return the build cache directory (~/.anvil/builds). -pub fn build_cache_dir() -> Result { - let dir = anvil_home()?.join("builds"); - fs::create_dir_all(&dir)?; - Ok(dir) -} - #[cfg(test)] mod tests { use super::*; @@ -226,4 +219,4 @@ mod tests { assert!(flags.contains("-Werror")); assert!(flags.contains("-I")); } -} +} \ No newline at end of file