Skip to main content

sift_queue/cli/commands/
add.rs

1use crate::queue::{Queue, Source};
2use crate::AddArgs;
3use anyhow::Result;
4use std::io::Read;
5use std::path::PathBuf;
6
7/// Execute the `sq add` command.
8pub fn execute(args: &AddArgs, queue_path: PathBuf) -> Result<i32> {
9    let queue = Queue::new(queue_path);
10
11    let mut sources: Vec<Source> = Vec::new();
12
13    for path in &args.diff {
14        sources.push(Source {
15            type_: "diff".to_string(),
16            path: Some(path.clone()),
17            content: None,
18            session_id: None,
19        });
20    }
21
22    for path in &args.file {
23        sources.push(Source {
24            type_: "file".to_string(),
25            path: Some(path.clone()),
26            content: None,
27            session_id: None,
28        });
29    }
30
31    for text in &args.text {
32        sources.push(Source {
33            type_: "text".to_string(),
34            path: None,
35            content: Some(text.clone()),
36            session_id: None,
37        });
38    }
39
40    for path in &args.directory {
41        sources.push(Source {
42            type_: "directory".to_string(),
43            path: Some(path.clone()),
44            content: None,
45            session_id: None,
46        });
47    }
48
49    if let Some(ref stdin_type) = args.stdin {
50        let mut content = String::new();
51        std::io::stdin().read_to_string(&mut content)?;
52        sources.push(Source {
53            type_: stdin_type.clone(),
54            path: None,
55            content: Some(content),
56            session_id: None,
57        });
58    }
59
60    let has_source = !sources.is_empty();
61    let has_description = args.description.is_some();
62    let has_title = args.title.is_some();
63    let has_metadata = args.metadata.is_some();
64
65    if !has_source && !has_description && !has_title && !has_metadata {
66        eprintln!(
67            "Error: At least one of --description, --title, --metadata, or a source is required"
68        );
69        eprintln!("Use --diff, --file, --text, --directory, --stdin, --description, --title, or --metadata");
70        return Ok(1);
71    }
72
73    let metadata = match &args.metadata {
74        Some(json_str) => match serde_json::from_str(json_str) {
75            Ok(v) => v,
76            Err(e) => {
77                eprintln!("Error: Invalid JSON for metadata: {}", e);
78                return Ok(1);
79            }
80        },
81        None => serde_json::Value::Object(serde_json::Map::new()),
82    };
83
84    let blocked_by: Vec<String> = match &args.blocked_by {
85        Some(ids) => ids
86            .split(',')
87            .map(|s| s.trim().to_string())
88            .filter(|s| !s.is_empty())
89            .collect(),
90        None => Vec::new(),
91    };
92
93    let item = queue.push_with_description(
94        sources,
95        args.title.clone(),
96        args.description.clone(),
97        metadata,
98        None,
99        blocked_by,
100    )?;
101
102    if args.json {
103        let json = serde_json::to_string_pretty(&item.to_json_value())?;
104        println!("{}", json);
105    } else {
106        println!("{}", item.id);
107        eprintln!(
108            "Added item {} with {} source(s)",
109            item.id,
110            item.sources.len()
111        );
112    }
113
114    Ok(0)
115}