✨ Initial git support
This commit is contained in:
parent
584bcd4a88
commit
b53ce1de5f
23
src/cli.rs
23
src/cli.rs
@ -1,16 +1,16 @@
|
||||
mod cmds;
|
||||
mod dates;
|
||||
pub mod git;
|
||||
pub mod output;
|
||||
mod tables;
|
||||
|
||||
mod cmds;
|
||||
|
||||
use crate::args::{Commands, TasksArgs};
|
||||
use crate::args::{Commands, GitExecute, TasksArgs};
|
||||
use crate::args::{
|
||||
CompleteTask, CreateTask, DeleteTask, ModifyTask, ShowTask, StartTask, StopTask,
|
||||
CompleteTask, CreateTask, DeleteTask, ModifyTask, ShowTask, StartTask, StopTask, SyncTasks,
|
||||
};
|
||||
use crate::tasks::{Tasks, TasksError};
|
||||
|
||||
pub fn execute(tasks: &mut Tasks, arguments: TasksArgs) -> Result<&mut Tasks, TasksError> {
|
||||
pub fn execute(tasks: &mut Tasks, arguments: TasksArgs) -> Result<(), TasksError> {
|
||||
match arguments.command {
|
||||
Commands::Add(CreateTask {
|
||||
title,
|
||||
@ -59,8 +59,17 @@ pub fn execute(tasks: &mut Tasks, arguments: TasksArgs) -> Result<&mut Tasks, Ta
|
||||
cmds::show(tasks, id)?;
|
||||
}
|
||||
|
||||
Commands::Git(GitExecute { command }) => match git::execute(&tasks.path, command) {
|
||||
Ok(..) => (),
|
||||
Err(..) => panic!("failed to execute git cmd"),
|
||||
},
|
||||
|
||||
Commands::Sync(SyncTasks { remote }) => match git::sync(&tasks.path, remote) {
|
||||
Ok(..) => (),
|
||||
Err(..) => panic!("failed"),
|
||||
},
|
||||
|
||||
_ => todo!(),
|
||||
};
|
||||
|
||||
Ok(tasks)
|
||||
Ok(())
|
||||
}
|
||||
|
@ -4,18 +4,13 @@ use crate::cli::tables;
|
||||
use crate::tasks::{Task, Tasks, TasksError};
|
||||
|
||||
fn parse_tags(tags: Option<String>) -> Option<Vec<String>> {
|
||||
if let Some(..) = tags {
|
||||
Some(tags.unwrap().split(',').map(str::to_string).collect())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
tags.map(|tags| tags.split(',').map(str::to_string).collect())
|
||||
}
|
||||
|
||||
pub fn show(tasks: &mut Tasks, id: Option<usize>) -> Result<(), TasksError> {
|
||||
// If no id is given, print out all tasks
|
||||
if let Some(..) = id {
|
||||
if let Some(id) = id {
|
||||
// Get the task the user wants to see
|
||||
let id = id.unwrap();
|
||||
let task = tasks.get_task(id)?;
|
||||
|
||||
// Generate the table for the singular task
|
||||
|
@ -2,8 +2,8 @@ use chrono::{Local, NaiveDateTime};
|
||||
use colored::{ColoredString, Colorize};
|
||||
|
||||
pub fn parse_fuzzy_date(date_string: Option<String>) -> Option<NaiveDateTime> {
|
||||
if let Some(..) = date_string {
|
||||
match fuzzydate::parse(date_string.unwrap()) {
|
||||
if let Some(date_string) = date_string {
|
||||
match fuzzydate::parse(date_string) {
|
||||
Ok(date) => Some(date),
|
||||
Err(err) => panic!("{} {:?}", "error:".red().bold(), err),
|
||||
}
|
||||
|
30
src/cli/git.rs
Normal file
30
src/cli/git.rs
Normal file
@ -0,0 +1,30 @@
|
||||
use std::error::Error;
|
||||
use std::process::Command;
|
||||
|
||||
use crate::cli::output;
|
||||
|
||||
pub fn execute(path: &str, command: String) -> Result<(), Box<dyn Error>> {
|
||||
let output = Command::new("git")
|
||||
.args(["-C", path])
|
||||
.args(command.split(' '))
|
||||
.output()?;
|
||||
|
||||
if !output.stdout.is_empty() {
|
||||
output::git(String::from_utf8(output.stdout).unwrap());
|
||||
};
|
||||
if !output.stderr.is_empty() {
|
||||
output::error(String::from_utf8(output.stderr).unwrap());
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn sync(repo_path: &str, remote: String) -> Result<(), Box<dyn Error>> {
|
||||
execute(
|
||||
repo_path,
|
||||
format!("pull --ff --no-rebase --no-edit --commit {remote}"),
|
||||
)?;
|
||||
execute(repo_path, format!("push {remote}"))?;
|
||||
|
||||
Ok(())
|
||||
}
|
@ -1,7 +1,11 @@
|
||||
use crate::tasks::Task;
|
||||
use colored::Colorize;
|
||||
|
||||
pub fn warning(msg: &str) {
|
||||
pub fn error(msg: String) {
|
||||
println!("{} {}", "error".red().bold(), msg);
|
||||
}
|
||||
|
||||
pub fn warning(msg: String) {
|
||||
println!("{} {}", "warning:".yellow().bold(), msg);
|
||||
}
|
||||
|
||||
@ -9,6 +13,11 @@ pub fn info(msg: String) {
|
||||
println!("{} {}", "info:".blue().bold(), msg);
|
||||
}
|
||||
|
||||
pub fn git(msg: String) {
|
||||
let msg = msg.strip_suffix('\n').unwrap_or(&msg);
|
||||
println!("{} {}", "git:".blue().bold(), msg.bright_black().italic());
|
||||
}
|
||||
|
||||
pub fn success(msg: String) {
|
||||
println!("{} {}", "success:".green().bold(), msg);
|
||||
}
|
||||
|
50
src/data.rs
50
src/data.rs
@ -2,24 +2,30 @@ use dirs::home_dir;
|
||||
use std::error::Error;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::string::ToString;
|
||||
|
||||
use crate::cli::git;
|
||||
use crate::cli::output;
|
||||
use crate::tasks::Tasks;
|
||||
|
||||
const TASKS_FILE_PATH: &str = "/.local/share/tasks";
|
||||
|
||||
pub fn save_tasks<P: AsRef<Path>>(path: P, tasks: &Tasks) -> Result<(), Box<dyn Error>> {
|
||||
// Convert the tasks to TOML format
|
||||
let data = toml::to_string_pretty(&tasks)?;
|
||||
|
||||
// Write the JSON to the file
|
||||
// Write the TOML to the file
|
||||
fs::write(path, data)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load_tasks<P: AsRef<Path>>(path: P) -> Result<Tasks, Box<dyn Error>> {
|
||||
// Read JSON from the file
|
||||
let data = fs::read_to_string(path)?;
|
||||
pub fn load_tasks<P: AsRef<Path> + ToString>(
|
||||
path: P,
|
||||
tasks_file: &str,
|
||||
) -> Result<Tasks, Box<dyn Error>> {
|
||||
let tasks_file_path = &format!("{}/{}", path.to_string(), tasks_file);
|
||||
|
||||
// Read TOML from the file
|
||||
let data = fs::read_to_string(tasks_file_path)?;
|
||||
|
||||
// Load the tasks from TOML form
|
||||
let tasks: Tasks = toml::from_str(&data)?;
|
||||
@ -27,11 +33,29 @@ pub fn load_tasks<P: AsRef<Path>>(path: P) -> Result<Tasks, Box<dyn Error>> {
|
||||
Ok(tasks)
|
||||
}
|
||||
|
||||
pub fn tasks_file_path() -> String {
|
||||
// Generate the path for the location of tasks
|
||||
format!(
|
||||
"{}{}",
|
||||
home_dir().unwrap().to_str().unwrap(),
|
||||
TASKS_FILE_PATH
|
||||
)
|
||||
pub fn ensure_repo(path: &str, tasks_file: &str) -> Result<(), Box<dyn Error>> {
|
||||
// Generate the path of the tasks file
|
||||
let tasks_file_path = &format!("{}/{}", path, tasks_file);
|
||||
|
||||
// Check if the path exists
|
||||
if !Path::new(path).exists() {
|
||||
output::warning(format!(
|
||||
"tasks repository {path} does not exist. creating..."
|
||||
));
|
||||
fs::create_dir_all(path).unwrap();
|
||||
let tasks = Tasks::new(path, tasks_file);
|
||||
save_tasks(tasks_file_path, &tasks).unwrap();
|
||||
git::execute(path, String::from("init"))?;
|
||||
git::execute(path, String::from("add ."))?;
|
||||
output::success(format!("created tasks repo {path}"));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn tasks_repo_string() -> String {
|
||||
// Generate the path for the location of tasks
|
||||
let home_dir = home_dir().unwrap();
|
||||
let home_dir = home_dir.to_str().unwrap();
|
||||
format!("{home_dir}/.local/share/inertia")
|
||||
}
|
||||
|
26
src/main.rs
26
src/main.rs
@ -3,36 +3,36 @@ mod cli;
|
||||
mod data;
|
||||
mod tasks;
|
||||
|
||||
use crate::args::TasksArgs;
|
||||
use crate::tasks::Tasks;
|
||||
use clap::Parser;
|
||||
use colored::*;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::args::TasksArgs;
|
||||
|
||||
fn main() {
|
||||
// Generate the file path for tasks
|
||||
let tasks_file_path = data::tasks_file_path();
|
||||
// Generate the file paths for tasks
|
||||
let repo_path = &data::tasks_repo_string();
|
||||
let tasks_file = "tasks";
|
||||
|
||||
// If the tasks file doesn't exist, create it first
|
||||
if !Path::new(&tasks_file_path).exists() {
|
||||
cli::output::warning("file '~/.local/share/tasks' does not exist. creating...");
|
||||
let tasks = Tasks::new(&tasks_file_path);
|
||||
data::save_tasks(&tasks_file_path, &tasks).unwrap();
|
||||
match data::ensure_repo(repo_path, tasks_file) {
|
||||
Ok(..) => (),
|
||||
Err(error) => panic!("{} {:?}", "error:".red().bold(), error),
|
||||
};
|
||||
|
||||
// Load tasks and check for any errors when loading the tasks
|
||||
let mut tasks = match data::load_tasks(&tasks_file_path) {
|
||||
let mut tasks = match data::load_tasks(repo_path, tasks_file) {
|
||||
Ok(tasks) => tasks,
|
||||
Err(error) => panic!("{} {:?}", "error:".red().bold(), error),
|
||||
};
|
||||
|
||||
// Parse command line arguments
|
||||
let arguments = TasksArgs::parse();
|
||||
let tasks = match cli::execute(&mut tasks, arguments) {
|
||||
Ok(tasks) => tasks,
|
||||
match cli::execute(&mut tasks, arguments) {
|
||||
Ok(..) => (),
|
||||
Err(error) => panic!("{} {:?}", "error:".red().bold(), error),
|
||||
};
|
||||
|
||||
// Save any changes
|
||||
data::save_tasks(tasks_file_path, tasks).unwrap()
|
||||
cli::git::execute(repo_path, String::from("add --all")).unwrap();
|
||||
data::save_tasks(&repo_path, &tasks).unwrap();
|
||||
}
|
||||
|
32
src/tasks.rs
32
src/tasks.rs
@ -26,7 +26,8 @@ pub struct Task {
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct Tasks {
|
||||
pub path: String, // Where the tasks are stored
|
||||
pub path: String, // Path to the tasks repository
|
||||
pub file: String, // Path to the tasks file in the repository
|
||||
pub tasks: Option<Vec<Task>>, // All the tasks in one vector
|
||||
}
|
||||
|
||||
@ -73,28 +74,28 @@ impl Task {
|
||||
deadline: Option<NaiveDateTime>,
|
||||
reminder: Option<NaiveDateTime>,
|
||||
) {
|
||||
if let Some(..) = title {
|
||||
self.title = title.unwrap();
|
||||
if let Some(title) = title {
|
||||
self.title = title;
|
||||
};
|
||||
|
||||
if let Some(..) = notes {
|
||||
self.notes = Some(notes.unwrap());
|
||||
if let Some(notes) = notes {
|
||||
self.notes = Some(notes);
|
||||
};
|
||||
|
||||
if let Some(..) = tags {
|
||||
self.tags = Some(tags.unwrap());
|
||||
if let Some(tags) = tags {
|
||||
self.tags = Some(tags);
|
||||
};
|
||||
|
||||
if let Some(..) = when {
|
||||
self.when = Some(when.unwrap());
|
||||
if let Some(when) = when {
|
||||
self.when = Some(when);
|
||||
};
|
||||
|
||||
if let Some(..) = deadline {
|
||||
self.deadline = Some(deadline.unwrap());
|
||||
if let Some(deadline) = deadline {
|
||||
self.deadline = Some(deadline);
|
||||
};
|
||||
|
||||
if let Some(..) = reminder {
|
||||
self.reminder = Some(reminder.unwrap());
|
||||
if let Some(reminder) = reminder {
|
||||
self.reminder = Some(reminder);
|
||||
};
|
||||
}
|
||||
|
||||
@ -116,9 +117,10 @@ impl Task {
|
||||
}
|
||||
|
||||
impl Tasks {
|
||||
pub fn new(tasks_path: &str) -> Self {
|
||||
pub fn new(repo_path: &str, tasks_file: &str) -> Self {
|
||||
Self {
|
||||
path: String::from(tasks_path),
|
||||
path: String::from(repo_path),
|
||||
file: String::from(tasks_file),
|
||||
tasks: None,
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user