1
/*
2
 * Hurl (https://hurl.dev)
3
 * Copyright (C) 2025 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::ArgMatches;
23
use hurl_core::input::Input;
24

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

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

            
32
207
pub fn color(arg_matches: &ArgMatches) -> Option<bool> {
33
207
    if has_flag(arg_matches, "color") {
34
6
        Some(true)
35
201
    } else if has_flag(arg_matches, "no_color") || has_flag(arg_matches, "in_place") {
36
6
        Some(false)
37
    } else {
38
195
        None
39
    }
40
}
41

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

            
53
207
pub fn output_format(arg_matches: &ArgMatches) -> Result<OutputFormat, OptionsError> {
54
207
    match get_string(arg_matches, "output_format")
55
207
        .unwrap_or("hurl".to_string())
56
207
        .as_str()
57
207
    {
58
207
        "hurl" => Ok(OutputFormat::Hurl),
59
117
        "json" => Ok(OutputFormat::Json),
60
60
        "html" => Ok(OutputFormat::Html),
61
        v => Err(OptionsError::Error(format!("Invalid output format {v}"))),
62
    }
63
}
64

            
65
207
pub fn in_place(arg_matches: &ArgMatches) -> Result<bool, OptionsError> {
66
207
    if has_flag(arg_matches, "in_place") {
67
6
        if input_format(arg_matches)? != InputFormat::Hurl {
68
            Err(OptionsError::Error(
69
                "You can use --in-place only hurl format!".to_string(),
70
            ))
71
6
        } else if get_string(arg_matches, "input_files").is_none() {
72
            Err(OptionsError::Error(
73
                "You can not use --in-place with standard input stream!".to_string(),
74
            ))
75
        } else {
76
6
            Ok(true)
77
        }
78
    } else {
79
201
        Ok(false)
80
    }
81
}
82

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

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

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

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

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

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