Initial git support

This commit is contained in:
Maddie H 2023-02-25 22:42:17 +00:00
parent 584bcd4a88
commit b53ce1de5f
No known key found for this signature in database
GPG Key ID: 64FAA9959751687D
8 changed files with 127 additions and 58 deletions

View File

@ -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(())
}

View File

@ -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

View File

@ -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
View 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(())
}

View File

@ -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);
}

View File

@ -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")
}

View File

@ -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();
}

View File

@ -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,
}
}