feat(sync): finish conf module
This commit is contained in:
parent
1fb4d920e5
commit
dca85d0f75
|
@ -8,7 +8,7 @@ edition = "2018"
|
||||||
all-features = true
|
all-features = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["google_calendar", "toggl"]
|
default = ["dotenv", "google_calendar", "toggl"]
|
||||||
google_calendar = []
|
google_calendar = []
|
||||||
toggl = []
|
toggl = []
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ toggl = []
|
||||||
app_dirs = "1.2.1"
|
app_dirs = "1.2.1"
|
||||||
chrono = { version = "0.4.9", features = ["serde"] }
|
chrono = { version = "0.4.9", features = ["serde"] }
|
||||||
colored = "1.8.0"
|
colored = "1.8.0"
|
||||||
|
dotenv = { version = "0.14.1", optional = true }
|
||||||
futures-preview = "=0.3.0-alpha.18"
|
futures-preview = "=0.3.0-alpha.18"
|
||||||
isahc = { version = "0.7.3", default-features = false, features = ["json", "http2", "static-curl"] }
|
isahc = { version = "0.7.3", default-features = false, features = ["json", "http2", "static-curl"] }
|
||||||
orgize = { path = "../orgize", default-features = false, features = ["chrono"] }
|
orgize = { path = "../orgize", default-features = false, features = ["chrono"] }
|
||||||
|
|
|
@ -1,50 +1,136 @@
|
||||||
use app_dirs::{app_root, AppDataType, AppInfo};
|
use std::env;
|
||||||
use serde::{Deserialize, Serialize};
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use app_dirs::{app_root, AppDataType, AppInfo};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::conf::google_calendar::*;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
const APP_INFO: AppInfo = AppInfo {
|
||||||
|
name: "orgize-sync",
|
||||||
|
author: "PoiScript",
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct Conf {
|
pub struct Conf {
|
||||||
|
#[serde(default = "default_env_path")]
|
||||||
|
pub env_path: PathBuf,
|
||||||
|
#[serde(default)]
|
||||||
pub files: Vec<File>,
|
pub files: Vec<File>,
|
||||||
#[cfg(feature = "google_calendar")]
|
#[cfg(feature = "google_calendar")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub google_calendar: Option<GoogleCalendarGlobalConf>,
|
pub google_calendar: Option<GoogleCalendarGlobalConf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
#[cfg(feature = "google_calendar")]
|
pub struct EnvConf {
|
||||||
pub struct GoogleCalendarGlobalConf {
|
#[serde(default = "default_env_path")]
|
||||||
pub client_id: String,
|
pub env_path: PathBuf,
|
||||||
pub client_secret: String,
|
|
||||||
pub token_dir: String,
|
|
||||||
pub token_filename: String,
|
|
||||||
pub property: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
pub fn user_config_path() -> PathBuf {
|
||||||
#[cfg(feature = "google_calendar")]
|
app_root(AppDataType::UserConfig, &APP_INFO).unwrap()
|
||||||
pub struct GoogleCalendarConf {
|
|
||||||
pub calendar: String,
|
|
||||||
pub append_new: bool,
|
|
||||||
pub append_headline: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
pub fn user_cache_path() -> PathBuf {
|
||||||
|
app_root(AppDataType::UserCache, &APP_INFO).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn default_config_path() -> PathBuf {
|
||||||
|
let mut path = user_config_path();
|
||||||
|
path.push("conf.toml");
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn default_env_path() -> PathBuf {
|
||||||
|
let mut path = user_cache_path();
|
||||||
|
path.push(".env");
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Conf {
|
||||||
|
pub fn new(path: Option<PathBuf>) -> Result<Self> {
|
||||||
|
let path = path.unwrap_or_else(default_config_path);
|
||||||
|
|
||||||
|
let content = fs::read(&path).expect(&format!(
|
||||||
|
"Failed to read file: {}",
|
||||||
|
path.as_path().display()
|
||||||
|
));
|
||||||
|
|
||||||
|
if cfg!(feature = "dotenv") {
|
||||||
|
let env_conf: EnvConf = toml::from_slice(&content)?;
|
||||||
|
dotenv::from_path(env_conf.env_path.as_path())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(toml::from_slice(&content)?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct File {
|
pub struct File {
|
||||||
pub path: String,
|
pub path: String,
|
||||||
pub name: String,
|
pub name: Option<String>,
|
||||||
#[cfg(feature = "google_calendar")]
|
#[cfg(feature = "google_calendar")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub google_calendar: Option<GoogleCalendarConf>,
|
pub google_calendar: Option<GoogleCalendarConf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_conf_path() -> Result<PathBuf> {
|
#[cfg(feature = "google_calendar")]
|
||||||
let mut path = app_root(
|
pub mod google_calendar {
|
||||||
AppDataType::UserConfig,
|
use super::*;
|
||||||
&AppInfo {
|
|
||||||
name: "orgize-sync",
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
author: "PoiScript",
|
pub struct GoogleCalendarGlobalConf {
|
||||||
},
|
#[serde(default = "default_client_id")]
|
||||||
)?;
|
pub client_id: String,
|
||||||
path.push("conf.toml");
|
#[serde(default = "default_client_secret")]
|
||||||
Ok(path)
|
pub client_secret: String,
|
||||||
|
#[serde(default = "default_token_dir")]
|
||||||
|
pub token_dir: PathBuf,
|
||||||
|
#[serde(default = "default_token_filename")]
|
||||||
|
pub token_filename: String,
|
||||||
|
#[serde(default = "default_property")]
|
||||||
|
pub property: String,
|
||||||
|
#[serde(default = "default_redirect_uri")]
|
||||||
|
pub redirect_uri: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct GoogleCalendarConf {
|
||||||
|
pub calendar: String,
|
||||||
|
#[serde(default)]
|
||||||
|
pub append_new: bool,
|
||||||
|
#[serde(default = "default_append_headline")]
|
||||||
|
pub append_headline: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_client_id() -> String {
|
||||||
|
env::var("GOOGLE_CLIENT_ID").unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_client_secret() -> String {
|
||||||
|
env::var("GOOGLE_CLIENT_SECRET").unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_token_dir() -> PathBuf {
|
||||||
|
app_root(AppDataType::UserCache, &APP_INFO).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_token_filename() -> String {
|
||||||
|
"google-token.json".into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_property() -> String {
|
||||||
|
"EVENT_ID".into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_redirect_uri() -> String {
|
||||||
|
"http://localhost".into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_append_headline() -> String {
|
||||||
|
"Sync".into()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,21 @@
|
||||||
use app_dirs::AppDirsError;
|
use app_dirs::AppDirsError;
|
||||||
|
use dotenv::Error as EnvError;
|
||||||
use isahc::http::Error as HttpError;
|
use isahc::http::Error as HttpError;
|
||||||
use isahc::Error as IsahcError;
|
use isahc::Error as IsahcError;
|
||||||
use std::convert::From;
|
use std::convert::From;
|
||||||
use std::io::Error as IOError;
|
use std::io::Error as IOError;
|
||||||
|
use toml::de::Error as TomlDeError;
|
||||||
|
use toml::ser::Error as TomlSerError;
|
||||||
use url::ParseError;
|
use url::ParseError;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
AppDirs(AppDirsError),
|
AppDirs(AppDirsError),
|
||||||
IO(IOError),
|
Env(EnvError),
|
||||||
Http(IsahcError),
|
Http(IsahcError),
|
||||||
|
IO(IOError),
|
||||||
|
TomlDe(TomlDeError),
|
||||||
|
TomlSer(TomlSerError),
|
||||||
Url(ParseError),
|
Url(ParseError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +25,12 @@ impl From<AppDirsError> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<EnvError> for Error {
|
||||||
|
fn from(err: EnvError) -> Self {
|
||||||
|
Error::Env(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<IOError> for Error {
|
impl From<IOError> for Error {
|
||||||
fn from(err: IOError) -> Self {
|
fn from(err: IOError) -> Self {
|
||||||
Error::IO(err)
|
Error::IO(err)
|
||||||
|
@ -37,6 +49,18 @@ impl From<HttpError> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<TomlDeError> for Error {
|
||||||
|
fn from(err: TomlDeError) -> Self {
|
||||||
|
Error::TomlDe(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TomlSerError> for Error {
|
||||||
|
fn from(err: TomlSerError) -> Self {
|
||||||
|
Error::TomlSer(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<ParseError> for Error {
|
impl From<ParseError> for Error {
|
||||||
fn from(err: ParseError) -> Self {
|
fn from(err: ParseError) -> Self {
|
||||||
Error::Url(err)
|
Error::Url(err)
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
mod conf;
|
mod conf;
|
||||||
mod error;
|
mod error;
|
||||||
|
|
||||||
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
use toml::to_string_pretty;
|
||||||
|
|
||||||
use crate::conf::default_conf_path;
|
use crate::conf::{
|
||||||
|
default_config_path, default_env_path, user_cache_path, user_config_path, Conf, EnvConf,
|
||||||
|
};
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
|
|
||||||
#[derive(StructOpt, Debug)]
|
#[derive(StructOpt, Debug)]
|
||||||
|
@ -28,30 +32,64 @@ enum Cmd {
|
||||||
conf_path: Option<PathBuf>,
|
conf_path: Option<PathBuf>,
|
||||||
},
|
},
|
||||||
#[structopt(name = "conf")]
|
#[structopt(name = "conf")]
|
||||||
Conf,
|
Conf {
|
||||||
|
#[structopt(short = "c", long = "conf", parse(from_os_str))]
|
||||||
|
conf_path: Option<PathBuf>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
let opt = Opt::from_args();
|
let opt = Opt::from_args();
|
||||||
|
|
||||||
match opt.subcommand {
|
match opt.subcommand {
|
||||||
|
Cmd::Init => {
|
||||||
|
fs::create_dir_all(user_config_path())?;
|
||||||
|
fs::create_dir_all(user_cache_path())?;
|
||||||
|
|
||||||
|
let default_env_path = default_env_path();
|
||||||
|
let default_config_path = default_config_path();
|
||||||
|
|
||||||
|
if default_env_path.as_path().exists() {
|
||||||
|
println!(
|
||||||
|
"{} already existed, skipping ...",
|
||||||
|
default_env_path.as_path().display()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
println!("Creating {} ...", default_env_path.as_path().display());
|
||||||
|
fs::write(default_env_path.clone(), "")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if default_config_path.as_path().exists() {
|
||||||
|
println!(
|
||||||
|
"{} already existed, skipping ...",
|
||||||
|
default_config_path.as_path().display()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
println!("Creating {} ...", default_config_path.as_path().display());
|
||||||
|
fs::write(
|
||||||
|
default_config_path,
|
||||||
|
to_string_pretty(&EnvConf {
|
||||||
|
env_path: default_env_path,
|
||||||
|
})?,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
Cmd::Sync {
|
Cmd::Sync {
|
||||||
conf_path,
|
conf_path,
|
||||||
skip_google_calendar,
|
skip_google_calendar,
|
||||||
skip_toggl,
|
skip_toggl,
|
||||||
} => {
|
} => {
|
||||||
let conf_path = conf_path
|
let conf = Conf::new(conf_path)?;
|
||||||
.map(Result::Ok)
|
|
||||||
.unwrap_or_else(default_conf_path)?;
|
|
||||||
|
|
||||||
println!("{:#?}", conf_path);
|
|
||||||
|
|
||||||
if cfg!(feature = "google_calendar") && !skip_google_calendar {}
|
if cfg!(feature = "google_calendar") && !skip_google_calendar {}
|
||||||
|
|
||||||
if cfg!(feature = "toggl") && !skip_toggl {}
|
if cfg!(feature = "toggl") && !skip_toggl {}
|
||||||
}
|
}
|
||||||
Cmd::Init => (),
|
Cmd::Conf { conf_path } => {
|
||||||
Cmd::Conf => (),
|
let conf = Conf::new(conf_path)?;
|
||||||
|
|
||||||
|
println!("{}", to_string_pretty(&conf)?);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
Loading…
Reference in a new issue