diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-02-21 16:59:31 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-02-21 16:59:31 +0900 |
| commit | 261c3996805bcdfb7ff271290f3e3557dd15cea7 (patch) | |
| tree | cc701824713b792729bb29f40181698efc387104 /crates/mozart/src/downloader.rs | |
| parent | 3535037592f149477c915a8b66da974eb59586db (diff) | |
| download | php-mozart-261c3996805bcdfb7ff271290f3e3557dd15cea7.tar.gz php-mozart-261c3996805bcdfb7ff271290f3e3557dd15cea7.tar.zst php-mozart-261c3996805bcdfb7ff271290f3e3557dd15cea7.zip | |
feat(cache): add filesystem-backed cache with TTL expiration and size-limited GC
Implement a cache module with CacheConfig and Cache structs supporting
read/write (string and binary), atomic writes via temp+rename, TTL-based
expiration, and size-limited garbage collection. Wire the repo cache into
packagist.rs and resolver.rs for API response caching, and the files
cache into downloader.rs for dist archive caching. Implement the
clear-cache command with full clear and --gc modes. All existing call
sites pass None for backward compatibility.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'crates/mozart/src/downloader.rs')
| -rw-r--r-- | crates/mozart/src/downloader.rs | 36 |
1 files changed, 35 insertions, 1 deletions
diff --git a/crates/mozart/src/downloader.rs b/crates/mozart/src/downloader.rs index e7ded03..cfed951 100644 --- a/crates/mozart/src/downloader.rs +++ b/crates/mozart/src/downloader.rs @@ -1,3 +1,4 @@ +use crate::cache::Cache; use sha1::{Digest, Sha1}; use std::collections::HashSet; use std::fs; @@ -76,11 +77,37 @@ impl DownloadProgress { /// If `expected_shasum` is provided and non-empty, verifies SHA-1 of the downloaded bytes. /// If `progress` is provided, increments it as bytes are received and sets the total from /// the `Content-Length` response header. +/// If `files_cache` is provided, the downloaded bytes are cached by URL; cache hits skip +/// the network request entirely. pub fn download_dist( url: &str, expected_shasum: Option<&str>, progress: Option<&mut DownloadProgress>, + files_cache: Option<&Cache>, ) -> anyhow::Result<Vec<u8>> { + // Build a cache key from the URL + let cache_key = Cache::sanitize_key(url); + + // Check cache first + if let Some(cache) = files_cache + && let Some(cached_bytes) = cache.read_bytes(&cache_key) + { + // Verify checksum against cache hit if provided + if let Some(shasum) = expected_shasum + && !shasum.is_empty() + { + let mut hasher = Sha1::new(); + hasher.update(&cached_bytes); + let computed = format!("{:x}", hasher.finalize()); + if computed == shasum { + return Ok(cached_bytes); + } + // Checksum mismatch — discard cache, re-download + } else { + return Ok(cached_bytes); + } + } + let response = reqwest::blocking::get(url)?; if !response.status().is_success() { @@ -126,6 +153,11 @@ pub fn download_dist( } } + // Write to cache + if let Some(cache) = files_cache { + let _ = cache.write_bytes(&cache_key, &bytes); + } + Ok(bytes) } @@ -292,6 +324,7 @@ pub fn extract_tar_gz(data: &[u8], target_dir: &Path) -> anyhow::Result<()> { /// - `vendor_dir`: path to `vendor/` directory /// - `package_name`: e.g. `"monolog/monolog"` /// - `progress`: optional mutable progress tracker to update during download +/// - `files_cache`: optional files cache; if provided, the archive bytes are cached by URL pub fn install_package( dist_url: &str, dist_type: &str, @@ -299,6 +332,7 @@ pub fn install_package( vendor_dir: &Path, package_name: &str, progress: Option<&mut DownloadProgress>, + files_cache: Option<&Cache>, ) -> anyhow::Result<()> { let target = vendor_dir.join(package_name); @@ -308,7 +342,7 @@ pub fn install_package( } fs::create_dir_all(&target)?; - let bytes = download_dist(dist_url, dist_shasum, progress)?; + let bytes = download_dist(dist_url, dist_shasum, progress, files_cache)?; match dist_type { "zip" => extract_zip(&bytes, &target)?, |
