use std::io::IsTerminal;
use std::path::PathBuf;
use crate::config::Config;
use crate::error::{Result, TixError};
use crate::planning::Planner;
use crate::storage::{IssueSelector, Store};
fn root_from_store(store: &Store) -> PathBuf {
Config::project_root(&store.issues_dir).unwrap_or_else(|| PathBuf::from("."))
}
pub fn run(config: &Config, store: &Store, cycle: Option<&str>, yes: bool) -> Result<()> {
let planner = Planner::from_config(config.clone(), root_from_store(store));
let today = crate::model::today();
let mut plan = planner.rollover_plan(store, &today);
if let Some(cycle) = cycle {
plan.retain(|target| target.from_cycle == cycle);
}
if plan.is_empty() {
println!("no rollover needed");
return Ok(());
}
let mut confirmed = yes || !std::io::stdin().is_terminal();
if !confirmed {
let total: usize = plan.iter().map(|t| t.issues.len()).sum();
eprint!("Apply rollover for {total} issue(s)? [y/N] ");
let mut line = String::new();
std::io::stdin()
.read_line(&mut line)
.map_err(TixError::Io)?;
confirmed = line.trim().eq_ignore_ascii_case("y");
}
if !confirmed {
eprintln!("aborted");
return Ok(());
}
for target in plan {
let mut moved = 0usize;
for number in target.issues {
let mut issue = store.get(IssueSelector::Number(number))?;
let mut cycles = issue.cycles.take().unwrap_or_default();
if cycles.iter().any(|c| c == &target.to_cycle) {
continue;
}
cycles.retain(|c| c != &target.from_cycle);
cycles.push(target.to_cycle.clone());
issue.cycles = Some(cycles);
issue.bump_updated();
store.update(&issue.filename, &issue)?;
moved += 1;
}
println!(
"moved {moved} issue(s) from \"{}\" to \"{}\"",
target.from_cycle, target.to_cycle
);
}
Ok(())
}