task_hookrs/
tw.rs

1//
2// This Source Code Form is subject to the terms of the Mozilla Public
3// License, v. 2.0. If a copy of the MPL was not distributed with this
4// file, You can obtain one at http://mozilla.org/MPL/2.0/.
5//
6
7//! This module offers functions to interact with taskwarrior. This will expect the `task` binary
8//! in your path. This will always call task and never interact with your `.task` directory itself.
9//! (This is in accordance with the taskwarrior api guide lines.)
10
11use crate::error::Error;
12use crate::import::import;
13use crate::task::Task;
14use std::io::Write;
15use std::iter::once;
16use std::process::{Child, Command, Stdio};
17
18use serde_json;
19
20/// This will give you all tasks which match the given query in the taskwarrior query syntax.
21/// This is not sanitized. Never get the query string from an untrusted user.
22pub fn query(query: &str) -> Result<Vec<Task>, Error> {
23    let mut cmd = add_query_to_cmd(query, Command::new("task"));
24    cmd.stdout(Stdio::piped());
25    run_query_cmd(cmd)
26}
27
28/// This will take a Command, and append the given query string splited at whitespace followed by
29/// the "export" command to the arguments of the Command.
30pub fn add_query_to_cmd(query: &str, mut cmd: Command) -> Command {
31    for x in query.split_whitespace().chain(once("export")) {
32        cmd.arg(x);
33    }
34    cmd
35}
36
37/// This executes the given Command and trys to convert the Result into a Vec<Task>.
38pub fn run_query_cmd(mut cmd: Command) -> Result<Vec<Task>, Error> {
39    let mut export = cmd.spawn()?;
40    export.wait()?;
41    import(export.stdout.ok_or(Error::TaskCmdError)?)
42}
43
44/// This function runs the given Command, pipes the tasks as JSON to it and returns a handle to the child process.
45pub fn save_to_cmd(tasks: Vec<&'_ Task>, mut cmd: Command) -> Result<Child, Error> {
46    let input_buffer = serde_json::to_string(&tasks)?;
47    let mut import = cmd.spawn()?;
48    import
49        .stdin
50        .as_mut()
51        .ok_or(Error::TaskCmdError)?
52        .write_all(input_buffer.as_bytes())?;
53    Ok(import)
54}
55
56/// This will save the given tasks to taskwarrior. Call with `Some(&task)` if you just have one
57/// task.
58/// This will block until the save was successful.
59pub fn save<'a, T>(tasks: T) -> Result<(), Error>
60where
61    T: IntoIterator<Item = &'a Task>,
62{
63    save_async(tasks)?.wait()?;
64    Ok(())
65}
66
67/// This function returns the handle to a child process which saves the given tasks.
68pub fn save_async<'a, T>(tasks: T) -> Result<Child, Error>
69where
70    T: IntoIterator<Item = &'a Task>,
71{
72    let mut cmd = Command::new("task");
73    cmd.arg("import").stdin(Stdio::piped());
74    save_to_cmd(tasks.into_iter().collect(), cmd)
75}