use std::io::{self, BufWriter, Write};
use std::path::PathBuf;
use anyhow::anyhow;
use anyhow::Context as _;
use fehler::{throw, throws};
use structopt::StructOpt;
use gitforge::forge;
use forge::TokenConfig;
use anyhow::Error as AE;
pub fn default<T>() -> T where T: Default { Default::default() }
#[derive(StructOpt)]
struct Opts {
#[structopt(
long="ron",
about="operation is 1 argument in RON (Rusty Object Notation) \
(this option currently mandatory)"
)]
format_ron: bool,
#[structopt(
long="log",
short="L",
about="default log level (verbosity)",
)]
log_level: Option<log::LevelFilter>,
#[structopt(long="token-file")] token_file: Option<PathBuf>,
#[structopt(long="no-token")] no_token: bool,
#[structopt(name="KIND", about="forge kind, eg github or gitlab")]
kind: forge::Kind,
#[structopt(name="HOST", about="forge (host) domain name")]
host: String,
#[structopt(name="OPERATION", about="operation (in RON syntax")]
op: Vec<String>,
}
#[throws(AE)]
fn main(){
let opts = Opts::from_args();
let mut log_builder = env_logger::Builder::from_env("GITFORGE_LOG");
if let Some(filter) = opts.log_level { log_builder.filter_level(filter); }
log_builder.init();
let req = match opts.format_ron {
true => match opts.op.as_slice() {
[op] => ron::de::from_str(op).context("parse request argument")?,
_ => throw!(anyhow!("OPERATION must be exactly argument")),
},
false => {
throw!(anyhow!("--ron required, no other format supported right now"));
},
};
let mut config = forge::Config {
kind: Some(opts.kind),
host: opts.host,
..default()
};
config.token = match &opts.token_file {
Some(token_file) => Some(TokenConfig::Path(token_file.clone())),
None if opts.no_token => Some(TokenConfig::Anonymous),
None => None,
};
let mut fo = config.forge().context("construct forge")?;
let resp = fo.request(&req).context("make request")?;
let mut bw = BufWriter::new(io::stdout());
ron::ser::to_writer(&mut bw, &resp).context("print response")?;
writeln!(bw, "").context("write newline")?;
bw.flush().context("flush stdout")?;
}