use std::path::PathBuf;
use crate::config::{ConfigProvider, WorkflowConfig};
use crate::error::Result;
use crate::internal_handlers::handle;
use crate::item::Item;
use crate::response::Response;
use crate::sort_and_filter::filter_and_sort_items;
#[derive(Debug)]
pub struct Workflow {
pub config: WorkflowConfig,
pub response: Response,
pub keyword: Option<String>,
pub(crate) sort_and_filter_results: bool,
}
impl Workflow {
pub fn new(config: WorkflowConfig) -> Result<Self> {
std::fs::create_dir_all(&config.workflow_data)?;
std::fs::create_dir_all(&config.workflow_cache)?;
Ok(Workflow {
config,
response: Response::default(),
keyword: None,
sort_and_filter_results: false,
})
}
pub fn set_filter_keyword(&mut self, keyword: String) {
self.keyword = Some(keyword);
self.sort_and_filter_results = true;
}
pub fn items(&mut self, items: Vec<Item>) {
self.response.items(items);
}
pub fn prepend_item(&mut self, item: Item) {
self.response.prepend_items(vec![item]);
}
pub fn prepend_items(&mut self, items: Vec<Item>) {
self.response.prepend_items(items);
}
pub fn append_items(&mut self, items: Vec<Item>) {
self.response.append_items(items);
}
pub fn append_item(&mut self, item: Item) {
self.response.append_items(vec![item]);
}
pub fn skip_knowledge(&mut self, skip: bool) {
self.response.skip_knowledge(skip);
}
pub fn cache(&mut self, duration: std::time::Duration, loose_reload: bool) {
self.response.cache(duration, loose_reload);
}
pub fn rerun(&mut self, interval: std::time::Duration) {
self.response.rerun(interval);
}
pub fn data_dir(&self) -> PathBuf {
self.config.workflow_data.clone()
}
pub fn cache_dir(&self) -> PathBuf {
self.config.workflow_cache.clone()
}
}
pub fn setup_workflow(provider: &dyn ConfigProvider) -> Workflow {
let config = match provider.config() {
Ok(c) => c,
Err(e) => {
eprintln!("Error loading config: {e}");
std::process::exit(1);
}
};
let mut workflow = match Workflow::new(config) {
Ok(workflow) => workflow,
Err(e) => {
eprintln!("Error creating workflow: {e}");
std::process::exit(1);
}
};
if handle(&mut workflow) {
std::process::exit(0);
}
workflow
}
pub fn finalize_workflow(mut workflow: Workflow, writer: &mut dyn std::io::Write) {
if workflow.sort_and_filter_results {
if let Some(keyword) = workflow.keyword.clone() {
workflow.response.items = filter_and_sort_items(workflow.response.items, keyword);
}
}
match workflow.response.write(writer) {
Ok(_) => {}
Err(e) => {
eprintln!("Error writing response: {e}");
std::process::exit(1);
}
}
}
#[cfg(test)]
mod tests {
use std::io::Cursor;
use tempfile::TempDir;
use super::*;
use crate::config::{self, ConfigProvider};
fn test_workflow() -> (Workflow, TempDir) {
let dir = tempfile::tempdir().unwrap();
let config = config::TestingProvider(dir.path().into()).config().unwrap();
(Workflow::new(config).unwrap(), dir)
}
#[test]
fn test_new_workflow() {
let (workflow, _dir) = test_workflow();
assert_eq!(workflow.response.items.len(), 0);
assert_eq!(workflow.keyword, None);
assert!(!workflow.sort_and_filter_results);
}
#[test]
fn test_prepend_item() {
let (mut workflow, _dir) = test_workflow();
let initial_item = Item::new("Initial Item");
workflow.items(vec![initial_item]);
let prepended_item = Item::new("Prepended Item");
workflow.prepend_item(prepended_item);
assert_eq!(workflow.response.items.len(), 2);
assert_eq!(workflow.response.items[0].title, "Prepended Item");
assert_eq!(workflow.response.items[1].title, "Initial Item");
}
#[test]
fn test_prepend_items() {
let (mut workflow, _dir) = test_workflow();
workflow.items(vec![
Item::new("First Item"),
Item::new("Second Item"),
Item::new("Third Item"),
]);
let prepended_items = vec![
Item::new("Prepended Item 1"),
Item::new("Prepended Item 2"),
Item::new("Prepended Item 3"),
];
workflow.prepend_items(prepended_items);
assert_eq!(workflow.response.items.len(), 6);
assert_eq!(workflow.response.items[0].title, "Prepended Item 1");
assert_eq!(workflow.response.items[1].title, "Prepended Item 2");
assert_eq!(workflow.response.items[3].title, "First Item");
assert_eq!(workflow.response.items[5].title, "Third Item");
}
#[test]
fn test_append_item() {
let (mut workflow, _dir) = test_workflow();
let initial_item = Item::new("Initial Item");
workflow.items(vec![initial_item]);
let appended_item = Item::new("Appended Item");
workflow.append_item(appended_item);
assert_eq!(workflow.response.items.len(), 2);
assert_eq!(workflow.response.items[0].title, "Initial Item");
assert_eq!(workflow.response.items[1].title, "Appended Item");
}
#[test]
fn test_append_items() {
let (mut workflow, _dir) = test_workflow();
workflow.items(vec![
Item::new("First Item"),
Item::new("Second Item"),
Item::new("Third Item"),
]);
let appended_items = vec![
Item::new("Appended Item 1"),
Item::new("Appended Item 2"),
Item::new("Appended Item 3"),
];
workflow.append_items(appended_items);
assert_eq!(workflow.response.items.len(), 6);
assert_eq!(workflow.response.items[0].title, "First Item");
assert_eq!(workflow.response.items[3].title, "Appended Item 1");
assert_eq!(workflow.response.items[5].title, "Appended Item 3");
}
#[test]
fn test_finalize_workflow_with_filtering() {
let (mut workflow, _dir) = test_workflow();
workflow.items(vec![
Item::new("Apple").subtitle("Fruit"),
Item::new("Banana").subtitle("Fruit"),
Item::new("Carrot").subtitle("Vegetable"),
]);
workflow.set_filter_keyword("fruit".to_string());
let mut buffer = Cursor::new(Vec::new());
finalize_workflow(workflow, &mut buffer);
let output = String::from_utf8(buffer.into_inner()).unwrap();
assert!(output.contains("Apple"));
assert!(output.contains("Banana"));
assert!(!output.contains("Carrot"));
}
#[test]
fn test_finalize_workflow_without_filtering() {
let (mut workflow, _dir) = test_workflow();
workflow.items(vec![
Item::new("Apple").subtitle("Fruit"),
Item::new("Banana").subtitle("Fruit"),
Item::new("Carrot").subtitle("Vegetable"),
]);
let mut buffer = Cursor::new(Vec::new());
finalize_workflow(workflow, &mut buffer);
let output = String::from_utf8(buffer.into_inner()).unwrap();
assert!(output.contains("Apple"));
assert!(output.contains("Banana"));
assert!(output.contains("Carrot"));
}
#[test]
fn test_setup_workflow() {
let dir = tempfile::tempdir().unwrap().keep();
let provider = config::TestingProvider(dir);
let workflow = setup_workflow(&provider);
assert_eq!(workflow.response.items.len(), 0);
assert_eq!(workflow.keyword, None);
assert!(!workflow.sort_and_filter_results);
assert!(provider.0.join("workflow_data").exists());
assert!(provider.0.join("workflow_cache").exists());
}
#[test]
fn test_cache_method() {
let (mut workflow, _dir) = test_workflow();
workflow.cache(std::time::Duration::from_secs(300), true);
let mut buffer = std::io::Cursor::new(Vec::new());
workflow.response.write(&mut buffer).unwrap();
let output = String::from_utf8(buffer.into_inner()).unwrap();
assert!(output.contains("\"cache\":{\"seconds\":300,\"loosereload\":true}"));
}
#[test]
fn test_rerun_method() {
let (mut workflow, _dir) = test_workflow();
workflow.rerun(std::time::Duration::from_secs(30));
let mut buffer = std::io::Cursor::new(Vec::new());
workflow.response.write(&mut buffer).unwrap();
let output = String::from_utf8(buffer.into_inner()).unwrap();
assert!(output.contains("\"rerun\":30"));
}
}