#![allow(
clippy::needless_pass_by_value,
clippy::new_ret_no_self,
clippy::redundant_closure,
clippy::single_char_pattern
)]
#![deny(unused_must_use)]
use failure::ResultExt;
use log::{error, warn, trace};
use std::cmp;
use std::ffi::OsString;
use std::path::PathBuf;
use std::process;
use structopt::StructOpt;
mod cargo;
mod exec;
mod lipo;
mod meta;
mod xcode;
type Result<T> = std::result::Result<T, failure::Error>;
#[derive(StructOpt, Debug)]
#[structopt(name = "cargo-lipo", bin_name = "cargo")]
#[structopt(author = "")]
#[structopt(raw(setting = "clap::AppSettings::SubcommandRequiredElseHelp"))]
struct CargoInvocation {
#[structopt(subcommand)]
cmd: Command,
}
#[derive(StructOpt, Debug)]
enum Command {
#[structopt(name = "lipo")]
#[structopt(author = "")]
Invocation(Invocation),
}
#[derive(StructOpt, Debug)]
struct Invocation {
#[structopt(long, default_value = "auto", value_name = "WHEN")]
color: Coloring,
#[structopt(long, short)]
#[structopt(parse(from_occurrences))]
verbose: u32,
#[structopt(long = "allow-run-on-non-macos")]
run_on_non_macos: bool,
#[structopt(long = "xcode-integ")]
#[structopt(conflicts_with = "release", conflicts_with = "targets")]
xcode_integ: bool,
#[structopt(long = "xcode-ignore-clean")]
#[structopt(requires = "xcode_integ")]
#[allow(dead_code)]
xcode_ignore_clean: bool,
#[structopt(long = "no-sanitize-env")]
no_sanitize_env: bool,
#[structopt(long)]
release: bool,
#[structopt(long)]
frozen: bool,
#[structopt(long)]
locked: bool,
#[structopt(long, short, value_name = "N")]
jobs: Option<u32>,
#[structopt(long)]
all: bool,
#[structopt(short, long = "package", value_name = "NAME")]
#[structopt(conflicts_with = "all")]
packages: Vec<String>,
#[structopt(long = "all-features")]
all_features: bool,
#[structopt(long = "no-default-features")]
no_default_features: bool,
#[structopt(long, value_name = "FEATURES")]
#[structopt(parse(from_os_str))]
features: Option<OsString>,
#[structopt(long = "manifest-path", value_name = "PATH")]
#[structopt(parse(from_os_str))]
manifest_path: Option<PathBuf>,
#[structopt(long, value_name = "TARGET1,TARGET2")]
#[structopt(value_delimiter = ",")]
#[structopt(default_value = "aarch64-apple-ios,x86_64-apple-ios")]
targets: Vec<String>,
}
fn main() {
let cargo = CargoInvocation::from_args();
let Command::Invocation(invocation) = cargo.cmd;
env_logger::Builder::from_default_env()
.default_format_timestamp(false)
.write_style(invocation.color.log_style())
.filter_module(
"cargo_lipo",
[log::LevelFilter::Info, log::LevelFilter::Debug, log::LevelFilter::Trace]
[cmp::min(invocation.verbose, 2) as usize],
)
.init();
trace!("Invocation: {:#?}", invocation);
if let Err(e) = run(invocation) {
error!("{}", e);
std::process::exit(1);
}
}
fn run(invocation: Invocation) -> Result<()> {
if !cfg!(target_os = "macos") {
if invocation.run_on_non_macos {
warn!("Running on non-macOS, `cargo lipo` will likely not work");
} else {
error!(
"Running on non-macOS, `cargo lipo` will likely not work. \
Use `--allow-run-on-non-macos` to override this check."
);
process::exit(1);
}
}
let meta = cargo_metadata::metadata(invocation.manifest_path.as_ref().map(|p| p.as_ref()))
.map_err(failure::SyncFailure::new)
.with_context(|e| format!("cargo_metadata failed: {}", e))?;
trace!("Metadata: {:#?}", meta);
let meta = meta::Meta::new(&invocation, &meta)?;
if invocation.xcode_integ {
xcode::integ(&meta, invocation)
} else {
lipo::build(&cargo::Cargo::new(&invocation), &meta, &invocation.targets)
}
}
#[derive(Copy, Clone, Debug)]
enum Coloring {
Auto,
Always,
Never,
}
impl Coloring {
pub fn value(self) -> &'static str {
match self {
Coloring::Auto => "auto",
Coloring::Always => "always",
Coloring::Never => "never",
}
}
pub fn log_style(self) -> env_logger::WriteStyle {
match self {
Coloring::Auto => env_logger::WriteStyle::Auto,
Coloring::Always => env_logger::WriteStyle::Always,
Coloring::Never => env_logger::WriteStyle::Never,
}
}
}
impl std::str::FromStr for Coloring {
type Err = String;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
match s {
"auto" => Ok(Coloring::Auto),
"always" => Ok(Coloring::Always),
"never" => Ok(Coloring::Never),
_ => Err(format!("Invalid coloring: '{}'", s)),
}
}
}