My personal project and infrastructure archive
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
nomicon/apps/cassiopeia/src/lib.rs

129 lines
3.5 KiB

//! Cassiopeia plain text time tracking tool
//!
//! Versions `0.1` and `0.2` were written in Ruby and are thus
//! deprecated. Most likely you are interested in `cass(1)`, the
//! simple plain text time tracking utility, part of the kookie-office
//! suite of commandline tools! This is the library powering it.
//!
//! For more documentation, check out:
//! https://git.spacekookie.de/kookienomicon/tree/apps/cassiopeia
mod data;
mod format;
pub mod meta;
mod time;
pub use data::{Session, TimeFile};
pub use format::load_file;
/// A state handler for all cass interactions
///
/// This could be a stateless API, but I like being able to refer to
/// fields that need to be saved for later here. This API wraps
/// around [`TimeFile`](crate::TimeFile), so that you don't have to! ✨
pub struct Cassiopeia {
path: String,
tf: TimeFile,
}
impl Cassiopeia {
/// Load a cass file from disk, parsing it into a [`TimeFile`](crate::TimeFile)
pub fn load(path: &str) -> Option<Self> {
let path = path.to_owned();
load_file(path.as_str()).map(|tf| Self { path, tf })
}
/// Store the modified time file back to disk
pub fn store(&self) -> Option<()> {
Some(())
}
/// Start a new work session (with optional 15 minute rounding)
pub fn start(&mut self, round: bool) -> Option<()> {
self.tf.start(round)
}
/// Stop the existing work session (with optional 15 minute rounding)
pub fn stop(&mut self, round: bool) -> Option<()> {
Some(())
}
/// Add an invoice block to the time file
pub fn invoice<'slf>(&'slf mut self) -> Invoicer<'slf> {
Invoicer::new(self)
}
}
/// An invoice generator builder
///
/// The most simple use-case of this type is to provide no parameters
/// and simply add an `INVOICE` line to the cass file. Adittionally
/// you may provide the client and project name, which will then
/// require the `client_db` path to be set as well.
///
/// ```rust,no_run
/// # let mut cass = cassiopeia::Cassiopeia::load("").unwrap();
/// cass.invoice().run();
/// ```
///
/// Additional errors can be thrown if the client or project are not
/// known in the client db.
///
/// ```rust,no_run
/// # let mut cass = cassiopeia::Cassiopeia::load("").unwrap();
/// cass.invoice()
/// .generate()
/// .db("/home/office/clients.yml".into())
/// .client("ACME".into())
/// .run();
/// ```
pub struct Invoicer<'cass> {
tf: &'cass mut Cassiopeia,
generate: bool,
client_db: String,
client: String,
project: String,
}
impl<'cass> Invoicer<'cass> {
pub fn new(tf: &'cass mut Cassiopeia) -> Self {
Self {
tf,
generate: false,
client_db: String::new(),
client: String::new(),
project: String::new(),
}
}
/// S
pub fn generate(self) -> Self {
Self {
generate: true,
..self
}
}
/// Provide the client database file (.yml format)
pub fn db(self, client_db: String) -> Self {
Self { client_db, ..self }
}
/// Provide the client to invoice
pub fn client(self, client: String) -> Self {
Self { client, ..self }
}
pub fn project(self, project: String) -> Self {
Self { project, ..self }
}
pub fn run(self) -> Option<()> {
if self.generate {
eprintln!("Integration with invoice(1) is currently not implemented. Sorry :()");
return None;
}
None
}
}