use std::path::{Path, PathBuf};
use crate::config::defaults::{
acceptance_root_path, acceptance_store_path_in, ensure_acceptance_store_usable,
AcceptanceStoreError,
};
use super::execution_manifest::ManifestStore;
use super::verification_evidence::{legacy_target_evidence, EvidenceStore};
tokio::task_local! {
pub(crate) static ACCEPTANCE_ROOT_OVERRIDE: PathBuf;
}
#[cfg(test)]
pub(crate) async fn scoped_acceptance_root_for_test<F, R>(root: PathBuf, fut: F) -> R
where
F: std::future::Future<Output = R>,
{
ACCEPTANCE_ROOT_OVERRIDE.scope(root, fut).await
}
fn resolved_acceptance_root(state_base_dir: Option<&str>) -> Result<PathBuf, AcceptanceStoreError> {
if let Ok(root) = ACCEPTANCE_ROOT_OVERRIDE.try_with(Clone::clone) {
return Ok(root);
}
Ok(acceptance_root_path(state_base_dir)?)
}
pub fn store_path(
state_base_dir: Option<&str>,
project_root: &Path,
workspace: &Path,
change_id: &str,
) -> Result<PathBuf, AcceptanceStoreError> {
acceptance_store_path_in(
&resolved_acceptance_root(state_base_dir)?,
project_root,
workspace,
change_id,
)
}
#[derive(Debug, Clone)]
pub struct AcceptanceStore {
root: PathBuf,
}
impl AcceptanceStore {
pub fn resolve(
state_base_dir: Option<&str>,
project_root: &Path,
workspace: &Path,
change_id: &str,
) -> Result<Self, AcceptanceStoreError> {
let root = store_path(state_base_dir, project_root, workspace, change_id)?;
ensure_acceptance_store_usable(&root)?;
Ok(Self { root })
}
pub fn at(root: impl Into<PathBuf>) -> Self {
Self { root: root.into() }
}
pub fn root(&self) -> &Path {
self.root.as_path()
}
pub fn evidence(&self) -> EvidenceStore {
EvidenceStore::new(self.root.clone())
}
pub fn manifests(&self) -> ManifestStore {
ManifestStore::new(self.root.clone())
}
pub fn clear(&self) {
let _ = std::fs::remove_dir_all(&self.root);
}
}
#[derive(Debug)]
pub enum EvidenceLocationRefusal {
Store(AcceptanceStoreError),
LegacyTargetEvidence(PathBuf),
}
impl EvidenceLocationRefusal {
pub fn category(&self) -> super::execution_manifest::AcceptanceHoldCategory {
use super::execution_manifest::AcceptanceHoldCategory;
match self {
Self::Store(_) => AcceptanceHoldCategory::StatePathUnavailable,
Self::LegacyTargetEvidence(_) => AcceptanceHoldCategory::LegacyTargetEvidence,
}
}
pub fn evidence(&self) -> String {
match self {
Self::Store(error) => format!("{}: {error}", error.code()),
Self::LegacyTargetEvidence(path) => format!(
"legacy Conflux-owned evidence exists at '{}'; it was not opened, parsed, \
migrated, rewritten, or deleted",
path.display()
),
}
}
}
pub fn prepare_store(
state_base_dir: Option<&str>,
project_root: &Path,
workspace: &Path,
change_id: &str,
) -> Result<AcceptanceStore, EvidenceLocationRefusal> {
if let Some(path) = legacy_target_evidence(workspace) {
return Err(EvidenceLocationRefusal::LegacyTargetEvidence(path));
}
AcceptanceStore::resolve(state_base_dir, project_root, workspace, change_id)
.map_err(EvidenceLocationRefusal::Store)
}
#[cfg(test)]
#[path = "evidence_location/tests.rs"]
mod tests;