summaryrefslogtreecommitdiffhomepage
path: root/mullvad-problem-report/src/main.rs
blob: 3aae8f2e30ce3e77e31d82ddbae50e4302c1ba50 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#![deny(rust_2018_idioms)]

use clap::{crate_authors, crate_name};
use mullvad_problem_report::{collect_report, metadata, send_problem_report, Error};
use std::{env, path::Path, process};
use talpid_types::ErrorExt;

fn main() {
    process::exit(match run() {
        Ok(()) => 0,
        Err(error) => {
            eprintln!("{}", error.display_chain());
            1
        }
    })
}

fn run() -> Result<(), Error> {
    env_logger::init();
    let app = clap::App::new(crate_name!())
        .version(metadata::PRODUCT_VERSION)
        .author(crate_authors!())
        .about("Mullvad VPN problem report tool. Collects logs and sends them to Mullvad support.")
        .setting(clap::AppSettings::SubcommandRequiredElseHelp)
        .global_settings(&[
            clap::AppSettings::DisableHelpSubcommand,
            clap::AppSettings::VersionlessSubcommands,
        ])
        .subcommand(
            clap::SubCommand::with_name("collect")
                .about("Collect problem report")
                .arg(
                    clap::Arg::with_name("output")
                        .help("The destination path for saving the collected report.")
                        .long("output")
                        .short("o")
                        .value_name("PATH")
                        .takes_value(true)
                        .required(true),
                )
                .arg(
                    clap::Arg::with_name("extra_logs")
                        .help("Paths to additional log files to be included.")
                        .multiple(true)
                        .value_name("EXTRA LOGS")
                        .takes_value(true)
                        .required(false),
                )
                .arg(
                    clap::Arg::with_name("redact")
                        .help("List of words and expressions to remove from the report")
                        .long("redact")
                        .value_name("PHRASE")
                        .multiple(true)
                        .takes_value(true),
                ),
        )
        .subcommand(
            clap::SubCommand::with_name("send")
                .about("Send collected problem report")
                .arg(
                    clap::Arg::with_name("report")
                        .long("report")
                        .short("r")
                        .help("The path to previously collected report file.")
                        .takes_value(true)
                        .required(true),
                )
                .arg(
                    clap::Arg::with_name("email")
                        .long("email")
                        .short("e")
                        .help("Reporter's email")
                        .takes_value(true)
                        .required(false),
                )
                .arg(
                    clap::Arg::with_name("message")
                        .long("message")
                        .short("m")
                        .help("Reporter's message")
                        .takes_value(true)
                        .required(false),
                ),
        );

    let matches = app.get_matches();

    if let Some(collect_matches) = matches.subcommand_matches("collect") {
        let redact_custom_strings = collect_matches
            .values_of_lossy("redact")
            .unwrap_or_else(Vec::new);
        let extra_logs = collect_matches
            .values_of_os("extra_logs")
            .map(|os_values| os_values.map(Path::new).collect())
            .unwrap_or_else(Vec::new);
        let output_path = Path::new(collect_matches.value_of_os("output").unwrap());
        collect_report(&extra_logs, output_path, redact_custom_strings)?;

        let expanded_output_path = output_path
            .canonicalize()
            .unwrap_or_else(|_| output_path.to_owned());
        println!(
            "Problem report written to {}",
            expanded_output_path.display()
        );
        println!("");
        println!("Send the problem report to support via the send subcommand. See:");
        println!(" $ {} send --help", env::args().next().unwrap());
        Ok(())
    } else if let Some(send_matches) = matches.subcommand_matches("send") {
        let report_path = Path::new(send_matches.value_of_os("report").unwrap());
        let user_email = send_matches.value_of("email").unwrap_or("");
        let user_message = send_matches.value_of("message").unwrap_or("");
        let cache_dir = mullvad_paths::get_cache_dir()?;
        send_problem_report(user_email, user_message, report_path, &cache_dir)
    } else {
        unreachable!("No sub command given");
    }
}