use std::ffi;
use std::path;
use std::process;
use failure;
use escargot;
pub trait CommandCargoExt
where
Self: Sized,
{
fn main_binary() -> Result<Self, failure::Error>;
fn cargo_bin<S: AsRef<ffi::OsStr>>(name: S) -> Result<Self, failure::Error>;
fn cargo_example<S: AsRef<ffi::OsStr>>(name: S) -> Result<Self, failure::Error>;
}
impl CommandCargoExt for process::Command {
fn main_binary() -> Result<Self, failure::Error> {
let cmd = main_binary_path()?;
Ok(process::Command::new(&cmd))
}
fn cargo_bin<S: AsRef<ffi::OsStr>>(name: S) -> Result<Self, failure::Error> {
let cmd = cargo_bin_path(name)?;
Ok(process::Command::new(&cmd))
}
fn cargo_example<S: AsRef<ffi::OsStr>>(name: S) -> Result<Self, failure::Error> {
let cmd = cargo_example_path(name)?;
Ok(process::Command::new(&cmd))
}
}
#[derive(Deserialize)]
struct MessageTarget<'a> {
#[serde(borrow)]
crate_types: Vec<&'a str>,
#[serde(borrow)]
kind: Vec<&'a str>,
}
#[derive(Deserialize)]
struct MessageFilter<'a> {
#[serde(borrow)]
reason: &'a str,
target: MessageTarget<'a>,
filenames: Vec<path::PathBuf>,
}
fn extract_filenames(msg: &escargot::Message, kind: &str) -> Option<path::PathBuf> {
let filter: MessageFilter = msg.convert().ok()?;
if filter.reason != "compiler-artifact" || filter.target.crate_types != ["bin"]
|| filter.target.kind != [kind]
{
None
} else {
Some(
filter
.filenames
.into_iter()
.next()
.expect("files must exist"),
)
}
}
pub fn main_binary_path() -> Result<path::PathBuf, failure::Error> {
let cargo = escargot::Cargo::new().build().current_release();
let bins: Vec<_> = cargo
.exec()?
.filter_map(|m| extract_filenames(&m, "bin"))
.collect();
if bins.is_empty() {
bail!("No binaries in crate");
} else if bins.len() != 1 {
bail!("Ambiguous which binary is intended: {:?}", bins);
}
Ok(bins.into_iter().next().expect("already validated"))
}
pub fn cargo_bin_path<S: AsRef<ffi::OsStr>>(name: S) -> Result<path::PathBuf, failure::Error> {
let cargo = escargot::Cargo::new().build().bin(name).current_release();
let bins: Vec<_> = cargo
.exec()?
.filter_map(|m| extract_filenames(&m, "bin"))
.collect();
assert_eq!(bins.len(), 1);
Ok(bins.into_iter().next().expect("already validated"))
}
pub fn cargo_example_path<S: AsRef<ffi::OsStr>>(name: S) -> Result<path::PathBuf, failure::Error> {
let cargo = escargot::Cargo::new()
.build()
.example(name)
.current_release();
let bins: Vec<_> = cargo
.exec()?
.filter_map(|m| extract_filenames(&m, "example"))
.collect();
assert_eq!(bins.len(), 1);
Ok(bins.into_iter().next().expect("already validated"))
}