mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-12-23 19:12:06 +03:00
Add --interactive option
This commit is contained in:
parent
d6767f7bc1
commit
da2dc6493b
28
Cargo.lock
generated
28
Cargo.lock
generated
@ -333,6 +333,7 @@ dependencies = [
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"termion",
|
||||
"url",
|
||||
]
|
||||
|
||||
@ -456,6 +457,12 @@ dependencies = [
|
||||
"autocfg 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "numtoa"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-probe"
|
||||
version = "0.1.2"
|
||||
@ -687,6 +694,15 @@ version = "0.1.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
|
||||
|
||||
[[package]]
|
||||
name = "redox_termios"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
||||
dependencies = [
|
||||
"redox_syscall",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.3.4"
|
||||
@ -807,6 +823,18 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termion"
|
||||
version = "1.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c22cec9d8978d906be5ac94bceb5a010d885c626c4c8855721a4dbd20e3ac905"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"numtoa",
|
||||
"redox_syscall",
|
||||
"redox_termios",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
|
@ -195,6 +195,11 @@ If you want to combine results from different Hurl executions in a unique html r
|
||||
Include the HTTP headers in the output (last entry).
|
||||
|
||||
|
||||
### --interactive {#interactive}
|
||||
|
||||
Stop between requests.
|
||||
This is similar to a break point, You can then continue (Press C) or quit (Press Q).
|
||||
|
||||
|
||||
### --json <file> {#json}
|
||||
|
||||
|
@ -28,6 +28,7 @@ libxml = "0.2.12"
|
||||
regex = "1.1.0"
|
||||
serde = "1.0.104"
|
||||
serde_json = "1.0.40"
|
||||
termion = "1.5.5"
|
||||
url = "2.1.0"
|
||||
|
||||
|
||||
|
42
packages/hurl/src/cli/interactive.rs
Normal file
42
packages/hurl/src/cli/interactive.rs
Normal file
@ -0,0 +1,42 @@
|
||||
extern crate termion;
|
||||
|
||||
use std::io::{stderr, stdin, Write};
|
||||
use termion::event::Key;
|
||||
use termion::input::TermRead;
|
||||
use termion::raw::IntoRawMode;
|
||||
|
||||
pub fn pre_entry() -> bool {
|
||||
let stdin = stdin();
|
||||
let mut stderr = stderr().into_raw_mode().unwrap();
|
||||
|
||||
eprintln!("\n\rinteractive mode:");
|
||||
write!(
|
||||
stderr,
|
||||
"\rPress Q (Quit) or C (Continue)\n\n\r{}",
|
||||
termion::cursor::Hide
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
stderr.flush().unwrap();
|
||||
let mut exit = false;
|
||||
|
||||
for c in stdin.keys() {
|
||||
print!("\r");
|
||||
match c.unwrap() {
|
||||
Key::Char('q') => {
|
||||
exit = true;
|
||||
break;
|
||||
}
|
||||
Key::Char('c') => {
|
||||
break;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
print!("{}\r{}", termion::clear::CurrentLine, termion::cursor::Show);
|
||||
exit
|
||||
}
|
||||
|
||||
pub fn post_entry() -> bool {
|
||||
false
|
||||
}
|
@ -22,4 +22,5 @@ pub use self::logger::{
|
||||
};
|
||||
|
||||
mod color;
|
||||
pub mod interactive;
|
||||
mod logger;
|
||||
|
@ -29,6 +29,7 @@ use chrono::{DateTime, Local};
|
||||
use clap::{AppSettings, ArgMatches};
|
||||
|
||||
use hurl::cli;
|
||||
use hurl::cli::interactive;
|
||||
use hurl::html;
|
||||
use hurl::http;
|
||||
use hurl::runner;
|
||||
@ -44,6 +45,7 @@ pub struct CLIOptions {
|
||||
pub color: bool,
|
||||
pub fail_fast: bool,
|
||||
pub insecure: bool,
|
||||
pub interactive: bool,
|
||||
pub variables: HashMap<String, String>,
|
||||
pub to_entry: Option<usize>,
|
||||
pub follow_location: bool,
|
||||
@ -168,11 +170,23 @@ fn execute(
|
||||
}
|
||||
Some(filename) => filename,
|
||||
};
|
||||
let pre_entry = if cli_options.interactive {
|
||||
interactive::pre_entry
|
||||
} else {
|
||||
|| false
|
||||
};
|
||||
let post_entry = if cli_options.interactive {
|
||||
interactive::post_entry
|
||||
} else {
|
||||
|| false
|
||||
};
|
||||
let options = RunnerOptions {
|
||||
fail_fast: cli_options.fail_fast,
|
||||
variables: cli_options.variables,
|
||||
to_entry: cli_options.to_entry,
|
||||
context_dir,
|
||||
pre_entry,
|
||||
post_entry,
|
||||
};
|
||||
runner::run_hurl_file(
|
||||
hurl_file,
|
||||
@ -411,6 +425,12 @@ fn app() -> clap::App<'static, 'static> {
|
||||
.long("insecure")
|
||||
.help("Allow insecure SSL connections"),
|
||||
)
|
||||
.arg(
|
||||
clap::Arg::with_name("interactive")
|
||||
.long("interactive")
|
||||
.conflicts_with("to_entry")
|
||||
.help("Turn on interactive mode"),
|
||||
)
|
||||
.arg(
|
||||
clap::Arg::with_name("json")
|
||||
.long("json")
|
||||
@ -470,6 +490,7 @@ fn app() -> clap::App<'static, 'static> {
|
||||
clap::Arg::with_name("to_entry")
|
||||
.long("to-entry")
|
||||
.value_name("ENTRY_NUMBER")
|
||||
.conflicts_with("interactive")
|
||||
.help("Execute hurl file to ENTRY_NUMBER (starting at 1)")
|
||||
.takes_value(true),
|
||||
)
|
||||
@ -519,7 +540,7 @@ pub fn unwrap_or_exit<T>(
|
||||
}
|
||||
|
||||
fn parse_options(matches: ArgMatches) -> Result<CLIOptions, CLIError> {
|
||||
let verbose = matches.is_present("verbose");
|
||||
let verbose = matches.is_present("verbose") || matches.is_present("interactive");
|
||||
let color = output_color(matches.clone());
|
||||
let fail_fast = !matches.is_present("fail_at_end");
|
||||
let variables = variables(matches.clone())?;
|
||||
@ -569,7 +590,7 @@ fn parse_options(matches: ArgMatches) -> Result<CLIOptions, CLIError> {
|
||||
};
|
||||
let compressed = matches.is_present("compressed");
|
||||
let user = matches.value_of("user").map(|x| x.to_string());
|
||||
|
||||
let interactive = matches.is_present("interactive");
|
||||
Ok(CLIOptions {
|
||||
verbose,
|
||||
color,
|
||||
@ -586,6 +607,7 @@ fn parse_options(matches: ArgMatches) -> Result<CLIOptions, CLIError> {
|
||||
connect_timeout,
|
||||
compressed,
|
||||
user,
|
||||
interactive,
|
||||
})
|
||||
}
|
||||
|
||||
@ -615,7 +637,7 @@ fn main() {
|
||||
Some(value) => Some(value.to_string()),
|
||||
_ => None,
|
||||
};
|
||||
let verbose = matches.is_present("verbose");
|
||||
let verbose = matches.is_present("verbose") || matches.is_present("interactive");
|
||||
let log_verbose = cli::make_logger_verbose(verbose);
|
||||
let color = output_color(matches.clone());
|
||||
let log_error_message = cli::make_logger_error_message(color);
|
||||
@ -663,7 +685,7 @@ fn main() {
|
||||
&log_error_message,
|
||||
);
|
||||
|
||||
if hurl_result.errors().is_empty() {
|
||||
if hurl_result.errors().is_empty() && !cli_options.interactive {
|
||||
// default
|
||||
// last entry + response + body
|
||||
if let Some(entry_result) = hurl_result.entries.last() {
|
||||
|
@ -28,6 +28,8 @@ pub struct RunnerOptions {
|
||||
pub variables: HashMap<String, String>,
|
||||
pub to_entry: Option<usize>,
|
||||
pub context_dir: String,
|
||||
pub pre_entry: fn() -> bool,
|
||||
pub post_entry: fn() -> bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
|
@ -70,6 +70,8 @@ use super::value::Value;
|
||||
/// variables,
|
||||
/// to_entry: None,
|
||||
/// context_dir: "current_dir".to_string(),
|
||||
/// pre_entry: || true,
|
||||
/// post_entry: || true,
|
||||
/// };
|
||||
///
|
||||
/// // Run the hurl file
|
||||
@ -117,6 +119,11 @@ pub fn run(
|
||||
.enumerate()
|
||||
.collect::<Vec<(usize, Entry)>>()
|
||||
{
|
||||
let exit = (options.pre_entry)();
|
||||
if exit {
|
||||
break;
|
||||
}
|
||||
|
||||
let entry_result = entry::run(
|
||||
entry,
|
||||
http_client,
|
||||
@ -130,10 +137,12 @@ pub fn run(
|
||||
for e in entry_result.errors.clone() {
|
||||
log_error(&e, false);
|
||||
}
|
||||
if options.fail_fast && !entry_result.errors.is_empty() {
|
||||
let exit = (options.post_entry)();
|
||||
if exit || (options.fail_fast && !entry_result.errors.is_empty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let time_in_ms = start.elapsed().as_millis();
|
||||
let success = entries
|
||||
.iter()
|
||||
|
@ -67,6 +67,8 @@ fn test_hurl_file() {
|
||||
variables,
|
||||
to_entry: None,
|
||||
context_dir: "current_dir".to_string(),
|
||||
pre_entry: || true,
|
||||
post_entry: || true,
|
||||
};
|
||||
|
||||
let log_verbose: fn(&str) = log_verbose;
|
||||
@ -206,6 +208,8 @@ fn test_hello() {
|
||||
variables,
|
||||
to_entry: None,
|
||||
context_dir: "current_dir".to_string(),
|
||||
pre_entry: || true,
|
||||
post_entry: || true,
|
||||
};
|
||||
let log_verbose: fn(&str) = log_verbose;
|
||||
let log_error_message: fn(bool, &str) = log_error_message;
|
||||
|
Loading…
Reference in New Issue
Block a user