Kaynağa Gözat

remove unused tau-cli

dasman 2 yıl önce
ebeveyn
işleme
9e410ede15

+ 0 - 34
bin/tau/tau-cli/Cargo.toml

@@ -1,34 +0,0 @@
-[package]
-name = "tau"
-description = "Command-line client for taud"
-version = "0.4.1"
-edition = "2021"
-authors = ["Dyne.org foundation <foundation@dyne.org>"]
-license = "AGPL-3.0-only"
-homepage = "https://dark.fi"
-repository = "https://codeberg.org/darkrenaissance/darkfi"
-
-[dependencies]
-libc = "0.2.155"
-darkfi = {path = "../../../", features = ["rpc"]}
-taud = {path = "../taud"}
-
-# Misc
-chrono = "0.4.38"
-colored = "2.1.0"
-log = "0.4.22"
-prettytable-rs = "0.10.0"
-simplelog = "0.12.2"
-smol = "2.0.0"
-term_grid = { git = "https://github.com/Dastan-glitch/rust-term-grid.git" }
-textwrap = "0.16.1"
-url = "2.5.2"
-
-# Encoding and parsing
-clap = {version = "4.4.11", features = ["derive"]}
-serde = {version = "1.0.204", features = ["derive"]}
-tinyjson = "2.5.1"
-
-[lints]
-workspace = true
-

+ 0 - 34
bin/tau/tau-cli/Makefile

@@ -1,34 +0,0 @@
-.POSIX:
-
-# Install prefix
-PREFIX = $(HOME)/.cargo
-
-# Cargo binary
-CARGO = cargo +nightly
-
-SRC = \
-	Cargo.toml \
-	../../../Cargo.toml \
-	$(shell find src -type f) \
-	$(shell find ../../../src -type f) \
-
-BIN = ../../../tau
-
-all: $(BIN)
-
-$(BIN): $(SRC)
-	$(CARGO) build $(TARGET_PRFX)$(RUST_TARGET) --release --package tau
-	cp -f ../../../target/$(RUST_TARGET)/release/tau $@
-
-clean:
-	rm -f $(BIN)
-
-install: all
-	mkdir -p $(DESTDIR)$(PREFIX)/bin
-	cp -f $(BIN) $(DESTDIR)$(PREFIX)/bin
-	chmod 755 $(DESTDIR)$(PREFIX)/bin/tau
-
-uninstall:
-	rm -f $(DESTDIR)$(PREFIX)/bin/tau
-
-.PHONY: all clean install uninstall

+ 0 - 195
bin/tau/tau-cli/src/drawdown.rs

@@ -1,195 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use std::collections::HashMap;
-
-use chrono::{Datelike, Duration, NaiveDate, Utc};
-use colored::Colorize;
-use term_grid::{Cell, Direction, Filling, Grid, GridOptions};
-
-use darkfi::{util::time::DateTime, Error, Result};
-
-use crate::primitives::{TaskEvent, TaskInfo};
-
-// Red
-const NO_TASK_SCALE: u8 = 50;
-const MIN_SCALE: usize = 90;
-const MAX_SCALE: usize = 255;
-const INCREASE_FACTOR: usize = 25;
-
-// Green
-const GREEN: u8 = 40;
-// Blue
-const BLUE: u8 = 50;
-
-/// Log drawdown gets all assignees of tasks, stores a vec of stopped tasks for each
-/// assignee in a hashmap, draw a heatmap of how many stopped tasks in each day of the
-/// specified month and assignee.
-pub fn drawdown(date: String, tasks: Vec<TaskInfo>, assignee: Option<String>) -> Result<()> {
-    let mut ret = HashMap::new();
-    let assignees = assignees(tasks.clone());
-
-    if assignee.is_none() {
-        println!("Assignees of this month's tasks are: {}", assignees.join(", "));
-        return Ok(())
-    }
-
-    let asgn = assignee.unwrap();
-
-    if !assignees.contains(&asgn) {
-        eprintln!("Assignee {} not found, run \"tau log -h\" for more information.", asgn);
-        return Ok(())
-    }
-
-    for assignee in assignees {
-        let stopped_tasks = tasks
-            .clone()
-            .into_iter()
-            .filter(|task| {
-                if task.assign.is_empty() {
-                    task.owner == asgn
-                } else {
-                    task.assign.contains(&asgn)
-                }
-            })
-            .collect::<Vec<TaskInfo>>();
-        ret.insert(assignee, stopped_tasks);
-    }
-
-    let mut naivedate = to_naivedate(date.clone())?;
-
-    println!("log drawdown for {} in {}", asgn, naivedate.format("%b %Y"));
-
-    let fdow = if naivedate.month() == 2 && !is_leap_year(naivedate.year()) {
-        ["   ", "1 ", "8 ", "15", "22", " "]
-    } else {
-        ["   ", "1 ", "8 ", "15", "22", "29"]
-    };
-
-    // Print first day of each week horizontally.
-    let mut dow_grid =
-        Grid::new(GridOptions { direction: Direction::LeftToRight, filling: Filling::Spaces(1) });
-    if ret.contains_key(&asgn) {
-        for i in fdow {
-            let cell = Cell::from(i);
-            dow_grid.add(cell)
-        }
-        let grid_display = dow_grid.fit_into_rows(1);
-        print!("{}", grid_display);
-    }
-
-    let mut grid =
-        Grid::new(GridOptions { direction: Direction::TopToBottom, filling: Filling::Spaces(1) });
-
-    let days_in_month = get_days_from_month(date)? as u32;
-
-    if ret.contains_key(&asgn) {
-        for _ in 0..7 {
-            let dow = naivedate.weekday().to_string();
-            let wcell = Cell::from(dow);
-            grid.add(wcell);
-            naivedate += Duration::days(1);
-        }
-        for day in 1..=days_in_month {
-            let owner_stopped_tasks = ret.get(&asgn).unwrap().to_owned();
-            let date_tasks: Vec<TaskInfo> = owner_stopped_tasks
-                .into_iter()
-                .filter(|t| {
-                    // last event is always state stop
-                    let event_date = DateTime::from_timestamp(
-                        t.events.last().unwrap_or(&TaskEvent::default()).timestamp.0,
-                        0,
-                    );
-                    event_date.day == day
-                })
-                .collect();
-
-            let red_scale = if date_tasks.is_empty() {
-                NO_TASK_SCALE
-            } else {
-                ((date_tasks.len() * INCREASE_FACTOR) + MIN_SCALE).clamp(MIN_SCALE, MAX_SCALE) as u8
-            };
-
-            let cell = Cell::from("▀▀".truecolor(red_scale, GREEN, BLUE));
-            grid.add(cell)
-        }
-    }
-
-    let grid_display = grid.fit_into_rows(7);
-    println!("{}", grid_display);
-
-    Ok(())
-}
-
-fn is_leap_year(year: i32) -> bool {
-    year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)
-}
-
-fn helper_parse_func(date: String) -> Result<(u32, i32)> {
-    if date.len() != 4 || date.parse::<u32>().is_err() {
-        return Err(Error::MalformedPacket)
-    }
-    let (month, year) = (date[..2].parse::<u32>().unwrap(), date[2..].parse::<i32>().unwrap());
-    let year = year + (Utc::now().year() / 100) * 100;
-
-    Ok((month, year))
-}
-
-pub fn to_naivedate(date: String) -> Result<NaiveDate> {
-    let (month, year) = helper_parse_func(date)?;
-    Ok(NaiveDate::from_ymd_opt(year, month, 1).unwrap())
-}
-
-fn get_days_from_month(date: String) -> Result<i64> {
-    let (month, year) = helper_parse_func(date)?;
-
-    Ok(NaiveDate::from_ymd_opt(
-        match month {
-            12 => year + 1,
-            _ => year,
-        },
-        match month {
-            12 => 1,
-            _ => month + 1,
-        },
-        1,
-    )
-    .unwrap()
-    .signed_duration_since(NaiveDate::from_ymd_opt(year, month, 1).unwrap())
-    .num_days())
-}
-
-fn assignees(tasks: Vec<TaskInfo>) -> Vec<String> {
-    let mut assignees = vec![];
-    for task in tasks {
-        // if task is stopped with no assignee specified we give credit to the owner
-        if task.assign.is_empty() {
-            if !assignees.contains(&task.owner) {
-                assignees.push(task.owner)
-            }
-        } else {
-            for assignee in task.assign {
-                if !assignees.contains(&assignee) {
-                    assignees.push(assignee)
-                }
-            }
-        }
-    }
-
-    assignees
-}

+ 0 - 236
bin/tau/tau-cli/src/filter.rs

@@ -1,236 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use std::{
-    io::{stdin, stdout, Write},
-    process::exit,
-};
-
-use chrono::{Datelike, Local, TimeZone, Utc};
-use log::error;
-
-use darkfi::Result;
-
-use crate::{
-    primitives::{State, TaskInfo},
-    util::due_as_timestamp,
-};
-
-pub fn apply_filter(tasks: &mut Vec<TaskInfo>, filter: &str) {
-    match filter {
-        "all" => {}
-        // Filter by state.
-        _ if filter.contains("state:") => {
-            let kv: Vec<&str> = filter.split(':').collect();
-            //if let Some(state) = Value::from(kv[1]).as_str() {
-            if let Some(state) = Some(kv[1]) {
-                match state {
-                    "open" => tasks.retain(|task| task.state == State::Open.to_string()),
-                    "start" => tasks.retain(|task| task.state == State::Start.to_string()),
-                    "pause" => tasks.retain(|task| task.state == State::Pause.to_string()),
-                    "stop" => tasks.retain(|task| task.state == State::Stop.to_string()),
-                    _ => {
-                        error!("Not implemented, states are open,start,pause and stop");
-                        exit(1)
-                    }
-                }
-            }
-        }
-
-        // Filter by tag
-        _ if filter.starts_with('+') => tasks.retain(|task| task.tags.contains(&filter.into())),
-
-        // Filter by month
-        _ if filter.contains("month:") => {
-            let kv: Vec<&str> = filter.split(':').collect();
-            if kv.len() == 2 {
-                //if let Some(value) = Value::from(kv[1]).as_str() {
-                if let Some(value) = Some(kv[1]) {
-                    if value.len() != 4 || value.parse::<u32>().is_err() {
-                        error!(
-                            "Please provide month date as \"MMYY\" (e.g. 0922 for September 2022)"
-                        );
-                        exit(1)
-                    }
-                    let (month, year) =
-                        (value[..2].parse::<u32>().unwrap(), value[2..].parse::<i32>().unwrap());
-
-                    let year = year + (Utc::now().year() / 100) * 100;
-                    tasks.retain(|task| {
-                        let date = task.created_at.0;
-                        let task_date = Utc.timestamp_nanos(date.try_into().unwrap()).date_naive();
-                        task_date.month() == month && task_date.year() == year
-                    })
-                } else {
-                    error!("Please provide month date as \"MMYY\" (e.g. 0922 for September 2022)");
-                    exit(1)
-                }
-            }
-        }
-
-        // Filter by assignee(s).
-        _ if filter.starts_with('@') => tasks.retain(|task| task.assign.contains(&filter.into())),
-
-        // Filter by project(s).
-        _ if filter.contains("project:") => {
-            let kv: Vec<&str> = filter.split(':').collect();
-            if kv.len() == 2 {
-                // OLD: if let Some(value) = Value::from(kv[1]).as_str() {
-                if let Some(value) = Some(kv[1]) {
-                    if value.is_empty() {
-                        tasks.retain(|task| task.project.is_empty())
-                    } else {
-                        tasks.retain(|task| task.project.contains(&value.to_string()))
-                    }
-                }
-            }
-        }
-
-        // Filter by rank.
-        _ if filter.contains("rank:") => {
-            let kv: Vec<&str> = filter.split(':').collect();
-            if kv.len() == 3 {
-                let value = kv[2].parse::<f32>().unwrap_or(0.0);
-                tasks.retain(|task| {
-                    if filter.contains("lt") {
-                        task.rank < Some(value)
-                    } else if filter.contains("gt") {
-                        task.rank > Some(value)
-                    } else {
-                        true
-                    }
-                })
-            }
-            tasks.retain(|task| task.rank.is_none())
-        }
-
-        // Filter by due date.
-        _ if filter.contains("due:") || filter.contains("due.") => {
-            let kv: Vec<&str> = filter.split(':').collect();
-            let due_op = if filter.contains('.') {
-                let due_op: Vec<&str> = kv[0].split('.').collect();
-                due_op[1]
-            } else {
-                ""
-            };
-
-            if kv.len() == 2 {
-                // OLD: let Value::from(kv[1]).as_str();
-                let value = Some(kv[1]);
-                if let Some(value) = value {
-                    if value.is_empty() {
-                        tasks.retain(|task| task.due.is_none())
-                    } else {
-                        let filter_date = if value == "today" {
-                            Local::now().date_naive()
-                        } else {
-                            let due_date = due_as_timestamp(value).unwrap_or(0);
-                            Utc.timestamp_nanos(due_date.try_into().unwrap()).date_naive()
-                        };
-
-                        tasks.retain(|task| {
-                            let date = if let Some(due) = task.due { due.0 } else { 0 };
-                            let task_date =
-                                Utc.timestamp_nanos(date.try_into().unwrap()).date_naive();
-
-                            match due_op {
-                                "not" => task_date != filter_date,
-                                "after" => task_date > filter_date,
-                                "before" => task_date < filter_date,
-                                "" | "is" => task_date == filter_date,
-                                _ => true,
-                            }
-                        })
-                    }
-                } else {
-                    error!("Please provide due date as \"DDMM\" (e.g. 2210 for October 22nd)");
-                    exit(1)
-                }
-            }
-        }
-
-        _ => {
-            println!("No matches.");
-            exit(1)
-        }
-    }
-}
-
-pub fn no_filter_warn() {
-    let mut s = String::new();
-    print!("This command has no filter, and will modify all tasks. Are you sure? (yes/no) ");
-    let _ = stdout().flush();
-    stdin().read_line(&mut s).unwrap_or(0);
-    match s.trim() {
-        "y" | "yes" => {}
-        _ => {
-            println!("Command prevented from running.");
-            exit(1)
-        }
-    }
-}
-
-pub fn get_ids(filters: &mut Vec<String>) -> Result<Vec<u32>> {
-    let mut vec_ids = vec![];
-    let mut matching_id = String::new();
-    if let Some(index) = filters.iter().position(|t| {
-        t.parse::<u32>().is_ok() || !t.contains(':') && (t.contains(',') || t.contains('-'))
-    }) {
-        matching_id.push_str(&filters.remove(index));
-    }
-
-    match matching_id {
-        _ if matching_id.parse::<u32>().is_ok() => {
-            let id = matching_id.parse::<u32>().unwrap();
-            vec_ids.push(id)
-        }
-        _ if !matching_id.contains(':') &&
-            (matching_id.contains(',') || matching_id.contains('-')) =>
-        {
-            let num = matching_id.replace(&[',', '-'][..], "");
-            if num.parse::<u32>().is_err() {
-                error!("Invalid ID number");
-                exit(1)
-            }
-            if matching_id.contains(',') {
-                let ids: Vec<&str> = matching_id.split(',').collect();
-                for id in ids {
-                    if id.contains('-') {
-                        let range: Vec<&str> = id.split('-').collect();
-                        let range =
-                            range[0].parse::<u32>().unwrap()..=range[1].parse::<u32>().unwrap();
-                        for rid in range {
-                            vec_ids.push(rid)
-                        }
-                    } else {
-                        vec_ids.push(id.parse::<u32>().unwrap())
-                    }
-                }
-            } else if matching_id.contains('-') {
-                let range: Vec<&str> = matching_id.split('-').collect();
-                let range = range[0].parse::<u32>().unwrap()..=range[1].parse::<u32>().unwrap();
-                for rid in range {
-                    vec_ids.push(rid)
-                }
-            }
-        }
-        _ => {}
-    }
-
-    Ok(vec_ids)
-}

+ 0 - 411
bin/tau/tau-cli/src/main.rs

@@ -1,411 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use std::{process::exit, sync::Arc};
-
-use clap::{Parser, Subcommand};
-use log::{error, info};
-use simplelog::{ColorChoice, TermLogger, TerminalMode};
-use smol::Executor;
-use url::Url;
-
-use darkfi::{
-    rpc::client::RpcClient,
-    util::cli::{get_log_config, get_log_level},
-    Result,
-};
-
-mod drawdown;
-mod filter;
-mod primitives;
-mod rpc;
-mod util;
-mod view;
-
-use drawdown::{drawdown, to_naivedate};
-use filter::{apply_filter, get_ids, no_filter_warn};
-use primitives::{task_from_cli, State, TaskEvent};
-use util::{due_as_timestamp, prompt_text};
-use view::{print_task_info, print_task_list};
-
-use taud::task_info::TaskInfo;
-
-const DEFAULT_PATH: &str = "~/tau_exported_tasks";
-
-#[derive(Parser)]
-#[clap(name = "tau", version)]
-#[clap(subcommand_precedence_over_arg = true)]
-struct Args {
-    #[arg(short, action = clap::ArgAction::Count)]
-    /// Increase verbosity (-vvv supported)
-    verbose: u8,
-
-    #[clap(short, long, default_value = "tcp://127.0.0.1:23330")]
-    /// taud JSON-RPC endpoint
-    endpoint: Url,
-
-    /// Search filters (zero or more)
-    filters: Vec<String>,
-
-    #[clap(subcommand)]
-    command: Option<TauSubcommand>,
-}
-
-#[derive(Subcommand)]
-enum TauSubcommand {
-    /// Add a new task.
-    ///
-    /// Quick start:
-    ///   Adding a new task named "New task":
-    ///     tau add New task
-    ///   New task with description:
-    ///     tau add Add more info to tau desc:"some awesome description"
-    ///   New task with project and assignee:
-    ///     tau add Third task project:p2p Arusty
-    ///   Add a task with due date September 12th and rank of 4.6:
-    ///     tau add Task no. Four due:1209 rank:4.6
-    ///
-    /// Notice that if the command does not have "desc" key it will open
-    /// an Editor so you can write the description there.
-    ///
-    /// Also note that "project" key can have multiple
-    /// comma-separated values.
-    /// "assign" on the other hand uses '@' character but also could be
-    /// multiple values, but like so:
-    /// @person1 @person2
-    ///
-    /// All keys example:
-    ///     tau add Improve CLI desc:"Description here" project:tau,darkirc @dave @rusty due:0210 rank:2.2
-    ///
-    #[clap(verbatim_doc_comment)]
-    Add {
-        /// Pairs of key:value (e.g. desc:description @dark).
-        values: Vec<String>,
-    },
-
-    /// Modify/Edit an existing task.
-    Modify {
-        #[clap(allow_hyphen_values = true)]
-        /// Values (e.g. project:blockchain).
-        values: Vec<String>,
-    },
-
-    /// List tasks.
-    List,
-
-    /// Start task(s).
-    Start,
-
-    /// Open task(s).
-    Open,
-
-    /// Pause task(s).
-    Pause,
-
-    /// Stop task(s).
-    Stop,
-
-    /// Set or Get comment for task(s).
-    Comment {
-        /// Set comment content if provided (Get comments otherwise).
-        content: Vec<String>,
-    },
-
-    /// Get all data about selected task(s).
-    Info,
-
-    /// Switch workspace.
-    Switch {
-        /// Tau workspace.
-        workspace: String,
-    },
-
-    /// Import tasks from a specified directory.
-    Import {
-        /// The parent directory from where you want to import tasks.
-        path: Option<String>,
-    },
-
-    /// Export tasks to a specified directory.
-    Export {
-        /// The parent directory to where you want to export tasks.
-        path: Option<String>,
-    },
-
-    /// Log drawdown.
-    Log {
-        /// The month in which we want to draw a heatmap (e.g. 0822 for August 2022).
-        month: Option<String>,
-        /// The person of which we want to draw a heatmap
-        /// (if not provided we list all assignees).
-        assignee: Option<String>,
-    },
-}
-
-pub struct Tau {
-    pub rpc_client: RpcClient,
-}
-
-fn main() -> Result<()> {
-    let args = Args::parse();
-
-    let log_level = get_log_level(args.verbose);
-    let log_config = get_log_config(args.verbose);
-    TermLogger::init(log_level, log_config, TerminalMode::Mixed, ColorChoice::Auto)?;
-
-    let executor = Arc::new(Executor::new());
-
-    smol::block_on(executor.run(async {
-        let rpc_client = RpcClient::new(args.endpoint, executor.clone()).await?;
-        let tau = Tau { rpc_client };
-
-        let mut filters = args.filters.clone();
-
-        // If IDs are provided in filter we use them to get the tasks from the daemon
-        // then remove IDs from filter so we can do apply_filter() normally.
-        // If not provided we use get_ids() to get them from the daemon.
-        let ids = get_ids(&mut filters)?;
-        let ids_clone = ids.clone();
-        let task_ids = if ids.is_empty() { tau.get_ids().await? } else { ids };
-
-        let mut tasks = if filters.contains(&"state:stop".to_string()) ||
-            filters.contains(&"all".to_string())
-        {
-            tau.get_stop_tasks(None).await?
-        } else {
-            vec![]
-        };
-        for id in task_ids {
-            tasks.push(tau.get_task_by_id(id).await?);
-        }
-
-        if ids_clone.len() == 1 && args.command.is_none() {
-            let tsk = tasks[0].clone();
-            print_task_info(tsk)?;
-
-            return Ok(())
-        }
-
-        for filter in filters {
-            apply_filter(&mut tasks, &filter);
-        }
-
-        // Parse subcommands
-        match args.command {
-            Some(sc) => match sc {
-                TauSubcommand::Add { values } => {
-                    let mut task = task_from_cli(values)?;
-                    if task.title.is_empty() {
-                        error!("Please provide a title for the task.");
-                        exit(1);
-                    };
-
-                    if task.desc.is_none() {
-                        task.desc = prompt_text(TaskInfo::from(task.clone()), "description")?;
-                    };
-
-                    if task.clone().desc.unwrap().trim().is_empty() {
-                        error!("Abort adding the task due to empty description.");
-                        exit(1)
-                    }
-
-                    let title = task.clone().title;
-
-                    let task_id = tau.add(task).await?;
-                    if task_id > 0 {
-                        println!("Created task {} \"{}\"", task_id, title);
-                    }
-                    Ok(())
-                }
-
-                TauSubcommand::Modify { values } => {
-                    if args.filters.is_empty() {
-                        no_filter_warn()
-                    }
-                    let base_task = task_from_cli(values)?;
-                    for task in tasks.clone() {
-                        let res = tau.update(task.id, base_task.clone()).await?;
-                        if res {
-                            let tsk = tau.get_task_by_id(task.id).await?;
-                            print_task_info(tsk)?;
-                        }
-                    }
-
-                    Ok(())
-                }
-
-                TauSubcommand::Start => {
-                    if args.filters.is_empty() {
-                        no_filter_warn()
-                    }
-                    let state = State::Start;
-                    for task in tasks {
-                        if tau.set_state(task.id, &state).await? {
-                            println!("Started task: {:?}", task.id);
-                        }
-                    }
-
-                    Ok(())
-                }
-
-                TauSubcommand::Open => {
-                    if args.filters.is_empty() {
-                        no_filter_warn()
-                    }
-                    let state = State::Open;
-                    for task in tasks {
-                        if tau.set_state(task.id, &state).await? {
-                            println!("Opened task: {:?}", task.id);
-                        }
-                    }
-
-                    Ok(())
-                }
-
-                TauSubcommand::Pause => {
-                    if args.filters.is_empty() {
-                        no_filter_warn()
-                    }
-                    let state = State::Pause;
-                    for task in tasks {
-                        if tau.set_state(task.id, &state).await? {
-                            println!("Paused task: {:?}", task.id);
-                        }
-                    }
-
-                    Ok(())
-                }
-
-                TauSubcommand::Stop => {
-                    if args.filters.is_empty() {
-                        no_filter_warn()
-                    }
-                    let state = State::Stop;
-                    for task in tasks {
-                        if tau.set_state(task.id, &state).await? {
-                            println!("Stopped task: {}", task.id);
-                        }
-                    }
-
-                    Ok(())
-                }
-
-                TauSubcommand::Comment { content } => {
-                    if args.filters.is_empty() {
-                        no_filter_warn()
-                    }
-                    for task in tasks {
-                        let comment = if content.is_empty() {
-                            prompt_text(task.clone(), "comment")?
-                        } else {
-                            Some(content.join(" "))
-                        };
-
-                        if comment.clone().unwrap().trim().is_empty() || comment.is_none() {
-                            error!("Abort due to empty comment.");
-                            exit(1)
-                        }
-
-                        let res = tau.set_comment(task.id, comment.unwrap().trim()).await?;
-                        if res {
-                            let tsk = tau.get_task_by_id(task.id).await?;
-                            print_task_info(tsk)?;
-                        }
-                    }
-                    Ok(())
-                }
-
-                TauSubcommand::Info => {
-                    for task in tasks {
-                        let task = tau.get_task_by_id(task.id).await?;
-                        print_task_info(task)?;
-                    }
-                    Ok(())
-                }
-
-                TauSubcommand::Switch { workspace } => {
-                    if tau.switch_ws(workspace.clone()).await? {
-                        println!("You are now on \"{}\" workspace", workspace);
-                    } else {
-                        println!("Workspace \"{}\" is not configured", workspace);
-                    }
-
-                    Ok(())
-                }
-
-                TauSubcommand::Export { path } => {
-                    let path = path.unwrap_or_else(|| DEFAULT_PATH.into());
-                    let res = tau.export_to(path.clone()).await?;
-
-                    if res {
-                        info!("Exported to {}", path);
-                    } else {
-                        error!("Error exporting to {}", path);
-                    }
-
-                    Ok(())
-                }
-
-                TauSubcommand::Import { path } => {
-                    let path = path.unwrap_or_else(|| DEFAULT_PATH.into());
-                    let res = tau.import_from(path.clone()).await?;
-
-                    if res {
-                        info!("Imported from {}", path);
-                    } else {
-                        error!("Error importing from {}", path);
-                    }
-
-                    Ok(())
-                }
-
-                TauSubcommand::Log { month, assignee } => {
-                    match month {
-                        Some(date) => {
-                            let ts = to_naivedate(date.clone())?
-                                .and_hms_opt(12, 0, 0)
-                                .unwrap()
-                                .timestamp();
-                            let tasks = tau.get_stop_tasks(Some(ts.try_into().unwrap())).await?;
-                            drawdown(date, tasks, assignee)?;
-                        }
-                        None => {
-                            let ws = tau.get_ws().await?;
-                            let tasks = tau.get_stop_tasks(None).await?;
-                            print_task_list(tasks, ws)?;
-                        }
-                    }
-
-                    Ok(())
-                }
-
-                TauSubcommand::List => {
-                    let ws = tau.get_ws().await?;
-                    print_task_list(tasks, ws)
-                }
-            },
-            None => {
-                let ws = tau.get_ws().await?;
-                print_task_list(tasks, ws)
-            }
-        }?;
-
-        tau.close_connection().await;
-        Ok(())
-    }))
-}

+ 0 - 105
bin/tau/tau-cli/src/primitives.rs

@@ -1,105 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use darkfi::{util::time::Timestamp, Result};
-
-use crate::due_as_timestamp;
-pub(crate) use taud::task_info::{State, TaskEvent, TaskInfo};
-
-#[derive(Clone, Debug)]
-pub struct BaseTask {
-    pub title: String,
-    pub tags: Vec<String>,
-    pub desc: Option<String>,
-    pub assign: Vec<String>,
-    pub project: Vec<String>,
-    pub due: Option<u64>,
-    pub rank: Option<f32>,
-}
-
-impl From<BaseTask> for TaskInfo {
-    fn from(value: BaseTask) -> Self {
-        Self {
-            ref_id: String::default(),
-            workspace: String::default(),
-            id: u32::default(),
-            title: value.title,
-            tags: value.tags,
-            desc: String::default(),
-            owner: String::default(),
-            assign: value.assign,
-            project: value.project,
-            due: value.due.map(Timestamp),
-            rank: value.rank,
-            created_at: Timestamp(u64::default()),
-            state: String::default(),
-            events: vec![],
-            comments: vec![],
-        }
-    }
-}
-
-pub fn task_from_cli(values: Vec<String>) -> Result<BaseTask> {
-    let mut title = String::new();
-    let mut tags = vec![];
-    let mut desc = None;
-    let mut project = vec![];
-    let mut assign = vec![];
-    let mut due = None;
-    let mut rank = None;
-
-    for val in values {
-        let field: Vec<&str> = val.split(':').collect();
-        if field.len() == 1 {
-            if field[0].starts_with('+') || field[0].starts_with('-') {
-                tags.push(field[0].into());
-                continue
-            }
-            if field[0].starts_with('@') {
-                assign.push(field[0].into());
-                continue
-            }
-            title.push_str(field[0]);
-            title.push(' ');
-            continue
-        }
-
-        if field.len() != 2 {
-            continue
-        }
-
-        if field[0] == "project" {
-            project = field[1].split(',').map(|s| s.into()).collect();
-        }
-
-        if field[0] == "desc" {
-            desc = Some(field[1].into());
-        }
-
-        if field[0] == "due" {
-            due = due_as_timestamp(field[1])
-        }
-
-        if field[0] == "rank" {
-            rank = Some(field[1].parse::<f32>()?);
-        }
-    }
-
-    let title = title.trim().into();
-    Ok(BaseTask { title, tags, desc, project, assign, due, rank })
-}

+ 0 - 193
bin/tau/tau-cli/src/rpc.rs

@@ -1,193 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use darkfi::{rpc::jsonrpc::JsonRequest, Result};
-use log::debug;
-use tinyjson::JsonValue;
-
-use crate::{
-    primitives::{BaseTask, State, TaskInfo},
-    Tau,
-};
-
-impl Tau {
-    pub async fn close_connection(&self) {
-        self.rpc_client.stop().await
-    }
-
-    /// Add a new task.
-    pub async fn add(&self, task: BaseTask) -> Result<u32> {
-        let mut params = vec![
-            JsonValue::String(task.title.clone()),
-            JsonValue::Array(task.tags.iter().map(|x| JsonValue::String(x.clone())).collect()),
-            JsonValue::String(task.desc.unwrap_or("".to_string())),
-            JsonValue::Array(task.assign.iter().map(|x| JsonValue::String(x.clone())).collect()),
-            JsonValue::Array(task.project.iter().map(|x| JsonValue::String(x.clone())).collect()),
-        ];
-
-        let due = if let Some(num) = task.due {
-            JsonValue::String(num.to_string())
-        } else {
-            JsonValue::Null
-        };
-        params.push(due);
-
-        let rank =
-            if let Some(num) = task.rank { JsonValue::Number(num.into()) } else { JsonValue::Null };
-        params.push(rank);
-
-        let req = JsonRequest::new("add", params);
-        let rep = self.rpc_client.request(req).await?;
-
-        debug!("Got reply: {:?}", rep);
-        Ok(*rep.get::<f64>().unwrap() as u32)
-    }
-
-    /// Get current open tasks ids.
-    pub async fn get_ids(&self) -> Result<Vec<u32>> {
-        let req = JsonRequest::new("get_ids", vec![]);
-        let rep = self.rpc_client.request(req).await?;
-
-        debug!("Got reply: {:?}", rep);
-
-        let mut ret = vec![];
-        for i in rep.get::<Vec<JsonValue>>().unwrap() {
-            ret.push(*i.get::<f64>().unwrap() as u32)
-        }
-
-        Ok(ret)
-    }
-
-    /// Update existing task given it's ID and some params.
-    pub async fn update(&self, id: u32, task: BaseTask) -> Result<bool> {
-        let mut params = vec![
-            JsonValue::String(task.title.clone()),
-            JsonValue::Array(task.tags.iter().map(|x| JsonValue::String(x.clone())).collect()),
-            JsonValue::String(task.desc.unwrap_or("".to_string())),
-            JsonValue::Array(task.assign.iter().map(|x| JsonValue::String(x.clone())).collect()),
-            JsonValue::Array(task.project.iter().map(|x| JsonValue::String(x.clone())).collect()),
-        ];
-
-        let due = if let Some(num) = task.due {
-            JsonValue::String(num.to_string())
-        } else {
-            JsonValue::Null
-        };
-        params.push(due);
-
-        let rank =
-            if let Some(num) = task.rank { JsonValue::Number(num.into()) } else { JsonValue::Null };
-        params.push(rank);
-
-        let req = JsonRequest::new(
-            "update",
-            vec![JsonValue::Number(id.into()), JsonValue::Array(params)],
-        );
-        let rep = self.rpc_client.request(req).await?;
-
-        debug!("Got reply: {:?}", rep);
-        Ok(*rep.get::<bool>().unwrap())
-    }
-
-    /// Set the state for a task.
-    pub async fn set_state(&self, id: u32, state: &State) -> Result<bool> {
-        let req = JsonRequest::new(
-            "set_state",
-            vec![JsonValue::Number(id.into()), JsonValue::String(state.to_string())],
-        );
-        let rep = self.rpc_client.request(req).await?;
-
-        debug!("Got reply: {:?}", rep);
-        Ok(*rep.get::<bool>().unwrap())
-    }
-
-    /// Set a comment for a task.
-    pub async fn set_comment(&self, id: u32, content: &str) -> Result<bool> {
-        let req = JsonRequest::new(
-            "set_comment",
-            vec![JsonValue::Number(id.into()), JsonValue::String(content.to_string())],
-        );
-        let rep = self.rpc_client.request(req).await?;
-
-        debug!("Got reply: {:?}", rep);
-        Ok(*rep.get::<bool>().unwrap())
-    }
-
-    /// Get task data by its ID.
-    pub async fn get_task_by_id(&self, id: u32) -> Result<TaskInfo> {
-        let req = JsonRequest::new("get_task_by_id", vec![JsonValue::Number(id.into())]);
-        let rep = self.rpc_client.request(req).await?;
-
-        debug!("Got reply: {:?}", rep);
-        let rep = rep.into();
-        Ok(rep)
-    }
-
-    /// Get month's stopped tasks.
-    pub async fn get_stop_tasks(&self, month: Option<u64>) -> Result<Vec<TaskInfo>> {
-        let param = if let Some(month) = month {
-            JsonValue::String(month.to_string())
-        } else {
-            JsonValue::Null
-        };
-
-        let req = JsonRequest::new("get_stop_tasks", vec![param]);
-        let rep = self.rpc_client.request(req).await?;
-
-        debug!("Got reply: {:?}", rep);
-        let rep =
-            rep.get::<Vec<JsonValue>>().unwrap().iter().map(|x| (*x).clone().into()).collect();
-        Ok(rep)
-    }
-
-    /// Switch workspace.
-    pub async fn switch_ws(&self, workspace: String) -> Result<bool> {
-        let req = JsonRequest::new("switch_ws", vec![JsonValue::String(workspace)]);
-        let rep = self.rpc_client.request(req).await?;
-
-        debug!("Got reply: {:?}", rep);
-        Ok(*rep.get::<bool>().unwrap())
-    }
-
-    /// Get current workspace.
-    pub async fn get_ws(&self) -> Result<String> {
-        let req = JsonRequest::new("get_ws", vec![]);
-        let rep = self.rpc_client.request(req).await?;
-
-        debug!("Got reply: {:?}", rep);
-        Ok(rep.get::<String>().unwrap().clone())
-    }
-
-    /// Export tasks.
-    pub async fn export_to(&self, path: String) -> Result<bool> {
-        let req = JsonRequest::new("export", vec![JsonValue::String(path)]);
-        let rep = self.rpc_client.request(req).await?;
-
-        debug!("Got reply: {:?}", rep);
-        Ok(*rep.get::<bool>().unwrap())
-    }
-
-    /// Import tasks.
-    pub async fn import_from(&self, path: String) -> Result<bool> {
-        let req = JsonRequest::new("import", vec![JsonValue::String(path)]);
-        let rep = self.rpc_client.request(req).await?;
-
-        debug!("Got reply: {:?}", rep);
-        Ok(*rep.get::<bool>().unwrap())
-    }
-}

+ 0 - 107
bin/tau/tau-cli/src/util.rs

@@ -1,107 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use std::{
-    env,
-    fs::{self, File},
-    io::Write,
-    process::Command,
-};
-
-use chrono::{Datelike, Local, NaiveDate};
-use log::error;
-
-use darkfi::{util::time::Timestamp, Result};
-
-use crate::{
-    primitives::TaskInfo,
-    view::{comments_table, events_table, taskinfo_table},
-};
-
-/// Parse due date (e.g. "1503" for 15 March) as i64 timestamp.
-pub fn due_as_timestamp(due: &str) -> Option<u64> {
-    if due.len() != 4 || due.parse::<u32>().is_err() {
-        error!("Due date must be digits of length 4 (e.g. \"1503\" for 15 March)");
-        return None
-    }
-    let (day, month) = (due[..2].parse::<u32>().unwrap(), due[2..].parse::<u32>().unwrap());
-
-    if day > 31 || month > 12 {
-        error!("Invalid or out-of-range date");
-        return None
-    }
-
-    let mut year = Local::now().year();
-
-    // Ensure the due date is in future
-    if month < Local::now().month() {
-        year += 1;
-    }
-
-    if month == Local::now().month() && day < Local::now().day() {
-        year += 1;
-    }
-
-    let dt = NaiveDate::from_ymd_opt(year, month, day).unwrap().and_hms_opt(12, 0, 0).unwrap();
-    dt.timestamp().try_into().ok()
-}
-
-/// Start up the preferred editor to edit a task's description.
-pub fn prompt_text(task_info: TaskInfo, what: &str) -> Result<Option<String>> {
-    // Create a temporary file with some comments inside.
-    let mut file_path = env::temp_dir();
-    let file_name = format!("tau-{}", Timestamp::current_time().0);
-    file_path.push(file_name);
-    let mut file = File::create(&file_path)?;
-
-    writeln!(file, "\n# Write your task {what} above this line.")?;
-    writeln!(file, "# Lines starting with \"#\" will be removed.")?;
-    writeln!(file, "# An empty {what} aborts the operation.")?;
-    writeln!(file, "\n# ------------------------ >8 ------------------------")?;
-    writeln!(file, "# Do not modify or remove the line above.")?;
-    writeln!(file, "# Everything below it will be ignored.")?;
-    writeln!(file, "\n{}", taskinfo_table(task_info.clone())?)?;
-    writeln!(file, "{}", events_table(task_info.clone())?)?;
-    writeln!(file, "{}", comments_table(task_info)?)?;
-
-    // Try $EDITOR, and if not, fallback to xdg-open.
-    let editor_argv0 = match env::var("EDITOR") {
-        Ok(v) => v,
-        Err(_) => "xdg-open".into(),
-    };
-
-    if let Err(e) = Command::new(editor_argv0).arg(&file_path).status() {
-        error!("Running $EDITOR failed, neither env or xdg-open are available");
-        return Err(e.into())
-    }
-
-    // Whatever has been written in the temp file will be read here.
-    let content = fs::read_to_string(&file_path)?;
-    fs::remove_file(&file_path)?;
-
-    let mut lines = vec![];
-    for i in content.lines() {
-        if !i.starts_with('#') {
-            lines.push(i.to_string())
-        }
-        if i == "# ------------------------ >8 ------------------------" {
-            break
-        }
-    }
-    Ok(Some(lines.join("\n")))
-}

+ 0 - 287
bin/tau/tau-cli/src/view.rs

@@ -1,287 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use std::{cmp::Ordering, fmt::Write, str::FromStr};
-
-use prettytable::{
-    format::{consts::FORMAT_NO_COLSEP, FormatBuilder, LinePosition, LineSeparator},
-    row, table, Cell, Row, Table,
-};
-use textwrap::fill;
-
-use darkfi::{
-    util::time::{timestamp_to_date, DateFormat},
-    Result,
-};
-
-use crate::{
-    primitives::{State, TaskInfo},
-    TaskEvent,
-};
-
-pub fn print_task_list(tasks: Vec<TaskInfo>, ws: String) -> Result<()> {
-    let mut tasks = tasks;
-
-    let mut table = Table::new();
-    table.set_format(
-        FormatBuilder::new()
-            .padding(1, 1)
-            .separators(&[LinePosition::Title], LineSeparator::new('-', ' ', ' ', ' '))
-            .build(),
-    );
-    table.set_titles(row!["ID", "Title", "Tags", "Project", "Assigned", "Due", "Rank"]);
-
-    // group tasks by state.
-    tasks.sort_by_key(|task| task.state.clone());
-
-    // sort tasks by there rank only if they are not stopped.
-    tasks.sort_by(|a, b| {
-        if a.state != "stop" && b.state != "stop" {
-            b.rank.partial_cmp(&a.rank).unwrap()
-        } else {
-            // because sort_by does not reorder equal elements
-            Ordering::Equal
-        }
-    });
-
-    let mut min_rank = None;
-    let mut max_rank = None;
-
-    if let Some(first) = tasks.first() {
-        max_rank = first.rank;
-    }
-
-    if let Some(last) = tasks.last() {
-        min_rank = last.rank;
-    }
-
-    for task in tasks {
-        let state = State::from_str(&task.state.clone())?;
-
-        let (max_style, min_style, mid_style, gen_style) = if state.is_start() {
-            ("bFg", "Fc", "Fg", "Fg")
-        } else if state.is_pause() {
-            ("iFYBd", "iFYBd", "iFYBd", "iFYBd")
-        } else if state.is_stop() {
-            ("Fr", "Fr", "Fr", "Fr")
-        } else {
-            ("", "", "", "")
-        };
-
-        let rank = if let Some(r) = task.rank { r.to_string() } else { "".to_string() };
-        let mut print_tags = vec![];
-        for tag in &task.tags {
-            let t = tag.replace('+', "");
-            print_tags.push(t)
-        }
-
-        let due_ = match task.due {
-            Some(ts) => ts.0,
-            None => 0,
-        };
-
-        table.add_row(Row::new(vec![
-            Cell::new(&task.id.to_string()).style_spec(gen_style),
-            Cell::new(&task.title).style_spec(gen_style),
-            Cell::new(&print_tags.join(", ")).style_spec(gen_style),
-            Cell::new(&task.project.join(", ")).style_spec(gen_style),
-            Cell::new(&task.assign.join(", ")).style_spec(gen_style),
-            Cell::new(&timestamp_to_date(due_, DateFormat::Date)).style_spec(gen_style),
-            if task.rank == max_rank {
-                Cell::new(&rank).style_spec(max_style)
-            } else if task.rank == min_rank {
-                Cell::new(&rank).style_spec(min_style)
-            } else {
-                Cell::new(&rank).style_spec(mid_style)
-            },
-        ]));
-    }
-
-    let workspace = format!("Workspace: {}", ws);
-    let mut ws_table = table!([workspace]);
-    ws_table.set_format(
-        FormatBuilder::new()
-            .padding(1, 1)
-            .separators(&[LinePosition::Bottom], LineSeparator::new('-', ' ', ' ', ' '))
-            .build(),
-    );
-
-    if unsafe { libc::isatty(libc::STDOUT_FILENO) } == 1 {
-        ws_table.printstd();
-        table.printstd();
-    } else {
-        for row in table.row_iter() {
-            for cell in row.iter() {
-                print!("{}\t", cell.get_content());
-            }
-            println!();
-        }
-    }
-
-    Ok(())
-}
-
-pub fn taskinfo_table(taskinfo: TaskInfo) -> Result<Table> {
-    let due_ = match taskinfo.due {
-        Some(ts) => ts.0,
-        None => 0,
-    };
-
-    let due = timestamp_to_date(due_, DateFormat::Date);
-    let created_at = timestamp_to_date(taskinfo.created_at.0, DateFormat::DateTime);
-    let rank = if let Some(r) = taskinfo.rank { r.to_string() } else { "".to_string() };
-
-    let mut table = table!(
-         [Bd => "ref_id", &taskinfo.ref_id],
-         ["workspace", &taskinfo.workspace],
-         [Bd =>"id", &taskinfo.id.to_string()],
-         ["owner", &taskinfo.owner],
-         [Bd =>"title", &taskinfo.title],
-         ["tags", &taskinfo.tags.join(", ")],
-         [Bd =>"desc", &taskinfo.desc.to_string()],
-         ["assign", taskinfo.assign.join(", ")],
-         [Bd =>"project", taskinfo.project.join(", ")],
-         ["due", due],
-         [Bd =>"rank", rank],
-         ["created_at", created_at],
-         [Bd =>"current_state", &taskinfo.state]);
-
-    table.set_format(
-        FormatBuilder::new()
-            .padding(1, 1)
-            .separators(&[LinePosition::Title], LineSeparator::new('-', ' ', ' ', ' '))
-            .build(),
-    );
-
-    table.set_titles(row!["Name", "Value"]);
-    Ok(table)
-}
-
-pub fn events_table(taskinfo: TaskInfo) -> Result<Table> {
-    let (events, timestamps) = &events_as_string(taskinfo.events);
-    let mut events_table = table!([events, timestamps]);
-    events_table.set_format(*FORMAT_NO_COLSEP);
-    events_table.set_titles(row!["Events"]);
-    Ok(events_table)
-}
-
-pub fn comments_table(taskinfo: TaskInfo) -> Result<Table> {
-    let (events, timestamps) = &comments_as_string(taskinfo.events);
-    let mut comments_table = table!([events, timestamps]);
-    comments_table.set_format(*FORMAT_NO_COLSEP);
-    comments_table.set_titles(row!["Comments"]);
-
-    Ok(comments_table)
-}
-
-pub fn print_task_info(taskinfo: TaskInfo) -> Result<()> {
-    let table = taskinfo_table(taskinfo.clone())?;
-    table.printstd();
-
-    let events_table = events_table(taskinfo.clone())?;
-    events_table.printstd();
-
-    let comments_table = comments_table(taskinfo)?;
-    comments_table.printstd();
-
-    println!();
-
-    Ok(())
-}
-
-pub fn events_as_string(events: Vec<TaskEvent>) -> (String, String) {
-    let mut events_str = String::new();
-    let mut timestamps_str = String::new();
-    let width = 50;
-    for event in events {
-        if event.action.as_str() == "comment" {
-            continue
-        }
-        writeln!(timestamps_str, "{}", event.timestamp).unwrap();
-        match event.action.as_str() {
-            "title" => {
-                writeln!(events_str, "- {} changed title to {}", event.author, event.content)
-                    .unwrap();
-            }
-            "rank" => {
-                writeln!(events_str, "- {} changed rank to {}", event.author, event.content)
-                    .unwrap();
-            }
-            "state" => {
-                writeln!(events_str, "- {} changed state to {}", event.author, event.content)
-                    .unwrap();
-            }
-            "assign" => {
-                writeln!(events_str, "- {} assigned {}", event.author, event.content).unwrap();
-            }
-            "project" => {
-                writeln!(events_str, "- {} changed project to {}", event.author, event.content)
-                    .unwrap();
-            }
-            "tags" => {
-                writeln!(events_str, "- {} changed tags to {}", event.author, event.content)
-                    .unwrap();
-            }
-            "due" => {
-                writeln!(
-                    events_str,
-                    "- {} changed due date to {}",
-                    event.author,
-                    timestamp_to_date(event.content.parse::<u64>().unwrap_or(0), DateFormat::Date)
-                )
-                .unwrap();
-            }
-            "desc" => {
-                // wrap long description
-                let ev_content =
-                    fill(&event.content, textwrap::Options::new(width).subsequent_indent("  "));
-                // skip wrapped lines to align timestamp with the first line
-                for _ in 1..ev_content.lines().count() {
-                    writeln!(timestamps_str, " ").unwrap();
-                }
-                writeln!(events_str, "- {} changed description to: {}", event.author, ev_content)
-                    .unwrap();
-            }
-            _ => {}
-        }
-    }
-    (events_str, timestamps_str)
-}
-
-pub fn comments_as_string(events: Vec<TaskEvent>) -> (String, String) {
-    let mut events_str = String::new();
-    let mut timestamps_str = String::new();
-    let width = 50;
-    for event in events {
-        if event.action.as_str() != "comment" {
-            continue
-        }
-        writeln!(timestamps_str, "{}", event.timestamp).unwrap();
-        if event.action.as_str() == "comment" {
-            // wrap long comments
-            let ev_content =
-                fill(&event.content, textwrap::Options::new(width).subsequent_indent("    "));
-            // skip wrapped lines to align timestamp with the first line
-            for _ in 1..ev_content.lines().count() {
-                writeln!(timestamps_str, " ").unwrap();
-            }
-            writeln!(events_str, "{}>  {}", event.author, ev_content).unwrap();
-        }
-    }
-    (events_str, timestamps_str)
-}

+ 1 - 3
contrib/docker/riscv.Dockerfile

@@ -43,8 +43,7 @@ COPY . /opt/darkfi
 # Cleanup existing binaries
 RUN rm -rf zkas bin/zkas/zkas darkfid bin/darkfid/darkfid \
     darkirc bin/darkirc/darkirc lilith bin/lilith/lilith \
-    tau-cli bin/tau/tau-cli/tau-cli taud bin/tau/taud/taud \
-    vanityaddr bin/vanityaddr/vanityaddr
+    taud bin/tau/taud/taud vanityaddr bin/vanityaddr/vanityaddr
 
 # Risc-V support is highly experimental so we have to add some hack patches
 # at Cargo.toml where [patch.crates-io] exists.
@@ -64,7 +63,6 @@ RUN make CARGO="cargo +${RUST_VER}" ${BINS} && \
     (if [ -e darkfid ]; then cp -a darkfid compiled-bins/; fi;) && \
     (if [ -e darkirc ]; then cp -a darkirc compiled-bins/; fi;) && \
     (if [ -e lilith ]; then cp -a lilith compiled-bins/; fi;) && \
-    (if [ -e "tau-cli" ]; then cp -a tau-cli compiled-bins/; fi;) && \
     (if [ -e taud ]; then cp -a taud compiled-bins/; fi;) && \
     (if [ -e vanityaddr ]; then cp -a vanityaddr compiled-bins/; fi;)
 

+ 0 - 1
contrib/docker/static.Dockerfile

@@ -53,7 +53,6 @@ RUN make clean && make ${BINS} &&  mkdir compiled-bins && \
     (if [ -e "genev-cli" ]; then cp -a genev-cli compiled-bins/; fi;) && \
     (if [ -e genevd ]; then cp -a genevd compiled-bins/; fi;) && \
     (if [ -e lilith ]; then cp -a lilith compiled-bins/; fi;) && \
-    (if [ -e "tau-cli" ]; then cp -a tau-cli compiled-bins/; fi;) && \
     (if [ -e taud ]; then cp -a taud compiled-bins/; fi;) && \
     (if [ -e vanityaddr ]; then cp -a vanityaddr compiled-bins/; fi;)