Skip to content

Commit

Permalink
feat: rewrite the format function to add the formatted files and to b…
Browse files Browse the repository at this point in the history
…etter handle errors happened on a project when formatting more than once at the same time (#86)

Signed-off-by: jaudiger <[email protected]>
  • Loading branch information
jaudiger authored Jul 14, 2024
1 parent 9b87faa commit e80c0e1
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 57 deletions.
54 changes: 37 additions & 17 deletions crates/brioche-core/src/script/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,61 @@ use std::path::PathBuf;

use crate::project::{ProjectHash, Projects};

#[tracing::instrument(skip(projects), err)]
pub async fn format(projects: &Projects, project_hash: ProjectHash) -> anyhow::Result<()> {
let module_paths = projects.project_module_paths(project_hash)?;
for path in &module_paths {
let contents = tokio::fs::read_to_string(path).await?;

let formatted_contents = format_code(&contents)?;

tokio::fs::write(path, &formatted_contents).await?;
}
/// Formats the specified project using the provided formatter.
///
/// This function takes a reference to the `Projects` struct, a `ProjectHash` representing the project to format.
/// It returns a `Result` containing a vector of `PathBuf` representing the paths of the formatted files,
/// or an `anyhow::Error` if an error occurs.
pub async fn format(
projects: &Projects,
project_hash: ProjectHash,
) -> anyhow::Result<Vec<PathBuf>> {
format_project(projects, project_hash, false).await
}

Ok(())
/// Checks the formatting of the specified project using the provided formatter.
///
/// This function takes a reference to the `Projects` struct, a `ProjectHash` representing the project to check.
/// It returns a `Result` containing a vector of `PathBuf` representing the paths of the unformatted files,
/// or an `anyhow::Error` if an error occurs.
pub async fn check_format(
projects: &Projects,
project_hash: ProjectHash,
) -> anyhow::Result<Vec<PathBuf>> {
format_project(projects, project_hash, true).await
}

#[tracing::instrument(skip(projects), err)]
pub async fn check_format(
async fn format_project(
projects: &Projects,
project_hash: ProjectHash,
check: bool,
) -> anyhow::Result<Vec<PathBuf>> {
let mut unformatted = vec![];
let mut result = vec![];

let module_paths = projects.project_module_paths(project_hash)?;
for path in &module_paths {
let contents = tokio::fs::read_to_string(path).await?;
for path in module_paths {
let contents = tokio::fs::read_to_string(&path).await?;

let formatted_contents = format_code(&contents)?;

// Check if the file was formatted
if contents != formatted_contents {
unformatted.push(path.to_owned());
if !check {
tokio::fs::write(&path, &formatted_contents).await?;
}

result.push(path);
}
}

Ok(unformatted)
Ok(result)
}

/// Formats the code using the specified formatter.
///
/// This function takes a string slice `contents` as input and formats the code using the `biome_js_formatter` crate.
/// It returns a `Result` containing the formatted code as a `String`, or an `anyhow::Error` if an error occurs.
pub fn format_code(contents: &str) -> anyhow::Result<String> {
let file_source =
biome_js_syntax::JsFileSource::ts().with_module_kind(biome_js_syntax::ModuleKind::Module);
Expand Down
123 changes: 83 additions & 40 deletions crates/brioche/src/format.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use std::{path::PathBuf, process::ExitCode};
use std::{
path::{Path, PathBuf},
process::ExitCode,
};

use brioche_core::reporter::ConsoleReporterKind;
use brioche_core::reporter::{ConsoleReporterKind, Reporter};
use clap::Parser;
use tracing::Instrument;

Expand All @@ -19,57 +22,97 @@ pub async fn format(args: FormatArgs) -> anyhow::Result<ExitCode> {
let (reporter, mut guard) =
brioche_core::reporter::start_console_reporter(ConsoleReporterKind::Auto)?;

let brioche = brioche_core::BriocheBuilder::new(reporter).build().await?;
let mut error_result = Option::None;
for project_path in args.project {
match project_format(&reporter, &project_path, args.check).await {
Err(err) => {
println!(
"Error occurred while formatting project '{project_path}': {err}",
project_path = project_path.display(),
err = err
);

let format_futures = args
.project
.into_iter()
.map(|project_path| {
let projects = brioche_core::project::Projects::default();

async { project_format(projects, brioche.clone(), project_path, args.check).await }
})
.map(|project_path| project_path.instrument(tracing::info_span!("format")))
.collect::<Vec<_>>();

let mut unformatted_files = Vec::new();
for future in format_futures {
unformatted_files.append(&mut future.await?);
error_result = Some(());
}
Ok(false) => {
error_result = Some(());
}
_ => {}
}
}
unformatted_files.sort();

let exit_code = if !args.check {
ExitCode::SUCCESS
} else if unformatted_files.is_empty() {
println!("All files formatted");
ExitCode::SUCCESS
} else {
println!("The following files are not formatted:");
for file in unformatted_files {
println!("- {}", file.display());
}
guard.shutdown_console().await;

let exit_code = if error_result.is_some() {
ExitCode::FAILURE
} else {
ExitCode::SUCCESS
};

guard.shutdown_console().await;

Ok(exit_code)
}

async fn project_format(
projects: brioche_core::project::Projects,
brioche: brioche_core::Brioche,
project_path: PathBuf,
reporter: &Reporter,
project_path: &Path,
check: bool,
) -> Result<Vec<PathBuf>, anyhow::Error> {
let project_hash = projects.load(&brioche, &project_path, true).await?;
) -> Result<bool, anyhow::Error> {
let brioche = brioche_core::BriocheBuilder::new(reporter.clone())
.build()
.await?;
let projects = brioche_core::project::Projects::default();

if check {
Ok(brioche_core::script::format::check_format(&projects, project_hash).await?)
} else {
brioche_core::script::format::format(&projects, project_hash).await?;
let project_hash = projects.load(&brioche, project_path, true).await?;

let result = async {
if check {
brioche_core::script::format::check_format(&projects, project_hash).await
} else {
brioche_core::script::format::format(&projects, project_hash).await
}
}
.instrument(tracing::info_span!("format"))
.await;

Ok(vec![])
match result {
Err(err) => Err(err),
Ok(mut files) => {
files.sort();

if !check {
if !files.is_empty() {
println!(
"The following files of project '{project_path}' have been formatted:\n{files}",
project_path = project_path.display(),
files = files
.iter()
.map(|file| format!("- {}", file.display()))
.collect::<Vec<_>>()
.join("\n")
);
}

Ok(true)
} else if files.is_empty() {
println!(
"All files of project '{project_path}' are formatted",
project_path = project_path.display()
);

Ok(true)
} else {
println!(
"The following files of project '{project_path}' are not formatted:\n{files}",
project_path = project_path.display(),
files = files
.iter()
.map(|file| format!("- {}", file.display()))
.collect::<Vec<_>>()
.join("\n")
);

Ok(false)
}
}
}
}

0 comments on commit e80c0e1

Please sign in to comment.