1 use anyhow::{anyhow, Result};
2 use app_oten::{self, handler::process_auth_app};
3 use clap::Parser;
4 use console::style;
5 use dotenv::dotenv;
6 use smbpndk_cli::{
7 account::process_account,
8 cli::{Cli, Commands},
9 project::process_project,
10 };
11 use smbpndk_model::CommandResult;
12 use std::{
13 fs::{create_dir_all, OpenOptions},
14 path::PathBuf,
15 str::FromStr,
16 };
17 use tracing::subscriber::set_global_default;
18 use tracing_bunyan_formatter::{BunyanFormattingLayer, JsonStorageLayer};
19 use tracing_subscriber::{filter::LevelFilter, prelude::*, EnvFilter};
20
21 fn setup_logging(level: Option<EnvFilter>) -> Result<()> {
22 // Log in the current directory
23 let log_path = match home::home_dir() {
24 Some(path) => {
25 create_dir_all(path.join(".smb"))?;
26 let log_path = [path.to_str().unwrap(), "/.smb/smbpndk-cli.log"].join("");
27 // Create the file if it doesn't exist
28 let _file = OpenOptions::new()
29 .create(true)
30 .write(true)
31 .open(&log_path)?;
32
33 PathBuf::from(log_path)
34 }
35 None => {
36 return Err(anyhow!("Could not find home directory."));
37 }
38 };
39
40 let file = OpenOptions::new()
41 .create(true)
42 .write(true)
43 .open(log_path)
44 .unwrap();
45
46 let env_filter = if let Some(filter) = level {
47 filter
48 } else {
49 EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("trace"))
50 };
51
52 let formatting_layer = BunyanFormattingLayer::new("smb".into(), file);
53 let level_filter = LevelFilter::from_str(&env_filter.to_string())?;
54
55 let subscriber = tracing_subscriber::registry()
56 .with(formatting_layer.with_filter(level_filter))
57 .with(JsonStorageLayer);
58
59 set_global_default(subscriber).expect("Failed to set global default subscriber");
60
61 Ok(())
62 }
63
64 #[tokio::main]
65 async fn main() {
66 dotenv().ok();
67 match run().await {
68 Ok(result) => {
69 let mut spinner = result.spinner;
70 spinner.stop_and_persist(&result.symbol, result.msg);
71 std::process::exit(1);
72 }
73 Err(e) => {
74 println!(
75 "\n{} {}",
76 style("✘".to_string()).for_stderr().red(),
77 style(e).red()
78 );
79 std::process::exit(1);
80 }
81 }
82 }
83
84 async fn run() -> Result<CommandResult> {
85 let cli = Cli::parse();
86
87 let log_level_error: Result<CommandResult> = Err(anyhow!(
88 "Invalid log level: {:?}.\n Valid levels are: trace, debug, info, warn, and error.",
89 cli.log_level
90 ));
91
92 if let Some(user_filter) = cli.log_level {
93 let filter = match EnvFilter::from_str(&user_filter) {
94 Ok(filter) => filter,
95 Err(_) => return log_level_error,
96 };
97 setup_logging(Some(filter))?;
98 } else {
99 setup_logging(None)?;
100 }
101
102 match cli.command {
103 Commands::Account { command } => process_account(command).await,
104 Commands::Project { command } => process_project(command).await,
105 Commands::Oten { command } => process_auth_app(command).await,
106 }
107 }