diff --git a/crates/rattler-bin/src/commands/create.rs b/crates/rattler-bin/src/commands/create.rs index 73bad476a..7ab8e7fd0 100644 --- a/crates/rattler-bin/src/commands/create.rs +++ b/crates/rattler-bin/src/commands/create.rs @@ -21,7 +21,7 @@ use rattler_conda_types::{ Channel, ChannelConfig, GenericVirtualPackage, MatchSpec, ParseStrictness, Platform, PrefixRecord, RepoDataRecord, Version, }; -use rattler_networking::{AuthenticationMiddleware, AuthenticationStorage}; +use rattler_networking::AuthenticationMiddleware; use rattler_repodata_gateway::{Gateway, RepoData, SourceConfig}; use rattler_solve::{ libsolv_c::{self}, @@ -147,11 +147,8 @@ pub async fn create(opt: Opt) -> anyhow::Result<()> { .build() .expect("failed to create client"); - let authentication_storage = AuthenticationStorage::default(); let download_client = reqwest_middleware::ClientBuilder::new(download_client) - .with_arc(Arc::new(AuthenticationMiddleware::new( - authentication_storage, - ))) + .with_arc(Arc::new(AuthenticationMiddleware::from_env_and_defaults()?)) .with(rattler_networking::OciMiddleware) .with(rattler_networking::GCSMiddleware) .build(); diff --git a/crates/rattler/src/cli/auth.rs b/crates/rattler/src/cli/auth.rs index 0873e8741..da7830211 100644 --- a/crates/rattler/src/cli/auth.rs +++ b/crates/rattler/src/cli/auth.rs @@ -1,6 +1,8 @@ //! This module contains CLI common entrypoint for authentication. use clap::Parser; -use rattler_networking::{Authentication, AuthenticationStorage}; +use rattler_networking::{ + authentication_storage::backends::file::FileStorageError, Authentication, AuthenticationStorage, +}; use thiserror; /// Command line arguments that contain authentication data @@ -71,6 +73,11 @@ pub enum AuthenticationCLIError { #[error("Authentication with anaconda.org requires a conda token. Use `--conda-token` to provide one")] AnacondaOrgBadMethod, + /// Wrapper for errors that are generated from the underlying storage system + /// (keyring or file system) + #[error("Failed to initialize the authentication storage system")] + InitializeStorageError(#[source] FileStorageError), + /// Wrapper for errors that are generated from the underlying storage system /// (keyring or file system) #[error("Failed to interact with the authentication storage system")] @@ -141,7 +148,8 @@ fn logout(args: LogoutArgs, storage: AuthenticationStorage) -> Result<(), Authen /// CLI entrypoint for authentication pub async fn execute(args: Args) -> Result<(), AuthenticationCLIError> { - let storage = AuthenticationStorage::default(); + let storage = AuthenticationStorage::from_env_and_defaults() + .map_err(AuthenticationCLIError::InitializeStorageError)?; match args.subcommand { Subcommand::Login(args) => login(args, storage), diff --git a/crates/rattler_networking/Cargo.toml b/crates/rattler_networking/Cargo.toml index 2c61af948..1e36bd80e 100644 --- a/crates/rattler_networking/Cargo.toml +++ b/crates/rattler_networking/Cargo.toml @@ -18,11 +18,11 @@ gcs = ["google-cloud-auth", "google-cloud-token"] [dependencies] anyhow = { workspace = true } +async-fd-lock = { workspace = true } async-trait = { workspace = true } base64 = { workspace = true } chrono = { workspace = true } dirs = { workspace = true } -fslock = { workspace = true } google-cloud-auth = { workspace = true, optional = true } google-cloud-token = { workspace = true, optional = true } http = { workspace = true } diff --git a/crates/rattler_networking/src/authentication_middleware.rs b/crates/rattler_networking/src/authentication_middleware.rs index 25e2a3af4..6fdf4ad7d 100644 --- a/crates/rattler_networking/src/authentication_middleware.rs +++ b/crates/rattler_networking/src/authentication_middleware.rs @@ -1,4 +1,5 @@ //! `reqwest` middleware that authenticates requests with data from the `AuthenticationStorage` +use crate::authentication_storage::backends::file::FileStorageError; use crate::{Authentication, AuthenticationStorage}; use async_trait::async_trait; use base64::prelude::BASE64_STANDARD; @@ -10,7 +11,7 @@ use std::sync::OnceLock; use url::Url; /// `reqwest` middleware to authenticate requests -#[derive(Clone, Default)] +#[derive(Clone)] pub struct AuthenticationMiddleware { auth_storage: AuthenticationStorage, } @@ -49,10 +50,17 @@ impl Middleware for AuthenticationMiddleware { impl AuthenticationMiddleware { /// Create a new authentication middleware with the given authentication storage - pub fn new(auth_storage: AuthenticationStorage) -> Self { + pub fn from_auth_storage(auth_storage: AuthenticationStorage) -> Self { Self { auth_storage } } + /// Create a new authentication middleware with the default authentication storage + pub fn from_env_and_defaults() -> Result { + Ok(Self { + auth_storage: AuthenticationStorage::from_env_and_defaults()?, + }) + } + /// Authenticate the given URL with the given authentication information fn authenticate_url(url: Url, auth: &Option) -> Url { if let Some(credentials) = auth { @@ -166,7 +174,9 @@ mod tests { ) { let (captured_tx, captured_rx) = tokio::sync::mpsc::channel(1); let client = reqwest_middleware::ClientBuilder::new(reqwest::Client::default()) - .with_arc(Arc::new(AuthenticationMiddleware::new(storage.clone()))) + .with_arc(Arc::new(AuthenticationMiddleware::from_auth_storage( + storage.clone(), + ))) .with_arc(Arc::new(CaptureAbortMiddleware { captured_tx })) .build(); @@ -176,8 +186,8 @@ mod tests { #[test] fn test_store_fallback() -> anyhow::Result<()> { let tdir = tempdir()?; - let mut storage = AuthenticationStorage::new(); - storage.add_backend(Arc::from(FileStorage::new( + let mut storage = AuthenticationStorage::empty(); + storage.add_backend(Arc::from(FileStorage::from_path( tdir.path().to_path_buf().join("auth.json"), )?)); @@ -191,8 +201,8 @@ mod tests { #[tokio::test] async fn test_conda_token_storage() -> anyhow::Result<()> { let tdir = tempdir()?; - let mut storage = AuthenticationStorage::new(); - storage.add_backend(Arc::from(FileStorage::new( + let mut storage = AuthenticationStorage::empty(); + storage.add_backend(Arc::from(FileStorage::from_path( tdir.path().to_path_buf().join("auth.json"), )?)); @@ -245,8 +255,8 @@ mod tests { #[tokio::test] async fn test_bearer_storage() -> anyhow::Result<()> { let tdir = tempdir()?; - let mut storage = AuthenticationStorage::new(); - storage.add_backend(Arc::from(FileStorage::new( + let mut storage = AuthenticationStorage::empty(); + storage.add_backend(Arc::from(FileStorage::from_path( tdir.path().to_path_buf().join("auth.json"), )?)); let host = "bearer.example.com"; @@ -305,8 +315,8 @@ mod tests { #[tokio::test] async fn test_basic_auth_storage() -> anyhow::Result<()> { let tdir = tempdir()?; - let mut storage = AuthenticationStorage::new(); - storage.add_backend(Arc::from(FileStorage::new( + let mut storage = AuthenticationStorage::empty(); + storage.add_backend(Arc::from(FileStorage::from_path( tdir.path().to_path_buf().join("auth.json"), )?)); let host = "basic.example.com"; @@ -383,8 +393,8 @@ mod tests { ("*.com", false), ] { let tdir = tempdir()?; - let mut storage = AuthenticationStorage::new(); - storage.add_backend(Arc::from(FileStorage::new( + let mut storage = AuthenticationStorage::empty(); + storage.add_backend(Arc::from(FileStorage::from_path( tdir.path().to_path_buf().join("auth.json"), )?)); @@ -418,7 +428,7 @@ mod tests { .to_str() .unwrap(), ), - || AuthenticationStorage::from_env().unwrap(), + || AuthenticationStorage::from_env_and_defaults().unwrap(), ); let host = "test.example.com"; diff --git a/crates/rattler_networking/src/authentication_storage/backends/file.rs b/crates/rattler_networking/src/authentication_storage/backends/file.rs index 1a661e966..c213945f5 100644 --- a/crates/rattler_networking/src/authentication_storage/backends/file.rs +++ b/crates/rattler_networking/src/authentication_storage/backends/file.rs @@ -1,17 +1,21 @@ //! file storage for passwords. use anyhow::Result; -use fslock::LockFile; +use async_fd_lock::{ + blocking::{LockRead, LockWrite}, + RwLockWriteGuard, +}; use std::collections::BTreeMap; +use std::fs::File; use std::path::Path; -use std::sync::Arc; -use std::{path::PathBuf, sync::Mutex}; +use std::path::PathBuf; +use std::sync::{Arc, RwLock}; use crate::authentication_storage::StorageBackend; use crate::Authentication; #[derive(Clone, Debug)] struct FileStorageCache { - cache: BTreeMap, + content: BTreeMap, file_exists: bool, } @@ -25,7 +29,7 @@ pub struct FileStorage { /// The cache of the file storage /// This is used to avoid reading the file from disk every time /// a credential is accessed - cache: Arc>, + cache: Arc>, } /// An error that can occur when accessing the file storage @@ -36,86 +40,80 @@ pub enum FileStorageError { IOError(#[from] std::io::Error), /// Failed to lock the file storage file - #[error("failed to lock file storage file {0}")] - FailedToLock(String, #[source] std::io::Error), + #[error("failed to lock file storage file: {0:?}")] + FailedToLock(async_fd_lock::LockError), /// An error occurred when (de)serializing the credentials #[error("JSON error: {0}")] JSONError(#[from] serde_json::Error), } -/// Lock the file storage file for reading and writing. This will block until the lock is -/// acquired. -fn lock_file_storage(path: &Path, write: bool) -> Result, FileStorageError> { - if !write && !path.exists() { - return Ok(None); - } - - std::fs::create_dir_all(path.parent().unwrap())?; - let path = path.with_extension("lock"); - let mut lock = fslock::LockFile::open(&path) - .map_err(|e| FileStorageError::FailedToLock(path.to_string_lossy().into_owned(), e))?; - - // First try to lock the file without block. If we can't immediately get the lock we block and issue a debug message. - if !lock - .try_lock_with_pid() - .map_err(|e| FileStorageError::FailedToLock(path.to_string_lossy().into_owned(), e))? - { - tracing::debug!("waiting for lock on {}", path.to_string_lossy()); - lock.lock_with_pid() - .map_err(|e| FileStorageError::FailedToLock(path.to_string_lossy().into_owned(), e))?; - } - - Ok(Some(lock)) -} - impl FileStorageCache { pub fn from_path(path: &Path) -> Result { let file_exists = path.exists(); - let cache = if file_exists { - lock_file_storage(path, false)?; - let file = std::fs::File::open(path)?; - let reader = std::io::BufReader::new(file); - serde_json::from_reader(reader)? + let content = if file_exists { + let read_guard = File::options() + .read(true) + .open(path)? + .lock_read() + .map_err(FileStorageError::FailedToLock)?; + serde_json::from_reader(read_guard)? } else { BTreeMap::new() }; - Ok(Self { cache, file_exists }) + Ok(Self { + content, + file_exists, + }) } } impl FileStorage { /// Create a new file storage with the given path - pub fn new(path: PathBuf) -> Result { + pub fn from_path(path: PathBuf) -> Result { // read the JSON file if it exists, and store it in the cache - let cache = Arc::new(Mutex::new(FileStorageCache::from_path(&path)?)); + let cache = Arc::new(RwLock::new(FileStorageCache::from_path(&path)?)); Ok(Self { path, cache }) } - /// Read the JSON file and deserialize it into a `BTreeMap`, or return an empty `BTreeMap` if the + /// Create a new file storage with the default path + pub fn new() -> Result { + let path = dirs::home_dir() + .unwrap() + .join(".rattler") + .join("credentials.json"); + Self::from_path(path) + } + + /// Updates the cache by reading the JSON file and deserializing it into a `BTreeMap`, or return an empty `BTreeMap` if the /// file does not exist fn read_json(&self) -> Result, FileStorageError> { let new_cache = FileStorageCache::from_path(&self.path)?; - let mut cache = self.cache.lock().unwrap(); - cache.cache = new_cache.cache; + let mut cache = self.cache.write().unwrap(); + cache.content = new_cache.content; cache.file_exists = new_cache.file_exists; - - Ok(cache.cache.clone()) + Ok(cache.content.clone()) } /// Serialize the given `BTreeMap` and write it to the JSON file fn write_json(&self, dict: &BTreeMap) -> Result<(), FileStorageError> { - let _lock = lock_file_storage(&self.path, true)?; - - let file = std::fs::File::create(&self.path)?; - let writer = std::io::BufWriter::new(file); - serde_json::to_writer(writer, dict)?; + let write_guard: std::result::Result< + RwLockWriteGuard, + async_fd_lock::LockError, + > = File::options() + .create(true) + .write(true) + .truncate(true) + .open(&self.path)? + .lock_write(); + let write_guard = write_guard.map_err(FileStorageError::FailedToLock)?; + serde_json::to_writer(write_guard, dict)?; // Store the new data in the cache - let mut cache = self.cache.lock().unwrap(); - cache.cache = dict.clone(); + let mut cache = self.cache.write().unwrap(); + cache.content = dict.clone(); cache.file_exists = true; Ok(()) @@ -130,8 +128,8 @@ impl StorageBackend for FileStorage { } fn get(&self, host: &str) -> Result> { - let cache = self.cache.lock().unwrap(); - Ok(cache.cache.get(host).cloned()) + let cache = self.cache.read().unwrap(); + Ok(cache.content.get(host).cloned()) } fn delete(&self, host: &str) -> Result<()> { @@ -144,21 +142,6 @@ impl StorageBackend for FileStorage { } } -impl Default for FileStorage { - fn default() -> Self { - let mut path = dirs::home_dir().unwrap(); - path.push(".rattler"); - path.push("credentials.json"); - Self::new(path.clone()).unwrap_or(Self { - path, - cache: Arc::new(Mutex::new(FileStorageCache { - cache: BTreeMap::new(), - file_exists: false, - })), - }) - } -} - #[cfg(test)] mod tests { use super::*; @@ -171,7 +154,7 @@ mod tests { let file = tempdir().unwrap(); let path = file.path().join("test.json"); - let storage = FileStorage::new(path.clone()).unwrap(); + let storage = FileStorage::from_path(path.clone()).unwrap(); assert_eq!(storage.get("test").unwrap(), None); @@ -207,6 +190,6 @@ mod tests { let mut file = std::fs::File::create(&path).unwrap(); file.write_all(b"invalid json").unwrap(); - assert!(FileStorage::new(path.clone()).is_err()); + assert!(FileStorage::from_path(path.clone()).is_err()); } } diff --git a/crates/rattler_networking/src/authentication_storage/storage.rs b/crates/rattler_networking/src/authentication_storage/storage.rs index 12a983ced..92054b50c 100644 --- a/crates/rattler_networking/src/authentication_storage/storage.rs +++ b/crates/rattler_networking/src/authentication_storage/storage.rs @@ -10,7 +10,11 @@ use url::Url; use super::{ authentication::Authentication, - backends::{file::FileStorage, keyring::KeyringAuthenticationStorage, netrc::NetRcStorage}, + backends::{ + file::{FileStorage, FileStorageError}, + keyring::KeyringAuthenticationStorage, + netrc::NetRcStorage, + }, StorageBackend, }; @@ -21,30 +25,14 @@ use super::{ /// Credentials are stored and retrieved from the backends in the /// order they are added to the storage pub struct AuthenticationStorage { - backends: Vec>, + /// Authentication backends + pub backends: Vec>, cache: Arc>>>, } -impl Default for AuthenticationStorage { - fn default() -> Self { - let mut storage = Self::new(); - - storage.add_backend(Arc::from(KeyringAuthenticationStorage::default())); - storage.add_backend(Arc::from(FileStorage::default())); - storage.add_backend(Arc::from(NetRcStorage::from_env().unwrap_or_else( - |(path, err)| { - tracing::warn!("error reading netrc file from {}: {}", path.display(), err); - NetRcStorage::default() - }, - ))); - - storage - } -} - impl AuthenticationStorage { /// Create a new authentication storage with no backends - pub fn new() -> Self { + pub fn empty() -> Self { Self { backends: vec![], cache: Arc::new(Mutex::new(HashMap::new())), @@ -52,36 +40,31 @@ impl AuthenticationStorage { } /// Create a new authentication storage with the default backends - /// respecting the `RATTLER_AUTH_FILE` environment variable. - /// If the variable is set, the file storage backend will be used - /// with the path specified in the variable - pub fn from_env() -> Result { + /// Following order: + /// - file storage from `RATTLER_AUTH_FILE` (if set) + /// - keyring storage + /// - file storage from the default location + /// - netrc storage + pub fn from_env_and_defaults() -> Result { + let mut storage = Self::empty(); + if let Ok(auth_file) = std::env::var("RATTLER_AUTH_FILE") { let path = std::path::Path::new(&auth_file); - tracing::info!( "\"RATTLER_AUTH_FILE\" environment variable set, using file storage at {}", auth_file ); - - Ok(Self::from_file(path)?) - } else { - Ok(Self::default()) + storage.add_backend(Arc::from(FileStorage::from_path(path.into())?)); } - } + storage.add_backend(Arc::from(KeyringAuthenticationStorage::default())); + storage.add_backend(Arc::from(FileStorage::new()?)); + storage.add_backend(Arc::from(NetRcStorage::from_env().unwrap_or_else( + |(path, err)| { + tracing::warn!("error reading netrc file from {}: {}", path.display(), err); + NetRcStorage::default() + }, + ))); - /// Create a new authentication storage with just a file storage backend - pub fn from_file(path: &std::path::Path) -> Result { - let mut storage = Self::new(); - let backend = FileStorage::new(path.to_path_buf()).map_err(|e| { - anyhow!( - "Error creating file storage backend from file ({}): {}", - path.display(), - e - ) - })?; - - storage.add_backend(Arc::from(backend)); Ok(storage) } diff --git a/crates/rattler_repodata_gateway/src/fetch/jlap/mod.rs b/crates/rattler_repodata_gateway/src/fetch/jlap/mod.rs index 3ff546ef2..f89aeb3cc 100644 --- a/crates/rattler_repodata_gateway/src/fetch/jlap/mod.rs +++ b/crates/rattler_repodata_gateway/src/fetch/jlap/mod.rs @@ -30,7 +30,7 @@ //! pub async fn main() { //! let subdir_url = Url::parse("https://conda.anaconda.org/conda-forge/osx-64/").unwrap(); //! let client = reqwest_middleware::ClientBuilder::new(reqwest::Client::new()) -//! .with_arc(Arc::new(AuthenticationMiddleware::default())) +//! .with_arc(Arc::new(AuthenticationMiddleware::from_env_and_defaults().unwrap())) //! .build(); //! let cache = Path::new("./cache"); //! let current_repo_data = cache.join("c93ef9c9.json"); diff --git a/crates/rattler_repodata_gateway/src/fetch/mod.rs b/crates/rattler_repodata_gateway/src/fetch/mod.rs index 1b31fff3f..59e42bf95 100644 --- a/crates/rattler_repodata_gateway/src/fetch/mod.rs +++ b/crates/rattler_repodata_gateway/src/fetch/mod.rs @@ -1472,7 +1472,9 @@ mod test { let client = Client::builder().no_gzip().build().unwrap(); let authenticated_client = reqwest_middleware::ClientBuilder::new(client) - .with_arc(Arc::new(AuthenticationMiddleware::default())) + .with_arc(Arc::new( + AuthenticationMiddleware::from_env_and_defaults().unwrap(), + )) .build(); let result = fetch_repo_data( diff --git a/py-rattler/pixi.toml b/py-rattler/pixi.toml index 290d248e9..f580c49bb 100644 --- a/py-rattler/pixi.toml +++ b/py-rattler/pixi.toml @@ -41,19 +41,19 @@ typer = "*" types-networkx = "*" [feature.test.tasks] -test = { cmd = "pytest --doctest-modules", depends_on = ["build"] } +test = { cmd = "pytest --doctest-modules", depends-on = ["build"] } fmt-python = "ruff format rattler examples tests" fmt-rust = "cargo fmt --all" lint-python = "ruff check ." lint-rust = "cargo clippy --all" -fmt = { depends_on = ["fmt-python", "fmt-rust"] } -lint = { depends_on = ["type-check", "lint-python", "lint-rust"] } -type-check = { cmd = "mypy", depends_on = ["build"] } +fmt = { depends-on = ["fmt-python", "fmt-rust"] } +lint = { depends-on = ["type-check", "lint-python", "lint-rust"] } +type-check = { cmd = "mypy", depends-on = ["build"] } # checks for the CI fmt-rust-check = "cargo fmt --all --check" fmt-python-check = "ruff format rattler examples tests --diff" -fmt-check = { depends_on = ["fmt-python-check", "fmt-rust-check"] } +fmt-check = { depends-on = ["fmt-python-check", "fmt-rust-check"] } [feature.docs.dependencies] mkdocs = ">=1.5.3,<2" diff --git a/py-rattler/src/error.rs b/py-rattler/src/error.rs index 0676219bc..37a44915d 100644 --- a/py-rattler/src/error.rs +++ b/py-rattler/src/error.rs @@ -8,6 +8,7 @@ use rattler_conda_types::{ VersionBumpError, VersionExtendError, }; use rattler_lock::{ConversionError, ParseCondaLockError}; +use rattler_networking::authentication_storage::backends::file::FileStorageError; use rattler_package_streaming::ExtractError; use rattler_repodata_gateway::{fetch::FetchRepoDataError, GatewayError}; use rattler_shell::activation::ActivationError; @@ -76,6 +77,8 @@ pub enum PyRattlerError { ), #[error(transparent)] ValidatePackageRecordsError(#[from] ValidatePackageRecordsError), + #[error(transparent)] + FileStorageError(#[from] FileStorageError), } fn pretty_print_error(mut err: &dyn Error) -> String { @@ -166,6 +169,9 @@ impl From for PyErr { PyRattlerError::ValidatePackageRecordsError(err) => { ValidatePackageRecordsException::new_err(pretty_print_error(&err)) } + PyRattlerError::FileStorageError(err) => { + FileStorageException::new_err(pretty_print_error(&err)) + } } } } @@ -202,3 +208,4 @@ create_exception!( PyException ); create_exception!(exceptions, ValidatePackageRecordsException, PyException); +create_exception!(exceptions, FileStorageException, PyException); diff --git a/py-rattler/src/networking/client.rs b/py-rattler/src/networking/client.rs index 2ff7fce32..b6cc5a231 100644 --- a/py-rattler/src/networking/client.rs +++ b/py-rattler/src/networking/client.rs @@ -1,5 +1,5 @@ -use crate::networking::middleware::PyMiddleware; -use pyo3::{pyclass, pymethods}; +use crate::{error::PyRattlerError, networking::middleware::PyMiddleware}; +use pyo3::{pyclass, pymethods, PyResult}; use rattler_networking::{ AuthenticationMiddleware, GCSMiddleware, MirrorMiddleware, OciMiddleware, }; @@ -16,22 +16,31 @@ pub struct PyClientWithMiddleware { impl PyClientWithMiddleware { #[new] #[pyo3(signature = (middlewares=None))] - pub fn new(middlewares: Option>) -> Self { + pub fn new(middlewares: Option>) -> PyResult { let middlewares = middlewares.unwrap_or_default(); - let client = reqwest_middleware::ClientBuilder::new(reqwest::Client::new()); - let client = middlewares - .into_iter() - .fold(client, |client, middleware| match middleware { - PyMiddleware::Mirror(middleware) => client.with(MirrorMiddleware::from(middleware)), - PyMiddleware::Authentication(middleware) => { - client.with(AuthenticationMiddleware::from(middleware)) + let mut client = reqwest_middleware::ClientBuilder::new(reqwest::Client::new()); + for middleware in middlewares { + match middleware { + PyMiddleware::Mirror(middleware) => { + client = client.with(MirrorMiddleware::from(middleware)); } - PyMiddleware::Oci(middleware) => client.with(OciMiddleware::from(middleware)), - PyMiddleware::Gcs(middleware) => client.with(GCSMiddleware::from(middleware)), - }); + PyMiddleware::Authentication(_) => { + client = client.with( + AuthenticationMiddleware::from_env_and_defaults() + .map_err(PyRattlerError::from)?, + ); + } + PyMiddleware::Oci(middleware) => { + client = client.with(OciMiddleware::from(middleware)); + } + PyMiddleware::Gcs(middleware) => { + client = client.with(GCSMiddleware::from(middleware)); + } + } + } let client = client.build(); - Self { inner: client } + Ok(Self { inner: client }) } } diff --git a/py-rattler/src/networking/middleware.rs b/py-rattler/src/networking/middleware.rs index cae3510c9..3e01bbf9a 100644 --- a/py-rattler/src/networking/middleware.rs +++ b/py-rattler/src/networking/middleware.rs @@ -1,7 +1,6 @@ use pyo3::{pyclass, pymethods, FromPyObject, PyResult}; use rattler_networking::{ - mirror_middleware::Mirror, AuthenticationMiddleware, AuthenticationStorage, GCSMiddleware, - MirrorMiddleware, OciMiddleware, + mirror_middleware::Mirror, GCSMiddleware, MirrorMiddleware, OciMiddleware, }; use std::collections::HashMap; use url::Url; @@ -70,12 +69,6 @@ impl PyAuthenticationMiddleware { } } -impl From for AuthenticationMiddleware { - fn from(_value: PyAuthenticationMiddleware) -> Self { - AuthenticationMiddleware::new(AuthenticationStorage::default()) - } -} - #[pyclass] #[repr(transparent)] #[derive(Clone)] diff --git a/py-rattler/src/networking/mod.rs b/py-rattler/src/networking/mod.rs index 28f8cd05c..692eb8bc8 100644 --- a/py-rattler/src/networking/mod.rs +++ b/py-rattler/src/networking/mod.rs @@ -33,7 +33,7 @@ pub fn py_fetch_repo_data<'a>( client: Option, ) -> PyResult> { let mut meta_futures = Vec::new(); - let client = client.unwrap_or(PyClientWithMiddleware::new(None)); + let client = client.unwrap_or(PyClientWithMiddleware::new(None)?); for (subdir, chan, platform) in get_subdir_urls(channels, platforms)? { let callback = callback.as_ref().map(|callback| {