use std::collections::BTreeMap;
use std::path::PathBuf;
use wyrd_loader::DeclarationInput;
use wyrd_spec::error::WyrdError;
use wyrd_spec::registry::{CardSubmission, DeclareCardRequest, RelativeArtifactPath};
use super::hash_artifacts;
use crate::cards::error::RegistryEngineError;
pub(crate) struct PreparedDeclaration {
pub(crate) request: DeclareCardRequest,
pub(crate) artifact_sources: BTreeMap<RelativeArtifactPath, PathBuf>,
}
pub(crate) async fn prepare(
input: &DeclarationInput,
) -> Result<PreparedDeclaration, RegistryEngineError> {
let mut submissions = input.submissions.clone();
for submission in &mut submissions {
hash_artifacts::validate_and_stamp(submission, &input.artifact_sources).await?;
}
validate_source_set(&submissions, &input.artifact_sources)?;
Ok(PreparedDeclaration {
request: DeclareCardRequest { submissions },
artifact_sources: input.artifact_sources.clone(),
})
}
fn validate_source_set(
submissions: &[CardSubmission],
sources: &BTreeMap<RelativeArtifactPath, PathBuf>,
) -> Result<(), RegistryEngineError> {
let declared = submissions
.iter()
.flat_map(|submission| {
submission
.artifacts
.iter()
.map(|entry| &entry.relative_path)
})
.collect::<std::collections::BTreeSet<_>>();
if let Some(missing) = declared.iter().find(|path| !sources.contains_key(*path)) {
return Err(WyrdError::RegistryUploadInterrupted {
message: "a declared artifact has no local source".to_owned(),
details: serde_json::json!({ "relative_path": missing.as_str() }),
}
.into());
}
if let Some(unexpected) = sources.keys().find(|path| !declared.contains(path)) {
return Err(WyrdError::RegistryInvalidArtifactPath {
message: "a local artifact source is not declared by any submission".to_owned(),
details: serde_json::json!({ "relative_path": unexpected.as_str() }),
}
.into());
}
Ok(())
}