-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This is a breaking change because authentication arguments had to be moved to subcommand.
- Loading branch information
1 parent
aea4244
commit 1ee0494
Showing
8 changed files
with
245 additions
and
77 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
use std::{ | ||
io::{stdout, Write}, | ||
os::unix::prelude::OsStrExt, | ||
path::PathBuf, | ||
}; | ||
|
||
use crate::config::Config; | ||
use crate::error::Error; | ||
use crate::rest_api::RestApi; | ||
use clap::Parser; | ||
use log::{LevelFilter, debug}; | ||
use super::ini; | ||
use super::env::EnvVar; | ||
|
||
#[derive(Debug, Parser)] | ||
#[clap(name = "netsuite", version = "abc123")] | ||
pub(crate) struct Opts { | ||
#[clap(short = 's', long, env, default_value = "netsuite")] | ||
ini_section: String, | ||
/// Where to load INI from, defaults to your OS's config directory. | ||
#[clap(short = 'p', long, env)] | ||
ini_path: Option<PathBuf>, | ||
#[clap(subcommand)] | ||
subcmd: SubCommand, | ||
} | ||
|
||
#[derive(Debug, Parser)] | ||
enum SubCommand { | ||
#[clap(name = "suiteql")] | ||
SuiteQl { | ||
/// The query to execute. If `-` is provided, query will be read from standard input. | ||
query: String, | ||
#[clap(short, long, env = EnvVar::Account.into())] | ||
account: String, | ||
#[clap(short = 'c', long, env = EnvVar::ConsumerKey.into())] | ||
consumer_key: String, | ||
#[clap(short = 'C', long, env = EnvVar::ConsumerSecret.into())] | ||
consumer_secret: String, | ||
#[clap(short = 't', long, env = EnvVar::TokenId.into())] | ||
token_id: String, | ||
#[clap(short = 'T', long, env = EnvVar::TokenSecret.into())] | ||
token_secret: String, | ||
#[clap(short, long, default_value = "1000")] | ||
limit: usize, | ||
#[clap(short, long, default_value = "0")] | ||
offset: usize, | ||
}, | ||
#[clap(name = "default-ini-path")] | ||
DefaultIniPath, | ||
} | ||
|
||
pub fn run() -> Result<(), Error> { | ||
|
||
if let Err(err) = ini::to_env() { | ||
debug!("Couldn't load INI: {}", err); | ||
}; | ||
|
||
let cli_opts = Opts::parse(); | ||
|
||
match &cli_opts.subcmd { | ||
SubCommand::SuiteQl { | ||
query, | ||
account, | ||
consumer_key, | ||
consumer_secret, | ||
token_id, | ||
token_secret, | ||
limit, | ||
offset, | ||
} => { | ||
let config = Config::new( | ||
&account, | ||
&consumer_key, | ||
&consumer_secret, | ||
&token_id, | ||
&token_secret, | ||
); | ||
let api = RestApi::new(&config); | ||
let result = api.suiteql.raw(query, *limit, *offset)?; | ||
println!("{}", result); | ||
} | ||
SubCommand::DefaultIniPath => { | ||
ini::default_location().map(|p| stdout().write(p.as_os_str().as_bytes())); | ||
} | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
pub enum EnvVar { | ||
Account, | ||
ConsumerKey, | ||
ConsumerSecret, | ||
TokenId, | ||
TokenSecret, | ||
} | ||
|
||
impl EnvVar { | ||
pub fn exists(key: &str) -> bool { | ||
match key { | ||
"ACCOUNT" => true, | ||
"CONSUMER_KEY" => true, | ||
"CONSUMER_SECRET" => true, | ||
"TOKEN_ID" => true, | ||
"TOKEN_SECRET" => true, | ||
_ => false, | ||
} | ||
} | ||
|
||
pub fn set(key: &str, val: &str) { | ||
if EnvVar::exists(key) { | ||
std::env::set_var(key, val); | ||
} | ||
} | ||
} | ||
|
||
impl From<EnvVar> for &'static str { | ||
fn from(var: EnvVar) -> Self { | ||
match var { | ||
EnvVar::Account => "ACCOUNT", | ||
EnvVar::ConsumerKey => "CONSUMER_KEY", | ||
EnvVar::ConsumerSecret => "CONSUMER_SECRET", | ||
EnvVar::TokenId => "TOKEN_ID", | ||
EnvVar::TokenSecret => "TOKEN_SECRET", | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
#[derive(thiserror::Error, Debug)] | ||
pub enum CliError { | ||
#[error("INI path could not be found")] | ||
MissingIniPath, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
use std::path::PathBuf; | ||
use clap::{IntoApp, AppSettings}; | ||
use configparser::ini::Ini; | ||
use log::debug; | ||
use super::CliError; | ||
use super::cli::Opts; | ||
use super::env::EnvVar; | ||
|
||
pub(crate) fn default_location() -> Option<PathBuf> { | ||
dirs::config_dir().map(|p| p.join("netsuite.ini")) | ||
} | ||
|
||
/// Ensure that configured ini values are exported as environment variables, so | ||
/// that they can later be loaded by Opts. | ||
// TODO: This is not very pretty. Submit issue/PR to clap for INI support. | ||
pub(crate) fn to_env() -> Result<(), CliError> { | ||
let maybe_ini_path = &default_location().map(|p| p.into_os_string()); | ||
let (ini_path, ini_section) = { | ||
let app = Opts::into_app() | ||
.global_setting(AppSettings::IgnoreErrors) | ||
.mut_arg("ini-path", |arg| match maybe_ini_path { | ||
Some(p) => arg.default_value_os(p), | ||
None => arg, | ||
}); | ||
let matches = app.get_matches(); | ||
let ini_section: String = matches.value_of_t_or_exit("ini-section"); | ||
let ini_path: PathBuf = match matches.value_of_t("ini-path") { | ||
Ok(p) => p, | ||
Err(_) => return Err(CliError::MissingIniPath), | ||
}; | ||
(ini_path, ini_section) | ||
}; | ||
|
||
let mut ini = Ini::new(); | ||
if ini_path.exists() { | ||
debug!("Loaded INI {:?}", &ini_path); | ||
ini.load(&ini_path).unwrap_or_default(); | ||
} else { | ||
debug!("INI {:?} doesn't exist. Nothing loaded.", &ini_path); | ||
} | ||
|
||
let section = ini.remove_section(&ini_section); | ||
if section.is_some() { | ||
debug!("Loaded INI section {}.", &ini_section); | ||
} else { | ||
debug!("No such INI section: {}.", &ini_section); | ||
} | ||
|
||
section.unwrap_or_default().into_iter().for_each(|(k, v)| { | ||
let k = k.to_ascii_uppercase(); | ||
if let Some(v) = v { | ||
EnvVar::set(&k, &v); | ||
} | ||
}); | ||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
mod ini; | ||
mod cli; | ||
mod env; | ||
mod error; | ||
|
||
pub use error::*; | ||
pub use cli::*; |