diff --git a/compiler-cli/src/main.rs b/compiler-cli/src/main.rs index 86c844537..a8e92cfa2 100644 --- a/compiler-cli/src/main.rs +++ b/compiler-cli/src/main.rs @@ -75,12 +75,17 @@ pub use gleam_core::{ use gleam_core::{ build::{package_compiler, Target}, + diagnostic::{self, Severity}, + error::wrap, hex::RetirementReason, project::Analysed, }; use hex::ApiKeyCommand as _; -use std::path::{Path, PathBuf}; +use std::{ + io::Write, + path::{Path, PathBuf}, +}; use structopt::{clap::AppSettings, StructOpt}; use strum::VariantNames; @@ -257,9 +262,10 @@ enum Docs { fn main() { initialise_logger(); panic::add_handler(); + let stderr = cli::stderr_buffer_writer(); let result = match Command::from_args() { - Command::Build { warnings_as_errors } => command_build(warnings_as_errors), + Command::Build { warnings_as_errors } => command_build(&stderr, warnings_as_errors), Command::Docs(Docs::Build) => docs::build(), @@ -307,25 +313,43 @@ fn main() { } Err(error) => { tracing::error!(error = ?error, "Failed"); - let buffer_writer = cli::stderr_buffer_writer(); - let mut buffer = buffer_writer.buffer(); + let mut buffer = stderr.buffer(); error.pretty(&mut buffer); - buffer_writer - .print(&buffer) - .expect("Final result error writing"); + stderr.print(&buffer).expect("Final result error writing"); std::process::exit(1); } } } -fn command_build(warnings_as_errors: bool) -> Result<(), Error> { +const REBAR_DEPRECATION_NOTICE: &str = "The built-in rebar3 support is deprecated and will \ +be removed in a future version of Gleam. + +Please switch to the new Gleam build tool or update your project to use the new `gleam \ +compile-package` API with your existing build tool. + +"; + +fn command_build(stderr: &termcolor::BufferWriter, warnings_as_errors: bool) -> Result<(), Error> { + let mut buffer = stderr.buffer(); let root = Path::new("./"); // Use new build tool if not in a rebar or mix project if !root.join("rebar.config").exists() && !root.join("mix.exs").exists() { return build::main().map(|_| ()); } - tracing::warn!("Running deprecated build process"); + + diagnostic::write_title( + &mut buffer, + "Deprecated rebar3 build command", + Severity::Warning, + ); + buffer + .write_all(wrap(REBAR_DEPRECATION_NOTICE).as_bytes()) + .expect("rebar deprecation message"); + buffer.flush().expect("flush"); + stderr + .print(&buffer) + .expect("command_build_rebar_deprecated_write"); // Read and type check project let (_config, analysed) = project::read_and_analyse(&root)?; diff --git a/compiler-core/src/diagnostic.rs b/compiler-core/src/diagnostic.rs index 317c68bc9..e5db386d5 100644 --- a/compiler-core/src/diagnostic.rs +++ b/compiler-core/src/diagnostic.rs @@ -70,24 +70,31 @@ pub struct ProjectErrorDiagnostic { pub label: String, } -pub fn write_title(buffer: &mut Buffer, title: &str) { +pub fn write_title(buffer: &mut Buffer, title: &str, severity: Severity) { use std::io::Write; use termcolor::{Color, ColorSpec, WriteColor}; + let (kind, colour) = match severity { + Severity::Bug => ("bug", Color::Red), + Severity::Error => ("error", Color::Red), + Severity::Warning => ("warning", Color::Yellow), + Severity::Note => ("note", Color::Blue), + Severity::Help => ("help", Color::Blue), + }; buffer - .set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Red))) - .expect("write_title"); - write!(buffer, "error").expect("write_title"); + .set_color(ColorSpec::new().set_bold(true).set_fg(Some(colour))) + .expect("write_title_color1"); + write!(buffer, "{}", kind).expect("write_title_kind"); buffer .set_color(ColorSpec::new().set_bold(true)) - .expect("write_title"); - write!(buffer, ": {}\n\n", title).expect("write_title"); - buffer.set_color(&ColorSpec::new()).expect("write_title"); + .expect("write_title_color2"); + write!(buffer, ": {}\n\n", title).expect("write_title_title"); + buffer + .set_color(&ColorSpec::new()) + .expect("write_title_reset"); } pub fn write_project(buffer: &mut Buffer, d: ProjectErrorDiagnostic) { use std::io::Write; - use termcolor::{ColorSpec, WriteColor}; - write_title(buffer, &d.title); - buffer.set_color(&ColorSpec::new()).expect("write_project"); + write_title(buffer, &d.title, Severity::Error); writeln!(buffer, "{}", d.label).expect("write_project"); } diff --git a/compiler-core/src/error.rs b/compiler-core/src/error.rs index 58b012f2e..5bc050faf 100644 --- a/compiler-core/src/error.rs +++ b/compiler-core/src/error.rs @@ -329,6 +329,7 @@ impl Error { self.pretty(&mut nocolor); String::from_utf8(nocolor.into_inner()).expect("Error printing produced invalid utf8") } + pub fn pretty(&self, buf: &mut Buffer) { use crate::type_::Error as TypeError; use std::io::Write; @@ -1724,7 +1725,7 @@ Try a different name for this module.", } Error::ImportCycle { modules } => { - crate::diagnostic::write_title(buf, "Import cycle"); + crate::diagnostic::write_title(buf, "Import cycle", Severity::Error); writeln!( buf, "The import statements for these modules form a cycle:\n" @@ -1740,7 +1741,7 @@ Try a different name for this module.", } Error::PackageCycle { packages } => { - crate::diagnostic::write_title(buf, "Dependency cycle"); + crate::diagnostic::write_title(buf, "Dependency cycle", Severity::Error); writeln!(buf, "The dependencies for these packages form a cycle:\n").unwrap(); import_cycle(buf, packages); wrap_writeln!( @@ -2041,6 +2042,6 @@ pub struct Unformatted { pub output: String, } -fn wrap(text: &str) -> String { +pub fn wrap(text: &str) -> String { textwrap::fill(text, std::cmp::min(75, textwrap::termwidth())) }