A cli program to easily handle .gitignore files
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

82 lines
3.0 KiB

  1. /*! TODO: Application description here
  2. This file provided by [rust-cli-boilerplate](https://github.com/ssokolow/rust-cli-boilerplate)
  3. */
  4. // Copyright 2017-2019, Stephan Sokolow
  5. // `error_chain` recursion adjustment
  6. #![recursion_limit = "1024"]
  7. // Make rustc's built-in lints more strict and set clippy into a whitelist-based configuration so
  8. // we see new lints as they get written (We'll opt back out selectively)
  9. #![warn(warnings, rust_2018_idioms, clippy::all, clippy::complexity, clippy::correctness,
  10. clippy::pedantic, clippy::perf, clippy::style, clippy::restriction)]
  11. // Opt out of the lints I've seen and don't want
  12. #![allow(clippy::float_arithmetic, clippy::implicit_return)]
  13. // stdlib imports
  14. use std::io;
  15. use std::convert::TryInto;
  16. // 3rd-party imports
  17. mod errors;
  18. use structopt::{clap, StructOpt};
  19. use log::error;
  20. // Local imports
  21. mod app;
  22. mod helpers;
  23. mod validators;
  24. /// Boilerplate to parse command-line arguments, set up logging, and handle bubbled-up `Error`s.
  25. ///
  26. /// Based on the `StructOpt` example from stderrlog and the suggested error-chain harness from
  27. /// [quickstart.rs](https://github.com/brson/error-chain/blob/master/examples/quickstart.rs).
  28. ///
  29. /// See `app::main` for the application-specific logic.
  30. ///
  31. /// **TODO:** Consider switching to Failure and look into `impl Termination` as a way to avoid
  32. /// having to put the error message pretty-printing inside main()
  33. fn main() {
  34. // Parse command-line arguments (exiting on parse error, --version, or --help)
  35. let opts = app::CliOpts::from_args();
  36. // Configure logging output so that -q is "decrease verbosity" rather than instant silence
  37. let verbosity = opts.boilerplate.verbose
  38. .saturating_add(app::DEFAULT_VERBOSITY)
  39. .saturating_sub(opts.boilerplate.quiet);
  40. stderrlog::new()
  41. .module(module_path!())
  42. .quiet(verbosity == 0)
  43. .verbosity(verbosity.saturating_sub(1).try_into().expect("should never even come close"))
  44. .timestamp(opts.boilerplate.timestamp.unwrap_or(stderrlog::Timestamp::Off))
  45. .init()
  46. .expect("initializing logging output");
  47. // If requested, generate shell completions and then exit with status of "success"
  48. if let Some(shell) = opts.boilerplate.dump_completions {
  49. app::CliOpts::clap().gen_completions_to(
  50. app::CliOpts::clap().get_bin_name().unwrap_or_else(|| clap::crate_name!()),
  51. shell,
  52. &mut io::stdout());
  53. std::process::exit(0);
  54. };
  55. if let Err(ref e) = app::main(opts) {
  56. // Write the top-level error message, then chained errors, then backtrace if available
  57. error!("error: {}", e);
  58. for e in e.iter().skip(1) {
  59. error!("caused by: {}", e);
  60. }
  61. if let Some(backtrace) = e.backtrace() {
  62. error!("backtrace: {:?}", backtrace);
  63. }
  64. // Exit with a nonzero exit code
  65. // TODO: Decide how to allow code to set this to something other than 1
  66. std::process::exit(1);
  67. }
  68. }
  69. // vim: set sw=4 sts=4 expandtab :