Skip to main content

tame_index/
error.rs

1//! Provides the various error types for this crate
2
3#[cfg(feature = "local")]
4pub use crate::index::local::LocalRegistryError;
5
6/// The core error type for this library
7#[derive(Debug, thiserror::Error)]
8pub enum Error {
9    /// Failed to deserialize a local cache entry
10    #[error(transparent)]
11    Cache(#[from] CacheError),
12    /// This library assumes utf-8 paths in all cases, a path was provided that
13    /// was not valid utf-8
14    #[error("unable to use non-utf8 path {:?}", .0)]
15    NonUtf8Path(std::path::PathBuf),
16    /// An environment variable was located, but had a non-utf8 value
17    #[error("environment variable {} has a non-utf8 value", .0)]
18    NonUtf8EnvVar(std::borrow::Cow<'static, str>),
19    /// A user-provided string was not a valid crate name
20    #[error(transparent)]
21    InvalidKrateName(#[from] InvalidKrateName),
22    /// The user specified a registry name that did not exist in any searched
23    /// .cargo/config.toml
24    #[error("registry '{}' was not located in any .cargo/config.toml", .0)]
25    UnknownRegistry(String),
26    /// An I/O error
27    #[error(transparent)]
28    Io(#[from] std::io::Error),
29    /// An I/O error occurred trying to access a specific path
30    #[error("I/O operation failed for path '{}': {}", .1, .0)]
31    IoPath(#[source] std::io::Error, crate::PathBuf),
32    /// A user provided URL was invalid
33    #[error(transparent)]
34    InvalidUrl(#[from] InvalidUrl),
35    /// Failed to de/serialize JSON
36    #[error(transparent)]
37    Json(#[from] serde_json::Error),
38    /// Failed to deserialize TOML
39    #[error(transparent)]
40    Toml(#[from] Box<toml_span::Error>),
41    /// An index entry did not contain any versions
42    #[error("index entry contained no versions for the crate")]
43    NoCrateVersions,
44    /// Failed to handle an HTTP response or request
45    #[error(transparent)]
46    Http(#[from] HttpError),
47    /// Failed to parse a semver version or requirement
48    #[error(transparent)]
49    Semver(#[from] semver::Error),
50    /// A local registry is invalid
51    #[cfg(feature = "local")]
52    #[error(transparent)]
53    Local(#[from] LocalRegistryError),
54    /// Failed to lock a file
55    #[error(transparent)]
56    Lock(#[from] crate::utils::flock::FileLockError),
57}
58
59impl From<std::path::PathBuf> for Error {
60    fn from(p: std::path::PathBuf) -> Self {
61        Self::NonUtf8Path(p)
62    }
63}
64
65/// Various kinds of reserved names disallowed by cargo
66#[derive(Debug, Copy, Clone)]
67pub enum ReservedNameKind {
68    /// The name is a Rust keyword
69    Keyword,
70    /// The name conflicts with a cargo artifact directory
71    Artifact,
72    /// The name has a special meaning on Windows
73    Windows,
74    /// The name conflicts with a Rust std library name
75    Standard,
76}
77
78impl std::fmt::Display for ReservedNameKind {
79    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80        match self {
81            Self::Keyword => f.write_str("rustlang keyword"),
82            Self::Artifact => f.write_str("cargo artifact"),
83            Self::Windows => f.write_str("windows reserved"),
84            Self::Standard => f.write_str("rustlang std library"),
85        }
86    }
87}
88
89/// Errors that can occur when validating a crate name
90#[derive(Debug, thiserror::Error)]
91pub enum InvalidKrateName {
92    /// The name had an invalid length
93    #[error("crate name had an invalid length of '{0}'")]
94    InvalidLength(usize),
95    /// The name contained an invalid character
96    #[error("invalid character '{invalid}` @ {index}")]
97    InvalidCharacter {
98        /// The invalid character
99        invalid: char,
100        /// The index of the character in the provided string
101        index: usize,
102    },
103    /// The name was one of the reserved names disallowed by cargo
104    #[error("the name '{reserved}' is reserved as '{kind}`")]
105    ReservedName {
106        /// The name that was reserved
107        reserved: &'static str,
108        /// The kind of the reserved name
109        kind: ReservedNameKind,
110    },
111}
112
113/// An error pertaining to a bad URL provided to the API
114#[derive(Debug, thiserror::Error)]
115#[error("the url '{url}' is invalid")]
116pub struct InvalidUrl {
117    /// The invalid url
118    pub url: String,
119    /// The reason it is invalid
120    pub source: InvalidUrlError,
121}
122
123/// The specific reason for the why the URL is invalid
124#[derive(Debug, thiserror::Error)]
125pub enum InvalidUrlError {
126    /// Sparse HTTP registry urls must be of the form `sparse+http(s)://`
127    #[error("sparse indices require the use of a url that starts with `sparse+http`")]
128    MissingSparse,
129    /// The `<modifier>+<scheme>://` is not supported
130    #[error("the scheme modifier is unknown")]
131    UnknownSchemeModifier,
132    /// Unable to find the `<scheme>://`
133    #[error("the scheme is missing")]
134    MissingScheme,
135    /// Attempted to construct a git index with a sparse URL
136    #[error("attempted to create a git index for a sparse URL")]
137    SparseForGit,
138}
139
140/// Errors related to a local index cache
141#[derive(Debug, thiserror::Error)]
142pub enum CacheError {
143    /// The cache entry is malformed
144    #[error("the cache entry is malformed")]
145    InvalidCacheEntry,
146    /// The cache version is old
147    #[error("the cache entry is an old, unsupported version")]
148    OutdatedCacheVersion,
149    /// The cache version is newer than the version supported by this crate
150    #[error("the cache entry is an unknown version, possibly written by a newer cargo version")]
151    UnknownCacheVersion,
152    /// The index version is newer than the version supported by this crate
153    #[error(
154        "the cache entry's index version is unknown, possibly written by a newer cargo version"
155    )]
156    UnknownIndexVersion,
157    /// The revision in the cache entry did match the requested revision
158    ///
159    /// This can occur when a git index is fetched and a newer revision is pulled
160    /// from the remote index, invalidating all local cache entries
161    #[error("the cache entry's revision does not match the current revision")]
162    OutdatedRevision,
163    /// A crate version in the cache file was malformed
164    #[error("a specific version in the cache entry is malformed")]
165    InvalidCrateVersion,
166}
167
168/// Errors related to HTTP requests or responses
169#[derive(Debug, thiserror::Error)]
170pub enum HttpError {
171    /// A [`reqwest::Error`]
172    #[cfg(any(feature = "sparse", feature = "local-builder"))]
173    #[error(transparent)]
174    Reqwest(#[from] reqwest::Error),
175    /// A status code was received that indicates user error, or possibly a
176    /// remote index that does not follow the protocol supported by this crate
177    #[error("status code '{code}': {msg}")]
178    StatusCode {
179        /// The status code
180        code: http::StatusCode,
181        /// The reason the status code raised an error
182        msg: &'static str,
183    },
184    /// A [`http::Error`]
185    #[error(transparent)]
186    Http(#[from] http::Error),
187    /// A string could not be parsed as a valid header value
188    #[error(transparent)]
189    InvalidHeaderValue(#[from] http::header::InvalidHeaderValue),
190    /// Unable to complete an async request for an `AsyncRemoteSparseIndex` within
191    /// the user allotted time
192    #[error("request could not be completed in the allotted timeframe")]
193    Timeout,
194}