fix cleaning 🐛
This commit is contained in:
@@ -81,6 +81,7 @@ chrono = { version = "0.4", features = ["serde"] }
|
|||||||
# CLI
|
# CLI
|
||||||
clap = { version = "4.5", features = ["derive"] }
|
clap = { version = "4.5", features = ["derive"] }
|
||||||
indicatif = "0.17"
|
indicatif = "0.17"
|
||||||
|
inquire = "0.7"
|
||||||
|
|
||||||
# Error handling
|
# Error handling
|
||||||
thiserror = "2.0"
|
thiserror = "2.0"
|
||||||
|
|||||||
@@ -31,5 +31,6 @@ tokio = { workspace = true }
|
|||||||
futures = { workspace = true }
|
futures = { workspace = true }
|
||||||
clap = { workspace = true }
|
clap = { workspace = true }
|
||||||
indicatif = { workspace = true }
|
indicatif = { workspace = true }
|
||||||
|
inquire = { workspace = true }
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
chrono = { workspace = true }
|
chrono = { workspace = true }
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
//! Background job status command.
|
//! Background job status command.
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
|
use inquire::Select;
|
||||||
use paracas_daemon::{DownloadJob, JobStatus, StateManager};
|
use paracas_daemon::{DownloadJob, JobStatus, StateManager};
|
||||||
|
|
||||||
/// Execute the status command.
|
/// Execute the status command.
|
||||||
@@ -15,8 +16,11 @@ pub(crate) fn status(
|
|||||||
StateManager::with_default_path().context("Failed to initialize state manager")?;
|
StateManager::with_default_path().context("Failed to initialize state manager")?;
|
||||||
|
|
||||||
// Handle cancellation request
|
// Handle cancellation request
|
||||||
|
// cancel_id is Some("") when --cancel is passed without a value
|
||||||
|
// cancel_id is Some(id) when --cancel <id> is passed
|
||||||
if let Some(id) = cancel_id {
|
if let Some(id) = cancel_id {
|
||||||
return cancel_job(&state_manager, id);
|
let id_opt = if id.is_empty() { None } else { Some(id) };
|
||||||
|
return cancel_job(&state_manager, id_opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle follow/watch mode
|
// Handle follow/watch mode
|
||||||
@@ -133,8 +137,63 @@ fn list_jobs(state: &StateManager, running_only: bool, show_all: bool) -> Result
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cancel_job(state: &StateManager, job_id: &str) -> Result<()> {
|
/// Prompt user to select a job from available cancellable jobs.
|
||||||
let id = job_id.parse().context("Invalid job ID format")?;
|
fn prompt_cancel_selection(state: &StateManager) -> Result<String> {
|
||||||
|
let jobs = state.list_jobs()?;
|
||||||
|
|
||||||
|
let filtered: Vec<_> = jobs
|
||||||
|
.into_iter()
|
||||||
|
.filter(|job| matches!(job.status, JobStatus::Running | JobStatus::Pending))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if filtered.is_empty() {
|
||||||
|
anyhow::bail!("No running or pending jobs found to cancel.");
|
||||||
|
}
|
||||||
|
|
||||||
|
let options: Vec<String> = filtered
|
||||||
|
.iter()
|
||||||
|
.map(|job| {
|
||||||
|
let instruments: Vec<_> = job.tasks.iter().map(|t| t.instrument_id.as_str()).collect();
|
||||||
|
let instruments_display = if instruments.len() > 3 {
|
||||||
|
format!(
|
||||||
|
"{}, ... (+{} more)",
|
||||||
|
instruments[..3].join(", "),
|
||||||
|
instruments.len() - 3
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
instruments.join(", ")
|
||||||
|
};
|
||||||
|
format!(
|
||||||
|
"{} | {:?} | {:.1}% | {}",
|
||||||
|
job.id,
|
||||||
|
job.status,
|
||||||
|
job.progress_percent(),
|
||||||
|
instruments_display
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let selection = Select::new("Select a job to cancel:", options)
|
||||||
|
.prompt()
|
||||||
|
.context("Job selection cancelled")?;
|
||||||
|
|
||||||
|
// Extract the job ID from the selection (first part before " | ")
|
||||||
|
let job_id = selection
|
||||||
|
.split(" | ")
|
||||||
|
.next()
|
||||||
|
.context("Failed to parse job selection")?
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
Ok(job_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cancel_job(state: &StateManager, job_id: Option<&str>) -> Result<()> {
|
||||||
|
let id_str = match job_id {
|
||||||
|
Some(id) => id.to_string(),
|
||||||
|
None => prompt_cancel_selection(state)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
let id = id_str.parse().context("Invalid job ID format")?;
|
||||||
|
|
||||||
let mut job: DownloadJob = state.load_job(id).context("Job not found")?;
|
let mut job: DownloadJob = state.load_job(id).context("Job not found")?;
|
||||||
|
|
||||||
|
|||||||
+13
-11
@@ -104,8 +104,8 @@ enum Commands {
|
|||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
follow: Option<u64>,
|
follow: Option<u64>,
|
||||||
|
|
||||||
/// Cancel a running job
|
/// Cancel a running job (prompts for selection if no job ID provided)
|
||||||
#[arg(long)]
|
#[arg(long, num_args = 0..=1, default_missing_value = "")]
|
||||||
cancel: Option<String>,
|
cancel: Option<String>,
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -164,20 +164,20 @@ enum Commands {
|
|||||||
enum JobAction {
|
enum JobAction {
|
||||||
/// Pause a running job
|
/// Pause a running job
|
||||||
Pause {
|
Pause {
|
||||||
/// Job ID to pause
|
/// Job ID to pause (if omitted, prompts for selection)
|
||||||
job_id: String,
|
job_id: Option<String>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Resume a paused job
|
/// Resume a paused job
|
||||||
Resume {
|
Resume {
|
||||||
/// Job ID to resume
|
/// Job ID to resume (if omitted, prompts for selection)
|
||||||
job_id: String,
|
job_id: Option<String>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Kill a running or paused job
|
/// Kill a running or paused job
|
||||||
Kill {
|
Kill {
|
||||||
/// Job ID to kill
|
/// Job ID to kill (if omitted, prompts for selection)
|
||||||
job_id: String,
|
job_id: Option<String>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Clean up finished jobs from storage
|
/// Clean up finished jobs from storage
|
||||||
@@ -269,12 +269,14 @@ async fn main() -> Result<()> {
|
|||||||
}
|
}
|
||||||
Commands::Job { action } => match action {
|
Commands::Job { action } => match action {
|
||||||
JobAction::Pause { job_id } => {
|
JobAction::Pause { job_id } => {
|
||||||
commands::job::job_command("pause", Some(&job_id), false)
|
commands::job::job_command("pause", job_id.as_deref(), false)
|
||||||
}
|
}
|
||||||
JobAction::Resume { job_id } => {
|
JobAction::Resume { job_id } => {
|
||||||
commands::job::job_command("resume", Some(&job_id), false)
|
commands::job::job_command("resume", job_id.as_deref(), false)
|
||||||
|
}
|
||||||
|
JobAction::Kill { job_id } => {
|
||||||
|
commands::job::job_command("kill", job_id.as_deref(), false)
|
||||||
}
|
}
|
||||||
JobAction::Kill { job_id } => commands::job::job_command("kill", Some(&job_id), false),
|
|
||||||
JobAction::Clean { all } => commands::job::job_command("clean", None, all),
|
JobAction::Clean { all } => commands::job::job_command("clean", None, all),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user