mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-06-26 10:54:26 +02:00
Add configuration-file support to the 'task' command
This commit is contained in:
parent
8af7ba286d
commit
0e926df578
6 changed files with 236 additions and 45 deletions
|
@ -9,6 +9,8 @@ clap = "^2.33.0"
|
|||
taskchampion = { path = "../taskchampion" }
|
||||
failure = "^0.1.8"
|
||||
prettytable-rs = "^0.8.0"
|
||||
config = "^0.10.1"
|
||||
dirs = "^3.0.1"
|
||||
|
||||
[dev-dependencies]
|
||||
assert_cmd = "^1.0.1"
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use crate::settings;
|
||||
use clap::Arg;
|
||||
use config::{Config, ConfigError};
|
||||
use failure::{format_err, Fallible};
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::cell::{Ref, RefCell};
|
||||
use taskchampion::{server, Replica, ReplicaConfig, ServerConfig, Task, Uuid};
|
||||
|
||||
pub(super) fn task_arg<'a>() -> Arg<'a, 'a> {
|
||||
|
@ -33,11 +34,15 @@ pub(super) fn get_task<S: AsRef<str>>(replica: &mut Replica, task_arg: S) -> Fal
|
|||
#[derive(Debug)]
|
||||
pub struct CommandInvocation {
|
||||
pub(crate) subcommand: Box<dyn super::SubCommandInvocation>,
|
||||
settings: RefCell<Config>,
|
||||
}
|
||||
|
||||
impl CommandInvocation {
|
||||
pub(crate) fn new(subcommand: Box<dyn super::SubCommandInvocation>) -> Self {
|
||||
Self { subcommand }
|
||||
Self {
|
||||
subcommand,
|
||||
settings: RefCell::new(Config::default()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(self) -> Fallible<()> {
|
||||
|
@ -46,28 +51,33 @@ impl CommandInvocation {
|
|||
|
||||
// -- utilities for command invocations
|
||||
|
||||
pub(super) fn get_settings(&self) -> Fallible<Ref<Config>> {
|
||||
{
|
||||
// use the special `_loaded" config value to detect whether we have
|
||||
// loaded the configuration yet
|
||||
let mut settings = self.settings.borrow_mut();
|
||||
if let Err(ConfigError::NotFound(_)) = settings.get_bool("_loaded") {
|
||||
settings.merge(settings::read_settings()?)?;
|
||||
settings.set("_loaded", true)?;
|
||||
}
|
||||
}
|
||||
Ok(self.settings.borrow())
|
||||
}
|
||||
|
||||
pub(super) fn get_replica(&self) -> Fallible<Replica> {
|
||||
// temporarily use $TASK_DB to locate the taskdb
|
||||
let taskdb_dir = env::var_os("TASK_DB").unwrap_or_else(|| OsString::from("/tmp/tasks"));
|
||||
let settings = self.get_settings()?;
|
||||
let replica_config = ReplicaConfig {
|
||||
taskdb_dir: taskdb_dir.into(),
|
||||
taskdb_dir: settings.get_str("data_dir")?.into(),
|
||||
};
|
||||
Ok(Replica::from_config(replica_config)?)
|
||||
}
|
||||
|
||||
pub(super) fn get_server(&self) -> Fallible<Box<dyn server::Server>> {
|
||||
// temporarily use $SYNC_SERVER_ORIGIN for the sync server
|
||||
let origin = env::var_os("SYNC_SERVER_ORIGIN")
|
||||
.map(|osstr| osstr.into_string().unwrap())
|
||||
.unwrap_or_else(|| String::from("http://localhost:8080"));
|
||||
let client_id = env::var_os("SYNC_SERVER_CLIENT_ID")
|
||||
.ok_or_else(|| format_err!("SYNC_SERVER_CLIENT_ID not set"))?;
|
||||
let client_id = client_id
|
||||
.into_string()
|
||||
.map_err(|_| format_err!("SYNC_SERVER_CLIENT_ID is not a valid UUID"))?;
|
||||
let settings = self.get_settings()?;
|
||||
let client_id = settings.get_str("server_client_id")?;
|
||||
let client_id = Uuid::parse_str(&client_id)?;
|
||||
Ok(server::from_config(ServerConfig::Remote {
|
||||
origin,
|
||||
origin: settings.get_str("server_origin")?,
|
||||
client_id,
|
||||
})?)
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ use failure::Fallible;
|
|||
use std::ffi::OsString;
|
||||
|
||||
mod cmd;
|
||||
pub(crate) mod settings;
|
||||
mod table;
|
||||
|
||||
use cmd::ArgMatchResult;
|
||||
|
|
35
cli/src/settings.rs
Normal file
35
cli/src/settings.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
use config::{Config, Environment, File, FileSourceFile};
|
||||
use failure::Fallible;
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub(crate) fn read_settings() -> Fallible<Config> {
|
||||
let mut settings = Config::default();
|
||||
|
||||
// set up defaults
|
||||
if let Some(mut dir) = dirs::data_local_dir() {
|
||||
dir.push("taskchampion");
|
||||
settings.set_default(
|
||||
"data_dir",
|
||||
// the config crate does not support non-string paths
|
||||
dir.to_str().expect("data_local_dir is not utf-8"),
|
||||
)?;
|
||||
}
|
||||
|
||||
// load either from the path in TASKCHAMPION_CONFIG, or from CONFIG_DIR/taskchampion
|
||||
if let Some(config_file) = env::var_os("TASKCHAMPION_CONFIG") {
|
||||
let config_file: PathBuf = config_file.into();
|
||||
let config_file: File<FileSourceFile> = config_file.into();
|
||||
settings.merge(config_file.required(true))?;
|
||||
env::remove_var("TASKCHAMPION_CONFIG");
|
||||
} else if let Some(mut dir) = dirs::config_dir() {
|
||||
dir.push("taskchampion");
|
||||
let config_file: File<FileSourceFile> = dir.into();
|
||||
settings.merge(config_file.required(false))?;
|
||||
}
|
||||
|
||||
// merge environment variables
|
||||
settings.merge(Environment::with_prefix("TASKCHAMPION"))?;
|
||||
|
||||
Ok(settings)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue