use crate::hash::digest_bytes;
use crate::observe::{self, Observation};
use crate::resolution::rust::identity::{PackageId, TargetId, index_of};
use crate::resolution::rust::manifest::ManifestFingerprint;
use crate::resolution::rust::package::RustPackage;
use crate::resolution::rust::project::RustProject;
use crate::resolution::rust::target::RustTarget;
use super::error::RustSnapshotError;
pub(super) fn validated_target(
project: &RustProject,
id: TargetId,
) -> Result<&RustTarget, RustSnapshotError> {
check_scope(project, id)?;
let target = project
.targets
.get(index_of(id.index()))
.ok_or(RustSnapshotError::UnknownTarget { index: id.index() })?;
check_manifests(project)?;
Ok(target)
}
pub(super) fn validated_package(
project: &RustProject,
id: PackageId,
) -> Result<&RustPackage, RustSnapshotError> {
check_package_scope(project, id)?;
let package = project
.packages
.get(index_of(id.index()))
.ok_or(RustSnapshotError::UnknownPackage { index: id.index() })?;
check_manifests(project)?;
Ok(package)
}
fn check_scope(project: &RustProject, id: TargetId) -> Result<(), RustSnapshotError> {
let issued = id.authority();
let scope = (
issued.same_root(&project.authority),
issued.same_revision(&project.authority),
);
match scope {
(false, _) => Err(RustSnapshotError::ForeignTarget),
(true, false) => Err(RustSnapshotError::StaleTarget),
(true, true) => Ok(()),
}
}
fn check_package_scope(project: &RustProject, id: PackageId) -> Result<(), RustSnapshotError> {
let issued = id.authority();
let scope = (
issued.same_root(&project.authority),
issued.same_revision(&project.authority),
);
match scope {
(false, _) => Err(RustSnapshotError::ForeignPackage),
(true, false) => Err(RustSnapshotError::StalePackage),
(true, true) => Ok(()),
}
}
fn check_manifests(project: &RustProject) -> Result<(), RustSnapshotError> {
for manifest in project.manifests.iter() {
observe::record(Observation::ManifestRead(&manifest.relative));
check_manifest(project, manifest)?;
}
Ok(())
}
fn check_manifest(
project: &RustProject,
manifest: &ManifestFingerprint,
) -> Result<(), RustSnapshotError> {
let path = project.root.join(&*manifest.relative);
let current = std::fs::read(&path).map_err(|source| RustSnapshotError::ManifestUnreadable {
manifest: Box::from(&*manifest.relative),
source,
})?;
match digest_bytes(¤t) == manifest.digest {
true => Ok(()),
false => Err(RustSnapshotError::ProjectManifestsChanged {
manifest: Box::from(&*manifest.relative),
}),
}
}