Skip to content

Commit 4760bd5

Browse files
authored
Merge pull request #21825 from Homebrew/brew-rs-use-more-tty
brew-rs/fetch: use functions from `tty` module
2 parents c437bf7 + 8817a58 commit 4760bd5

2 files changed

Lines changed: 61 additions & 24 deletions

File tree

Library/Homebrew/rust/brew-rs/src/commands/fetch.rs

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::BrewResult;
22
use crate::delegate;
33
use crate::homebrew;
4+
use crate::utils::tty;
45
use anyhow::{Context, anyhow, bail};
56
use rayon::prelude::*;
67
use reqwest::blocking::Client;
@@ -22,9 +23,6 @@ use std::time::{Duration, Instant};
2223
use url::Url;
2324

2425
const FETCH_RETRIES: usize = 2;
25-
const ANSI_BLUE: &str = "\x1b[34m";
26-
const ANSI_GREEN: &str = "\x1b[32m";
27-
const ANSI_RESET: &str = "\x1b[0m";
2826
const CONNECT_TIMEOUT_SECS: u64 = 15;
2927
const REQUEST_TIMEOUT_SECS: u64 = 600;
3028
const FALSY_ENV_VALUES: [&str; 5] = ["false", "no", "off", "nil", "0"];
@@ -87,7 +85,6 @@ pub fn run(args: &[String]) -> BrewResult<ExitCode> {
8785
);
8886
}
8987

90-
let tty_output = io::stdout().is_terminal();
9188
let download_threads = download_concurrency(bottles.len());
9289
let show_progress = should_render_progress(download_progress_enabled(), download_threads);
9390
let progress = bottles
@@ -116,7 +113,7 @@ pub fn run(args: &[String]) -> BrewResult<ExitCode> {
116113
.par_iter()
117114
.zip(progress.par_iter())
118115
.try_for_each(|(bottle, progress)| {
119-
fetch_bottle(bottle, client.as_ref(), progress, show_progress, tty_output)
116+
fetch_bottle(bottle, client.as_ref(), progress, show_progress)
120117
})
121118
});
122119

@@ -388,15 +385,14 @@ fn fetch_bottle(
388385
client: &Client,
389386
progress: &Arc<Mutex<DownloadProgress>>,
390387
show_progress: bool,
391-
tty_output: bool,
392388
) -> BrewResult<()> {
393389
if bottle.cached_download.exists() {
394390
update_download_phase(progress, "verifying");
395391
verify_checksum(&bottle.cached_download, &bottle.bottle_sha256)?;
396392
ensure_symlink(bottle)?;
397393
mark_download_complete(progress);
398394
if !show_progress {
399-
print_downloaded_bottle(bottle, tty_output);
395+
print_downloaded_bottle(bottle);
400396
}
401397
return Ok(());
402398
}
@@ -437,7 +433,7 @@ fn fetch_bottle(
437433
ensure_symlink(bottle)?;
438434
mark_download_complete(progress);
439435
if !show_progress {
440-
print_downloaded_bottle(bottle, tty_output);
436+
print_downloaded_bottle(bottle);
441437
}
442438
Ok(())
443439
})();
@@ -456,12 +452,12 @@ fn fetch_bottle(
456452
Err(last_error.unwrap_or_else(|| anyhow!("Failed to fetch {}", bottle.formula_name)))
457453
}
458454

459-
fn print_downloaded_bottle(bottle: &BottleFetch, tty_output: bool) {
460-
let status = if tty_output {
461-
format!("{ANSI_GREEN}✔︎{ANSI_RESET}")
462-
} else {
463-
"✔︎".to_string()
464-
};
455+
fn print_downloaded_bottle(bottle: &BottleFetch) {
456+
let status = format!(
457+
"{green}✔︎{reset}",
458+
green = tty::green(),
459+
reset = tty::reset(),
460+
);
465461
println!(
466462
"{status} Bottle {} ({})",
467463
bottle.display_name, bottle.display_version
@@ -959,7 +955,7 @@ impl ProgressRenderer {
959955
.filter_map(|entry| entry.lock().ok().map(|entry| entry.message.len()))
960956
.max()
961957
.unwrap_or(0);
962-
let _ = write!(stdout, "\x1b[?25l");
958+
let _ = write!(stdout, "{}", tty::hide_cursor());
963959
let mut rendered_lines = 0;
964960
let mut printed_done = vec![false; progress.len()];
965961

@@ -981,16 +977,23 @@ impl ProgressRenderer {
981977
.filter_map(|(index, entry)| {
982978
if entry.done {
983979
if !printed_done[index] {
984-
let _ =
985-
writeln!(stdout, "{ANSI_GREEN}✔︎{ANSI_RESET} {}", entry.message);
980+
let _ = writeln!(
981+
stdout,
982+
"{green}✔︎{reset} {message}",
983+
green = tty::green(),
984+
reset = tty::reset(),
985+
message = entry.message
986+
);
986987
printed_done[index] = true;
987988
}
988989
return None;
989990
}
990991

991992
Some(format!(
992-
"{ANSI_BLUE}{}{ANSI_RESET} {}",
993+
"{}{}{} {}",
994+
tty::blue(),
993995
spinner.frame(),
996+
tty::reset(),
994997
format_progress_message(
995998
&entry.message,
996999
entry.phase,
@@ -1005,7 +1008,7 @@ impl ProgressRenderer {
10051008

10061009
rendered_lines = pending_lines.len();
10071010
for (index, line) in pending_lines.iter().enumerate() {
1008-
let _ = write!(stdout, "{line}\x1b[K");
1011+
let _ = write!(stdout, "{line}{clear}", clear = tty::clear_to_end());
10091012
if index + 1 < pending_lines.len() {
10101013
let _ = writeln!(stdout);
10111014
}
@@ -1019,14 +1022,14 @@ impl ProgressRenderer {
10191022
if rendered_lines == 1 {
10201023
let _ = write!(stdout, "\r");
10211024
} else if rendered_lines > 1 {
1022-
let _ = write!(stdout, "\x1b[{}A\r", rendered_lines - 1);
1025+
let _ = write!(stdout, "{}\r", tty::move_cursor_up(rendered_lines - 1));
10231026
}
10241027

10251028
thread::sleep(Duration::from_millis(50));
10261029
}
10271030

10281031
clear_rendered_lines(&mut stdout, rendered_lines);
1029-
let _ = write!(stdout, "\x1b[?25h");
1032+
let _ = write!(stdout, "{}", tty::show_cursor());
10301033
let _ = stdout.flush();
10311034
});
10321035

@@ -1046,18 +1049,18 @@ fn clear_rendered_lines(stdout: &mut impl Write, lines: usize) {
10461049

10471050
let _ = write!(stdout, "\r");
10481051
if lines > 1 {
1049-
let _ = write!(stdout, "\x1b[{}A", lines - 1);
1052+
let _ = write!(stdout, "{}", tty::move_cursor_up(lines - 1));
10501053
}
10511054

10521055
for index in 0..lines {
1053-
let _ = write!(stdout, "\x1b[2K");
1056+
let _ = write!(stdout, "{}", tty::clear_entire_line());
10541057
if index + 1 < lines {
10551058
let _ = writeln!(stdout);
10561059
}
10571060
}
10581061

10591062
if lines > 1 {
1060-
let _ = write!(stdout, "\x1b[{}A", lines - 1);
1063+
let _ = write!(stdout, "{}", tty::move_cursor_up(lines - 1));
10611064
}
10621065
let _ = write!(stdout, "\r");
10631066
}

Library/Homebrew/rust/brew-rs/src/utils/tty.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use std::sync::OnceLock;
77

88
// Color codes
99
const RED: &str = "31";
10+
const GREEN: &str = "32";
1011
const YELLOW: &str = "33";
1112
const BLUE: &str = "34";
1213

@@ -73,13 +74,46 @@ macro_rules! ansi_methods_and_functions {
7374

7475
ansi_methods_and_functions! {
7576
red => RED,
77+
green => GREEN,
7678
yellow => YELLOW,
7779
blue => BLUE,
7880
reset => RESET,
7981
bold => BOLD,
8082
underline => UNDERLINE,
8183
}
8284

85+
pub struct MoveCursorUp(pub usize);
86+
87+
impl fmt::Display for MoveCursorUp {
88+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89+
write!(f, "\x1B[{}A", self.0)
90+
}
91+
}
92+
93+
#[inline]
94+
pub fn move_cursor_up(line_count: usize) -> MoveCursorUp {
95+
MoveCursorUp(line_count)
96+
}
97+
98+
#[inline]
99+
pub fn clear_to_end() -> &'static str {
100+
"\x1B[K"
101+
}
102+
103+
#[inline]
104+
pub fn clear_entire_line() -> &'static str {
105+
"\x1B[2K"
106+
}
107+
108+
#[inline]
109+
pub fn hide_cursor() -> &'static str {
110+
"\x1B[?25l"
111+
}
112+
113+
#[inline]
114+
pub fn show_cursor() -> &'static str {
115+
"\x1B[?25h"
116+
}
83117
pub fn width() -> usize {
84118
*TTY_WIDTH.get_or_init(|| {
85119
if let Ok(command) = Command::new("/bin/stty").arg("size").output() {

0 commit comments

Comments
 (0)