use anyhow::{anyhow, Context, Result};
use std::{
mem,
path::{Path, PathBuf},
};
pub enum BuildCommand {
Build(BuildArgs),
Version,
Help,
}
impl BuildCommand {
pub fn parse_args<A>(args: A) -> Result<Self>
where
A: Iterator<Item = String>,
{
let mut manifest_path: Option<PathBuf> = None;
let mut cargo_args = Vec::new();
let mut quiet = false;
{
fn set<T>(arg: &mut Option<T>, value: Option<T>) -> Result<()> {
let previous = mem::replace(arg, value);
if previous.is_some() {
return Err(anyhow!("multiple arguments of same type provided"));
}
Ok(())
}
let mut arg_iter = args;
while let Some(arg) = arg_iter.next() {
match arg.as_ref() {
"--help" | "-h" => {
return Ok(BuildCommand::Help);
}
"--version" => {
return Ok(BuildCommand::Version);
}
"--quiet" => {
quiet = true;
}
"--manifest-path" => {
let next = arg_iter.next();
set(
&mut manifest_path,
next.as_ref()
.map(|p| Path::new(&p).canonicalize())
.transpose()
.context("--manifest-path invalid")?,
)?;
cargo_args.push(arg);
if let Some(next) = next {
cargo_args.push(next);
}
}
_ if arg.starts_with("--manifest-path=") => {
let path = Path::new(arg.trim_start_matches("--manifest-path="))
.canonicalize()
.context("--manifest-path invalid")?;
set(&mut manifest_path, Some(path))?;
cargo_args.push(arg);
}
_ => {
cargo_args.push(arg);
}
};
}
}
Ok(BuildCommand::Build(BuildArgs {
manifest_path,
cargo_args,
quiet,
}))
}
}
#[derive(Debug, Clone)]
pub struct BuildArgs {
manifest_path: Option<PathBuf>,
cargo_args: Vec<String>,
quiet: bool,
}
impl BuildArgs {
pub fn manifest_path(&self) -> Option<&Path> {
self.manifest_path.as_deref()
}
pub fn cargo_args(&self) -> &[String] {
&self.cargo_args.as_ref()
}
pub fn quiet(&self) -> bool {
self.quiet
}
}