|
|
|
@ -1,11 +1,11 @@ |
|
|
|
|
use crate::{ |
|
|
|
|
cass::{Cassiopeia, TimeFile}, |
|
|
|
|
Address, Client, Io, |
|
|
|
|
Address, Client, Invoice, InvoiceId, Io, |
|
|
|
|
}; |
|
|
|
|
use serde::{Deserialize, Serialize}; |
|
|
|
|
use std::collections::BTreeMap; |
|
|
|
|
use std::{ |
|
|
|
|
fs::File, |
|
|
|
|
fs::{self, File, OpenOptions as Oo}, |
|
|
|
|
io::{Read, Write}, |
|
|
|
|
path::PathBuf, |
|
|
|
|
}; |
|
|
|
@ -31,25 +31,27 @@ pub struct Config { |
|
|
|
|
pub invoice_dir: PathBuf, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl Config { |
|
|
|
|
fn load(path: PathBuf) -> Self { |
|
|
|
|
let mut buf = String::new(); |
|
|
|
|
let mut f = File::open(path).unwrap(); |
|
|
|
|
f.read_to_string(&mut buf).unwrap(); |
|
|
|
|
Self::from_yaml(buf) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn store(&self, path: PathBuf) { |
|
|
|
|
let mut f = Oo::new().truncate(true).write(true).open(path).unwrap(); |
|
|
|
|
let buf = self.to_yaml(); |
|
|
|
|
f.write_all(buf.as_bytes()).unwrap(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl Meta { |
|
|
|
|
pub fn new(dir: BaseDirs) -> Self { |
|
|
|
|
// Get the path to the configuration, and make sure a default
|
|
|
|
|
// configuration is created if none exists yet.
|
|
|
|
|
let path = dir.find_config_file("config.yml").unwrap_or_else(|| { |
|
|
|
|
let path = dir.place_config_file("config.yml").unwrap(); |
|
|
|
|
let mut cfg = File::create(path.clone()).unwrap(); |
|
|
|
|
|
|
|
|
|
let buf = "revisioning: true |
|
|
|
|
invoicedir: $HOME/.local/k-office/"; |
|
|
|
|
cfg.write_all(buf.as_bytes()).unwrap(); |
|
|
|
|
path |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
let mut cfg = File::open(path).unwrap(); |
|
|
|
|
|
|
|
|
|
let mut buf = String::new(); |
|
|
|
|
cfg.read_to_string(&mut buf).unwrap(); |
|
|
|
|
let yml = Config::from_yaml(buf); |
|
|
|
|
let path = config_path(&dir); |
|
|
|
|
let yml = Config::load(path); |
|
|
|
|
|
|
|
|
|
Self { |
|
|
|
|
dir, |
|
|
|
@ -63,10 +65,19 @@ invoicedir: $HOME/.local/k-office/"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn load_timefile(&mut self, path: &str) { |
|
|
|
|
let timefile = Cassiopeia::load(path) |
|
|
|
|
.expect("Timefile not found") |
|
|
|
|
.timefile(); |
|
|
|
|
self.timefile = Some(timefile); |
|
|
|
|
self.timefile = Some(Cassiopeia::load(path) |
|
|
|
|
.map(|s| s.timefile()) |
|
|
|
|
.unwrap_or_else(|e| fatal!("Failed reading timefile: {}", e.to_string()))); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn load_config(&self) -> Config { |
|
|
|
|
let path = config_path(&self.dir); |
|
|
|
|
Config::load(path) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn store_config(&self, cfg: Config) { |
|
|
|
|
let path = config_path(&self.dir); |
|
|
|
|
cfg.store(path); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn client_mut(&mut self, name: &str) -> Option<&mut Client> { |
|
|
|
@ -83,12 +94,65 @@ invoicedir: $HOME/.local/k-office/"; |
|
|
|
|
}, |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn new_invoice_id(&self) -> InvoiceId { |
|
|
|
|
let files = match fs::read_dir(self.invoice_dir.as_path()) { |
|
|
|
|
Ok(f) => f, |
|
|
|
|
Err(_) => { |
|
|
|
|
let path = self |
|
|
|
|
.dir |
|
|
|
|
.create_config_directory("invoices") |
|
|
|
|
.unwrap_or_else(|_| fatal!("Failed to create invoice directory")); |
|
|
|
|
fs::read_dir(path).unwrap() |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
files.into_iter().fold(InvoiceId::date(), |inv, f| { |
|
|
|
|
let f = f.unwrap(); |
|
|
|
|
let i = Invoice::load(&f.path()).unwrap(); |
|
|
|
|
inv.find_next(&i) |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Update a configuration value and write it back to disk
|
|
|
|
|
pub fn update_config(&self, key: String, value: Option<String>) { |
|
|
|
|
let mut cfg = self.load_config(); |
|
|
|
|
match (key.as_str(), value) { |
|
|
|
|
("invoice_dir", Some(val)) => cfg.invoice_dir = PathBuf::new().join(val), |
|
|
|
|
("invoice_dir", None) => fatal!("Can not unset 'invoice_dir' configuration key"), |
|
|
|
|
(key, _) => fatal!("Unrecognised configuration key '{}'", key), |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
self.store_config(cfg); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Initialise a k-office application state
|
|
|
|
|
pub fn initialise() -> Meta { |
|
|
|
|
let dir = BaseDirs::with_prefix("k-koffice").unwrap(); |
|
|
|
|
dir.create_config_directory("") |
|
|
|
|
.expect("Couldn't create config directory"); |
|
|
|
|
.unwrap_or_else(|_| fatal!("Couldn't create config directory")); |
|
|
|
|
Meta::new(dir) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn config_path(dir: &BaseDirs) -> PathBuf { |
|
|
|
|
dir.find_config_file("config.yml").unwrap_or_else(|| { |
|
|
|
|
let path = dir.place_config_file("config.yml").unwrap(); |
|
|
|
|
let mut cfg = File::create(path.clone()).unwrap(); |
|
|
|
|
|
|
|
|
|
let invoice_dir: String = dir |
|
|
|
|
.get_config_home() |
|
|
|
|
.join("invoices") |
|
|
|
|
.to_str() |
|
|
|
|
.map(Into::into) |
|
|
|
|
.unwrap_or_else(|| fatal!("XDG_CONFIG_HOME contained non UTF-8 characters :(")); |
|
|
|
|
|
|
|
|
|
let buf = format!( |
|
|
|
|
"revisioning: true |
|
|
|
|
invoice_dir: {}", |
|
|
|
|
invoice_dir |
|
|
|
|
); |
|
|
|
|
cfg.write_all(buf.as_bytes()).unwrap(); |
|
|
|
|
path |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|