mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-11-23 00:44:55 +03:00
Fix test progress bar for small screens.
This commit is contained in:
parent
6546d11cf8
commit
8aba7c2bef
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -527,6 +527,7 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"sha2",
|
"sha2",
|
||||||
"similar",
|
"similar",
|
||||||
|
"terminal_size",
|
||||||
"termion",
|
"termion",
|
||||||
"url",
|
"url",
|
||||||
"uuid",
|
"uuid",
|
||||||
|
@ -44,6 +44,7 @@ lazy_static = "1.5.0"
|
|||||||
# uuid features: lets you generate random UUIDs and use a faster (but still sufficiently random) RNG
|
# uuid features: lets you generate random UUIDs and use a faster (but still sufficiently random) RNG
|
||||||
uuid = { version = "1.8.0", features = ["v4" , "fast-rng"] }
|
uuid = { version = "1.8.0", features = ["v4" , "fast-rng"] }
|
||||||
similar = "2.5.0"
|
similar = "2.5.0"
|
||||||
|
terminal_size = "0.3.0"
|
||||||
|
|
||||||
[target.'cfg(unix)'.dependencies]
|
[target.'cfg(unix)'.dependencies]
|
||||||
termion = "4.0.2"
|
termion = "4.0.2"
|
||||||
|
@ -31,6 +31,8 @@ pub struct ParProgress {
|
|||||||
mode: Mode,
|
mode: Mode,
|
||||||
/// The standard error format for message: ANSI or plain.
|
/// The standard error format for message: ANSI or plain.
|
||||||
format: Format,
|
format: Format,
|
||||||
|
/// The maximum width of the progress string, in chars.
|
||||||
|
max_width: Option<usize>,
|
||||||
/// Save last progress bar refresh to limits flickering.
|
/// Save last progress bar refresh to limits flickering.
|
||||||
throttle: Throttle,
|
throttle: Throttle,
|
||||||
}
|
}
|
||||||
@ -52,12 +54,18 @@ const FIRST_THROTTLE: Duration = Duration::from_millis(16);
|
|||||||
|
|
||||||
impl ParProgress {
|
impl ParProgress {
|
||||||
/// Creates a new instance.
|
/// Creates a new instance.
|
||||||
pub fn new(max_running_displayed: usize, mode: Mode, color: bool) -> Self {
|
pub fn new(
|
||||||
|
max_running_displayed: usize,
|
||||||
|
mode: Mode,
|
||||||
|
color: bool,
|
||||||
|
max_width: Option<usize>,
|
||||||
|
) -> Self {
|
||||||
let format = if color { Format::Ansi } else { Format::Plain };
|
let format = if color { Format::Ansi } else { Format::Plain };
|
||||||
ParProgress {
|
ParProgress {
|
||||||
max_running_displayed,
|
max_running_displayed,
|
||||||
mode,
|
mode,
|
||||||
format,
|
format,
|
||||||
|
max_width,
|
||||||
throttle: Throttle::new(UPDATE_INTERVAL, FIRST_THROTTLE),
|
throttle: Throttle::new(UPDATE_INTERVAL, FIRST_THROTTLE),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -91,6 +99,7 @@ impl ParProgress {
|
|||||||
count,
|
count,
|
||||||
self.max_running_displayed,
|
self.max_running_displayed,
|
||||||
self.format,
|
self.format,
|
||||||
|
self.max_width,
|
||||||
) else {
|
) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
@ -199,13 +208,15 @@ impl Throttle {
|
|||||||
///
|
///
|
||||||
/// `max_running_displayed` is used to limit the number of running progress bar. If more jobs are
|
/// `max_running_displayed` is used to limit the number of running progress bar. If more jobs are
|
||||||
/// running, a label "...x more" is displayed.
|
/// running, a label "...x more" is displayed.
|
||||||
/// `color` is `true` when the returned progress string uses color.
|
/// `format` is the format of the progress string (ANSI or plain).
|
||||||
|
/// The progress string is wrapped with new lines at width `max_width`.
|
||||||
fn build_progress(
|
fn build_progress(
|
||||||
workers: &[(Worker, WorkerState)],
|
workers: &[(Worker, WorkerState)],
|
||||||
completed: usize,
|
completed: usize,
|
||||||
count: Option<usize>,
|
count: Option<usize>,
|
||||||
max_running_displayed: usize,
|
max_running_displayed: usize,
|
||||||
format: Format,
|
format: Format,
|
||||||
|
max_width: Option<usize>,
|
||||||
) -> Option<String> {
|
) -> Option<String> {
|
||||||
// Select the running workers to be displayed
|
// Select the running workers to be displayed
|
||||||
let mut workers = workers
|
let mut workers = workers
|
||||||
@ -237,7 +248,7 @@ fn build_progress(
|
|||||||
})
|
})
|
||||||
.max()
|
.max()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let max_width = 2 * (((max as f64).log10() as usize) + 1) + 1;
|
let max_completed_width = 2 * (((max as f64).log10() as usize) + 1) + 1;
|
||||||
|
|
||||||
// Construct all the progress strings
|
// Construct all the progress strings
|
||||||
let mut all_progress = String::new();
|
let mut all_progress = String::new();
|
||||||
@ -248,6 +259,8 @@ fn build_progress(
|
|||||||
}
|
}
|
||||||
None => format!("Executed files: {completed}\n"),
|
None => format!("Executed files: {completed}\n"),
|
||||||
};
|
};
|
||||||
|
// We don't wrap this string for the moment, there is low chance to overlap the maximum width
|
||||||
|
// of the terminal.
|
||||||
all_progress.push_str(&progress);
|
all_progress.push_str(&progress);
|
||||||
|
|
||||||
for (_, state) in &workers {
|
for (_, state) in &workers {
|
||||||
@ -259,7 +272,7 @@ fn build_progress(
|
|||||||
{
|
{
|
||||||
let entry_index = entry_index + 1; // entry index display is 1-based
|
let entry_index = entry_index + 1; // entry index display is 1-based
|
||||||
let requests = format!("{entry_index}/{entry_count}");
|
let requests = format!("{entry_index}/{entry_count}");
|
||||||
let padding = " ".repeat(max_width - requests.len());
|
let padding = " ".repeat(max_completed_width - requests.len());
|
||||||
let bar = progress_bar(entry_index, *entry_count);
|
let bar = progress_bar(entry_index, *entry_count);
|
||||||
|
|
||||||
let mut progress = StyledString::new();
|
let mut progress = StyledString::new();
|
||||||
@ -271,6 +284,13 @@ fn build_progress(
|
|||||||
progress.push_with("Running", Style::new().cyan().bold());
|
progress.push_with("Running", Style::new().cyan().bold());
|
||||||
progress.push("\n");
|
progress.push("\n");
|
||||||
|
|
||||||
|
// We wrap the progress string with new lines if necessary
|
||||||
|
if let Some(max_width) = max_width {
|
||||||
|
if progress.len() >= max_width {
|
||||||
|
progress = progress.wrap(max_width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let progress = progress.to_string(format);
|
let progress = progress.to_string(format);
|
||||||
all_progress.push_str(&progress);
|
all_progress.push_str(&progress);
|
||||||
}
|
}
|
||||||
@ -370,7 +390,14 @@ mod tests {
|
|||||||
(w4, WorkerState::Idle),
|
(w4, WorkerState::Idle),
|
||||||
];
|
];
|
||||||
|
|
||||||
let progress = build_progress(&workers, completed, total, max_displayed, Format::Plain);
|
let progress = build_progress(
|
||||||
|
&workers,
|
||||||
|
completed,
|
||||||
|
total,
|
||||||
|
max_displayed,
|
||||||
|
Format::Plain,
|
||||||
|
None,
|
||||||
|
);
|
||||||
assert!(progress.is_none());
|
assert!(progress.is_none());
|
||||||
|
|
||||||
workers[0].1 = new_running_state(&jobs[0], 0, 10);
|
workers[0].1 = new_running_state(&jobs[0], 0, 10);
|
||||||
@ -379,7 +406,14 @@ mod tests {
|
|||||||
workers[3].1 = new_running_state(&jobs[3], 0, 7);
|
workers[3].1 = new_running_state(&jobs[3], 0, 7);
|
||||||
workers[4].1 = new_running_state(&jobs[4], 0, 4);
|
workers[4].1 = new_running_state(&jobs[4], 0, 4);
|
||||||
|
|
||||||
let progress = build_progress(&workers, completed, total, max_displayed, Format::Plain);
|
let progress = build_progress(
|
||||||
|
&workers,
|
||||||
|
completed,
|
||||||
|
total,
|
||||||
|
max_displayed,
|
||||||
|
Format::Plain,
|
||||||
|
None,
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
progress.unwrap(),
|
progress.unwrap(),
|
||||||
"\
|
"\
|
||||||
@ -397,7 +431,14 @@ Executed files: 75/100 (75%)\n\
|
|||||||
workers[3].1 = new_running_state(&jobs[3], 3, 7);
|
workers[3].1 = new_running_state(&jobs[3], 3, 7);
|
||||||
workers[4].1 = new_running_state(&jobs[4], 1, 4);
|
workers[4].1 = new_running_state(&jobs[4], 1, 4);
|
||||||
|
|
||||||
let progress = build_progress(&workers, completed, total, max_displayed, Format::Plain);
|
let progress = build_progress(
|
||||||
|
&workers,
|
||||||
|
completed,
|
||||||
|
total,
|
||||||
|
max_displayed,
|
||||||
|
Format::Plain,
|
||||||
|
None,
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
progress.unwrap(),
|
progress.unwrap(),
|
||||||
"\
|
"\
|
||||||
@ -415,7 +456,14 @@ Executed files: 75/100 (75%)\n\
|
|||||||
workers[3].1 = new_running_state(&jobs[3], 5, 7);
|
workers[3].1 = new_running_state(&jobs[3], 5, 7);
|
||||||
workers[4].1 = new_running_state(&jobs[4], 2, 4);
|
workers[4].1 = new_running_state(&jobs[4], 2, 4);
|
||||||
|
|
||||||
let progress = build_progress(&workers, completed, total, max_displayed, Format::Plain);
|
let progress = build_progress(
|
||||||
|
&workers,
|
||||||
|
completed,
|
||||||
|
total,
|
||||||
|
max_displayed,
|
||||||
|
Format::Plain,
|
||||||
|
None,
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
progress.unwrap(),
|
progress.unwrap(),
|
||||||
"\
|
"\
|
||||||
@ -433,7 +481,14 @@ Executed files: 75/100 (75%)\n\
|
|||||||
workers[3].1 = WorkerState::Idle;
|
workers[3].1 = WorkerState::Idle;
|
||||||
workers[4].1 = new_running_state(&jobs[4], 3, 4);
|
workers[4].1 = new_running_state(&jobs[4], 3, 4);
|
||||||
|
|
||||||
let progress = build_progress(&workers, completed, total, max_displayed, Format::Plain);
|
let progress = build_progress(
|
||||||
|
&workers,
|
||||||
|
completed,
|
||||||
|
total,
|
||||||
|
max_displayed,
|
||||||
|
Format::Plain,
|
||||||
|
None,
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
progress.unwrap(),
|
progress.unwrap(),
|
||||||
"\
|
"\
|
||||||
@ -449,7 +504,14 @@ Executed files: 75/100 (75%)\n\
|
|||||||
workers[3].1 = WorkerState::Idle;
|
workers[3].1 = WorkerState::Idle;
|
||||||
workers[4].1 = WorkerState::Idle;
|
workers[4].1 = WorkerState::Idle;
|
||||||
|
|
||||||
let progress = build_progress(&workers, completed, total, max_displayed, Format::Plain);
|
let progress = build_progress(
|
||||||
|
&workers,
|
||||||
|
completed,
|
||||||
|
total,
|
||||||
|
max_displayed,
|
||||||
|
Format::Plain,
|
||||||
|
None,
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
progress.unwrap(),
|
progress.unwrap(),
|
||||||
"\
|
"\
|
||||||
@ -475,7 +537,7 @@ Executed files: 75/100 (75%)\n\
|
|||||||
assert_eq!(progress_bar(2, 3), "[========> ] 2/3");
|
assert_eq!(progress_bar(2, 3), "[========> ] 2/3");
|
||||||
assert_eq!(progress_bar(3, 3), "[================> ] 3/3");
|
assert_eq!(progress_bar(3, 3), "[================> ] 3/3");
|
||||||
|
|
||||||
// Progress strings with 1 entries:
|
// Progress strings with 1 entry:
|
||||||
assert_eq!(progress_bar(1, 1), "[> ] 1/1");
|
assert_eq!(progress_bar(1, 1), "[> ] 1/1");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,11 +95,12 @@ impl ParallelRunner {
|
|||||||
/// whether as a raw response body bytes, or in a structured JSON output.
|
/// whether as a raw response body bytes, or in a structured JSON output.
|
||||||
///
|
///
|
||||||
/// The runner can repeat running a list of jobs. For instance, when repeating two times the job
|
/// The runner can repeat running a list of jobs. For instance, when repeating two times the job
|
||||||
/// sequence (`a`, `b`, `c`), runner will act as if it runs (`a`, `b`, `c`).
|
/// sequence (`a`, `b`, `c`), runner will act as if it runs (`a`, `b`, `c`, `a`, `b`, `c`).
|
||||||
///
|
///
|
||||||
/// If `test` mode is `true` the runner is run in "test" mode, reporting the success or failure
|
/// If `test` mode is `true` the runner is run in "test" mode, reporting the success or failure
|
||||||
/// of each file on standard error. Additionally to the test mode, a `progress_bar` designed for
|
/// of each file on standard error. In addition to the test mode, a `progress_bar` designed for
|
||||||
/// parallel run progression can be used.
|
/// parallel run progression can be used. When the progress bar is displayed, it's wrapped with
|
||||||
|
/// new lines at width `max_width`.
|
||||||
///
|
///
|
||||||
/// `color` determines if color if used in standard error.
|
/// `color` determines if color if used in standard error.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
@ -109,6 +110,7 @@ impl ParallelRunner {
|
|||||||
test: bool,
|
test: bool,
|
||||||
progress_bar: bool,
|
progress_bar: bool,
|
||||||
color: bool,
|
color: bool,
|
||||||
|
max_width: Option<usize>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// Worker are running on theirs own thread, while parallel runner is running in the main
|
// Worker are running on theirs own thread, while parallel runner is running in the main
|
||||||
// thread.
|
// thread.
|
||||||
@ -128,7 +130,7 @@ impl ParallelRunner {
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let mode = Mode::new(test, progress_bar);
|
let mode = Mode::new(test, progress_bar);
|
||||||
let progress = ParProgress::new(MAX_RUNNING_DISPLAYED, mode, color);
|
let progress = ParProgress::new(MAX_RUNNING_DISPLAYED, mode, color, max_width);
|
||||||
|
|
||||||
ParallelRunner {
|
ParallelRunner {
|
||||||
workers,
|
workers,
|
||||||
|
@ -174,6 +174,7 @@ pub fn run_par(
|
|||||||
let output_type = options
|
let output_type = options
|
||||||
.output_type
|
.output_type
|
||||||
.to_output_type(options.include, options.color);
|
.to_output_type(options.include, options.color);
|
||||||
|
let max_width = terminal_size::terminal_size().map(|(w, _)| w.0 as usize);
|
||||||
|
|
||||||
let jobs = files
|
let jobs = files
|
||||||
.iter()
|
.iter()
|
||||||
@ -192,6 +193,7 @@ pub fn run_par(
|
|||||||
options.test,
|
options.test,
|
||||||
options.progress_bar,
|
options.progress_bar,
|
||||||
options.color,
|
options.color,
|
||||||
|
max_width,
|
||||||
);
|
);
|
||||||
let results = runner.run(&jobs)?;
|
let results = runner.run(&jobs)?;
|
||||||
let results = results.into_iter().map(HurlRun::from).collect();
|
let results = results.into_iter().map(HurlRun::from).collect();
|
||||||
|
Loading…
Reference in New Issue
Block a user