Skip to content

Commit

Permalink
CLI: Changes to improve logs + Fix in test method
Browse files Browse the repository at this point in the history
- Main methods provides a collection of spawn results from all the
  involved jobs in the method
- Fix in test method: install was called for jobs that doesn't have test
  commands yet.
- Spawn results won't be merged anymore
- Logs will always collected to improve source code readability
  • Loading branch information
AmmarAbouZor committed Feb 25, 2024
1 parent f89993a commit 803eb8f
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 164 deletions.
52 changes: 27 additions & 25 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,10 @@ async fn main() -> Result<(), Error> {
} => {
report_opt = get_report_option(report)?;
let targets = get_targets_or_default(target);
let report = !matches!(report_opt, ReportOptions::None);
join_all(
targets
.iter()
.map(|module| module.build(production, report))
.map(|module| module.build(production))
.collect::<Vec<_>>(),
)
.await
Expand Down Expand Up @@ -146,33 +145,36 @@ async fn main() -> Result<(), Error> {
let mut success: bool = true;
for (idx, res) in results.iter().enumerate() {
match res {
Ok(status) => {
let print_err = match &report_opt {
ReportOptions::None => true,
ReportOptions::Stdout(stdout) => {
if !status.is_empty() {
write_report(status, stdout)?;
Ok(statuses) => {
for status in statuses {
let print_err = match &report_opt {
ReportOptions::None => true,
ReportOptions::Stdout(stdout) => {
if !status.is_empty() {
write_report(status, stdout)?;
}
false
}
false
}
ReportOptions::File(path, file) => {
if !status.is_empty() {
write_report(status, file)?;
}
if idx == results.len() - 1 {
let full_path = path.canonicalize().unwrap_or_else(|_| path.to_owned());
println!("Report is written to '{}'", full_path.display());
ReportOptions::File(path, file) => {
if !status.is_empty() {
write_report(status, file)?;
}
if idx == results.len() - 1 {
let full_path =
path.canonicalize().unwrap_or_else(|_| path.to_owned());
println!("Report is written to '{}'", full_path.display());
}
false
}
false
}
};
};

if !status.status.success() {
if print_err {
eprintln!("Failed with errors");
eprintln!("{}:\n{}", status.job, status.report.join(""));
if !status.status.success() {
if print_err {
eprintln!("Failed with errors");
eprintln!("{}:\n{}", status.job, status.report.join(""));
}
success = false;
}
success = false;
}
}
Err(err) => {
Expand Down
57 changes: 25 additions & 32 deletions cli/src/modules/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::{Kind, Manager};
use crate::{fstools, location::get_root, spawner::SpawnResult, Target};
use anyhow::{bail, Context, Error};
use async_trait::async_trait;
use std::{fs, path::PathBuf, process::ExitStatus};
use std::{fs, path::PathBuf};

const PATH: &str = "application/holder";

Expand Down Expand Up @@ -33,7 +33,7 @@ impl Manager for Module {
// For app we don't need --production
Some(String::from("yarn install"))
}
async fn after(&self, prod: bool, report: bool) -> Result<Option<SpawnResult>, Error> {
async fn after(&self, prod: bool) -> Result<Option<SpawnResult>, Error> {
let mut report_logs = Vec::new();
let src = Target::Client
.get()
Expand All @@ -44,29 +44,26 @@ impl Manager for Module {
bail!("Not found: {}", src.display());
}
if !dest.exists() {
if report {
let msg = format!("creating directory: {}", dest.display());
report_logs.push(msg);
}
let msg = format!("creating directory: {}", dest.display());
report_logs.push(msg);

fs::create_dir(&dest)?;
}
let prev = dest.join("client");
if prev.exists() {
if report {
let msg = format!("removig directory: {}", prev.display());
report_logs.push(msg);
}
let msg = format!("removig directory: {}", prev.display());
report_logs.push(msg);

fstools::rm_folder(prev).await?;
}

if report {
let msg = format!(
"copying directory: '{}' to '{}'",
src.display(),
dest.display()
);
report_logs.push(msg);
}
let msg = format!(
"copying directory: '{}' to '{}'",
src.display(),
dest.display()
);
report_logs.push(msg);

fstools::cp_folder(src.clone(), dest.clone()).await?;

let rename_from = dest.join(
Expand All @@ -75,22 +72,18 @@ impl Manager for Module {
);
let rename_to = dest.join("client");

if report {
let msg = format!(
"renaming '{}' to '{}'",
rename_from.display(),
rename_to.display()
);
report_logs.push(msg);
}
let msg = format!(
"renaming '{}' to '{}'",
rename_from.display(),
rename_to.display()
);
report_logs.push(msg);

std::fs::rename(rename_from, rename_to)?;

Ok(Some(SpawnResult {
report: report_logs,
status: ExitStatus::default(),
job: "Copy App Build Artifacts".into(),
cmd: "Multiple file system commands".into(),
}))
Ok(Some(SpawnResult::create_for_fs(
"Copy App Build Artifacts".into(),
report_logs,
)))
}
}
135 changes: 81 additions & 54 deletions cli/src/modules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,21 +79,38 @@ pub trait Manager {
fn test_cmds(&self) -> Vec<TestCommand> {
Vec::new()
}
async fn reset(&self) -> Result<SpawnResult, Error> {
self.clean().await?;
fstools::rm_folder(self.cwd().join("dist")).await?;
Ok(SpawnResult::empty())
async fn reset(&self) -> Result<Vec<SpawnResult>, Error> {
let mut results = Vec::new();
let clean_result = self.clean().await?;
results.push(clean_result);

let dist_path = self.cwd().join("dist");

let remove_log = format!("removing {}", dist_path.display());

fstools::rm_folder(dist_path).await?;

let job = format!("Reset {}", self.owner());

results.push(SpawnResult::create_for_fs(job, vec![remove_log]));

Ok(results)
}
async fn clean(&self) -> Result<(), Error> {
match self.kind() {
Kind::Ts => {
fstools::rm_folder(self.cwd().join("node_modules")).await?;
}
Kind::Rs => {
fstools::rm_folder(self.cwd().join("target")).await?;
}
}
Ok(())
async fn clean(&self) -> Result<SpawnResult, Error> {
let mut logs = Vec::new();
let path = match self.kind() {
Kind::Ts => self.cwd().join("node_modules"),
Kind::Rs => self.cwd().join("target"),
};

let remove_log = format!("removing directory {}", path.display());
logs.push(remove_log);

fstools::rm_folder(path).await?;

let job = format!("Clean {}", self.owner());

Ok(SpawnResult::create_for_fs(job, logs))
}
async fn install(&self, prod: bool) -> Result<SpawnResult, Error> {
let cmd = if self.install_cmd(prod).is_some() {
Expand All @@ -120,17 +137,20 @@ pub trait Manager {
Kind::Rs => Ok(SpawnResult::empty()),
}
}
async fn after(&self, _prod: bool, _report: bool) -> Result<Option<SpawnResult>, Error> {
async fn after(&self, _prod: bool) -> Result<Option<SpawnResult>, Error> {
Ok(None)
}
async fn build(&self, prod: bool, report: bool) -> Result<SpawnResult, Error> {
self.install(false).await?;
async fn build(&self, prod: bool) -> Result<Vec<SpawnResult>, Error> {
let mut results = Vec::new();
let install_result = self.install(false).await?;
results.push(install_result);
let deps: Vec<Box<dyn Manager + Sync + Send>> =
self.deps().iter().map(|target| target.get()).collect();
for module in deps {
let status = module.build(prod, report).await?;
if !status.status.success() {
return Ok(status);
let status = module.build(prod).await?;
results.extend(status);
if results.iter().any(|res| !res.status.success()) {
return Ok(results);
}
}
let path = get_root().join(self.cwd());
Expand All @@ -139,34 +159,45 @@ pub trait Manager {
.unwrap_or_else(|| self.kind().build_cmd(prod));
let caption = format!("Bulid {}", self.owner());
match spawn(&cmd, Some(path), caption, None).await {
Ok(mut status) => {
Ok(status) => {
if !status.status.success() {
Ok(status)
results.push(status);
Ok(results)
} else {
let res = self.after(prod, report).await?;
if matches!(self.kind(), Kind::Ts) && prod {
self.clean().await?;
self.install(prod).await?;
results.push(status);
let res = self.after(prod).await?;
if let Some(result) = res {
results.push(result);
}

if let Some(res_after) = res {
status.merge_with(res_after);
if matches!(self.kind(), Kind::Ts) && prod {
let clean_res = self.clean().await?;
results.push(clean_res);
let install_res = self.install(prod).await?;
results.push(install_res);
}

Ok(status)
Ok(results)
}
}
Err(err) => Err(err),
}
}
async fn check(&self) -> Result<SpawnResult, Error> {
async fn check(&self) -> Result<Vec<SpawnResult>, Error> {
let mut results = Vec::new();
match self.kind() {
Kind::Ts => {
self.install(false).await?;
self.lint().await
let install_result = self.install(false).await?;
let lint_restul = self.lint().await?;
results.push(install_result);
results.push(lint_restul);
}
Kind::Rs => {
let clippy_result = self.clippy().await?;
results.push(clippy_result);
}
Kind::Rs => self.clippy().await,
}

Ok(results)
}
async fn lint(&self) -> Result<SpawnResult, Error> {
let path = get_root().join(self.cwd());
Expand All @@ -192,18 +223,19 @@ pub trait Manager {
.await
}

// flat_map in main() to get rid of the double join calls
async fn test(&self) -> Result<SpawnResult, Error> {
self.install(false).await?;
// TODO: Check if we need to run the dependencies tests too

async fn test(&self) -> Result<Vec<SpawnResult>, Error> {
let test_cmds = self.test_cmds();
if test_cmds.is_empty() {
return Ok(SpawnResult::empty());
return Ok(Vec::new());
}

let mut results = Vec::new();

let install_res = self.install(false).await?;
results.push(install_res);

let caption = format!("Test {}", self.owner());
let results = join_all(test_cmds.iter().map(|cmd| {
let spawn_results = join_all(test_cmds.iter().map(|cmd| {
spawn(
&cmd.command,
Some(cmd.cwd.to_owned()),
Expand All @@ -213,18 +245,13 @@ pub trait Manager {
}))
.await;

// return the first failed result, or the first one if all was successful
let return_pos = results
.iter()
.position(|res| match res {
Ok(result) => !result.status.success(),
Err(_) => true,
})
.unwrap_or(0);

results
.into_iter()
.nth(return_pos)
.expect("Commands has been checked if they are empty before spawning tasks")
for res in spawn_results {
match res {
Ok(spawn_res) => results.push(spawn_res),
Err(err) => return Err(err),
}
}

Ok(results)
}
}
Loading

0 comments on commit 803eb8f

Please sign in to comment.