So much premature optimization
This commit is contained in:
parent
77cabd9e3e
commit
ab9b3647f9
8 changed files with 91 additions and 79 deletions
20
src/cli.rs
20
src/cli.rs
|
@ -33,6 +33,26 @@ pub struct Cli {
|
|||
pub config_file_path: Option<String>,
|
||||
}
|
||||
|
||||
impl Cli {
|
||||
pub async fn exec(self) -> Result<()> {
|
||||
let tasks = Arc::new(crate::tasks::Tasks::try_new(
|
||||
self.config_file_path,
|
||||
self.data_directory,
|
||||
)?);
|
||||
|
||||
match self.command {
|
||||
Commands::Ui(args) => args.run(tasks).await,
|
||||
Commands::Purge(args) => args.run(tasks).await,
|
||||
Commands::Cleanup(args) => args.run(tasks).await,
|
||||
Commands::Sync(args) => args.sync(tasks).await,
|
||||
Commands::List(args) => args.list(tasks).await,
|
||||
Commands::Jira(jira) => jira.exec(tasks).await,
|
||||
Commands::Gitlab(gitlab) => gitlab.exec(tasks).await,
|
||||
Commands::Config(config) => config.exec(tasks).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum Commands {
|
||||
/// List local tasks with options for syncing
|
||||
|
|
|
@ -8,19 +8,12 @@ pub enum Command {
|
|||
impl Command {
|
||||
pub async fn exec(&self, tasks: SharedTasks) -> Result<()> {
|
||||
match self {
|
||||
Command::Show => self.show().await,
|
||||
Command::Show => self.show(tasks).await,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn show(&self) -> Result<()> {}
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
pub struct MeArgs {}
|
||||
|
||||
impl MeArgs {
|
||||
pub async fn me(&self, tasks: SharedTasks) -> Result<()> {
|
||||
println!("{:#?}", tasks.gitlab()?.me().await?);
|
||||
pub async fn show(&self, tasks: SharedTasks) -> Result<()> {
|
||||
println!("{:#?}", tasks.config());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use crate::prelude::*;
|
||||
|
||||
use std::{collections::HashMap, fmt::Debug, path::Path};
|
||||
use std::{fmt::Debug, path::Path};
|
||||
|
||||
use color_eyre::{eyre::Context, Section};
|
||||
use config::{builder::DefaultState, Config as CConfig, ConfigBuilder};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
@ -25,38 +26,22 @@ pub struct Config {
|
|||
}
|
||||
|
||||
impl Config {
|
||||
pub fn load<P>(config_file_path: Option<P>) -> Result<Self>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
pub fn load(config_file_path: &Path) -> Result<Self> {
|
||||
let c = Self::builder(config_file_path)?.build()?;
|
||||
Ok(c.try_deserialize()?)
|
||||
Ok(c.try_deserialize()
|
||||
.suggestion("run `taskr config setup` to ensure valid configuration")
|
||||
.with_context(|| "failed to deserialize configuration")?)
|
||||
}
|
||||
|
||||
pub fn builder<P>(config_file_path: Option<P>) -> Result<ConfigBuilder<DefaultState>>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let config_file_path: Box<dyn AsRef<Path>> = config_file_path
|
||||
.as_ref()
|
||||
.map(|s| Ok::<Box<dyn AsRef<Path>>, anyhow::Error>(Box::new(s.as_ref())))
|
||||
.unwrap_or_else(|| {
|
||||
Ok(Box::new(
|
||||
xdg::BaseDirectories::new()?.get_config_file("taskr/config.toml"),
|
||||
))
|
||||
})?;
|
||||
|
||||
Ok(Self::default_builder()
|
||||
.map_err(anyhow::Error::from)?
|
||||
pub fn builder(config_file_path: &Path) -> Result<ConfigBuilder<DefaultState>>
|
||||
where {
|
||||
Ok(Self::default_builder()?
|
||||
.add_source(config::File::from((*config_file_path).as_ref()).required(false))
|
||||
.add_source(config::Environment::with_prefix("taskr").separator("__")))
|
||||
}
|
||||
|
||||
pub fn default_builder() -> Result<ConfigBuilder<DefaultState>> {
|
||||
Ok(CConfig::builder()
|
||||
.set_default("version", CURRENT_VERSION)?
|
||||
.set_default("jira", Option::<HashMap<String, config::Value>>::None)?
|
||||
.set_default("gitlab", Option::<HashMap<String, config::Value>>::None)?)
|
||||
Ok(CConfig::builder().set_default("version", CURRENT_VERSION)?)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
|
20
src/main.rs
20
src/main.rs
|
@ -12,31 +12,19 @@ mod task;
|
|||
mod tasks;
|
||||
mod tui;
|
||||
|
||||
use config::Config;
|
||||
|
||||
use crate::cli::{Cli, Commands};
|
||||
use crate::prelude::*;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
observe::setup_error_handling()?;
|
||||
|
||||
let cli = Cli::new();
|
||||
let conf = Config::load(cli.config_file_path)?;
|
||||
|
||||
// this guard causes logs to be flushed when dropped (which is at the end of
|
||||
// this function which would be the end of our program)
|
||||
// https://docs.rs/tracing-appender/latest/tracing_appender/non_blocking/struct.WorkerGuard.html
|
||||
let _log_guard = observe::setup_logging(cli.logs_directory, cli.tracing_env_filter)?;
|
||||
let _log_guard = observe::setup_logging(&cli.logs_directory, &cli.tracing_env_filter)?;
|
||||
|
||||
let tasks = Arc::new(crate::tasks::Tasks::try_new(conf, cli.data_directory)?);
|
||||
|
||||
let result = match cli.command {
|
||||
Commands::Ui(args) => args.run(tasks).await,
|
||||
Commands::Purge(args) => args.run(tasks).await,
|
||||
Commands::Cleanup(args) => args.run(tasks).await,
|
||||
Commands::Sync(args) => args.sync(tasks).await,
|
||||
Commands::List(args) => args.list(tasks).await,
|
||||
Commands::Jira(jira) => jira.exec(tasks).await,
|
||||
Commands::Gitlab(gitlab) => gitlab.exec(tasks).await,
|
||||
};
|
||||
result
|
||||
cli.exec().await
|
||||
}
|
||||
|
|
|
@ -4,9 +4,14 @@ use std::path::Path;
|
|||
use tracing_appender::non_blocking::WorkerGuard;
|
||||
use tracing_subscriber::{filter::LevelFilter, EnvFilter};
|
||||
|
||||
pub fn setup_error_handling() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn setup_logging<T, S>(
|
||||
logs_directory: Option<T>,
|
||||
env_filter_directive: Option<S>,
|
||||
logs_directory: &Option<T>,
|
||||
env_filter_directive: &Option<S>,
|
||||
) -> Result<WorkerGuard>
|
||||
where
|
||||
T: AsRef<Path>,
|
||||
|
@ -38,7 +43,6 @@ where
|
|||
.map(S::as_ref)
|
||||
.unwrap_or("taskr=trace,info");
|
||||
|
||||
color_eyre::install().expect("Failed to install color_eyre");
|
||||
let filter = EnvFilter::builder()
|
||||
.with_default_directive(LevelFilter::TRACE.into())
|
||||
.parse_lossy(env_filter);
|
||||
|
|
|
@ -1,3 +1 @@
|
|||
use anyhow::Error;
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
pub type Result<T> = color_eyre::Result<T>;
|
||||
|
|
|
@ -85,15 +85,15 @@ impl Display for Task {
|
|||
}
|
||||
|
||||
impl TryFrom<IVec> for Task {
|
||||
type Error = anyhow::Error;
|
||||
type Error = serde_json::Error;
|
||||
|
||||
fn try_from(value: IVec) -> std::prelude::v1::Result<Self, Self::Error> {
|
||||
serde_json::from_slice(&value).map_err(|e| e.into())
|
||||
serde_json::from_slice(&value)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryInto<IVec> for &Task {
|
||||
type Error = anyhow::Error;
|
||||
type Error = serde_json::Error;
|
||||
|
||||
fn try_into(self) -> std::prelude::v1::Result<IVec, Self::Error> {
|
||||
Ok(IVec::from(serde_json::to_vec(self)?))
|
||||
|
@ -101,7 +101,7 @@ impl TryInto<IVec> for &Task {
|
|||
}
|
||||
|
||||
impl TryFrom<&Issue> for Task {
|
||||
type Error = anyhow::Error;
|
||||
type Error = std::num::ParseIntError;
|
||||
|
||||
fn try_from(value: &Issue) -> std::prelude::v1::Result<Self, Self::Error> {
|
||||
let mut tags = HashSet::from_iter(value.fields.labels.iter().map(|s| s.to_owned()));
|
||||
|
|
60
src/tasks.rs
60
src/tasks.rs
|
@ -19,9 +19,10 @@ use crate::{gitlab::GitLab, jira::Jira, result::Result};
|
|||
pub type Db = sled::Db;
|
||||
|
||||
pub struct Tasks {
|
||||
config: Config,
|
||||
data_dir: PathBuf,
|
||||
config_file_path: PathBuf,
|
||||
|
||||
config: OnceLock<Config>,
|
||||
gitlab: OnceLock<GitLab>,
|
||||
jira: OnceLock<Jira>,
|
||||
|
||||
|
@ -31,30 +32,42 @@ pub struct Tasks {
|
|||
const MY_DONE_STATUS_CATEGORY_KEY: &str = "done";
|
||||
|
||||
impl Tasks {
|
||||
pub fn try_new<D>(config: Config, data_dir: Option<D>) -> Result<Self>
|
||||
pub fn try_new<D>(config_file_path: Option<D>, data_dir: Option<D>) -> Result<Self>
|
||||
where
|
||||
D: AsRef<Path>,
|
||||
{
|
||||
let config = OnceLock::new();
|
||||
let gitlab = OnceLock::new();
|
||||
let jira = OnceLock::new();
|
||||
|
||||
let mut default_data_dir = Default::default();
|
||||
let data_dir = data_dir
|
||||
.as_ref()
|
||||
.map(D::as_ref)
|
||||
.map(Result::Ok)
|
||||
.unwrap_or_else(|| {
|
||||
// really want to avoid calling this so it's put in here to force it to be lazy
|
||||
// also have to shove it in a function-scoped variable so the
|
||||
// reference we create in this closure has the same lifetime as the function
|
||||
default_data_dir =
|
||||
xdg::BaseDirectories::new()?.create_data_directory("taskr/data")?;
|
||||
Ok(default_data_dir.as_ref())
|
||||
})?;
|
||||
let xdgonce = OnceLock::new();
|
||||
let xdg = || -> Result<&xdg::BaseDirectories> {
|
||||
match xdgonce.get() {
|
||||
Some(x) => Ok(x),
|
||||
None => {
|
||||
let result = xdg::BaseDirectories::new()?;
|
||||
let _ = xdgonce.set(result);
|
||||
Ok(xdgonce.get().unwrap())
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let config_file_path: PathBuf = if let Some(p) = config_file_path {
|
||||
p.as_ref().to_owned()
|
||||
} else {
|
||||
xdg()?.get_config_file("taskr/config.toml")
|
||||
};
|
||||
|
||||
let data_dir: PathBuf = if let Some(p) = data_dir {
|
||||
p.as_ref().to_owned()
|
||||
} else {
|
||||
xdg()?.create_data_directory("taskr/data")?
|
||||
};
|
||||
|
||||
let db = OnceLock::new();
|
||||
let data_dir: PathBuf = data_dir.to_owned();
|
||||
|
||||
Ok(Self {
|
||||
config_file_path,
|
||||
config,
|
||||
gitlab,
|
||||
jira,
|
||||
|
@ -63,6 +76,17 @@ impl Tasks {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn config(&self) -> Result<&Config> {
|
||||
match self.config.get() {
|
||||
Some(c) => Ok(c),
|
||||
None => {
|
||||
let result = Config::load(self.config_file_path.as_path())?;
|
||||
let _ = self.config.set(result);
|
||||
Ok(self.config.get().unwrap())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn db(&self) -> Result<&Db> {
|
||||
match self.db.get() {
|
||||
Some(d) => Ok(d),
|
||||
|
@ -109,7 +133,7 @@ impl Tasks {
|
|||
}
|
||||
};
|
||||
let result =
|
||||
GitLab::try_new(&format!("{}/api/v4", self.config.gitlab.url), &gl_token)?;
|
||||
GitLab::try_new(&format!("{}/api/v4", self.config()?.gitlab.url), &gl_token)?;
|
||||
let _ = self.gitlab.set(result);
|
||||
Ok(self.gitlab.get().unwrap())
|
||||
// TODO: ensure the token works?
|
||||
|
@ -152,7 +176,7 @@ impl Tasks {
|
|||
}
|
||||
};
|
||||
|
||||
let result = Jira::try_new(&format!("{}", self.config.jira.url), &jira_token)?;
|
||||
let result = Jira::try_new(&format!("{}", self.config()?.jira.url), &jira_token)?;
|
||||
let _ = self.jira.set(result);
|
||||
Ok(self.jira.get().unwrap())
|
||||
// TODO: ensure the token works?
|
||||
|
|
Loading…
Reference in a new issue