1
/*
2
 * Hurl (https://hurl.dev)
3
 * Copyright (C) 2024 Orange
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 *          http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 */
18
use std::io;
19
use std::io::IsTerminal;
20
use std::path::{Path, PathBuf};
21

            
22
use clap::parser::ValueSource;
23
use clap::ArgMatches;
24

            
25
use super::OptionsError;
26
use crate::cli::options::{InputFormat, OutputFormat};
27

            
28
180
pub fn check(arg_matches: &ArgMatches) -> bool {
29
180
    has_flag(arg_matches, "check")
30
}
31

            
32
180
pub fn color(arg_matches: &ArgMatches) -> bool {
33
180
    if has_flag(arg_matches, "color") {
34
6
        true
35
174
    } else if has_flag(arg_matches, "no_color") || has_flag(arg_matches, "in_place") {
36
3
        false
37
    } else {
38
171
        io::stdout().is_terminal()
39
    }
40
}
41

            
42
180
pub fn input_format(arg_matches: &ArgMatches) -> Result<InputFormat, OptionsError> {
43
180
    match get_string(arg_matches, "input_format").unwrap().as_str() {
44
180
        "hurl" => Ok(InputFormat::Hurl),
45
3
        "curl" => Ok(InputFormat::Curl),
46
        v => Err(OptionsError::Error(format!("Invalid input format {v}"))),
47
    }
48
}
49

            
50
180
pub fn output_format(arg_matches: &ArgMatches) -> Result<OutputFormat, OptionsError> {
51
180
    // Deprecated --format option
52
180
    if arg_matches.value_source("format") == Some(ValueSource::CommandLine) {
53
        eprintln!("--format is deprecated. use --out instead.");
54
        return match get_string(arg_matches, "format").unwrap().as_str() {
55
            "hurl" => Ok(OutputFormat::Hurl),
56
            "json" => Ok(OutputFormat::Json),
57
            "html" => Ok(OutputFormat::Html),
58
            v => Err(OptionsError::Error(format!("Invalid output format {v}"))),
59
        };
60
    }
61
180

            
62
180
    match get_string(arg_matches, "output_format").unwrap().as_str() {
63
180
        "hurl" => Ok(OutputFormat::Hurl),
64
99
        "json" => Ok(OutputFormat::Json),
65
51
        "html" => Ok(OutputFormat::Html),
66
        v => Err(OptionsError::Error(format!("Invalid output format {v}"))),
67
    }
68
}
69

            
70
180
pub fn in_place(arg_matches: &ArgMatches) -> Result<bool, OptionsError> {
71
180
    if has_flag(arg_matches, "in_place") {
72
3
        if get_string(arg_matches, "input_format") != Some("hurl".to_string()) {
73
            Err(OptionsError::Error(
74
                "You can use --in-place only hurl format!".to_string(),
75
            ))
76
3
        } else if get_string(arg_matches, "input_files").is_none() {
77
            Err(OptionsError::Error(
78
                "You can not use --in-place with standard input stream!".to_string(),
79
            ))
80
        } else {
81
3
            Ok(true)
82
        }
83
    } else {
84
177
        Ok(false)
85
    }
86
}
87

            
88
/// Returns the input files from the positional arguments and input stream
89
180
pub fn input_files(arg_matches: &ArgMatches) -> Result<Vec<String>, OptionsError> {
90
180
    let mut files = vec![];
91
180
    if let Some(filenames) = get_strings(arg_matches, "input_files") {
92
357
        for filename in filenames {
93
180
            let path = Path::new(&filename);
94
180
            if path.exists() {
95
180
                files.push(filename);
96
180
            } else {
97
                return Err(OptionsError::Error(format!(
98
                    "error: Cannot access '{}': No such file or directory",
99
                    path.display()
100
                )));
101
            }
102
        }
103
    }
104
180
    if files.is_empty() && !io::stdin().is_terminal() {
105
3
        files.push("-".to_string());
106
    }
107
180
    Ok(files)
108
}
109

            
110
180
pub fn output_file(arg_matches: &ArgMatches) -> Option<PathBuf> {
111
180
    get_string(arg_matches, "output").map(|s| Path::new(&s).to_path_buf())
112
}
113

            
114
180
pub fn standalone(arg_matches: &ArgMatches) -> Result<bool, OptionsError> {
115
180
    if has_flag(arg_matches, "standalone") {
116
3
        if get_string(arg_matches, "output_format") != Some("html".to_string()) {
117
            Err(OptionsError::Error(
118
                "use --standalone option only with html output".to_string(),
119
            ))
120
        } else {
121
3
            Ok(true)
122
        }
123
    } else {
124
177
        Ok(false)
125
    }
126
}
127

            
128
1068
fn has_flag(matches: &ArgMatches, name: &str) -> bool {
129
1068
    matches.get_one::<bool>(name) == Some(&true)
130
}
131

            
132
549
pub fn get_string(matches: &ArgMatches, name: &str) -> Option<String> {
133
672
    matches.get_one::<String>(name).map(|x| x.to_string())
134
}
135

            
136
/// Returns an optional list of `String` from the command line `matches` given the option `name`.
137
180
pub fn get_strings(matches: &ArgMatches, name: &str) -> Option<Vec<String>> {
138
180
    matches
139
180
        .get_many::<String>(name)
140
240
        .map(|v| v.map(|x| x.to_string()).collect())
141
}