use anyhow::Result;
use std::path::Path;
use crate::cli::{commands, dispatch, pipeline};
use super::dispatch::DispatchContext;
use super::helpers::{StageFailure, collect_managed_surface, load_config, resolve_languages};
pub(crate) mod report;
type CrateSurface = (Vec<crate::core::backend::GeneratedFile>, Vec<StageFailure>);
pub(crate) fn managed_surface<C, R>(
crates: &[C],
targets: &[String],
base_dir: &Path,
mut render_crate: R,
) -> Result<Vec<commands::adopt::ManagedOutput>>
where
R: FnMut(&C) -> Result<CrateSurface>,
{
let mut managed = Vec::new();
for crate_config in crates {
let (surface, stage_failures) = render_crate(crate_config)?;
for failure in &stage_failures {
if failure.affects_any(targets) {
anyhow::bail!(
"[{}] {} -- this affects one of the requested targets, so `alef adopt` \
cannot answer for it",
failure.stage,
failure.message
);
}
tracing::debug!(
stage = failure.stage,
"tolerating stage failure: no requested target comes from this stage: {}",
failure.message
);
}
managed.extend(commands::adopt::managed_outputs(&surface, base_dir));
}
Ok(managed)
}
pub(crate) fn handle(
targets: Vec<String>,
write: bool,
converged_only: bool,
clobber_create_once_seeds: bool,
context: &DispatchContext,
) -> Result<()> {
let config_path = &context.config_path;
let base_dir = std::env::current_dir()?;
let (_workspace, resolved) = load_config(config_path)?;
let crates_to_process = dispatch::select_crates(&resolved, &context.crate_filter)?;
let managed = managed_surface(&crates_to_process, &targets, &base_dir, |resolved_cfg| {
let languages = resolve_languages(resolved_cfg, None)?;
let api = pipeline::extract(resolved_cfg, config_path, false)?;
collect_managed_surface(&languages, &api, resolved_cfg, config_path, &base_dir)
})?;
let options = commands::adopt::AdoptBatchOptions {
base_dir: base_dir.clone(),
write,
converged_only,
clobber_create_once_seeds,
};
let outcome = commands::adopt::run_batch(&targets, &options, &managed)?;
let summary = report::AdoptSummary::merge(&outcome, !write);
report::emit(&report::render(&summary, converged_only));
report::log_diagnostics(&summary);
report_failures(&outcome, targets.len())
}
fn report_failures(outcome: &commands::adopt::AdoptBatchOutcome, requested: usize) -> Result<()> {
let failures: Vec<(&str, &anyhow::Error)> = outcome.failures().collect();
if failures.is_empty() {
return Ok(());
}
for (target, error) in &failures {
tracing::error!("{target}: {error:#}");
}
anyhow::bail!(
"{} of {} adopt target(s) could not be adopted; each is reported above",
failures.len(),
requested
)
}
#[cfg(test)]
mod tests;