Maybe I can mutex now

This commit is contained in:
Daniel Flanagan 2024-04-18 08:21:43 -05:00
parent 1607a223cc
commit 1cac4fc187
8 changed files with 386 additions and 28 deletions

271
Cargo.lock generated
View file

@ -339,6 +339,9 @@ name = "bitflags"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
dependencies = [
"serde",
]
[[package]]
name = "block-buffer"
@ -554,6 +557,55 @@ dependencies = [
"crossbeam-utils",
]
[[package]]
name = "config"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7328b20597b53c2454f0b1919720c25c7339051c02b72b7e05409e00b14132be"
dependencies = [
"async-trait",
"convert_case",
"json5",
"lazy_static",
"nom",
"pathdiff",
"ron",
"rust-ini",
"serde",
"serde_json",
"toml",
"yaml-rust",
]
[[package]]
name = "const-random"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359"
dependencies = [
"const-random-macro",
]
[[package]]
name = "const-random-macro"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
dependencies = [
"getrandom",
"once_cell",
"tiny-keccak",
]
[[package]]
name = "convert_case"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "core-foundation"
version = "0.9.4"
@ -637,6 +689,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "crypto-common"
version = "0.1.6"
@ -678,6 +736,15 @@ dependencies = [
"subtle",
]
[[package]]
name = "dlv-list"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f"
dependencies = [
"const-random",
]
[[package]]
name = "either"
version = "1.9.0"
@ -1028,6 +1095,12 @@ dependencies = [
"tracing",
]
[[package]]
name = "hashbrown"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
[[package]]
name = "hashbrown"
version = "0.14.3"
@ -1197,7 +1270,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4"
dependencies = [
"equivalent",
"hashbrown",
"hashbrown 0.14.3",
]
[[package]]
@ -1259,6 +1332,17 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "json5"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1"
dependencies = [
"pest",
"pest_derive",
"serde",
]
[[package]]
name = "keyring"
version = "2.3.2"
@ -1285,6 +1369,12 @@ version = "0.2.153"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]]
name = "linked-hash-map"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
[[package]]
name = "linux-keyutils"
version = "0.2.4"
@ -1329,7 +1419,7 @@ version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc"
dependencies = [
"hashbrown",
"hashbrown 0.14.3",
]
[[package]]
@ -1387,6 +1477,12 @@ dependencies = [
"unicase",
]
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "miniz_oxide"
version = "0.7.2"
@ -1438,6 +1534,16 @@ dependencies = [
"memoffset 0.7.1",
]
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "nu-ansi-term"
version = "0.46.0"
@ -1604,6 +1710,16 @@ dependencies = [
"vcpkg",
]
[[package]]
name = "ordered-multimap"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ed8acf08e98e744e5384c8bc63ceb0364e68a6854187221c18df61c4797690e"
dependencies = [
"dlv-list",
"hashbrown 0.13.2",
]
[[package]]
name = "ordered-stream"
version = "0.2.0"
@ -1686,12 +1802,63 @@ version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
[[package]]
name = "pathdiff"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
[[package]]
name = "percent-encoding"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]]
name = "pest"
version = "2.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "311fb059dee1a7b802f036316d790138c613a4e8b180c822e3925a662e9f0c95"
dependencies = [
"memchr",
"thiserror",
"ucd-trie",
]
[[package]]
name = "pest_derive"
version = "2.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f73541b156d32197eecda1a4014d7f868fd2bcb3c550d5386087cfba442bf69c"
dependencies = [
"pest",
"pest_generator",
]
[[package]]
name = "pest_generator"
version = "2.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c35eeed0a3fab112f75165fdc026b3913f4183133f19b49be773ac9ea966e8bd"
dependencies = [
"pest",
"pest_meta",
"proc-macro2",
"quote",
"syn 2.0.53",
]
[[package]]
name = "pest_meta"
version = "2.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2adbf29bb9776f28caece835398781ab24435585fe0d4dc1374a61db5accedca"
dependencies = [
"once_cell",
"pest",
"sha2",
]
[[package]]
name = "pin-project-lite"
version = "0.2.13"
@ -1770,7 +1937,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919"
dependencies = [
"once_cell",
"toml_edit",
"toml_edit 0.19.15",
]
[[package]]
@ -1846,6 +2013,9 @@ name = "redact"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7301863b5e5486c9f18320ccc1aedce9a5fdf3056ae89fa021933d6f054430f"
dependencies = [
"serde",
]
[[package]]
name = "redox_syscall"
@ -2016,6 +2186,28 @@ dependencies = [
"rand",
]
[[package]]
name = "ron"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94"
dependencies = [
"base64",
"bitflags 2.5.0",
"serde",
"serde_derive",
]
[[package]]
name = "rust-ini"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e2a3bcec1f113553ef1c88aae6c020a369d03d55b58de9869a0908930385091"
dependencies = [
"cfg-if",
"ordered-multimap",
]
[[package]]
name = "rustc-demangle"
version = "0.1.23"
@ -2169,6 +2361,15 @@ dependencies = [
"syn 2.0.53",
]
[[package]]
name = "serde_spanned"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1"
dependencies = [
"serde",
]
[[package]]
name = "serde_urlencoded"
version = "0.7.1"
@ -2423,6 +2624,7 @@ dependencies = [
"clap",
"clap_derive",
"color-eyre",
"config",
"crossterm",
"futures",
"keyring",
@ -2518,6 +2720,15 @@ dependencies = [
"time-core",
]
[[package]]
name = "tiny-keccak"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
dependencies = [
"crunchy",
]
[[package]]
name = "tinyvec"
version = "1.6.0"
@ -2599,11 +2810,26 @@ dependencies = [
"tracing",
]
[[package]]
name = "toml"
version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit 0.22.9",
]
[[package]]
name = "toml_datetime"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
@ -2613,7 +2839,20 @@ checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
dependencies = [
"indexmap",
"toml_datetime",
"winnow",
"winnow 0.5.40",
]
[[package]]
name = "toml_edit"
version = "0.22.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4"
dependencies = [
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
"winnow 0.6.6",
]
[[package]]
@ -2717,6 +2956,12 @@ version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "ucd-trie"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
[[package]]
name = "uds_windows"
version = "1.1.0"
@ -3089,6 +3334,15 @@ dependencies = [
"memchr",
]
[[package]]
name = "winnow"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0c976aaaa0e1f90dbb21e9587cdaf1d9679a1cde8875c0d6bd83ab96a208352"
dependencies = [
"memchr",
]
[[package]]
name = "winreg"
version = "0.50.0"
@ -3115,6 +3369,15 @@ dependencies = [
"winapi",
]
[[package]]
name = "yaml-rust"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [
"linked-hash-map",
]
[[package]]
name = "zbus"
version = "3.15.2"

View file

@ -10,11 +10,12 @@ chrono-humanize = "0.2.3"
clap = { version = "4.5.4", features = ["derive"] }
clap_derive = "4.5.4"
color-eyre = "0.6.3"
config = "0.14.0"
crossterm = "0.27.0"
futures = "0.3.30"
keyring = "2.3.2"
ratatui = "0.26.2"
redact = "0.1.9"
redact = { version = "0.1.9", features = ["serde"] }
regex = "1.10.3"
reqwest = { version = "0.11.26", features = ["json", "socks"] }
reqwest-middleware = "0.2.5"

View file

@ -26,6 +26,10 @@ pub struct Cli {
/// The directory that data is stored in (defaults to $XDG_DATA_HOME/taskr/data)
#[arg(long, default_value = None)]
pub data_directory: Option<String>,
/// The configuration file to load (defaults to $XDG_CONFIG_HOME/taskr/config.toml)
#[arg(long, default_value = None)]
pub data_directory: Option<String>,
}
#[derive(Subcommand)]

View file

@ -1 +1,79 @@
use crate::prelude::*;
use std::{collections::HashMap, fmt::Debug};
use config::{builder::DefaultState, Config as CConfig, ConfigBuilder};
use serde::{Deserialize, Serialize};
const CURRENT_VERSION: u64 = 1;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Gitlab {
pub url: String,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Jira {
pub url: String,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Config {
pub version: u64,
pub gitlab: Option<Gitlab>,
pub jira: Option<Jira>,
}
const CONFIG_FILE_PATH: &str = "./conf.toml";
impl Config {
pub fn load() -> Result<Self> {
let c = Self::builder()?.build()?;
Ok(c.try_deserialize()?)
}
pub fn builder() -> Result<ConfigBuilder<DefaultState>> {
let p = std::path::PathBuf::from(CONFIG_FILE_PATH);
if !p.exists() {
// TODO: this won't output since tracing is not setup before we load
// config, so we need something like
// https://docs.rs/tracing-capture/latest/tracing_capture/
// to capture trace events to be output _after_ configuration has
// loaded and the "actual" subscriber is setup
warn!(
"Config file '{}' doesn't exist, so defaults will likely be loaded!",
p.display(),
);
}
// TODO: log whether or not we were able to load conf.toml?
Ok(Self::default_builder()
.map_err(anyhow::Error::from)?
.add_source(config::File::from(p).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)?)
}
#[allow(dead_code)]
pub fn defaults() -> Result<Self> {
let c = Self::default_builder()?.build()?;
Ok(c.try_deserialize()?)
}
}
#[cfg(test)]
mod tests {
use crate::config::*;
#[test]
fn defaults_deserialize_to_valid_config() -> Result<()> {
println!("Defaults: {:?}", Config::defaults()?);
Ok(())
}
}

View file

@ -12,11 +12,14 @@ mod task;
mod tasks;
mod tui;
use config::Config;
use crate::cli::{Cli, Commands};
use crate::prelude::*;
#[tokio::main]
async fn main() -> Result<()> {
let conf = Config::load()?;
let cli = Cli::new();
// this guard causes logs to be flushed when dropped (which is at the end of
@ -24,7 +27,7 @@ async fn main() -> Result<()> {
// 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 tasks = Arc::new(crate::tasks::Tasks::try_new(cli.data_directory)?);
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,

View file

@ -1,5 +1,6 @@
#![allow(unused_imports)]
pub use crate::config::Config;
pub use crate::result::Result;
pub use regex::Regex;
pub use std::sync::Arc;

View file

@ -19,7 +19,9 @@ use crate::{gitlab::GitLab, jira::Jira, result::Result};
pub type Db = sled::Db;
pub struct Tasks {
config: Config,
data_dir: PathBuf,
gitlab: OnceLock<GitLab>,
jira: OnceLock<Jira>,
@ -29,7 +31,7 @@ pub struct Tasks {
const MY_DONE_STATUS_CATEGORY_KEY: &str = "done";
impl Tasks {
pub fn try_new<D>(data_dir: Option<D>) -> Result<Self>
pub fn try_new<D>(config: Config, data_dir: Option<D>) -> Result<Self>
where
D: AsRef<Path>,
{
@ -53,6 +55,7 @@ impl Tasks {
let data_dir: PathBuf = data_dir.to_owned();
Ok(Self {
config,
gitlab,
jira,
data_dir,
@ -105,7 +108,14 @@ impl Tasks {
token
}
};
let result = GitLab::try_new("https://git.hq.bill.com/api/v4", &gl_token)?;
let result = GitLab::try_new(
&format!(
"{}/api/v4",
self.config
.require_or_prompt_and_set::<String>("gitlab.url")?
),
&gl_token,
)?;
let _ = self.gitlab.set(result);
Ok(self.gitlab.get().unwrap())
// TODO: ensure the token works?
@ -148,7 +158,14 @@ impl Tasks {
}
};
let result = Jira::try_new("https://billcom.atlassian.net", &jira_token)?;
let result = Jira::try_new(
&format!(
"{}",
self.config
.require_or_prompt_and_set::<String>("jira.url")?
),
&jira_token,
)?;
let _ = self.jira.set(result);
Ok(self.jira.get().unwrap())
// TODO: ensure the token works?

View file

@ -13,27 +13,11 @@ use ratatui::{
use signal_hook::consts::*;
use signal_hook_tokio::Signals;
use std::io::stdout;
use tokio::task::JoinHandle;
pub struct Tui {
tasks: SharedTasks,
}
async fn handle_signals(mut signals: Signals, channel: ) {
while let Some(signal) = signals.next().await {
match signal {
SIGHUP => {
// Reload configuration
// Reopen the log file
}
SIGTERM | SIGINT | SIGQUIT => {
// Shutdown the system;
},
_ => unreachable!(),
}
}
}
impl Tui {
pub fn new(tasks: SharedTasks) -> Self {
Self { tasks }
@ -49,8 +33,17 @@ impl Tui {
let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
terminal.clear()?;
let mut signals = Signals::new(&[SIGHUP, SIGTERM, SIGINT, SIGQUIT])?;
let signalled: Arc<Mutex<bool>> = Arc::new(Mutex::new(false));
let handle = signals.handle();
let signaler = Arc::clone(&signalled);
tokio::spawn(async move {
// await a signal - once we receive one mark the boolean as true to
// quit the app
signals.next().await;
let mut signalled = signaler.lock().await;
*signalled = true;
});
// TODO: enable isig to re-allow ctrl-z?
loop {
@ -74,12 +67,10 @@ impl Tui {
}
}
}
println!("Waiting for signal...");
if signals.next().await.is_some() {
if *(*signalled).lock().await {
break;
}
}
// TODO main loop
handle.close();
stdout().execute(LeaveAlternateScreen)?;