use crate::runtime::fs::FileIdentity;
use crate::runtime::vfs::Placement;
use cap_std::fs::Dir;
use std::path::{Path, PathBuf};
use wasmtime::{Result, bail};
pub(super) struct Location {
pub dir: std::sync::Arc<Dir>,
pub identity: FileIdentity,
pub host: PathBuf,
}
impl Location {
pub(super) fn new(
dir: std::sync::Arc<Dir>,
placement: &Placement,
relative: &Path,
) -> Result<Self> {
let host = if relative == Path::new(".") {
placement.host().to_path_buf()
} else {
placement.host().join(relative)
};
let identity = FileIdentity::of(&dir.dir_metadata()?)?;
let opened = Dir::open_ambient_dir(&host, cap_std::ambient_authority())?;
if FileIdentity::of(&opened.dir_metadata()?)? != identity {
bail!("git: the repository's host path no longer names its directory");
}
Ok(Self {
dir,
identity,
host,
})
}
pub(super) fn git_dir(&self) -> Result<PathBuf> {
let by_handle = FileIdentity::of(&self.dir.open_dir(".git")?.dir_metadata()?)?;
let path = self.host.join(".git");
let by_path = Dir::open_ambient_dir(&path, cap_std::ambient_authority())?;
if FileIdentity::of(&by_path.dir_metadata()?)? != by_handle {
bail!("git: the repository's .git no longer names its metadata");
}
Ok(path)
}
}
#[cfg(test)]
impl Location {
pub(super) fn at(host: &Path) -> Self {
let dir = Dir::open_ambient_dir(host, cap_std::ambient_authority()).unwrap();
Self {
identity: FileIdentity::of(&dir.dir_metadata().unwrap()).unwrap(),
dir: std::sync::Arc::new(dir),
host: host.to_path_buf(),
}
}
pub(super) fn of_vfs(vfs: &crate::runtime::Vfs) -> Self {
Self::at(vfs.root())
}
}