dep.rs

 1use anyhow::{bail, Result};
 2use std::path::Path;
 3
 4use crate::cli::DepAction;
 5use crate::db;
 6
 7pub fn run(root: &Path, action: &DepAction, json: bool) -> Result<()> {
 8    let conn = db::open(root)?;
 9
10    match action {
11        DepAction::Add { child, parent } => {
12            if !db::task_exists(&conn, child)? {
13                bail!("task '{child}' not found");
14            }
15            if !db::task_exists(&conn, parent)? {
16                bail!("task '{parent}' not found");
17            }
18            if db::would_cycle(&conn, parent, child)? {
19                bail!("adding dependency would create a cycle: {child} → {parent} → … → {child}");
20            }
21            conn.execute(
22                "INSERT OR IGNORE INTO blockers (task_id, blocker_id) VALUES (?1, ?2)",
23                [child, parent],
24            )?;
25            conn.execute(
26                "UPDATE tasks SET updated = ?1 WHERE id = ?2",
27                rusqlite::params![db::now_utc(), child],
28            )?;
29            if json {
30                println!("{}", serde_json::json!({"child": child, "blocker": parent}));
31            } else {
32                let c = crate::color::stdout_theme();
33                println!(
34                    "{}{child}{} blocked by {}{parent}{}",
35                    c.green, c.reset, c.yellow, c.reset
36                );
37            }
38        }
39        DepAction::Rm { child, parent } => {
40            conn.execute(
41                "DELETE FROM blockers WHERE task_id = ?1 AND blocker_id = ?2",
42                [child, parent],
43            )?;
44            conn.execute(
45                "UPDATE tasks SET updated = ?1 WHERE id = ?2",
46                rusqlite::params![db::now_utc(), child],
47            )?;
48            if !json {
49                let c = crate::color::stdout_theme();
50                println!(
51                    "{}{child}{} no longer blocked by {}{parent}{}",
52                    c.green, c.reset, c.yellow, c.reset
53                );
54            }
55        }
56        DepAction::Tree { id } => {
57            println!("{id}");
58            let mut stmt = conn.prepare("SELECT id FROM tasks WHERE parent = ?1 ORDER BY id")?;
59            let children: Vec<String> = stmt
60                .query_map([id], |r| r.get(0))?
61                .collect::<rusqlite::Result<_>>()?;
62            for child in &children {
63                println!("  {child}");
64            }
65        }
66    }
67
68    Ok(())
69}