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