1mod cli;
4
5use std::ffi::OsString;
6
7use clap::Parser;
8use tracing_subscriber::EnvFilter;
9
10use cli::Cli;
11
12const DEFAULT_LOG_FILTER: &str = "info";
14
15pub fn main() {
18 init_tracing();
19 let cli = Cli::parse_from(strip_cargo_subcommand(std::env::args_os()));
20 if let Err(error) = cli.run() {
21 tracing::error!("npmgen failed: {}", error_chain(&error));
22 std::process::exit(1);
23 }
24}
25
26fn error_chain(error: &dyn std::error::Error) -> String {
29 let mut message = error.to_string();
30 let mut source = error.source();
31 while let Some(cause) = source {
32 message.push_str(": ");
33 message.push_str(&cause.to_string());
34 source = cause.source();
35 }
36 message
37}
38
39fn init_tracing() {
40 tracing_subscriber::fmt()
43 .with_env_filter(
44 EnvFilter::try_from_default_env()
45 .unwrap_or_else(|_| EnvFilter::new(DEFAULT_LOG_FILTER)),
46 )
47 .with_target(false)
48 .init();
49}
50
51fn strip_cargo_subcommand(args: impl Iterator<Item = OsString>) -> Vec<OsString> {
54 let mut args: Vec<OsString> = args.collect();
55 if args.get(1).and_then(|arg| arg.to_str()) == Some("npmgen") {
56 args.remove(1);
57 }
58 args
59}
60
61#[cfg(test)]
62mod tests {
63 use super::strip_cargo_subcommand;
64 use std::ffi::OsString;
65
66 fn argv(parts: &[&str]) -> Vec<OsString> {
67 parts.iter().map(OsString::from).collect()
68 }
69
70 #[test]
71 fn drops_cargo_injected_subcommand() {
72 let stripped =
73 strip_cargo_subcommand(argv(&["cargo-npmgen", "npmgen", "--out", "x"]).into_iter());
74 assert_eq!(stripped, argv(&["cargo-npmgen", "--out", "x"]));
75 }
76
77 #[test]
78 fn leaves_direct_invocations_untouched() {
79 let standalone = strip_cargo_subcommand(argv(&["npmgen", "--out", "x"]).into_iter());
80 assert_eq!(standalone, argv(&["npmgen", "--out", "x"]));
81
82 let direct = strip_cargo_subcommand(argv(&["cargo-npmgen", "--out", "x"]).into_iter());
83 assert_eq!(direct, argv(&["cargo-npmgen", "--out", "x"]));
84 }
85}