use std::path::Path;
use stow_types::index::ArtifactIndexRow;
use stow_types::rustc::ParsedRustcArgs;
use crate::artifact_cache::{self, CachedArtifactBundle};
use crate::fetch::{self, BundleRef};
use crate::inject;
use crate::verify;
use crate::config::StowConfig;
pub use crate::index::IndexSlice;
#[derive(Debug)]
pub struct ConsumeConfig(StowConfig);
impl ConsumeConfig {
pub fn load() -> stow_types::error::Result<Self> {
StowConfig::load().map(Self)
}
}
pub async fn ensure_slice(
config: &ConsumeConfig,
target: &str,
rustc_version: &str,
) -> stow_types::error::Result<IndexSlice> {
crate::index::ensure_slice(&config.0, target, rustc_version).await
}
#[derive(Debug)]
pub struct ServedBundle {
pub compile_key: String,
pub crate_name: String,
inner: CachedArtifactBundle,
}
#[derive(Debug)]
pub enum StageFailure {
Unavailable(stow_types::error::Error),
Unverifiable(stow_types::error::Error),
}
impl std::fmt::Display for StageFailure {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Unavailable(error) | Self::Unverifiable(error) => error.fmt(f),
}
}
}
pub async fn stage_verified_bundle(
config: &ConsumeConfig,
slice: &IndexSlice,
row: &ArtifactIndexRow,
entry_dir: &Path,
) -> Result<(), StageFailure> {
let target = slice.index.header.target.as_str();
let rustc_version = slice.index.header.rustc_version.as_str();
let bundle_ref = BundleRef::from_index_row(target, rustc_version, row);
let bytes = fetch::download_bundle_bytes(&config.0, &bundle_ref)
.await
.map_err(|error| {
StageFailure::Unavailable(stow_types::error::Error::msg(format!(
"fetch bundle for `{}` {}: {error}",
row.crate_name, row.version
)))
})?;
let bundle = fetch::parse_downloaded_bundle(bytes)
.await
.map_err(StageFailure::Unverifiable)?;
fetch::validate_bundle_identity(
&bundle,
row.crate_name.as_str(),
row.c_metadata.as_str(),
target,
rustc_version,
)
.map_err(StageFailure::Unverifiable)?;
verify::verify_bundle_signature(&config.0, &bundle)
.await
.map_err(StageFailure::Unverifiable)?;
artifact_cache::store_bundle_entry_dir(entry_dir, &bundle)
.map_err(StageFailure::Unverifiable)?;
Ok(())
}
pub fn load_served_bundle(
store_dir: &Path,
lease_dir: &Path,
compile_key: &str,
) -> stow_types::error::Result<Option<ServedBundle>> {
let Some(bundle) = artifact_cache::load_bundle_entry_dir(
&store_dir.join(compile_key),
lease_dir,
compile_key,
)?
else {
return Ok(None);
};
Ok(Some(ServedBundle {
compile_key: bundle.compile_key.clone(),
crate_name: bundle.crate_name.clone(),
inner: bundle,
}))
}
pub async fn serve_bundle_outputs(
parsed: &ParsedRustcArgs,
bundle: &ServedBundle,
) -> stow_types::error::Result<()> {
inject::write_artifacts(
parsed,
&bundle.inner,
inject::OutputDirWriters::UntrustedCodeToo,
)
.await
}