Support roc format to stdout/from stdin

This commit is contained in:
Richard Feldman 2023-10-18 23:02:38 -04:00
parent 77d2136d00
commit e442f18e68
No known key found for this signature in database
GPG key ID: F1F21AA5B1D9E43B
3 changed files with 272 additions and 133 deletions

View file

@ -1,11 +1,12 @@
//! The `roc` binary that brings together all functionality in the Roc toolset.
use bumpalo::Bump;
use roc_build::link::LinkType;
use roc_build::program::{check_file, CodeGenBackend};
use roc_cli::{
build_app, format, test, BuildConfig, FormatMode, CMD_BUILD, CMD_CHECK, CMD_DEV, CMD_DOCS,
CMD_FORMAT, CMD_GEN_STUB_LIB, CMD_GLUE, CMD_REPL, CMD_RUN, CMD_TEST, CMD_VERSION,
DIRECTORY_OR_FILES, FLAG_CHECK, FLAG_DEV, FLAG_LIB, FLAG_NO_LINK, FLAG_TARGET, FLAG_TIME,
GLUE_DIR, GLUE_SPEC, ROC_FILE,
build_app, format_files, format_src, test, BuildConfig, FormatMode, CMD_BUILD, CMD_CHECK,
CMD_DEV, CMD_DOCS, CMD_FORMAT, CMD_GEN_STUB_LIB, CMD_GLUE, CMD_REPL, CMD_RUN, CMD_TEST,
CMD_VERSION, DIRECTORY_OR_FILES, FLAG_CHECK, FLAG_DEV, FLAG_LIB, FLAG_NO_LINK, FLAG_STDIN,
FLAG_STDOUT, FLAG_TARGET, FLAG_TIME, GLUE_DIR, GLUE_SPEC, ROC_FILE,
};
use roc_docs::generate_docs_html;
use roc_error_macros::user_error;
@ -15,7 +16,7 @@ use roc_load::{FunctionKind, LoadingProblem, Threading};
use roc_packaging::cache::{self, RocCacheDir};
use roc_target::Target;
use std::fs::{self, FileType};
use std::io;
use std::io::{self, Read, Write};
use std::path::{Path, PathBuf};
use std::str::FromStr;
use target_lexicon::Triple;
@ -151,7 +152,7 @@ fn main() -> io::Result<()> {
)?)
}
Some((CMD_CHECK, matches)) => {
let arena = bumpalo::Bump::new();
let arena = Bump::new();
let emit_timings = matches.get_flag(FLAG_TIME);
let roc_file_path = matches.get_one::<PathBuf>(ROC_FILE).unwrap();
@ -219,46 +220,102 @@ fn main() -> io::Result<()> {
Ok(0)
}
Some((CMD_FORMAT, matches)) => {
let maybe_values = matches.get_many::<OsString>(DIRECTORY_OR_FILES);
let mut values: Vec<OsString> = Vec::new();
match maybe_values {
None => {
let mut os_string_values: Vec<OsString> = Vec::new();
read_all_roc_files(
&std::env::current_dir()?.as_os_str().to_os_string(),
&mut os_string_values,
)?;
for os_string in os_string_values {
values.push(os_string);
}
let from_stdin = matches.get_flag(FLAG_STDIN);
let to_stdout = matches.get_flag(FLAG_STDOUT);
let format_mode = if to_stdout {
FormatMode::WriteToStdout
} else {
match matches.get_flag(FLAG_CHECK) {
true => FormatMode::CheckOnly,
false => FormatMode::WriteToFile,
}
Some(os_values) => {
for os_string in os_values {
values.push(os_string.to_owned());
}
}
}
let mut roc_files = Vec::new();
// Populate roc_files
for os_str in values {
let metadata = fs::metadata(os_str.clone())?;
roc_files_recursive(os_str.as_os_str(), metadata.file_type(), &mut roc_files)?;
}
let format_mode = match matches.get_flag(FLAG_CHECK) {
true => FormatMode::CheckOnly,
false => FormatMode::Format,
};
let format_exit_code = match format(roc_files, format_mode) {
Ok(_) => 0,
Err(message) => {
eprintln!("{message}");
1
if from_stdin && matches!(format_mode, FormatMode::WriteToFile) {
eprintln!("When using the --stdin flag, either the --check or the --stdout flag must also be specified. (Otherwise, it's unclear what filename to write to!)");
std::process::exit(1);
}
let roc_files = {
let mut roc_files = Vec::new();
let mut values: Vec<OsString> = Vec::new();
match matches.get_many::<OsString>(DIRECTORY_OR_FILES) {
Some(os_values) => {
for os_string in os_values {
values.push(os_string.to_owned());
}
}
None => {
let mut os_string_values: Vec<OsString> = Vec::new();
read_all_roc_files(
&std::env::current_dir()?.as_os_str().to_os_string(),
&mut os_string_values,
)?;
for os_string in os_string_values {
values.push(os_string);
}
}
}
// Populate roc_files
for os_str in values {
let metadata = fs::metadata(os_str.clone())?;
roc_files_recursive(os_str.as_os_str(), metadata.file_type(), &mut roc_files)?;
}
roc_files
};
let format_exit_code = if from_stdin {
let mut buf = Vec::new();
let arena = Bump::new();
io::stdin().read_to_end(&mut buf)?;
let src = std::str::from_utf8(&buf).unwrap_or_else(|err| {
eprintln!("Stdin contained invalid UTF-8 bytes: {err:?}");
std::process::exit(1);
});
match format_src(&arena, src) {
Ok(formatted_src) => {
match format_mode {
FormatMode::CheckOnly => {
if src == formatted_src {
eprintln!("One or more files need to be reformatted.");
1
} else {
0
}
}
FormatMode::WriteToStdout => {
std::io::stdout().lock().write_all(src.as_bytes()).unwrap();
0
}
FormatMode::WriteToFile => {
// We would have errored out already if you specified --stdin
// without either --stdout or --check specified as well.
unreachable!()
}
}
}
Err(problem) => {
eprintln!("`roc format` failed: {problem:?}");
1
}
}
} else {
match format_files(roc_files, format_mode) {
Ok(()) => 0,
Err(message) => {
eprintln!("{message}");
1
}
}
};