use std::fmt::Write;
use eyre::WrapErr;
use lib::core::dag::{CommitSet, Dag};
use lib::core::effects::Effects;
use lib::git::Repo;
use thiserror::Error;
use tracing::instrument;
use crate::opts::{ResolveRevsetOptions, Revset};
use crate::revset::Expr;
use super::eval::EvalError;
use super::parser::ParseError;
use super::{eval, parse};
#[allow(clippy::enum_variant_names)]
#[derive(Debug, Error)]
pub enum ResolveError {
#[error("parse error in {expr:?}: {source}")]
ParseError { expr: String, source: ParseError },
#[error("evaluation error in {expr:?}: {source}")]
EvalError { expr: String, source: EvalError },
#[error("DAG query error: {source}")]
DagError { source: eden_dag::Error },
#[error(transparent)]
OtherError { source: eyre::Error },
}
impl ResolveError {
pub fn describe(self, effects: &Effects) -> eyre::Result<()> {
match self {
ResolveError::ParseError { expr, source } => {
writeln!(
effects.get_error_stream(),
"Parse error for expression '{}': {}",
expr,
source
)?;
Ok(())
}
ResolveError::EvalError { expr, source } => {
writeln!(
effects.get_error_stream(),
"Evaluation error for expression '{}': {}",
expr,
source
)?;
Ok(())
}
ResolveError::DagError { source } => Err(source.into()),
ResolveError::OtherError { source } => Err(source),
}
}
}
pub fn check_revset_syntax(repo: &Repo, revsets: &[Revset]) -> Result<(), ParseError> {
for Revset(revset) in revsets {
if let Ok(Some(_)) = repo.revparse_single_commit(revset) {
continue;
}
let _expr: Expr = parse(revset)?;
}
Ok(())
}
#[instrument]
pub fn resolve_commits(
effects: &Effects,
repo: &Repo,
dag: &mut Dag,
revsets: &[Revset],
options: &ResolveRevsetOptions,
) -> Result<Vec<CommitSet>, ResolveError> {
let mut dag_with_obsolete = if options.show_hidden_commits {
Some(
dag.clear_obsolete_commits(repo)
.map_err(|err| ResolveError::OtherError { source: err })?,
)
} else {
None
};
let dag = dag_with_obsolete.as_mut().unwrap_or(dag);
let mut commit_sets = Vec::new();
for Revset(revset) in revsets {
if let Ok(Some(commit)) = repo.revparse_single_commit(revset) {
let commit_set = CommitSet::from(commit.get_oid());
dag.sync_from_oids(effects, repo, CommitSet::empty(), commit_set.clone())
.map_err(|err| ResolveError::OtherError { source: err })?;
commit_sets.push(commit_set);
continue;
}
let expr = parse(revset).map_err(|err| ResolveError::ParseError {
expr: revset.clone(),
source: err,
})?;
let commits = eval(effects, repo, dag, &expr).map_err(|err| ResolveError::EvalError {
expr: revset.clone(),
source: err,
})?;
commit_sets.push(commits);
}
Ok(commit_sets)
}
pub fn resolve_default_smartlog_commits(
effects: &Effects,
repo: &Repo,
dag: &mut Dag,
) -> eyre::Result<CommitSet> {
let revset = Revset::default_smartlog_revset();
let results = resolve_commits(
effects,
repo,
dag,
&[revset],
&ResolveRevsetOptions::default(),
)
.wrap_err("Resolving default smartlog commits")?;
let commits = results.first().unwrap();
Ok(commits.clone())
}