diff --git a/crates/rattler/src/install/mod.rs b/crates/rattler/src/install/mod.rs index 82c6bfbf1..ef1a17965 100644 --- a/crates/rattler/src/install/mod.rs +++ b/crates/rattler/src/install/mod.rs @@ -41,6 +41,7 @@ use std::{ pub use apple_codesign::AppleCodeSignBehavior; pub use driver::InstallDriver; +use fs_err::tokio as tokio_fs; use futures::{stream::FuturesUnordered, FutureExt, StreamExt}; #[cfg(feature = "indicatif")] pub use installer::{ @@ -265,7 +266,7 @@ pub async fn link_package( .to_owned(); // Ensure target directory exists - tokio::fs::create_dir_all(&target_dir) + tokio_fs::create_dir_all(&target_dir) .await .map_err(InstallError::FailedToCreateTargetDirectory)?; @@ -661,12 +662,12 @@ async fn can_create_symlinks(target_dir: &Path) -> bool { let uuid = uuid::Uuid::new_v4(); let symlink_path = target_dir.join(format!("symtest_{uuid}")); #[cfg(windows)] - let result = tokio::fs::symlink_file("./", &symlink_path).await; + let result = tokio_fs::symlink_file("./", &symlink_path).await; #[cfg(unix)] - let result = tokio::fs::symlink("./", &symlink_path).await; + let result = tokio_fs::symlink("./", &symlink_path).await; match result { Ok(_) => { - if let Err(e) = tokio::fs::remove_file(&symlink_path).await { + if let Err(e) = tokio_fs::remove_file(&symlink_path).await { tracing::warn!( "failed to delete temporary file '{}': {e}", symlink_path.display() @@ -693,7 +694,7 @@ async fn can_create_hardlinks(target_dir: &Path, package_dir: &Path) -> bool { #[cfg(unix)] async fn paths_have_same_filesystem(a: &Path, b: &Path) -> bool { use std::os::unix::fs::MetadataExt; - match tokio::join!(tokio::fs::metadata(a), tokio::fs::metadata(b)) { + match tokio::join!(tokio_fs::metadata(a), tokio_fs::metadata(b)) { (Ok(a), Ok(b)) => a.dev() == b.dev(), _ => false, } diff --git a/crates/rattler/src/install/unlink.rs b/crates/rattler/src/install/unlink.rs index 028effa48..cb5775d49 100644 --- a/crates/rattler/src/install/unlink.rs +++ b/crates/rattler/src/install/unlink.rs @@ -1,5 +1,6 @@ //! Unlinking packages from an environment. +use fs_err::tokio as tokio_fs; use std::{ collections::HashSet, ffi::OsString, @@ -115,13 +116,13 @@ pub(crate) fn recursively_remove_empty_directories( /// Remove files in trash folder that are not currently in use. pub async fn empty_trash(target_prefix: &Path) -> Result<(), UnlinkError> { let trash_dir = target_prefix.join(".trash"); - match tokio::fs::read_dir(&trash_dir).await { + match tokio_fs::read_dir(&trash_dir).await { Ok(mut read_dir) => { let mut files_left_in_trash = false; while let Some(entry) = read_dir.next_entry().await.map_err(|e| { UnlinkError::FailedToReadDirectory(trash_dir.to_string_lossy().to_string(), e) })? { - tokio::fs::remove_file(entry.path()) + tokio_fs::remove_file(entry.path()) .await .or_else(|e| match e.kind() { ErrorKind::NotFound => Ok(()), @@ -136,7 +137,7 @@ pub async fn empty_trash(target_prefix: &Path) -> Result<(), UnlinkError> { })?; } if !files_left_in_trash { - tokio::fs::remove_dir(&trash_dir).await.map_err(|e| { + tokio_fs::remove_dir(&trash_dir).await.map_err(|e| { UnlinkError::FailedToDeleteDirectory(trash_dir.to_string_lossy().to_string(), e) })?; } @@ -157,7 +158,7 @@ async fn move_to_trash(target_prefix: &Path, path: &Path) -> Result<(), UnlinkEr let mut trash_dest = target_prefix.join(".trash"); match tokio::fs::try_exists(&trash_dest).await { Ok(true) => {} - Ok(false) => tokio::fs::create_dir(&trash_dest).await.map_err(|e| { + Ok(false) => tokio_fs::create_dir(&trash_dest).await.map_err(|e| { UnlinkError::FailedToCreateDirectory(trash_dest.to_string_lossy().to_string(), e) })?, Err(e) => { @@ -174,7 +175,7 @@ async fn move_to_trash(target_prefix: &Path, path: &Path) -> Result<(), UnlinkEr } new_filename.push(format!("{}.trash", Uuid::new_v4().simple())); trash_dest.push(new_filename); - match tokio::fs::rename(path, &trash_dest).await { + match tokio_fs::rename(path, &trash_dest).await { Ok(_) => Ok(()), Err(e) => Err(UnlinkError::FailedToMoveFile( path.to_string_lossy().to_string(), @@ -192,7 +193,7 @@ pub async fn unlink_package( // Remove all entries for paths in prefix_record.paths_data.paths.iter() { let p = target_prefix.join(&paths.relative_path); - match tokio::fs::remove_file(&p).await { + match tokio_fs::remove_file(&p).await { Ok(_) => {} Err(e) => match e.kind() { // Simply ignore if the file is already gone. @@ -213,11 +214,9 @@ pub async fn unlink_package( .join("conda-meta") .join(prefix_record.file_name()); - tokio::fs::remove_file(&conda_meta_path) - .await - .map_err(|e| { - UnlinkError::FailedToDeleteFile(conda_meta_path.to_string_lossy().to_string(), e) - })?; + tokio_fs::remove_file(&conda_meta_path).await.map_err(|e| { + UnlinkError::FailedToDeleteFile(conda_meta_path.to_string_lossy().to_string(), e) + })?; Ok(()) } diff --git a/crates/rattler_cache/Cargo.toml b/crates/rattler_cache/Cargo.toml index 95426e92e..6a4f84ce0 100644 --- a/crates/rattler_cache/Cargo.toml +++ b/crates/rattler_cache/Cargo.toml @@ -14,6 +14,7 @@ anyhow.workspace = true dashmap.workspace = true dirs.workspace = true futures.workspace = true +fs-err.workspace = true fxhash.workspace = true itertools.workspace = true parking_lot.workspace = true diff --git a/crates/rattler_cache/src/package_cache/mod.rs b/crates/rattler_cache/src/package_cache/mod.rs index 443a1e98d..ede1796f9 100644 --- a/crates/rattler_cache/src/package_cache/mod.rs +++ b/crates/rattler_cache/src/package_cache/mod.rs @@ -14,6 +14,7 @@ pub use cache_key::CacheKey; pub use cache_lock::CacheLock; use cache_lock::CacheRwLock; use dashmap::DashMap; +use fs_err::tokio as tokio_fs; use futures::TryFutureExt; use itertools::Itertools; use parking_lot::Mutex; @@ -309,7 +310,7 @@ where // Ensure the directory containing the lock-file exists. if let Some(root_dir) = lock_file_path.parent() { - tokio::fs::create_dir_all(root_dir) + tokio_fs::create_dir_all(root_dir) .map_err(|e| { PackageCacheError::LockError( format!("failed to create cache directory: '{}", root_dir.display()), diff --git a/crates/rattler_package_streaming/Cargo.toml b/crates/rattler_package_streaming/Cargo.toml index 3bbf7eb2f..edeb46827 100644 --- a/crates/rattler_package_streaming/Cargo.toml +++ b/crates/rattler_package_streaming/Cargo.toml @@ -13,6 +13,7 @@ readme.workspace = true [dependencies] bzip2 = { workspace = true } chrono = { workspace = true } +fs-err = { workspace = true } futures-util = { workspace = true } num_cpus = { workspace = true } rattler_conda_types = { path = "../rattler_conda_types", version = "0.29.2", default-features = false } diff --git a/crates/rattler_package_streaming/src/reqwest/tokio.rs b/crates/rattler_package_streaming/src/reqwest/tokio.rs index 949efd987..88266651c 100644 --- a/crates/rattler_package_streaming/src/reqwest/tokio.rs +++ b/crates/rattler_package_streaming/src/reqwest/tokio.rs @@ -2,6 +2,7 @@ //! async context. use crate::{DownloadReporter, ExtractError, ExtractResult}; +use fs_err::tokio as tokio_fs; use futures_util::stream::TryStreamExt; use rattler_conda_types::package::ArchiveType; use rattler_digest::Sha256Hash; @@ -40,7 +41,7 @@ async fn get_reader( if url.scheme() == "file" { let file = - tokio::fs::File::open(url.to_file_path().expect("Could not convert to file path")) + tokio_fs::File::open(url.to_file_path().expect("Could not convert to file path")) .await .map_err(ExtractError::IoError)?; diff --git a/crates/rattler_package_streaming/tests/extract.rs b/crates/rattler_package_streaming/tests/extract.rs index 4b9f5b181..99cb42aac 100644 --- a/crates/rattler_package_streaming/tests/extract.rs +++ b/crates/rattler_package_streaming/tests/extract.rs @@ -4,6 +4,7 @@ use std::{ path::{Path, PathBuf}, }; +use fs_err::tokio as tokio_fs; use rattler_conda_types::package::IndexJson; use rattler_package_streaming::{ read::{extract_conda_via_buffering, extract_conda_via_streaming, extract_tar_bz2}, @@ -189,7 +190,7 @@ async fn test_extract_tar_bz2_async(#[case] input: Url, #[case] sha256: &str, #[ .unwrap(); let target_dir = temp_dir.join(file_path.file_stem().unwrap()); let result = rattler_package_streaming::tokio::async_read::extract_tar_bz2( - tokio::fs::File::open(&test_data_dir().join(file_path)) + tokio_fs::File::open(&test_data_dir().join(file_path)) .await .unwrap(), &target_dir, @@ -214,7 +215,7 @@ async fn test_extract_conda_async(#[case] input: Url, #[case] sha256: &str, #[ca let target_dir = temp_dir.join(file_path.file_stem().unwrap()); let result: rattler_package_streaming::ExtractResult = rattler_package_streaming::tokio::async_read::extract_conda( - tokio::fs::File::open(&test_data_dir().join(file_path)) + tokio_fs::File::open(&test_data_dir().join(file_path)) .await .unwrap(), &target_dir, diff --git a/crates/rattler_repodata_gateway/src/fetch/jlap/mod.rs b/crates/rattler_repodata_gateway/src/fetch/jlap/mod.rs index 5c0184925..3ff546ef2 100644 --- a/crates/rattler_repodata_gateway/src/fetch/jlap/mod.rs +++ b/crates/rattler_repodata_gateway/src/fetch/jlap/mod.rs @@ -882,7 +882,7 @@ mod test { let cache_repo_data_path = cache_dir.path().join(format!("{cache_key}.json")); if let Some(content) = cache_repo_data { - tokio::fs::write(cache_repo_data_path.clone(), content) + tokio_fs::write(cache_repo_data_path.clone(), content) .await .unwrap(); } @@ -953,7 +953,7 @@ mod test { .unwrap(); // Make assertions - let repo_data = tokio::fs::read_to_string(test_env.cache_repo_data) + let repo_data = tokio_fs::read_to_string(test_env.cache_repo_data) .await .unwrap(); diff --git a/crates/rattler_repodata_gateway/src/fetch/mod.rs b/crates/rattler_repodata_gateway/src/fetch/mod.rs index 4fa1dfa98..54f495085 100644 --- a/crates/rattler_repodata_gateway/src/fetch/mod.rs +++ b/crates/rattler_repodata_gateway/src/fetch/mod.rs @@ -805,7 +805,7 @@ async fn check_valid_download_target( if url.scheme() == "file" { // If the url is a file url we can simply check if the file exists. let path = url.to_file_path().unwrap(); - let exists = tokio::fs::metadata(path).await.is_ok(); + let exists = tokio_fs::metadata(path).await.is_ok(); tracing::debug!( "'{url}' seems to be {}", if exists { "available" } else { "unavailable" } @@ -1021,6 +1021,7 @@ mod test { use crate::utils::Encoding; use crate::Reporter; use assert_matches::assert_matches; + use fs_err::tokio as tokio_fs; use hex_literal::hex; use rattler_networking::AuthenticationMiddleware; use reqwest::Client; @@ -1038,7 +1039,7 @@ mod test { encoding: Encoding, ) -> Result<(), std::io::Error> { // Open the file for writing - let mut file = tokio::fs::File::create(destination).await.unwrap(); + let mut file = tokio_fs::File::create(destination).await.unwrap(); match encoding { Encoding::Passthrough => { diff --git a/crates/rattler_repodata_gateway/src/gateway/sharded_subdir/index.rs b/crates/rattler_repodata_gateway/src/gateway/sharded_subdir/index.rs index 223075c13..799810cb4 100644 --- a/crates/rattler_repodata_gateway/src/gateway/sharded_subdir/index.rs +++ b/crates/rattler_repodata_gateway/src/gateway/sharded_subdir/index.rs @@ -2,6 +2,7 @@ use std::{path::Path, str::FromStr, sync::Arc, time::SystemTime}; use async_fd_lock::{LockWrite, RwLockWriteGuard}; use bytes::Bytes; +use fs_err::tokio as tokio_fs; use futures::TryFutureExt; use http::{HeaderMap, Method, Uri}; use http_cache_semantics::{AfterResponse, BeforeRequest, CachePolicy, RequestLike}; @@ -100,7 +101,7 @@ pub async fn fetch_index( // Make sure the cache directory exists if let Some(parent) = cache_path.parent() { - tokio::fs::create_dir_all(parent).await.map_err(|err| { + tokio_fs::create_dir_all(parent).await.map_err(|err| { GatewayError::IoError(format!("failed to create '{}'", parent.display()), err) })?; } diff --git a/crates/rattler_repodata_gateway/src/gateway/sharded_subdir/mod.rs b/crates/rattler_repodata_gateway/src/gateway/sharded_subdir/mod.rs index 74f3a998d..a5a2d5d6f 100644 --- a/crates/rattler_repodata_gateway/src/gateway/sharded_subdir/mod.rs +++ b/crates/rattler_repodata_gateway/src/gateway/sharded_subdir/mod.rs @@ -6,6 +6,7 @@ use crate::{ reporter::ResponseReporterExt, GatewayError, Reporter, }; +use fs_err::tokio as tokio_fs; use http::{header::CACHE_CONTROL, HeaderValue, StatusCode}; use rattler_conda_types::{ Channel, ChannelUrl, PackageName, RepoDataRecord, Shard, ShardedRepodata, @@ -88,7 +89,7 @@ impl ShardedSubdir { // Determine the cache directory and make sure it exists. let cache_dir = cache_dir.join("shards-v1"); - tokio::fs::create_dir_all(&cache_dir) + tokio_fs::create_dir_all(&cache_dir) .await .map_err(FetchRepoDataError::IoError)?; @@ -122,7 +123,7 @@ impl SubdirClient for ShardedSubdir { // Read the cached shard if self.cache_action != CacheAction::NoCache { - match tokio::fs::read(&shard_cache_path).await { + match tokio_fs::read(&shard_cache_path).await { Ok(cached_bytes) => { // Decode the cached shard return parse_records( diff --git a/crates/rattler_repodata_gateway/src/utils/mod.rs b/crates/rattler_repodata_gateway/src/utils/mod.rs index edc1f46d1..447c141e1 100644 --- a/crates/rattler_repodata_gateway/src/utils/mod.rs +++ b/crates/rattler_repodata_gateway/src/utils/mod.rs @@ -46,6 +46,7 @@ pub(crate) fn url_to_cache_filename(url: &Url) -> String { pub(crate) mod test { use std::path::{Path, PathBuf}; + use fs_err::tokio as tokio_fs; use tempfile::NamedTempFile; use url::Url; @@ -73,7 +74,7 @@ pub(crate) mod test { // Create the parent directory if it doesn't exist let parent_dir = path.parent().unwrap(); - tokio::fs::create_dir_all(&parent_dir).await.unwrap(); + tokio_fs::create_dir_all(&parent_dir).await.unwrap(); // Acquire a lock on the file to ensure we don't download the file twice. let mut lock = fslock::LockFile::open(&parent_dir.join(".lock")).unwrap(); @@ -95,7 +96,7 @@ pub(crate) mod test { "https://rattler-test.pixi.run/test-data/channels/conda-forge/{subdir}/repodata.json" )) .await?; - tokio::fs::write(&mut file, data.bytes().await?) + tokio_fs::write(&mut file, data.bytes().await?) .await .unwrap(); file.persist(&path).unwrap();