/*! Gitig is a small cli program to handle gitignore files It helps adding new entries to ignore and start a new project with templates from [Github](https://github.com/github/gitignore). This project used [rust-cli-boilerplate](https://github.com/ssokolow/rust-cli-boilerplate) */ // Copyright 2017-2019, Stephan Sokolow // `error_chain` recursion adjustment #![recursion_limit = "1024"] // Make rustc's built-in lints more strict and set clippy into a whitelist-based configuration so // we see new lints as they get written (We'll opt back out selectively) #![warn( warnings, rust_2018_idioms, clippy::all, clippy::complexity, clippy::correctness, clippy::pedantic, clippy::perf, clippy::style, clippy::restriction )] // Opt out of the lints I've seen and don't want #![allow( clippy::float_arithmetic, clippy::implicit_return, clippy::filter_map, clippy::wildcard_imports, clippy::integer_arithmetic )] #[macro_use] extern crate error_chain; // stdlib imports use std::convert::TryInto; // 3rd-party imports mod errors; use log::trace; use structopt::StructOpt; // Local imports mod app; mod cache; mod gitignore; mod helpers; mod template; /// Boilerplate to parse command-line arguments, set up logging, and handle bubbled-up `Error`s. /// /// Based on the `StructOpt` example from stderrlog and the suggested error-chain harness from /// [quickstart.rs](https://github.com/brson/error-chain/blob/master/examples/quickstart.rs). /// /// See `app::main` for the application-specific logic. /// /// **TODO:** Consider switching to Failure and look into `impl Termination` as a way to avoid /// having to put the error message pretty-printing inside main() #[allow(clippy::result_expect_used, clippy::exit, clippy::use_debug)] fn main() { // Parse command-line arguments (exiting on parse error, --version, or --help) let opts = app::CliOpts::from_args(); // Configure logging output so that -q is "decrease verbosity" rather than instant silence let verbosity = opts .boilerplate .verbose .saturating_add(app::DEFAULT_VERBOSITY) .saturating_sub(opts.boilerplate.quiet); stderrlog::new() .module(module_path!()) .quiet(verbosity == 0) .verbosity(verbosity.saturating_sub(1).try_into().expect("should never even come close")) .timestamp(opts.boilerplate.timestamp.unwrap_or(stderrlog::Timestamp::Off)) .init() .expect("initializing logging output"); trace!("Initialized logging, {} v{}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")); trace!("Starting with application"); if let Err(ref e) = app::main(opts) { use std::io::prelude::*; let stderr = std::io::stderr(); let mut lock = stderr.lock(); // Write the top-level error message, then chained errors, then backtrace if available writeln!(lock, "error: {}", e).expect("error while writing error"); for e in e.iter().skip(1) { writeln!(lock, "caused by: {}", e).expect("error while writing error"); } if let Some(backtrace) = e.backtrace() { writeln!(lock, "backtrace: {:?}", backtrace).expect("error while writing error"); } std::process::exit(1); } } // vim: set sw=4 sts=4 expandtab :