Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion crates/rattler_cache/src/package_cache/cache_lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::{
use digest::generic_array::GenericArray;
use fs4::fs_std::FileExt;
use rattler_conda_types::package::{IndexJson, PathsJson};
use rattler_digest::Sha256Hash;
use rattler_digest::{Md5Hash, Sha256Hash};

use crate::package_cache::PackageCacheLayerError;

Expand All @@ -23,6 +23,8 @@ use crate::package_cache::PackageCacheLayerError;
pub struct CacheMetadata {
pub(super) revision: u64,
pub(super) sha256: Option<Sha256Hash>,
pub(super) md5: Option<Md5Hash>,
pub(super) size: Option<u64>,
pub(super) path: PathBuf,
pub(super) index_json: Option<IndexJson>,
pub(super) paths_json: Option<PathsJson>,
Expand Down Expand Up @@ -59,6 +61,21 @@ impl CacheMetadata {
pub fn paths_json(&self) -> Option<&PathsJson> {
self.paths_json.as_ref()
}

/// Returns the SHA256 hash of the package archive, if known.
pub fn sha256(&self) -> Option<&Sha256Hash> {
self.sha256.as_ref()
}

/// Returns the MD5 hash of the package archive, if known.
pub fn md5(&self) -> Option<&Md5Hash> {
self.md5.as_ref()
}

/// Returns the size of the package archive in bytes, if known.
pub fn size(&self) -> Option<u64> {
self.size
}
}

/// A global lock for the entire package cache.
Expand Down
32 changes: 30 additions & 2 deletions crates/rattler_cache/src/package_cache/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -475,12 +475,20 @@ impl PackageCache {
let sha256 = cache_key.sha256();
let md5 = cache_key.md5();
let download_reporter = reporter.clone();

// Shared state to capture extract result metadata from the fetch closure.
let extract_metadata: Arc<
Mutex<Option<(rattler_digest::Sha256Hash, rattler_digest::Md5Hash, u64)>>,
> = Arc::new(Mutex::new(None));
let extract_metadata_clone = extract_metadata.clone();

// Get or fetch the package, using the specified fetch function
self.get_or_fetch(cache_key, move |destination| {
let mut cache_metadata = self.get_or_fetch(cache_key, move |destination| {
let url = url.clone();
let client = client.clone();
let retry_policy = retry_policy.clone();
let download_reporter = download_reporter.clone();
let extract_metadata_clone = extract_metadata_clone.clone();
async move {
let mut current_try = 0;
// Retry until the retry policy says to stop
Expand Down Expand Up @@ -549,6 +557,9 @@ impl PackageCache {
});
}
}
// Capture the extract result metadata for the caller.
*extract_metadata_clone.lock() =
Some((result.sha256, result.md5, result.total_size));
return Ok(());
}
Err(err) => err,
Expand Down Expand Up @@ -584,7 +595,18 @@ impl PackageCache {
}
}
}, reporter)
.await
.await?;

// Propagate extract result metadata (sha256, md5, size) into the cache metadata.
if let Some((sha256, md5, size)) = extract_metadata.lock().take() {
if cache_metadata.sha256.is_none() {
cache_metadata.sha256 = Some(sha256);
}
cache_metadata.md5 = Some(md5);
cache_metadata.size = Some(size);
}

Ok(cache_metadata)
}
}

Expand Down Expand Up @@ -646,6 +668,8 @@ where
return Ok(CacheMetadata {
revision: cache_revision,
sha256: locked_sha256,
md5: None,
size: None,
path: path_inner,
index_json: None,
paths_json: None,
Expand All @@ -668,6 +692,8 @@ where
return Ok(CacheMetadata {
revision: cache_revision,
sha256: locked_sha256,
md5: None,
size: None,
path,
index_json: Some(index_json),
paths_json: Some(paths_json),
Expand Down Expand Up @@ -770,6 +796,8 @@ where
Ok(CacheMetadata {
revision: new_revision,
sha256: given_sha.copied(),
md5: None,
size: None,
path,
index_json: None,
paths_json: None,
Expand Down
41 changes: 25 additions & 16 deletions crates/rattler_repodata_gateway/src/gateway/direct_url_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,18 +57,22 @@ impl DirectUrlQuery {
/// Execute the Repodata query using the cache as a source for the
/// index.json
pub async fn execute(self) -> Result<Vec<Arc<RepoDataRecord>>, DirectUrlQueryError> {
let (index_json, archive_type): (IndexJson, CondaArchiveType) = if let Ok(file_path) =
self.url.to_file_path()
{
let (index_json, archive_type, sha256, md5, size): (
IndexJson,
CondaArchiveType,
Option<Sha256Hash>,
Option<Md5Hash>,
Option<u64>,
) = if let Ok(file_path) = self.url.to_file_path() {
// Determine the type of the archive
let Some(archive_type) = CondaArchiveType::try_from(&file_path) else {
return Err(DirectUrlQueryError::InvalidFilename(
file_path.display().to_string(),
));
};

match rattler_package_streaming::seek::read_package_file(&file_path) {
Ok(index_json) => (index_json, archive_type),
let index_json = match rattler_package_streaming::seek::read_package_file(&file_path) {
Ok(index_json) => index_json,
Err(ExtractError::IoError(io)) => return Err(DirectUrlQueryError::IndexJson(io)),
Err(ExtractError::UnsupportedArchiveType) => {
return Err(DirectUrlQueryError::InvalidFilename(
Expand All @@ -80,7 +84,12 @@ impl DirectUrlQuery {
e.to_string(),
)));
}
}
};

// For local files, compute size from file metadata.
let size = std::fs::metadata(&file_path).ok().map(|m| m.len());

(index_json, archive_type, self.sha256, self.md5, size)
} else {
// Convert the url to an archive identifier.
let Some(archive_identifier) = CondaArchiveIdentifier::try_from_url(&self.url) else {
Expand Down Expand Up @@ -110,10 +119,15 @@ impl DirectUrlQuery {
.await?;

// Extract package record from index json
(
IndexJson::from_package_directory(cache_lock.path())?,
archive_type,
)
let index_json = IndexJson::from_package_directory(cache_lock.path())?;

// Use the sha256/md5/size from the extract result if available,
// falling back to the values provided by the caller.
let sha256 = cache_lock.sha256().copied().or(self.sha256);
let md5 = cache_lock.md5().copied().or(self.md5);
let size = cache_lock.size();

(index_json, archive_type, sha256, md5, size)
};

let identifier = DistArchiveIdentifier::try_from_url(&self.url).unwrap_or_else(|| {
Expand All @@ -127,12 +141,7 @@ impl DirectUrlQuery {
}
});

let package_record = PackageRecord::from_index_json(
index_json,
None, // size is unknown for direct urls
self.sha256,
self.md5,
)?;
let package_record = PackageRecord::from_index_json(index_json, size, sha256, md5)?;

tracing::debug!("Package record build from direct url: {:?}", package_record);

Expand Down
Loading