Add init command
This commit is contained in:
parent
cb83a386dc
commit
ba84742a13
10 changed files with 151 additions and 93 deletions
6
Cargo.lock
generated
6
Cargo.lock
generated
|
@ -838,15 +838,19 @@ name = "dpts-cli"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"chrono-tz",
|
||||
"clap",
|
||||
"dpts-core",
|
||||
"dpts-client",
|
||||
"thiserror 2.0.12",
|
||||
"tokio",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dpts-client"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono-tz",
|
||||
"clap",
|
||||
"dpts-core",
|
||||
"serde",
|
||||
|
|
|
@ -6,7 +6,10 @@ edition.workspace = true
|
|||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
dpts-core = {workspace = true}
|
||||
dpts-client = {workspace = true}
|
||||
chrono = {workspace = true}
|
||||
chrono-tz.workspace = true
|
||||
clap = {workspace = true, features = ["derive"]}
|
||||
thiserror.workspace = true
|
||||
thiserror.workspace = true
|
||||
tokio.workspace = true
|
||||
toml.workspace = true
|
|
@ -3,6 +3,18 @@ pub enum Error {
|
|||
#[error("Parse int error")]
|
||||
ParseInt(#[from] std::num::ParseIntError),
|
||||
#[error("Missing config value: ({0})")]
|
||||
MissingConfig(String)
|
||||
MissingConfig(String),
|
||||
#[error("Parse toml error")]
|
||||
TomlDe(#[from] toml::de::Error),
|
||||
|
||||
}
|
||||
|
||||
impl From<dpts_client::error::Error> for Error {
|
||||
fn from(e: dpts_client::error::Error) -> Self {
|
||||
match e {
|
||||
dpts_client::error::Error::TomlDe(x)=> Self::TomlDe(x),
|
||||
dpts_client::error::Error::ParseInt(x) => Self::ParseInt(x),
|
||||
dpts_client::error::Error::MissingConfig(x) => Self::MissingConfig(x),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
72
dpts-cli/src/init.rs
Normal file
72
dpts-cli/src/init.rs
Normal file
|
@ -0,0 +1,72 @@
|
|||
use clap::{Args, Subcommand};
|
||||
use chrono_tz::Tz;
|
||||
use crate::error::Error;
|
||||
use dpts_client::auth::try_login;
|
||||
use dpts_client::config::{
|
||||
Config,
|
||||
ClientConfig,
|
||||
ClientRemoteStorageConfig,
|
||||
ClientStorageConfig,
|
||||
PartialGlobalConfig
|
||||
};
|
||||
|
||||
#[derive(Args, Clone, Debug)]
|
||||
pub struct InitArgs {
|
||||
#[command(subcommand)]
|
||||
pub command: InitCommand,
|
||||
}
|
||||
|
||||
impl InitArgs {
|
||||
pub fn run(self) -> Result<(), Error> {
|
||||
match self.command {
|
||||
InitCommand::Local(x) => x.run(),
|
||||
InitCommand::Remote(x) => x.run(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Clone, Debug, Subcommand)]
|
||||
|
||||
enum InitCommand {
|
||||
Local(InitLocalArgs),
|
||||
Remote(InitRemoteArgs),
|
||||
}
|
||||
|
||||
#[derive(Args, Clone, Debug)]
|
||||
pub struct InitLocalArgs {
|
||||
pub time_zone: Option<Tz>,
|
||||
}
|
||||
|
||||
impl InitLocalArgs {
|
||||
pub fn run(self) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Args, Clone, Debug)]
|
||||
pub struct InitRemoteArgs {
|
||||
pub endpoint: String,
|
||||
#[arg(short, long)]
|
||||
pub user_name: String,
|
||||
#[arg(short, long)]
|
||||
pub password: String,
|
||||
#[arg(short, long)]
|
||||
pub time_zone: Option<Tz>,
|
||||
}
|
||||
|
||||
impl InitRemoteArgs {
|
||||
pub fn run(self) -> Result<(), Error> {
|
||||
let token: String = try_login(&self.user_name, &self.password, &self.endpoint)?;
|
||||
let config: Config = Config{
|
||||
global: PartialGlobalConfig {
|
||||
time_zone: self.time_zone.clone()
|
||||
},
|
||||
client: ClientConfig {
|
||||
storage: ClientStorageConfig::Remote(ClientRemoteStorageConfig {
|
||||
endpoint: self.endpoint,
|
||||
access_key: token,
|
||||
}),
|
||||
}
|
||||
};
|
||||
todo!() // Write config
|
||||
}
|
||||
}
|
|
@ -1,13 +1,15 @@
|
|||
//mod label;
|
||||
pub mod error;
|
||||
mod init;
|
||||
mod record;
|
||||
|
||||
|
||||
|
||||
//use label::LabelArgs;
|
||||
use record::{RecordArgs,RecordAddArgs};
|
||||
|
||||
use error::Error;
|
||||
|
||||
use init::InitArgs;
|
||||
use clap::{Args, CommandFactory, Parser, Subcommand};
|
||||
|
||||
use std::ffi::OsString;
|
||||
|
@ -22,18 +24,18 @@ struct Cli {
|
|||
|
||||
#[derive(Clone, Debug, Subcommand)]
|
||||
enum Command {
|
||||
Init(InitArgs),
|
||||
Record(RecordArgs),
|
||||
}
|
||||
|
||||
|
||||
fn main() -> Result<(), Error> {
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Error> {
|
||||
let cli = Cli::parse();
|
||||
match cli.command {
|
||||
//Some(Commands::Add(x)) => x.run(),
|
||||
Command::Init(x) => x.run(),
|
||||
//Some(Commands::Label(x)) => x.run(),
|
||||
Command::Record(x) => x.run(),
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -8,9 +8,10 @@ default = ["clap"]
|
|||
clap = ["dep:clap"]
|
||||
|
||||
[dependencies]
|
||||
chrono-tz.workspace = true
|
||||
clap = { workspace = true, optional = true }
|
||||
dpts-core.workspace = true
|
||||
serde.workspace = true
|
||||
thiserror.workspace = true
|
||||
tokio.workspace = true
|
||||
toml.workspace = true
|
||||
toml.workspace = true
|
||||
|
|
5
dpts-client/src/auth.rs
Normal file
5
dpts-client/src/auth.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
use crate::error::Error;
|
||||
|
||||
pub fn try_login(user_name: &str, password: &str, endpoint: &str) -> Result<String, Error> {
|
||||
todo!()
|
||||
}
|
|
@ -1,7 +1,10 @@
|
|||
mod storage;
|
||||
|
||||
pub use dpts_core::config::*;
|
||||
pub use storage::*;
|
||||
|
||||
|
||||
|
||||
use crate::error::Error;
|
||||
use serde::{
|
||||
Deserialize,
|
||||
|
@ -12,84 +15,45 @@ use tokio::sync::OnceCell;
|
|||
|
||||
pub static CLIENT_CONFIG: OnceCell<ClientConfig> = OnceCell::const_new();
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
|
||||
|
||||
pub struct ClientConfig {
|
||||
pub storage: ClientStorageConfig,
|
||||
}
|
||||
|
||||
impl TryFrom<&PartialClientConfig> for ClientConfig {
|
||||
type Error = Error;
|
||||
fn try_from(p: &PartialClientConfig) -> Result<ClientConfig, Self::Error> {
|
||||
Ok(ClientConfig{
|
||||
storage: p.clone().storage.ok_or(Error::MissingConfig("storage".to_string()))?,
|
||||
})
|
||||
|
||||
}
|
||||
pub struct Config {
|
||||
pub client: ClientConfig,
|
||||
pub global: PartialGlobalConfig,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
pub struct PartialClientConfig {
|
||||
pub storage: Option<ClientStorageConfig>,
|
||||
pub struct ClientConfig {
|
||||
pub storage: ClientStorageConfig,
|
||||
}
|
||||
|
||||
impl PartialClientConfig {
|
||||
|
||||
}
|
||||
|
||||
|
||||
impl Default for PartialClientConfig {
|
||||
fn default() -> Self {
|
||||
PartialClientConfig {
|
||||
storage: None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use chrono_tz::UTC;
|
||||
use tokio::sync::OnceCell;
|
||||
const EMPTY_CONFIG_TOML: &str = r#""#;
|
||||
static EMPTY_CONFIG_STRUCT: OnceCell<PartialClientConfig> = OnceCell::const_new();
|
||||
|
||||
async fn get_empty_config_struct() -> &'static PartialClientConfig {
|
||||
EMPTY_CONFIG_STRUCT.get_or_init(|| async {
|
||||
PartialClientConfig{
|
||||
storage: None,
|
||||
}
|
||||
}).await
|
||||
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn deserialize_empty_client_config() {
|
||||
let config: PartialClientConfig = toml::from_str(EMPTY_CONFIG_TOML).unwrap();
|
||||
assert_eq!(&config, get_empty_config_struct().await);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn serialize_empty_client_config() {
|
||||
assert_eq!(EMPTY_CONFIG_TOML, toml::to_string(get_empty_config_struct().await).unwrap());
|
||||
}
|
||||
|
||||
const LOCAL_STORAGE_CONFIG_TOML: &str = r#"time_zone = "UTC"
|
||||
const LOCAL_STORAGE_CONFIG_TOML: &str = r#"[client]
|
||||
storage = "local"
|
||||
|
||||
[global]
|
||||
"#;
|
||||
static LOCAL_STORAGE_CONFIG_STRUCT: OnceCell<PartialClientConfig> = OnceCell::const_new();
|
||||
static LOCAL_STORAGE_CONFIG_STRUCT: OnceCell<Config> = OnceCell::const_new();
|
||||
|
||||
async fn get_local_storage_client_config_struct() -> &'static PartialClientConfig {
|
||||
async fn get_local_storage_client_config_struct() -> &'static Config {
|
||||
LOCAL_STORAGE_CONFIG_STRUCT.get_or_init(|| async {
|
||||
PartialClientConfig{
|
||||
storage: Some(ClientStorageConfig::Local),
|
||||
Config{
|
||||
client: ClientConfig{
|
||||
storage: ClientStorageConfig::Local,
|
||||
},
|
||||
global: PartialGlobalConfig { time_zone: None },
|
||||
}
|
||||
}).await
|
||||
}
|
||||
#[tokio::test]
|
||||
async fn deserialize_local_storage_client_config() {
|
||||
let config: PartialClientConfig = toml::from_str(LOCAL_STORAGE_CONFIG_TOML).unwrap();
|
||||
let config: Config = toml::from_str(LOCAL_STORAGE_CONFIG_TOML).unwrap();
|
||||
assert_eq!(&config, get_local_storage_client_config_struct().await);
|
||||
}
|
||||
|
||||
|
@ -98,27 +62,31 @@ storage = "local"
|
|||
assert_eq!(LOCAL_STORAGE_CONFIG_TOML, toml::to_string(get_local_storage_client_config_struct().await).unwrap());
|
||||
}
|
||||
|
||||
const REMOTE_STORAGE_CONFIG_TOML: &str = r#"time_zone = "UTC"
|
||||
|
||||
[storage.remote]
|
||||
const REMOTE_STORAGE_CONFIG_TOML: &str = r#"[client.storage.remote]
|
||||
endpoint = "https://example.com"
|
||||
access_key = "test"
|
||||
|
||||
[global]
|
||||
time_zone = "UTC"
|
||||
"#;
|
||||
static REMOTE_STORAGE_CONFIG_STRUCT: OnceCell<PartialClientConfig> = OnceCell::const_new();
|
||||
static REMOTE_STORAGE_CONFIG_STRUCT: OnceCell<Config> = OnceCell::const_new();
|
||||
|
||||
async fn get_remote_storage_client_config_struct() -> &'static PartialClientConfig {
|
||||
async fn get_remote_storage_client_config_struct() -> &'static Config {
|
||||
REMOTE_STORAGE_CONFIG_STRUCT.get_or_init(|| async {
|
||||
PartialClientConfig{
|
||||
storage: Some(ClientStorageConfig::Remote(ClientRemoteStorageConfig {
|
||||
endpoint: "https://example.com".to_string(),
|
||||
access_key: "test".to_string(),
|
||||
})),
|
||||
Config{
|
||||
client: ClientConfig {
|
||||
storage: ClientStorageConfig::Remote(ClientRemoteStorageConfig {
|
||||
endpoint: "https://example.com".to_string(),
|
||||
access_key: "test".to_string(),
|
||||
})
|
||||
},
|
||||
global: PartialGlobalConfig { time_zone: Some(UTC) }
|
||||
}
|
||||
}).await
|
||||
}
|
||||
#[tokio::test]
|
||||
async fn deserialize_remote_storage_client_config() {
|
||||
let config: PartialClientConfig = toml::from_str(REMOTE_STORAGE_CONFIG_TOML).unwrap();
|
||||
let config: Config = toml::from_str(REMOTE_STORAGE_CONFIG_TOML).unwrap();
|
||||
assert_eq!(&config, get_remote_storage_client_config_struct().await);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +1,8 @@
|
|||
pub mod auth;
|
||||
pub mod config;
|
||||
pub mod error;
|
||||
|
||||
pub fn add(left: u64, right: u64) -> u64 {
|
||||
left + right
|
||||
}
|
||||
use error::Error;
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let result = add(2, 2);
|
||||
assert_eq!(result, 4);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
use chrono_tz::Tz;
|
||||
#[cfg(feature="clap")]
|
||||
use clap::Args;
|
||||
use serde::Deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::sync::OnceCell;
|
||||
|
||||
use crate::Error;
|
||||
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
pub struct GlobalConfig {
|
||||
pub time_zone: Tz,
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ impl TryFrom<PartialGlobalConfig> for GlobalConfig{
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||
#[cfg_attr(feature="clap", derive(Args))]
|
||||
pub struct PartialGlobalConfig {
|
||||
#[cfg_attr(feature="clap", arg(short, long))]
|
||||
|
|
Loading…
Add table
Reference in a new issue