Skip to content

Commit

Permalink
[CLI] Check with multiple arguments (#91)
Browse files Browse the repository at this point in the history
* feat: add ability to specify multiple registries and projects while doing a check

Signed-off-by: jaudiger <jeremy.audiger@ioterop.com>

* refactor: uniformize with what is done in the check function

Signed-off-by: jaudiger <jeremy.audiger@ioterop.com>

* chore: use registry_project instead of registry

Signed-off-by: jaudiger <jeremy.audiger@ioterop.com>

* chore: remove a unused import.

Signed-off-by: jaudiger <jeremy.audiger@ioterop.com>

---------

Signed-off-by: jaudiger <jeremy.audiger@ioterop.com>
  • Loading branch information
jaudiger authored Jul 17, 2024
1 parent ee2479c commit 45411ff
Show file tree
Hide file tree
Showing 3 changed files with 174 additions and 64 deletions.
121 changes: 99 additions & 22 deletions crates/brioche/src/check.rs
Original file line number Diff line number Diff line change
@@ -1,51 +1,128 @@
use std::path::PathBuf;
use std::process::ExitCode;

use brioche_core::project::ProjectHash;
use brioche_core::project::Projects;
use brioche_core::reporter::ConsoleReporterKind;
use brioche_core::reporter::Reporter;
use brioche_core::Brioche;
use clap::Parser;
use tracing::Instrument;

use crate::consolidate_result;

#[derive(Debug, Parser)]
pub struct CheckArgs {
#[command(flatten)]
project: super::ProjectArgs,
project: super::MultipleProjectArgs,
}

pub async fn check(args: CheckArgs) -> 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 brioche = brioche_core::BriocheBuilder::new(reporter.clone())
.build()
.await?;
let projects = brioche_core::project::Projects::default();

let check_future = async {
let project_hash = super::load_project(&brioche, &projects, &args.project).await?;
let mut error_result = Option::None;

let num_lockfiles_updated = projects.commit_dirty_lockfiles().await?;
if num_lockfiles_updated > 0 {
tracing::info!(num_lockfiles_updated, "updated lockfiles");
}
// Handle the case where no projects and no registries are specified
let projects_path =
if args.project.project.is_empty() && args.project.registry_project.is_empty() {
vec![PathBuf::from(".")]
} else {
args.project.project
};

let checked = brioche_core::script::check::check(&brioche, &projects, project_hash).await?;
// Loop over the projects
for project_path in projects_path {
let project_name = format!("project '{name}'", name = project_path.display());

guard.shutdown_console().await;
match projects.load(&brioche, &project_path, true).await {
Ok(project_hash) => {
let result =
run_check(&reporter, &brioche, &projects, project_hash, &project_name).await;
consolidate_result(&reporter, &project_name, result, &mut error_result);
}
Err(e) => {
consolidate_result(&reporter, &project_name, Err(e), &mut error_result);
}
}
}

let result = checked.ensure_ok(brioche_core::script::check::DiagnosticLevel::Message);
// Loop over the registry projects
for registry_project in args.project.registry_project {
let project_name = format!("registry project '{registry_project}'");

match result {
Ok(()) => {
println!("No errors found 🎉");
anyhow::Ok(ExitCode::SUCCESS)
match projects
.load_from_registry(
&brioche,
&registry_project,
&brioche_core::project::Version::Any,
)
.await
{
Ok(project_hash) => {
let result =
run_check(&reporter, &brioche, &projects, project_hash, &project_name).await;
consolidate_result(&reporter, &project_name, result, &mut error_result);
}
Err(diagnostics) => {
diagnostics.write(&brioche.vfs, &mut std::io::stdout())?;
anyhow::Ok(ExitCode::FAILURE)
Err(e) => {
consolidate_result(&reporter, &project_name, Err(e), &mut error_result);
}
}
};
}

let exit_code = check_future
.instrument(tracing::info_span!("check"))
.await?;
guard.shutdown_console().await;

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

Ok(exit_code)
}

async fn run_check(
reporter: &Reporter,
brioche: &Brioche,
projects: &Projects,
project_hash: ProjectHash,
project_name: &String,
) -> Result<bool, anyhow::Error> {
let num_lockfiles_updated = projects.commit_dirty_lockfiles().await?;
if num_lockfiles_updated > 0 {
tracing::info!(num_lockfiles_updated, "updated lockfiles");
}

let result =
async { brioche_core::script::check::check(brioche, projects, project_hash).await }
.instrument(tracing::info_span!("check"))
.await?
.ensure_ok(brioche_core::script::check::DiagnosticLevel::Message);

match result {
Ok(()) => {
reporter.emit(superconsole::Lines::from_multiline_string(
&format!("No errors found in {project_name} 🎉",),
superconsole::style::ContentStyle::default(),
));

Ok(true)
}
Err(diagnostics) => {
let mut output = Vec::new();
diagnostics.write(&brioche.vfs, &mut output)?;

reporter.emit(superconsole::Lines::from_multiline_string(
&String::from_utf8(output)?,
superconsole::style::ContentStyle::default(),
));

Ok(false)
}
}
}
80 changes: 38 additions & 42 deletions crates/brioche/src/format.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use std::{
path::{Path, PathBuf},
process::ExitCode,
};
use std::{path::PathBuf, process::ExitCode};

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

use crate::consolidate_result;

#[derive(Debug, Parser)]
pub struct FormatArgs {
/// The path to the project directory to format
Expand All @@ -22,28 +24,32 @@ 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.clone())
.build()
.await?;
let projects = brioche_core::project::Projects::default();

let mut error_result = Option::None;
for project_path in args.project {
match project_format(&reporter, &project_path, args.check).await {
Err(err) => {
reporter.emit(superconsole::Lines::from_multiline_string(
&format!(
"Error occurred while formatting project '{project_path}': {err}",
project_path = project_path.display(),
err = err
),
superconsole::style::ContentStyle {
foreground_color: Some(superconsole::style::Color::Red),
..superconsole::style::ContentStyle::default()
},
));

error_result = Some(());
// Loop over the projects
for project_path in args.project {
let project_name = format!("project '{name}'", name = project_path.display());

match projects.load(&brioche, &project_path, true).await {
Ok(project_hash) => {
let result = run_format(
&reporter,
&projects,
project_hash,
&project_name,
args.check,
)
.await;
consolidate_result(&reporter, &project_name, result, &mut error_result);
}
Ok(false) => {
error_result = Some(());
Err(e) => {
consolidate_result(&reporter, &project_name, Err(e), &mut error_result);
}
_ => {}
}
}

Expand All @@ -58,23 +64,18 @@ pub async fn format(args: FormatArgs) -> anyhow::Result<ExitCode> {
Ok(exit_code)
}

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

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
brioche_core::script::format::check_format(projects, project_hash).await
} else {
brioche_core::script::format::format(&projects, project_hash).await
brioche_core::script::format::format(projects, project_hash).await
}
}
.instrument(tracing::info_span!("format"))
Expand All @@ -89,8 +90,7 @@ async fn project_format(
if !files.is_empty() {
reporter.emit(superconsole::Lines::from_multiline_string(
&format!(
"The following files of project '{project_path}' have been formatted:\n{files}",
project_path = project_path.display(),
"The following files of {project_name} have been formatted:\n{files}",
files = files
.iter()
.map(|file| format!("- {}", file.display()))
Expand All @@ -104,19 +104,15 @@ async fn project_format(
Ok(true)
} else if files.is_empty() {
reporter.emit(superconsole::Lines::from_multiline_string(
&format!(
"All files of project '{project_path}' are formatted",
project_path = project_path.display()
),
&format!("All files of {project_name} are formatted",),
superconsole::style::ContentStyle::default(),
));

Ok(true)
} else {
reporter.emit(superconsole::Lines::from_multiline_string(
&format!(
"The following files of project '{project_path}' are not formatted:\n{files}",
project_path = project_path.display(),
"The following files of {project_name} are not formatted:\n{files}",
files = files
.iter()
.map(|file| format!("- {}", file.display()))
Expand Down
37 changes: 37 additions & 0 deletions crates/brioche/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,18 @@ struct ProjectArgs {
registry: Option<String>,
}

#[derive(Debug, clap::Args)]
#[group(required = false, multiple = false)]
struct MultipleProjectArgs {
/// The path of the project directory to build [default: .]
#[clap(short, long)]
project: Vec<PathBuf>,

/// The name of a registry project to build
#[clap(id = "registry", short, long)]
registry_project: Vec<String>,
}

async fn load_project(
brioche: &brioche_core::Brioche,
projects: &brioche_core::project::Projects,
Expand All @@ -253,3 +265,28 @@ async fn load_project(

Ok(project_hash)
}

fn consolidate_result(
reporter: &brioche_core::reporter::Reporter,
project_name: &String,
result: Result<bool, anyhow::Error>,
error_result: &mut Option<()>,
) {
match result {
Err(err) => {
reporter.emit(superconsole::Lines::from_multiline_string(
&format!("Error occurred with {project_name}: {err}", err = err),
superconsole::style::ContentStyle {
foreground_color: Some(superconsole::style::Color::Red),
..superconsole::style::ContentStyle::default()
},
));

*error_result = Some(());
}
Ok(false) => {
*error_result = Some(());
}
_ => {}
}
}

0 comments on commit 45411ff

Please sign in to comment.