#![deny(unsafe_code)]
#![warn(future_incompatible, nonstandard_style, rust_2018_idioms)]
#![warn(
rustdoc::broken_intra_doc_links,
rustdoc::missing_crate_level_docs,
rustdoc::private_intra_doc_links
)]
#![warn(clippy::pedantic)]
#![allow(
clippy::cast_possible_truncation,
clippy::cast_sign_loss,
clippy::if_not_else,
clippy::items_after_statements,
clippy::missing_panics_doc,
clippy::module_name_repetitions,
clippy::must_use_candidate,
clippy::similar_names,
clippy::shadow_unrelated,
clippy::unreadable_literal,
clippy::unseparated_literal_suffix
)]
#![warn(
clippy::debug_assert_with_mut_call,
clippy::disallowed_method,
clippy::disallowed_type,
clippy::fallible_impl_from,
clippy::imprecise_flops,
clippy::mutex_integer,
clippy::path_buf_push_overwrite,
clippy::string_lit_as_bytes,
clippy::use_self,
clippy::useless_transmute
)]
#![warn(
clippy::dbg_macro,
clippy::exit,
clippy::float_cmp_const,
clippy::map_err_ignore,
clippy::mem_forget,
clippy::missing_enforced_import_renames,
clippy::rest_pat_in_fully_bound_structs,
clippy::string_to_string,
clippy::todo,
clippy::unimplemented,
clippy::verbose_file_reads
)]
#![allow()]
use cargo_build_dist::{BuildOptions, Context, Mode};
use clap::{App, Arg};
use log::debug;
use std::{
env,
fmt::{Debug, Formatter},
io::Write,
path::PathBuf,
};
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
use cargo_build_dist::{Error, Result};
const ARG_DEBUG: &str = "debug";
const ARG_RELEASE: &str = "release";
const ARG_MANIFEST_PATH: &str = "manifest-path";
const ARG_VERBOSE: &str = "verbose";
const ARG_DRY_RUN: &str = "dry-run";
const ARG_FORCE: &str = "force";
struct MainError(Error);
impl Debug for MainError {
fn fmt(&self, _f: &mut Formatter<'_>) -> std::fmt::Result {
let mut stderr = StandardStream::stderr(ColorChoice::Always);
stderr
.set_color(
ColorSpec::new()
.set_fg(Some(Color::Red))
.set_intense(true)
.set_bold(true),
)
.unwrap();
write!(&mut stderr, "Error").unwrap();
stderr.reset().unwrap();
writeln!(&mut stderr, ": {}", self.0.description()).unwrap();
if let Some(source) = self.0.source() {
stderr
.set_color(
ColorSpec::new()
.set_fg(Some(Color::White))
.set_intense(true)
.set_bold(true),
)
.unwrap();
write!(&mut stderr, "Caused by").unwrap();
stderr.reset().unwrap();
writeln!(&mut stderr, ": {}", source).unwrap();
}
if let Some(explanation) = self.0.explanation() {
stderr
.set_color(
ColorSpec::new()
.set_fg(Some(Color::Yellow))
.set_bold(true)
.set_intense(true),
)
.unwrap();
writeln!(&mut stderr, "\n{}", explanation).unwrap();
stderr.reset().unwrap();
}
if let Some(output) = self.0.output() {
stderr
.set_color(
ColorSpec::new()
.set_fg(Some(Color::Blue))
.set_bold(true)
.set_intense(true),
)
.unwrap();
writeln!(&mut stderr, "\nOutput follows:").unwrap();
stderr.reset().unwrap();
writeln!(&mut stderr, "{}", output).unwrap();
}
Ok(())
}
}
fn main() -> std::result::Result<(), MainError> {
run().map_err(MainError)
}
fn get_matches() -> clap::ArgMatches<'static> {
let mut args: Vec<String> = std::env::args().collect();
if args.len() == 2 && args[1] == "build-dist" {
args.remove(0);
}
App::new("cargo build-dist")
.version(env!("CARGO_PKG_VERSION"))
.author("Legion Labs <devs@legionlabs.com>")
.about("Build distributable artifacts from cargo crates.")
.arg(
Arg::with_name(ARG_DEBUG)
.short("d")
.long(ARG_DEBUG)
.required(false)
.help("Print debug information verbosely"),
)
.arg(
Arg::with_name(ARG_RELEASE)
.long(ARG_RELEASE)
.required(false)
.help("Use release build artifacts"),
)
.arg(
Arg::with_name(ARG_VERBOSE)
.short("v")
.long(ARG_VERBOSE)
.required(false)
.help("Print debug information verbosely"),
)
.arg(
Arg::with_name(ARG_DRY_RUN)
.short("n")
.long(ARG_DRY_RUN)
.required(false)
.help("Do not really push any artifacts"),
)
.arg(
Arg::with_name(ARG_FORCE)
.short("f")
.long(ARG_FORCE)
.required(false)
.help("Push artifacts even if they already exist - this can be dangerous"),
)
.arg(
Arg::with_name(ARG_MANIFEST_PATH)
.short("m")
.long(ARG_MANIFEST_PATH)
.takes_value(true)
.required(false)
.help("Path to Cargo.toml"),
)
.get_matches_from(args)
}
fn run() -> Result<()> {
let matches = get_matches();
let mut log_level = log::LevelFilter::Off;
if matches.is_present(ARG_DEBUG) {
log_level = log::LevelFilter::Debug;
}
env_logger::Builder::new().filter_level(log_level).init();
debug!("Log level set to: {}", log_level);
if let Some(path) = matches.value_of(ARG_MANIFEST_PATH) {
if path.trim().is_empty() {
return Err(Error::new(format!(
"`--{}` cannot be empty",
ARG_MANIFEST_PATH
)));
}
}
let mode = Mode::from_release_flag(matches.is_present(ARG_RELEASE));
match mode {
Mode::Debug => {
debug!(
"`--{}` was not specified: using debug build artifacts",
ARG_RELEASE
);
}
Mode::Release => {
debug!(
"`--{}` was specified: using release build artifacts",
ARG_RELEASE
);
}
}
let mut context_builder = Context::builder();
let manifest_path = matches.value_of(ARG_MANIFEST_PATH).map(PathBuf::from);
match &manifest_path {
Some(manifest_path) => {
debug!(
"`--{}` was specified: using manifest path: {}",
ARG_MANIFEST_PATH,
manifest_path.display()
);
context_builder = context_builder.with_manifest_path(manifest_path);
}
None => {
debug!(
"`--{}` was not specified: using current directory",
ARG_MANIFEST_PATH
);
}
}
let context = context_builder.build()?;
let options = BuildOptions {
dry_run: matches.is_present(ARG_DRY_RUN),
force: matches.is_present(ARG_FORCE),
verbose: matches.is_present(ARG_VERBOSE),
mode,
};
context.build_dist_targets(&options)
}