Fork of daniellemaywood.uk/gleam — Wasm codegen work
2

Configure Feed

Select the types of activity you want to include in your feed.

gleam / compiler-cli / src / cli.rs
7.1 kB 265 lines
1// SPDX-License-Identifier: Apache-2.0 2// SPDX-FileCopyrightText: 2020 The Gleam contributors 3 4use ecow::EcoString; 5use gleam_core::{ 6 build::Telemetry, 7 error::{Error, StandardIoAction}, 8 manifest::{Changed, ChangedGit, PackageChanges}, 9}; 10use hexpm::version::Version; 11use itertools::Itertools as _; 12use std::{ 13 io::{IsTerminal, Write}, 14 time::{Duration, Instant}, 15}; 16use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor}; 17 18#[derive(Debug, Default, Clone)] 19pub struct Reporter; 20 21impl Reporter { 22 pub fn new() -> Self { 23 Self 24 } 25} 26 27impl Telemetry for Reporter { 28 fn compiled_package(&self, duration: Duration) { 29 print_compiled(duration); 30 } 31 32 fn compiling_package(&self, name: &str) { 33 print_compiling(name); 34 } 35 36 fn checked_package(&self, duration: Duration) { 37 print_checked(duration); 38 } 39 40 fn checking_package(&self, name: &str) { 41 print_checking(name); 42 } 43 44 fn downloading_package(&self, name: &str) { 45 print_downloading(name) 46 } 47 48 fn packages_downloaded(&self, start: Instant, count: usize) { 49 print_packages_downloaded(start, count) 50 } 51 52 fn resolving_package_versions(&self) { 53 print_resolving_versions() 54 } 55 56 fn running(&self, name: &str) { 57 print_running(name); 58 } 59 60 fn waiting_for_build_directory_lock(&self) { 61 print_waiting_for_build_directory_lock() 62 } 63 64 fn resolved_package_versions(&self, changes: &PackageChanges) { 65 print_package_changes(changes) 66 } 67} 68 69pub fn ask(question: &str) -> Result<String, Error> { 70 print!("{question}: "); 71 std::io::stdout().flush().expect("ask stdout flush"); 72 let mut answer = String::new(); 73 let _ = std::io::stdin() 74 .read_line(&mut answer) 75 .map_err(|e| Error::StandardIo { 76 action: StandardIoAction::Read, 77 err: Some(e.kind()), 78 })?; 79 Ok(answer.trim().to_string()) 80} 81 82pub fn confirm(question: &str) -> Result<bool, Error> { 83 let answer = ask(&format!("{question} [y/n]"))?; 84 match answer.as_str() { 85 "y" | "yes" | "Y" | "YES" => Ok(true), 86 _ => Ok(false), 87 } 88} 89 90pub fn confirm_with_text(response: &str) -> Result<bool, Error> { 91 let answer = ask(&format!("Type '{response}' to continue"))?; 92 Ok(response == answer) 93} 94 95pub fn ask_password(question: &str) -> Result<EcoString, Error> { 96 let prompt = format!("{question} (will not be printed as you type): "); 97 rpassword::prompt_password(prompt) 98 .map_err(|e| Error::StandardIo { 99 action: StandardIoAction::Read, 100 err: Some(e.kind()), 101 }) 102 .map(|s| EcoString::from(s.trim())) 103} 104 105pub fn print_publishing(name: &str, version: &Version) { 106 print_colourful_prefix("Publishing", &format!("{name} v{version}")) 107} 108 109pub fn print_published(detail: &str) { 110 print_colourful_prefix("Published", detail) 111} 112 113pub fn print_retired(package: &str, version: &str) { 114 print_colourful_prefix("Retired", &format!("{package} {version}")) 115} 116 117pub fn print_unretired(package: &str, version: &str) { 118 print_colourful_prefix("Unretired", &format!("{package} {version}")) 119} 120 121pub fn print_publishing_documentation() { 122 print_colourful_prefix("Publishing", "documentation"); 123} 124 125fn print_downloading(text: &str) { 126 print_colourful_prefix("Downloading", text) 127} 128 129fn print_waiting_for_build_directory_lock() { 130 print_colourful_prefix("Waiting", "for build directory lock") 131} 132 133fn print_resolving_versions() { 134 print_colourful_prefix("Resolving", "versions") 135} 136 137fn print_compiling(text: &str) { 138 print_colourful_prefix("Compiling", text) 139} 140 141pub(crate) fn print_exported(text: &str) { 142 print_colourful_prefix("Exported", text) 143} 144 145pub(crate) fn print_checking(text: &str) { 146 print_colourful_prefix("Checking", text) 147} 148 149pub(crate) fn print_compiled(duration: Duration) { 150 print_colourful_prefix("Compiled", &format!("in {}", seconds(duration))) 151} 152 153pub(crate) fn print_checked(duration: Duration) { 154 print_colourful_prefix("Checked", &format!("in {}", seconds(duration))) 155} 156 157pub(crate) fn print_running(text: &str) { 158 print_colourful_prefix("Running", text) 159} 160 161pub(crate) fn print_package_changes(changes: &PackageChanges) { 162 for (name, version) in changes.added.iter().sorted() { 163 print_added(&format!("{name} v{version}")); 164 } 165 for Changed { name, old, new } in changes.changed.iter().sorted_by_key(|p| &p.name) { 166 print_changed(&format!("{name} v{old} -> v{new}")); 167 } 168 for ChangedGit { 169 name, 170 old_hash, 171 new_hash, 172 } in changes.changed_git.iter().sorted_by_key(|p| &p.name) 173 { 174 print_changed(&format!("{name} {old_hash} -> {new_hash}")); 175 } 176 for name in changes.removed.iter().sorted() { 177 print_removed(name); 178 } 179} 180 181fn print_added(text: &str) { 182 print_colourful_prefix("Added", text) 183} 184 185fn print_changed(text: &str) { 186 print_colourful_prefix("Changed", text) 187} 188 189fn print_removed(text: &str) { 190 print_colourful_prefix("Removed", text) 191} 192 193pub(crate) fn print_generating_documentation() { 194 print_colourful_prefix("Generating", "documentation") 195} 196 197pub(crate) fn print_transferring_ownership() { 198 print_colourful_prefix("Transferring", "ownership"); 199} 200 201pub(crate) fn print_transferred_ownership() { 202 print_colourful_prefix("Transferred", "ownership"); 203} 204 205pub(crate) fn print_adding_owner() { 206 print_colourful_prefix("Adding", "owner"); 207} 208 209pub(crate) fn print_added_owner() { 210 print_colourful_prefix("Added", "owner"); 211} 212 213fn print_packages_downloaded(start: Instant, count: usize) { 214 let elapsed = seconds(start.elapsed()); 215 let msg = match count { 216 1 => format!("1 package in {elapsed}"), 217 _ => format!("{count} packages in {elapsed}"), 218 }; 219 print_colourful_prefix("Downloaded", &msg) 220} 221 222pub fn seconds(duration: Duration) -> String { 223 format!("{:.2}s", duration.as_millis() as f32 / 1000.) 224} 225 226pub fn print_colourful_prefix(prefix: &str, text: &str) { 227 let buffer_writer = stderr_buffer_writer(); 228 let mut buffer = buffer_writer.buffer(); 229 buffer 230 .set_color( 231 ColorSpec::new() 232 .set_intense(true) 233 .set_fg(Some(Color::Magenta)), 234 ) 235 .expect("print_green_prefix"); 236 write!(buffer, "{prefix: >11}").expect("print_green_prefix"); 237 buffer 238 .set_color(&ColorSpec::new()) 239 .expect("print_green_prefix"); 240 writeln!(buffer, " {text}").expect("print_green_prefix"); 241 buffer_writer.print(&buffer).expect("print_green_prefix"); 242} 243 244pub fn stderr_buffer_writer() -> BufferWriter { 245 // Don't add color codes to the output if standard error isn't connected to a terminal 246 BufferWriter::stderr(color_choice()) 247} 248 249fn colour_forced() -> bool { 250 if let Ok(force) = std::env::var("FORCE_COLOR") { 251 !force.is_empty() 252 } else { 253 false 254 } 255} 256 257fn color_choice() -> ColorChoice { 258 if colour_forced() { 259 ColorChoice::Always 260 } else if std::io::stderr().is_terminal() { 261 ColorChoice::Auto 262 } else { 263 ColorChoice::Never 264 } 265}