Fork of daniellemaywood.uk/gleam — Wasm codegen work
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}