use std::fs::File;
use std::io::{prelude::*, stdout, BufWriter};
use std::path::{Path, PathBuf};
use anyhow::{Context, Error};
use human_panic::setup_panic;
use log::Level;
use loggerv::{Logger, Output};
use structopt::StructOpt;
use semantic_release_rust::{list_packages, prepare, publish, verify_conditions};
#[derive(StructOpt)]
struct Opt {
#[structopt(short, long, parse(from_occurrences))]
verbose: u64,
#[structopt(short, long, parse(from_os_str))]
output: Option<PathBuf>,
#[structopt(subcommand)]
subcommand: Subcommand,
}
#[derive(StructOpt)]
enum Subcommand {
ListPackages(CommonOpt),
#[structopt(verbatim_doc_comment)]
VerifyConditions(CommonOpt),
Prepare(PrepareOpt),
Publish(PublishOpt),
}
#[derive(StructOpt)]
struct CommonOpt {
#[structopt(long, parse(from_os_str))]
manifest_path: Option<PathBuf>,
}
#[derive(StructOpt)]
struct PrepareOpt {
#[structopt(flatten)]
common: CommonOpt,
next_version: String,
}
#[derive(StructOpt)]
struct PublishOpt {
#[structopt(flatten)]
common: CommonOpt,
#[structopt(long)]
no_dirty: bool,
}
impl Subcommand {
fn run(&self, w: impl Write) -> Result<(), Error> {
use Subcommand::*;
match self {
ListPackages(opt) => Ok(list_packages(w, opt.manifest_path())?),
VerifyConditions(opt) => Ok(verify_conditions(w, opt.manifest_path())?),
Prepare(opt) => Ok(prepare(w, opt.common.manifest_path(), &opt.next_version)?),
Publish(opt) => Ok(publish(w, opt.common.manifest_path(), opt.no_dirty)?),
}
}
}
fn main() -> Result<(), Error> {
setup_panic!();
let opt = Opt::from_args();
Logger::new()
.output(&Level::Trace, Output::Stderr)
.output(&Level::Debug, Output::Stderr)
.output(&Level::Info, Output::Stderr)
.verbosity(opt.verbose)
.init()?;
match opt.output {
Some(path) => {
let file = File::create(&path)
.with_context(|| format!("Failed to create output file {}", path.display()))?;
opt.subcommand.run(BufWriter::new(file))
}
None => opt.subcommand.run(BufWriter::new(stdout())),
}
}
impl CommonOpt {
fn manifest_path(&self) -> Option<&Path> {
self.manifest_path.as_deref()
}
}