use std::path::{Path, PathBuf};
use zhao_core::adapters::dbt::DbtAdapterError;
use zhao_core::git::{self, GitError};
use zhao_core::model::ParsedProject;
use crate::adapter::ResolvedAdapter;
#[derive(Debug, thiserror::Error)]
pub enum BaselineError {
#[error("{path}: {source}")]
Manifest {
path: String,
#[source]
source: DbtAdapterError,
},
#[error(transparent)]
Git(#[from] GitError),
#[error(transparent)]
Dbt(#[from] DbtAdapterError),
}
pub fn resolve(
adapter: &ResolvedAdapter,
state_path: Option<&Path>,
project_dir: &Path,
against: &str,
dbt_command: &str,
extra_args: &[String],
) -> Result<ParsedProject, BaselineError> {
if let Some(path) = state_path {
return adapter
.parse(path)
.map_err(|source| BaselineError::Manifest {
path: path.display().to_string(),
source,
});
}
let repo_root = git::repo_root(project_dir)?;
let canonical_repo_root = repo_root.canonicalize().unwrap_or(repo_root);
let canonical_project_dir = project_dir
.canonicalize()
.unwrap_or_else(|_| project_dir.to_path_buf());
let relative_project_dir = canonical_project_dir
.strip_prefix(&canonical_repo_root)
.unwrap_or(Path::new("."));
let merge_base = git::resolve_merge_base(&canonical_repo_root, against)?;
let worktree = git::create_worktree(&canonical_repo_root, &merge_base)?;
let worktree_project_dir = worktree.path().join(relative_project_dir);
if worktree_project_dir.join("packages.yml").exists()
|| worktree_project_dir.join("dependencies.yml").exists()
{
crate::log::log_dbt_result(
"deps",
&worktree_project_dir,
project_dir,
adapter.deps(&worktree_project_dir, dbt_command, extra_args),
)?;
}
crate::log::log_dbt_result(
"compile",
&worktree_project_dir,
project_dir,
adapter.compile(&worktree_project_dir, dbt_command, extra_args),
)?;
let manifest_path = worktree_project_dir.join("target").join("manifest.json");
capture_baseline_manifest(&manifest_path, project_dir);
Ok(adapter.parse(&manifest_path)?)
}
fn capture_baseline_manifest(manifest_path: &Path, project_dir: &Path) {
let dest_dir = project_dir.join("target").join("zhao");
if let Err(err) = std::fs::create_dir_all(&dest_dir) {
eprintln!(
"warning: could not create {} to capture the baseline manifest: {err}",
dest_dir.display()
);
return;
}
let dest: PathBuf = dest_dir.join("baseline_manifest.json");
let write_result = (|| -> std::io::Result<()> {
let contents = std::fs::read(manifest_path)?;
let mut temp_file = tempfile::NamedTempFile::new_in(&dest_dir)?;
std::io::Write::write_all(&mut temp_file, &contents)?;
temp_file.persist(&dest).map_err(|err| err.error)?;
Ok(())
})();
if let Err(err) = write_result {
eprintln!(
"warning: could not capture the baseline manifest to {}: {err}",
dest.display()
);
}
}