diff --git a/CHANGELOG.md b/CHANGELOG.md index 95f506e..017d187 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] - ReleaseDate +### Fixed +- [PR#18](https://github.com/EmbarkStudios/tame-index/pull/18) resolved [#16](https://github.com/EmbarkStudios/tame-index/issues/16) by marking `ComboIndexCache` and `ComboIndex` as `#[non_exhaustive]`. This avoids build breaks if the `local` feature is enabled in one transitive dependency and not in another, as much as I hate `non_exhaustive`. + +### Changed +- [PR#18](https://github.com/EmbarkStudios/tame-index/pull/18) changed `SparseIndex::make_remote_request` to take an optional [ETag](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag), completely avoiding disk I/O, which allows `SparseIndex` to be used for making and parsing requests without worrying about cargo's global package lock. + ## [0.4.1] - 2023-08-21 ### Added - [PR#15](https://github.com/EmbarkStudios/tame-index/pull/15) added the `native-certs` feature to be able to use the OS certificate store instead of `webpki-roots`. Thanks [@Shnatsel](https://github.com/Shnatsel)! diff --git a/Cargo.toml b/Cargo.toml index 5735d38..ac45688 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,7 +59,7 @@ twox-hash = { version = "1.6", default-features = false } [dependencies.gix] optional = true -version = "0.51" +version = "0.52" default-features = false features = [ "max-performance-safe", diff --git a/deny.toml b/deny.toml index 1a34175..66866ac 100644 --- a/deny.toml +++ b/deny.toml @@ -46,20 +46,14 @@ deny = [{ name = "openssl" }, { name = "curl" }] skip = [ # several users of this old version { name = "bitflags", version = "=1.3.2" }, - # tempfile uses an old version - { name = "fastrand", version = "=1.9.0" }, # imara-diff uses an old version { name = "hashbrown", version = "=0.12.3" }, - # trust-dns-proto uses an old version - { name = "idna", version = "=0.2.3" }, # toml-edit is user a newer version :p { name = "indexmap", version = "=1.9.3" }, # trust-dns-resolver pulls in a new version than the rest of them use (including itself) { name = "socket2", version = "=0.4.9" }, # A bunch of users still of syn 1.0 :p { name = "syn", version = "=1.0.109" }, - # Reqwest depends on 2 versions :p - { name = "winreg", version = "=0.10.1" }, ] skip-tree = [] diff --git a/src/error.rs b/src/error.rs index 44acfa4..6e3a4f0 100644 --- a/src/error.rs +++ b/src/error.rs @@ -180,6 +180,9 @@ pub enum HttpError { /// A [`http::Error`] #[error(transparent)] Http(#[from] http::Error), + /// A string could not be parsed as a valid header value + #[error(transparent)] + InvalidHeaderValue(#[from] http::header::InvalidHeaderValue), /// Unable to complete an async request for an `AsyncRemoteSparseIndex` within /// the user allotted time #[error("request could not be completed in the allotted timeframe")] diff --git a/src/index.rs b/src/index.rs index 9bb3300..d00229e 100644 --- a/src/index.rs +++ b/src/index.rs @@ -101,6 +101,7 @@ impl IndexConfig { use crate::Error; /// Provides simpler access to the cache for an index, regardless of the registry kind +#[non_exhaustive] pub enum ComboIndexCache { /// A git index Git(GitIndex), diff --git a/src/index/combo.rs b/src/index/combo.rs index d412172..58595cd 100644 --- a/src/index/combo.rs +++ b/src/index/combo.rs @@ -6,6 +6,7 @@ use crate::{ }; /// A wrapper around either a [`RemoteGitIndex`] or [`RemoteSparseIndex`] +#[non_exhaustive] pub enum ComboIndex { /// A standard git based registry index. No longer the default for crates.io /// as of 1.70.0 diff --git a/src/index/sparse.rs b/src/index/sparse.rs index a64e0aa..50f5c08 100644 --- a/src/index/sparse.rs +++ b/src/index/sparse.rs @@ -79,6 +79,10 @@ impl SparseIndex { /// Creates an HTTP request that can be sent via your HTTP client of choice /// to retrieve the current metadata for the specified crate /// + /// If specified, the etag is used instead of the possible etag stored in + /// a local cache entry, resulting in no disk I/O being performed by this + /// method + /// /// See [`Self::parse_remote_response`] processing the response from the remote /// index /// @@ -87,6 +91,7 @@ impl SparseIndex { pub fn make_remote_request( &self, name: KrateName<'_>, + etag: Option<&str>, ) -> Result, Error> { use http::header; @@ -145,7 +150,15 @@ impl SparseIndex { None }; - let _ = set_cache_version(headers); + if let Some(etag) = etag { + let hv = + header::HeaderValue::from_str(etag.trim()).map_err(crate::HttpError::from)?; + headers.insert(header::IF_NONE_MATCH, hv); + } else { + // Use the etag (or last modified, though crates.io does not use this AFAICT) + // from the cache entry if it exists + let _ = set_cache_version(headers); + } } const EMPTY: &[u8] = &[]; diff --git a/src/index/sparse_remote.rs b/src/index/sparse_remote.rs index 73af057..d4fb6c8 100644 --- a/src/index/sparse_remote.rs +++ b/src/index/sparse_remote.rs @@ -31,7 +31,7 @@ impl RemoteSparseIndex { name: KrateName<'_>, write_cache_entry: bool, ) -> Result, Error> { - let req = self.index.make_remote_request(name)?; + let req = self.index.make_remote_request(name, None)?; let req = req.try_into()?; let res = self.client.execute(req)?; @@ -109,7 +109,7 @@ impl AsyncRemoteSparseIndex { name: KrateName<'_>, write_cache_entry: bool, ) -> Result, Error> { - let req = self.index.make_remote_request(name)?.try_into()?; + let req = self.index.make_remote_request(name, None)?.try_into()?; let res = Self::exec_request(&self.client, req).await?; self.index @@ -181,7 +181,7 @@ impl AsyncRemoteSparseIndex { match kname .as_str() .try_into() - .and_then(|name| Ok(self.index.make_remote_request(name)?.try_into()?)) + .and_then(|name| Ok(self.index.make_remote_request(name, None)?.try_into()?)) { Ok(req) => { let client = self.client.clone(); diff --git a/src/lib.rs b/src/lib.rs index 52887fd..2c76ea5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] #![doc = include_str!("../README.md")] pub mod error; diff --git a/tests/sparse.rs b/tests/sparse.rs index 13095be..0bc1a6c 100644 --- a/tests/sparse.rs +++ b/tests/sparse.rs @@ -29,7 +29,7 @@ fn make_request_without_cache() { let index = crates_io(env!("CARGO_MANIFEST_DIR")); let req = index - .make_remote_request("serde".try_into().unwrap()) + .make_remote_request("serde".try_into().unwrap(), None) .unwrap(); let hdrs = req.headers(); @@ -61,7 +61,15 @@ fn make_request_with_cache() { .unwrap(); let req = index - .make_remote_request("etag-krate".try_into().unwrap()) + .make_remote_request("etag-krate".try_into().unwrap(), None) + .unwrap(); + + assert_eq!(req.headers().get(header::IF_NONE_MATCH).unwrap(), ETAG); + } + + { + let req = index + .make_remote_request("etag-specified-krate".try_into().unwrap(), Some(ETAG)) .unwrap(); assert_eq!(req.headers().get(header::IF_NONE_MATCH).unwrap(), ETAG); @@ -78,7 +86,7 @@ fn make_request_with_cache() { .unwrap(); let req = index - .make_remote_request("modified-krate".try_into().unwrap()) + .make_remote_request("modified-krate".try_into().unwrap(), None) .unwrap(); assert_eq!(req.headers().get(header::IF_MODIFIED_SINCE).unwrap(), DATE);