Config stuff working
This commit is contained in:
parent
75816058cf
commit
9d61b04731
3 changed files with 93 additions and 58 deletions
|
@ -47,6 +47,7 @@
|
|||
|
||||
# debugger
|
||||
lldb
|
||||
gdbgui
|
||||
|
||||
# libs
|
||||
libopus
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
use std::{fs::File, io::Write};
|
||||
|
||||
use cliclack::input;
|
||||
use cliclack::{input, password};
|
||||
use futures::StreamExt;
|
||||
use signal_hook::consts::*;
|
||||
use signal_hook_tokio::Signals;
|
||||
|
||||
use crate::cli::prelude::*;
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum Command {
|
||||
/// Write the current config (without secrets) in TOML format
|
||||
Show,
|
||||
|
||||
/// Interactively setup a Taskr configuration
|
||||
Setup,
|
||||
}
|
||||
|
||||
|
@ -14,66 +18,78 @@ impl Command {
|
|||
pub async fn exec(&self, tasks: SharedTasks) -> Result<()> {
|
||||
match self {
|
||||
Command::Show => self.show(tasks).await,
|
||||
Command::Setup => self.setup(tasks).await,
|
||||
Command::Setup => Self::setup(tasks).await,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn show(&self, tasks: SharedTasks) -> Result<()> {
|
||||
println!("{:#?}", tasks.config());
|
||||
println!("{}", toml::to_string_pretty(tasks.config()?)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn setup(&self, tasks: SharedTasks) -> Result<()> {
|
||||
pub async fn setup(stasks: SharedTasks) -> Result<()> {
|
||||
use cliclack::{intro, outro};
|
||||
|
||||
// TODO: maybe use the normal builder
|
||||
let tasks = stasks.clone();
|
||||
let cliclack_handle: tokio::task::JoinHandle<Result<()>> = tokio::spawn(async move {
|
||||
// TODO: maybe use the normal builder
|
||||
// TODO: handle sigint and reset the terminal gracefully
|
||||
|
||||
intro("Configure taskr")?;
|
||||
intro("Configure taskr")?;
|
||||
|
||||
// let gitlab_url: String = input("What is your GitLab URL?")
|
||||
// .placeholder("https://gitlab.com")
|
||||
// .validate_interactively(|input: &String| match url::Url::parse(input) {
|
||||
// Ok(_) => Ok(()),
|
||||
// Err(_) => Err("Must be a URL"),
|
||||
// })
|
||||
// .interact()?;
|
||||
let gitlab_url: String = input("What is your GitLab URL?")
|
||||
.placeholder("https://gitlab.com")
|
||||
.validate_interactively(|input: &String| match url::Url::parse(input) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(_) => Err("Must be a URL"),
|
||||
})
|
||||
.interact()?;
|
||||
|
||||
// let jira_url: String = input("What is your Jira URL?")
|
||||
// .placeholder("https://company.atlassian.net")
|
||||
// .validate_interactively(|input: &String| match url::Url::parse(input) {
|
||||
// Ok(_) => Ok(()),
|
||||
// Err(_) => Err("Must be a URL"),
|
||||
// })
|
||||
// .interact()?;
|
||||
let jira_url: String = input("What is your Jira URL?")
|
||||
.placeholder("https://company.atlassian.net")
|
||||
.validate_interactively(|input: &String| match url::Url::parse(input) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(_) => Err("Must be a URL"),
|
||||
})
|
||||
.interact()?;
|
||||
|
||||
let gitlab_url = "https://gitlab.com";
|
||||
let jira_url = "https://jira.com";
|
||||
let mut config = Config::build(
|
||||
Config::builder(&tasks.config_file_path)?
|
||||
.set_override("gitlab.url", gitlab_url.as_str())?
|
||||
.set_override("jira.url", jira_url.as_str())?,
|
||||
)?;
|
||||
|
||||
let config_builder = Config::builder(&tasks.config_file_path)?
|
||||
.set_override("gitlab.url", gitlab_url)?
|
||||
.set_override("jira.url", jira_url)?
|
||||
.set_override("secrets.gitlab_token", gitlab_url)?
|
||||
.set_override("secrets.jira_token", jira_url)?;
|
||||
// TODO: link user to page to setup tokens
|
||||
config.secrets.gitlab_token =
|
||||
password("What is your GitLab Personal Access Token? (scopes: read_api)")
|
||||
// .placeholder("glpat-XXXX...")
|
||||
.interact()?;
|
||||
|
||||
dbg!(&config_builder);
|
||||
let built = config_builder.build()?;
|
||||
dbg!(&built);
|
||||
config.secrets.jira_token = password("What is your Jira API Token?").interact()?;
|
||||
|
||||
let config_result = built.try_deserialize();
|
||||
dbg!(&config_result);
|
||||
if let Err(err) = &config_result {
|
||||
match err {
|
||||
config::ConfigError::Type { origin, unexpected, expected, key } => println!("Type Error at key {key:#?} expected {expected:#?} from origin {origin:#?} (unexpected: {unexpected:#?})"),
|
||||
config::ConfigError::Message(str) => println!("Message {err:#?} {str}"),
|
||||
_ => println!("I dunno. {err:#?}"),
|
||||
}
|
||||
}
|
||||
let config = config_result?;
|
||||
let mut file = File::create(&tasks.config_file_path)?;
|
||||
file.write_all(toml::to_string(&config)?.as_bytes())?;
|
||||
config.save(&tasks.config_file_path)?;
|
||||
|
||||
// TODO: initialize known keyring values/entries
|
||||
outro("All set! Try `taskr list --sync` now!")?;
|
||||
Ok(())
|
||||
});
|
||||
|
||||
let mut signals = Signals::new(&[SIGHUP, SIGTERM, SIGINT, SIGQUIT])?;
|
||||
let signal_handle = signals.handle();
|
||||
|
||||
// TODO: either we will die, get a signal, or we setup
|
||||
|
||||
tokio::select! {
|
||||
_ = signals.next() => {
|
||||
// outro_cancel("Canceled taskr setup")?;
|
||||
}
|
||||
_ = cliclack_handle => {
|
||||
signal_handle.close();
|
||||
}
|
||||
};
|
||||
|
||||
// reset our terminal?
|
||||
|
||||
// TODO: initialize known keyring values/entries
|
||||
outro("All set! Try `taskr list --sync` now!")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::prelude::*;
|
||||
|
||||
use std::{collections::HashMap, fmt::Debug, path::Path};
|
||||
use std::{collections::HashMap, fmt::Debug, fs::File, io::Write, path::Path};
|
||||
|
||||
use color_eyre::{eyre::Context, Section};
|
||||
use config::{builder::DefaultState, Config as CConfig, ConfigBuilder, Value};
|
||||
|
@ -20,8 +20,8 @@ pub struct Jira {
|
|||
|
||||
#[derive(Deserialize, Debug, Clone, Default)]
|
||||
pub struct Secrets {
|
||||
jira_token: String,
|
||||
gitlab_token: String,
|
||||
pub jira_token: String,
|
||||
pub gitlab_token: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
|
@ -36,15 +36,10 @@ pub struct Config {
|
|||
|
||||
impl Config {
|
||||
pub fn load(config_file_path: &Path) -> Result<Self> {
|
||||
let builder = Self::builder(config_file_path)?.build()?;
|
||||
let mut conf: Self = builder
|
||||
.try_deserialize()
|
||||
.suggestion("run `taskr config setup` to ensure valid configuration")
|
||||
.with_context(|| "failed to deserialize configuration")?;
|
||||
let mut conf = Self::build(Self::builder(config_file_path)?)?;
|
||||
|
||||
if conf.secrets.jira_token == "" {
|
||||
conf.secrets.jira_token =
|
||||
keyring::Entry::new("taskr", "gitlab_token")?.get_password()?;
|
||||
conf.secrets.jira_token = keyring::Entry::new("taskr", "jira_token")?.get_password()?;
|
||||
}
|
||||
|
||||
if conf.secrets.gitlab_token == "" {
|
||||
|
@ -55,6 +50,30 @@ impl Config {
|
|||
Ok(conf)
|
||||
}
|
||||
|
||||
/// This should inject the files/values/whatever into their appropriate
|
||||
/// places such that the next time Self::load() is called (with the same
|
||||
/// `config_file_path`) you end up with the same Self.
|
||||
pub fn save(&self, config_file_path: &Path) -> Result<()> {
|
||||
if let Some(p) = config_file_path.parent() {
|
||||
std::fs::create_dir_all(p)?;
|
||||
}
|
||||
let mut file = File::create(config_file_path)?;
|
||||
file.write_all(toml::to_string(self)?.as_bytes())?;
|
||||
|
||||
keyring::Entry::new("taskr", "gitlab_token")?.set_password(&self.secrets.gitlab_token)?;
|
||||
keyring::Entry::new("taskr", "jira_token")?.set_password(&self.secrets.jira_token)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn build(builder: ConfigBuilder<DefaultState>) -> Result<Self> {
|
||||
builder
|
||||
.build()?
|
||||
.try_deserialize()
|
||||
.suggestion("run `taskr config setup` to ensure valid configuration")
|
||||
.with_context(|| "failed to deserialize configuration")
|
||||
}
|
||||
|
||||
pub fn builder(config_file_path: &Path) -> Result<ConfigBuilder<DefaultState>>
|
||||
where {
|
||||
Ok(Self::default_builder()?
|
||||
|
@ -76,8 +95,7 @@ where {
|
|||
|
||||
#[allow(dead_code)]
|
||||
pub fn defaults() -> Result<Self> {
|
||||
let c = Self::default_builder()?.build()?;
|
||||
Ok(c.try_deserialize()?)
|
||||
Self::build(Self::default_builder()?)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue