mod connectors;
mod operations;
mod property;
mod status;
mod util;
extern crate gittask;
use std::process::ExitCode;
use clap::{Parser, Subcommand};
use crate::operations::{task_clear, task_create, task_delete, task_edit, task_export, task_get, task_import, task_list, task_pull, task_push, task_replace, task_set, task_show, task_stats, task_status, task_unset};
use crate::operations::comment::*;
use crate::operations::config::*;
use crate::operations::config::properties::*;
use crate::operations::config::status::*;
use crate::operations::label::*;
#[derive(Parser)]
#[command(version, about = "Local-first task manager/bug tracker within your git repository which can sync issues from/to GitHub, Gitlab, Jira Cloud and Redmine.", arg_required_else_help(true))]
struct Args {
#[command(subcommand)]
command: Option<Command>,
}
#[derive(Subcommand)]
enum Command {
List {
#[arg(short, long, value_delimiter = ',')]
status: Option<Vec<String>>,
#[arg(short, long)]
keyword: Option<String>,
#[arg(short, long)]
from: Option<String>,
#[arg(short, long)]
until: Option<String>,
#[arg(long)]
author: Option<String>,
#[arg(short, long, value_delimiter = ',')]
columns: Option<Vec<String>>,
#[arg(long)]
headers: bool,
#[arg(long, value_delimiter = ',')]
sort: Option<Vec<String>>,
#[arg(short, long)]
limit: Option<usize>,
#[arg(long)]
filter: Option<String>,
#[arg(long)]
no_color: bool,
},
Show {
id: String,
#[arg(long)]
no_color: bool,
},
#[clap(visible_aliases(["add", "new"]))]
Create {
name: String,
description: Option<String>,
#[arg(short, long, conflicts_with = "description")]
no_desc: bool,
#[arg(short, long)]
push: bool,
#[arg(short, long)]
remote: Option<String>,
#[arg(long = "connector", aliases = ["conn"])]
connector_type: Option<String>,
},
Status {
#[clap(required = true)]
ids: String,
#[clap(required = true)]
status: String,
#[arg(short, long)]
push: bool,
#[arg(short, long)]
remote: Option<String>,
#[arg(long = "connector", aliases = ["conn"])]
connector_type: Option<String>,
#[arg(long)]
no_color: bool,
},
Get {
id: String,
prop_name: String,
},
Set {
#[clap(required = true)]
ids: String,
prop_name: String,
value: String,
#[arg(short, long)]
push: bool,
#[arg(short, long)]
remote: Option<String>,
#[arg(long = "connector", aliases = ["conn"])]
connector_type: Option<String>,
#[arg(long)]
no_color: bool,
},
Replace {
#[clap(required = true)]
ids: String,
#[clap(required = true)]
prop_name: String,
#[clap(required = true)]
search: String,
#[clap(required = true)]
replace: String,
#[arg(alias = "rx", long)]
regex: bool,
#[arg(short, long)]
push: bool,
#[arg(short, long)]
remote: Option<String>,
#[arg(long = "connector", aliases = ["conn"])]
connector_type: Option<String>,
#[arg(long)]
no_color: bool,
},
Unset {
ids: String,
prop_name: String,
},
Edit {
id: String,
prop_name: String,
},
Comment {
#[command(subcommand)]
subcommand: CommentCommand,
},
#[clap(visible_aliases(["lab", "lbl"]))]
Label {
#[command(subcommand)]
subcommand: LabelCommand,
},
Import {
ids: Option<String>,
#[arg(short, long)]
format: Option<String>,
},
Export {
ids: Option<String>,
#[arg(short, long, value_delimiter = ',')]
status: Option<Vec<String>>,
#[arg(short, long)]
limit: Option<usize>,
#[arg(short, long)]
format: Option<String>,
#[arg(short, long)]
pretty: bool,
},
Pull {
ids: Option<String>,
#[arg(short, long, conflicts_with = "ids")]
limit: Option<usize>,
#[arg(short, long, conflicts_with = "ids")]
status: Option<String>,
#[arg(short, long)]
remote: Option<String>,
#[arg(long = "connector", aliases = ["conn"])]
connector_type: Option<String>,
#[arg(long, aliases = ["nc"])]
no_comments: bool,
#[arg(long, aliases = ["nl"])]
no_labels: bool,
},
Push {
ids: String,
#[arg(short, long)]
remote: Option<String>,
#[arg(long = "connector", aliases = ["conn"])]
connector_type: Option<String>,
#[arg(short, long)]
no_comments: bool,
#[arg(long, aliases = ["nl"])]
no_labels: bool,
#[arg(long)]
no_color: bool,
},
Stats {
#[arg(long)]
no_color: bool,
},
#[clap(visible_aliases(["del", "remove", "rem"]))]
Delete {
#[clap(required = true)]
ids: Option<String>,
#[arg(short, long, value_delimiter = ',', conflicts_with = "ids", required_unless_present = "ids")]
status: Option<Vec<String>>,
#[arg(short, long)]
push: bool,
#[arg(short, long)]
remote: Option<String>,
#[arg(long = "connector", aliases = ["conn"])]
connector_type: Option<String>,
},
Clear,
#[clap(visible_aliases(["cfg"]))]
Config {
#[command(subcommand)]
subcommand: ConfigCommand,
},
}
#[derive(Subcommand)]
enum CommentCommand {
#[clap(visible_aliases(["create", "new"]))]
Add {
task_id: String,
text: Option<String>,
#[arg(short, long)]
push: bool,
#[arg(short, long)]
remote: Option<String>,
#[arg(long = "connector", aliases = ["conn"])]
connector_type: Option<String>,
},
Set {
task_id: String,
comment_id: String,
text: String,
#[arg(short, long)]
push: bool,
#[arg(short, long)]
remote: Option<String>,
#[arg(long = "connector", aliases = ["conn"])]
connector_type: Option<String>,
},
Edit {
task_id: String,
comment_id: String,
#[arg(short, long)]
push: bool,
#[arg(short, long)]
remote: Option<String>,
#[arg(long = "connector", aliases = ["conn"])]
connector_type: Option<String>,
},
#[clap(visible_aliases(["del", "remove", "rem"]))]
Delete {
task_id: String,
comment_id: String,
#[arg(short, long)]
push: bool,
#[arg(short, long)]
remote: Option<String>,
#[arg(long = "connector", aliases = ["conn"])]
connector_type: Option<String>,
},
}
#[derive(Subcommand)]
enum LabelCommand {
#[clap(visible_aliases(["create", "new"]))]
Add {
task_id: String,
name: String,
color: Option<String>,
#[arg(short, long, aliases = ["desc"])]
description: Option<String>,
#[arg(short, long)]
push: bool,
#[arg(short, long)]
remote: Option<String>,
#[arg(long = "connector", aliases = ["conn"])]
connector_type: Option<String>,
},
#[clap(visible_aliases(["del", "remove", "rem"]))]
Delete {
task_id: String,
name: String,
#[arg(short, long)]
push: bool,
#[arg(short, long)]
remote: Option<String>,
#[arg(long = "connector", aliases = ["conn"])]
connector_type: Option<String>,
},
}
#[derive(Subcommand)]
enum ConfigCommand {
Get {
param: String,
},
Set {
param: String,
value: String,
#[arg(long = "move")]
move_ref: bool,
},
List,
Status {
#[command(subcommand)]
subcommand: StatusCommand,
},
#[clap(visible_aliases(["props", "prop"]))]
Properties {
#[command(subcommand)]
subcommand: PropertiesCommand,
},
Connectors {
#[command(subcommand)]
subcommand: ConnectorsCommand,
},
}
#[derive(Subcommand)]
#[clap(visible_aliases(["conns", "conn"]))]
pub(crate) enum ConnectorsCommand {
List {
name: Option<String>,
},
}
#[derive(Subcommand)]
enum StatusCommand {
#[clap(visible_aliases(["create", "new"]))]
Add {
name: String,
shortcut: String,
color: String,
is_done: Option<bool>,
},
#[clap(visible_aliases(["del", "remove", "rem"]))]
Delete {
name: String,
#[arg(short, long)]
force: bool,
},
Get {
name: String,
param: String,
},
Set {
name: String,
param: String,
value: String,
},
List,
Import,
Export {
#[arg(short, long)]
pretty: bool,
},
Reset,
}
#[derive(Subcommand)]
enum PropertiesCommand {
#[clap(visible_aliases(["create", "new"]))]
Add {
name: String,
value_type: String,
color: String,
#[arg(long, short)]
style: Option<String>,
#[arg(long = "enum_value", num_args = 1..)]
enum_values: Option<Vec<String>>,
#[arg(long = "cond_format", num_args = 1..)]
cond_format: Option<Vec<String>>,
},
#[clap(visible_aliases(["del", "remove", "rem"]))]
Delete {
name: String,
#[arg(short, long)]
force: bool,
},
Get {
name: String,
param: String,
},
Set {
name: String,
param: String,
value: String,
},
#[clap(visible_aliases(["enums"]))]
Enum {
#[command(subcommand)]
subcommand: PropertiesEnumCommand,
},
#[clap(visible_aliases(["cond"]))]
CondFormat {
#[command(subcommand)]
subcommand: PropertiesCondFormatCommand,
},
List,
Import,
Export {
#[arg(short, long)]
pretty: bool,
},
Reset,
}
#[derive(Subcommand)]
enum PropertiesEnumCommand {
List {
name: String,
},
#[clap(visible_aliases(["create", "new"]))]
Add {
name: String,
enum_value_name: String,
enum_value_color: String,
enum_value_style: Option<String>,
},
Get {
property: String,
enum_value_name: String,
parameter: String,
},
Set {
name: String,
enum_value_name: String,
enum_value_color: String,
enum_value_style: Option<String>,
},
#[clap(visible_aliases(["del", "remove", "rem"]))]
Delete {
name: String,
enum_value_name: String,
},
}
#[derive(Subcommand)]
enum PropertiesCondFormatCommand {
List {
name: String,
},
#[clap(visible_aliases(["create", "new"]))]
Add {
name: String,
cond_format_expr: String,
cond_format_color: String,
cond_format_style: Option<String>,
},
Clear {
name: String,
},
}
fn main() -> ExitCode {
let _ = enable_ansi_support::enable_ansi_support();
let args = Args::parse();
let success = match args.command {
Some(Command::List { status, keyword, filter, from, until, author, columns, headers, sort, limit, no_color }) => task_list(status, keyword, filter, from, until, author, columns, headers, sort, limit, no_color),
Some(Command::Show { id, no_color }) => task_show(id, no_color),
Some(Command::Create { name, description, no_desc, push, remote, connector_type: connector }) => task_create(name, description, no_desc, push, &remote, &connector),
Some(Command::Status { ids, status, push, remote, connector_type: connector, no_color }) => task_status(ids, status, push, &remote, &connector, no_color),
Some(Command::Get { id, prop_name }) => task_get(id, prop_name),
Some(Command::Set { ids, prop_name, value, push, remote, connector_type: connector, no_color }) => task_set(ids, prop_name, value, push, &remote, &connector, no_color),
Some(Command::Replace { ids, prop_name, search, replace, regex, push, remote, connector_type: connector, no_color }) => task_replace(ids, prop_name, search, replace, regex, push, &remote, &connector, no_color),
Some(Command::Unset { ids, prop_name }) => task_unset(ids, prop_name),
Some(Command::Edit { id, prop_name }) => task_edit(id, prop_name),
Some(Command::Comment { subcommand }) => task_comment(subcommand),
Some(Command::Label { subcommand }) => task_label(subcommand),
Some(Command::Import { ids, format }) => task_import(ids, format),
Some(Command::Export { ids, status, limit, format, pretty }) => task_export(ids, status, limit, format, pretty),
Some(Command::Pull { ids, limit, status, remote, connector_type: connector, no_comments, no_labels }) => task_pull(ids, limit, status, &remote, &connector, no_comments, no_labels),
Some(Command::Push { ids, remote, connector_type: connector, no_comments, no_labels, no_color }) => task_push(ids, &remote, &connector, no_comments, no_labels, no_color),
Some(Command::Stats { no_color }) => task_stats(no_color),
Some(Command::Delete { ids, status, push, remote, connector_type: connector }) => task_delete(ids, status, push, &remote, &connector),
Some(Command::Clear) => task_clear(),
Some(Command::Config { subcommand }) => task_config(subcommand),
None => false
};
if success { ExitCode::SUCCESS } else { ExitCode::FAILURE }
}
fn task_comment(subcommand: CommentCommand) -> bool {
match subcommand {
CommentCommand::Add { task_id, text, push, remote, connector_type: connector } => task_comment_add(task_id, text, push, &remote, &connector),
CommentCommand::Set { task_id, comment_id, text, push, remote, connector_type: connector } => task_comment_set(task_id, comment_id, text, push, &remote, &connector),
CommentCommand::Edit { task_id, comment_id, push, remote, connector_type: connector } => task_comment_edit(task_id, comment_id, push, &remote, &connector),
CommentCommand::Delete { task_id, comment_id, push, remote, connector_type: connector } => task_comment_delete(task_id, comment_id, push, &remote, &connector),
}
}
fn task_label(subcommand: LabelCommand) -> bool {
match subcommand {
LabelCommand::Add { task_id, name, color, description, push, remote, connector_type: connector } => task_label_add(task_id, name, color, description, push, &remote, &connector),
LabelCommand::Delete { task_id, name, push, remote, connector_type: connector } => task_label_delete(task_id, name, push, &remote, &connector),
}
}
fn task_config(subcommand: ConfigCommand) -> bool {
match subcommand {
ConfigCommand::Get { param } => task_config_get(param),
ConfigCommand::Set { param, value, move_ref } => task_config_set(param, value, move_ref),
ConfigCommand::List => task_config_list(),
ConfigCommand::Status { subcommand } => task_config_status(subcommand),
ConfigCommand::Properties { subcommand } => task_config_properties(subcommand),
ConfigCommand::Connectors { subcommand } => task_config_connectors(subcommand),
}
}
fn task_config_connectors(subcommand: ConnectorsCommand) -> bool {
match subcommand {
ConnectorsCommand::List { name } => task_config_connectors_list(name),
}
}
fn task_config_status(subcommand: StatusCommand) -> bool {
match subcommand {
StatusCommand::Add { name, shortcut, color, is_done } => task_config_status_add(name, shortcut, color, is_done),
StatusCommand::Delete { name, force } => task_config_status_delete(name, force),
StatusCommand::Get { name, param } => task_config_status_get(name, param),
StatusCommand::Set { name, param, value } => task_config_status_set(name, param, value),
StatusCommand::List => task_config_status_list(),
StatusCommand::Import => task_config_status_import(),
StatusCommand::Export { pretty } => task_config_status_export(pretty),
StatusCommand::Reset => task_config_status_reset(),
}
}
fn task_config_properties(subcommand: PropertiesCommand) -> bool {
match subcommand {
PropertiesCommand::Add { name, value_type, color, style, enum_values, cond_format } => task_config_properties_add(name, value_type, color, style, enum_values, cond_format),
PropertiesCommand::Delete { name, force } => task_config_properties_delete(name, force),
PropertiesCommand::Get { name, param } => task_config_properties_get(name, param),
PropertiesCommand::Set { name, param, value } => task_config_properties_set(name, param, value),
PropertiesCommand::Enum { subcommand } => task_config_properties_enum(subcommand),
PropertiesCommand::CondFormat { subcommand } => task_config_properties_cond_format(subcommand),
PropertiesCommand::List => task_config_properties_list(),
PropertiesCommand::Import => task_config_properties_import(),
PropertiesCommand::Export { pretty } => task_config_properties_export(pretty),
PropertiesCommand::Reset => task_config_properties_reset(),
}
}
fn task_config_properties_enum(subcommand: PropertiesEnumCommand) -> bool {
match subcommand {
PropertiesEnumCommand::List { name } => task_config_properties_enum_list(name),
PropertiesEnumCommand::Add { name, enum_value_name, enum_value_color, enum_value_style } => task_config_properties_enum_add(name, enum_value_name, enum_value_color, enum_value_style),
PropertiesEnumCommand::Get { property, enum_value_name, parameter } => task_config_properties_enum_get(property, enum_value_name, parameter),
PropertiesEnumCommand::Set { name, enum_value_name, enum_value_color, enum_value_style } => task_config_properties_enum_set(name, enum_value_name, enum_value_color, enum_value_style),
PropertiesEnumCommand::Delete { name, enum_value_name } => task_config_properties_enum_delete(name, enum_value_name),
}
}
fn task_config_properties_cond_format(subcommand: PropertiesCondFormatCommand) -> bool {
match subcommand {
PropertiesCondFormatCommand::List { name } => task_config_properties_cond_format_list(name),
PropertiesCondFormatCommand::Add { name, cond_format_expr, cond_format_color, cond_format_style } => task_config_properties_cond_format_add(name, cond_format_expr, cond_format_color, cond_format_style),
PropertiesCondFormatCommand::Clear { name } => task_config_properties_cond_format_clear(name),
}
}