gitig 0.3.0

A cli utility to manage gitignore files easily
/*! 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 :