[feat] improve error handling for file operations and subprocess execution; refactor main to modularize execution flow

This commit is contained in:
2025-08-08 17:04:42 +02:00
parent c27af0b89a
commit a0216a0e18
3 changed files with 47 additions and 18 deletions

View File

@@ -1,8 +1,6 @@
use crate::OutputEntry; use crate::OutputEntry;
use crate::{decode_audio_to_pcm_f32_ffmpeg, find_model_file}; use crate::{decode_audio_to_pcm_f32_ffmpeg, find_model_file};
use anyhow::{Context, Result, anyhow}; use anyhow::{Context, Result, anyhow};
#[cfg(not(test))]
use libloading::Library;
use std::env; use std::env;
use std::path::Path; use std::path::Path;
@@ -52,15 +50,8 @@ fn check_lib(names: &[&str]) -> bool {
} }
#[cfg(not(test))] #[cfg(not(test))]
{ {
if std::env::var("POLYSCRIBE_DISABLE_DLOPEN").ok().as_deref() == Some("1") { // Disabled runtime dlopen probing to avoid loader instability; rely on environment overrides.
return false; let _ = names;
}
for n in names {
// Attempt to dlopen; ignore errors
if let Ok(_lib) = unsafe { Library::new(n) } {
return true;
}
}
false false
} }
} }

View File

@@ -302,7 +302,7 @@ pub fn find_model_file() -> Result<PathBuf> {
/// Decode an input media file to 16kHz mono f32 PCM using ffmpeg available on PATH. /// Decode an input media file to 16kHz mono f32 PCM using ffmpeg available on PATH.
pub fn decode_audio_to_pcm_f32_ffmpeg(audio_path: &Path) -> Result<Vec<f32>> { pub fn decode_audio_to_pcm_f32_ffmpeg(audio_path: &Path) -> Result<Vec<f32>> {
let output = Command::new("ffmpeg") let output = match Command::new("ffmpeg")
.arg("-i") .arg("-i")
.arg(audio_path) .arg(audio_path)
.arg("-f") .arg("-f")
@@ -313,7 +313,22 @@ pub fn decode_audio_to_pcm_f32_ffmpeg(audio_path: &Path) -> Result<Vec<f32>> {
.arg("16000") .arg("16000")
.arg("pipe:1") .arg("pipe:1")
.output() .output()
.with_context(|| format!("Failed to execute ffmpeg for {}", audio_path.display()))?; {
Ok(o) => o,
Err(e) => {
if e.kind() == std::io::ErrorKind::NotFound {
return Err(anyhow!(
"ffmpeg not found on PATH. Please install ffmpeg and ensure it is available."
));
} else {
return Err(anyhow!(
"Failed to execute ffmpeg for {}: {}",
audio_path.display(),
e
));
}
}
};
if !output.status.success() { if !output.status.success() {
return Err(anyhow!( return Err(anyhow!(
"ffmpeg failed for {}: {}", "ffmpeg failed for {}: {}",

View File

@@ -159,11 +159,15 @@ fn prompt_speaker_name_for_path(path: &Path, default_name: &str, enabled: bool)
let mut buf = String::new(); let mut buf = String::new();
match io::stdin().read_line(&mut buf) { match io::stdin().read_line(&mut buf) {
Ok(_) => { Ok(_) => {
let s = buf.trim(); let raw = buf.trim();
if s.is_empty() { if raw.is_empty() {
return default_name.to_string();
}
let sanitized = sanitize_speaker_name(raw);
if sanitized.is_empty() {
default_name.to_string() default_name.to_string()
} else { } else {
s.to_string() sanitized
} }
} }
Err(_) => default_name.to_string(), Err(_) => default_name.to_string(),
@@ -196,11 +200,16 @@ struct LastModelCleanup {
impl Drop for LastModelCleanup { impl Drop for LastModelCleanup {
fn drop(&mut self) { fn drop(&mut self) {
// Ensure .last_model does not persist across program runs // Ensure .last_model does not persist across program runs
let _ = std::fs::remove_file(&self.path); if let Err(e) = std::fs::remove_file(&self.path) {
// Best-effort cleanup; ignore missing file; warn for other errors
if e.kind() != std::io::ErrorKind::NotFound {
warnlog!("Failed to remove {}: {}", self.path.display(), e);
}
}
} }
} }
fn main() -> Result<()> { fn run() -> Result<()> {
// Parse CLI // Parse CLI
let args = Args::parse(); let args = Args::parse();
@@ -692,6 +701,20 @@ fn main() -> Result<()> {
Ok(()) Ok(())
} }
fn main() {
if let Err(e) = run() {
errorlog!("{}", e);
if VERBOSE.load(Ordering::Relaxed) >= 1 {
let mut src = e.source();
while let Some(s) = src {
errorlog!("caused by: {}", s);
src = s.source();
}
}
std::process::exit(1);
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;