mod input;
mod merge;
mod normalize;
mod parse;
mod report;
#[cfg(test)]
mod tests;
use std::path::PathBuf;
use anyhow::{Context, Result};
use clap::Args;
use crate::config::Resolved;
use crate::queue;
use super::QueueImportFormat;
use input::read_input;
use merge::merge_imported_tasks;
use normalize::normalize_task;
use parse::{parse_csv_tasks, parse_json_tasks};
use report::ImportReport;
#[derive(Args)]
#[command(
after_long_help = "Examples:\n ralph queue export --format json | ralph queue import --format json --dry-run\n ralph queue import --format csv --input tasks.csv\n ralph queue import --format tsv --input - --on-duplicate rename < tasks.tsv\n ralph queue import --format json --input tasks.json --on-duplicate skip"
)]
pub struct QueueImportArgs {
#[arg(long, value_enum)]
pub format: QueueImportFormat,
#[arg(long, short)]
pub input: Option<PathBuf>,
#[arg(long)]
pub dry_run: bool,
#[arg(long, value_enum, default_value_t = OnDuplicate::Fail)]
pub on_duplicate: OnDuplicate,
}
#[derive(Clone, Copy, Debug, clap::ValueEnum)]
#[clap(rename_all = "snake_case")]
pub enum OnDuplicate {
Fail,
Skip,
Rename,
}
pub(crate) fn handle(resolved: &Resolved, force: bool, args: QueueImportArgs) -> Result<()> {
let _queue_lock = queue::acquire_queue_lock(&resolved.repo_root, "queue import", force)?;
let input = read_input(args.input.as_ref()).context("read import input")?;
let mut imported = match args.format {
QueueImportFormat::Json => parse_json_tasks(&input)?,
QueueImportFormat::Csv => parse_csv_tasks(&input, b',')?,
QueueImportFormat::Tsv => parse_csv_tasks(&input, b'\t')?,
};
let now = crate::timeutil::now_utc_rfc3339_or_fallback();
let max_depth = resolved.config.queue.max_dependency_depth.unwrap_or(10);
let (mut queue_file, done_file) = crate::queue::load_and_validate_queues(resolved, true)?;
let done_ref = done_file
.as_ref()
.filter(|done| !done.tasks.is_empty() || resolved.done_path.exists());
for task in &mut imported {
normalize_task(task, &now);
}
let report = merge_imported_tasks(
&mut queue_file,
done_ref,
imported,
&resolved.id_prefix,
resolved.id_width,
max_depth,
&now,
args.on_duplicate,
)?;
let warnings = queue::validate_queue_set(
&queue_file,
done_ref,
&resolved.id_prefix,
resolved.id_width,
max_depth,
)?;
queue::log_warnings(&warnings);
if !args.dry_run {
crate::undo::create_undo_snapshot(resolved, "queue import")?;
}
if args.dry_run {
log::info!("Dry run: no changes written. {}", report.summary());
return Ok(());
}
queue::save_queue(&resolved.queue_path, &queue_file)?;
log::info!("Imported tasks. {}", report.summary());
Ok(())
}