diff --git a/Cargo.lock b/Cargo.lock index 7f0d31549..dbc91130f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3582,6 +3582,7 @@ name = "pixi_build_frontend" version = "0.1.0" dependencies = [ "dashmap", + "fs-err 2.11.0", "futures", "insta", "itertools 0.13.0", @@ -3634,6 +3635,7 @@ dependencies = [ "clap", "console", "dirs", + "fs-err 2.11.0", "insta", "itertools 0.13.0", "miette 7.2.0", @@ -3673,6 +3675,7 @@ name = "pixi_glob" version = "0.1.0" dependencies = [ "dashmap", + "fs-err 2.11.0", "insta", "itertools 0.13.0", "memchr", @@ -3692,6 +3695,7 @@ dependencies = [ "console", "dunce", "fancy_display", + "fs-err 2.11.0", "glob", "indexmap 2.6.0", "insta", @@ -3780,6 +3784,7 @@ name = "pixi_utils" version = "0.1.0" dependencies = [ "fd-lock", + "fs-err 2.11.0", "indicatif", "insta", "itertools 0.13.0", @@ -4024,6 +4029,7 @@ name = "pypi_mapping" version = "0.1.0" dependencies = [ "async-once-cell", + "fs-err 2.11.0", "futures", "http-cache-reqwest", "itertools 0.13.0", diff --git a/clippy.toml b/clippy.toml index 8e85afba9..b91418829 100644 --- a/clippy.toml +++ b/clippy.toml @@ -5,3 +5,24 @@ ignore-interior-mutability = [ "pixi::project::environment::Environment", "pixi::project::solve_group::SolveGroup", ] + +disallowed-methods = [ + "std::fs::canonicalize", + "std::fs::copy", + "std::fs::create_dir", + "std::fs::create_dir_all", + "std::fs::hard_link", + "std::fs::metadata", + "std::fs::read", + "std::fs::read_dir", + "std::fs::read_link", + "std::fs::read_to_string", + "std::fs::remove_dir", + "std::fs::remove_dir_all", + "std::fs::remove_file", + "std::fs::rename", + "std::fs::set_permissions", + "std::fs::soft_link", + "std::fs::symlink_metadata", + "std::fs::write", +] diff --git a/crates/pixi_build_frontend/Cargo.toml b/crates/pixi_build_frontend/Cargo.toml index 976b86429..c154b48ea 100644 --- a/crates/pixi_build_frontend/Cargo.toml +++ b/crates/pixi_build_frontend/Cargo.toml @@ -11,6 +11,7 @@ version = "0.1.0" [dependencies] dashmap = { workspace = true } +fs-err = { workspace = true } futures = { workspace = true } itertools = { workspace = true } jsonrpsee = { workspace = true, features = ["client"] } diff --git a/crates/pixi_build_frontend/src/protocols/builders/conda_build/protocol.rs b/crates/pixi_build_frontend/src/protocols/builders/conda_build/protocol.rs index 136823cf2..4255e0a55 100644 --- a/crates/pixi_build_frontend/src/protocols/builders/conda_build/protocol.rs +++ b/crates/pixi_build_frontend/src/protocols/builders/conda_build/protocol.rs @@ -257,7 +257,7 @@ mod test { #[case::pinject("conda-render/pinject.txt")] #[case::microarch("conda-render/microarch-level.txt")] fn test_extract_rendered_recipe(#[case] path: &str) { - let rendered_recipe = std::fs::read_to_string( + let rendered_recipe = fs_err::read_to_string( Path::new(env!("CARGO_MANIFEST_DIR")) .join("test-data") .join(path), diff --git a/crates/pixi_config/Cargo.toml b/crates/pixi_config/Cargo.toml index 47772f06a..c0b8881df 100644 --- a/crates/pixi_config/Cargo.toml +++ b/crates/pixi_config/Cargo.toml @@ -13,6 +13,7 @@ version = "0.1.0" clap = { workspace = true, features = ["std", "derive", "env"] } console = { workspace = true } dirs = { workspace = true } +fs-err = { workspace = true } itertools = { workspace = true } miette = { workspace = true } pixi_consts = { workspace = true } diff --git a/crates/pixi_config/src/lib.rs b/crates/pixi_config/src/lib.rs index b32971711..f077049f4 100644 --- a/crates/pixi_config/src/lib.rs +++ b/crates/pixi_config/src/lib.rs @@ -11,7 +11,6 @@ use reqwest_middleware::ClientWithMiddleware; use serde::{de::IntoDeserializer, Deserialize, Serialize}; use std::{ collections::{BTreeSet as Set, HashMap}, - fs, path::{Path, PathBuf}, process::{Command, Stdio}, str::FromStr, @@ -747,7 +746,7 @@ impl Config { /// I/O errors or parsing errors pub fn from_path(path: &Path) -> miette::Result { tracing::debug!("Loading config from {}", path.display()); - let s = fs::read_to_string(path) + let s = fs_err::read_to_string(path) .into_diagnostic() .wrap_err(format!("failed to read config from '{}'", path.display()))?; @@ -1201,13 +1200,13 @@ impl Config { tracing::debug!("Saving config to: {}", to.display()); let parent = to.parent().expect("config path should have a parent"); - fs::create_dir_all(parent) + fs_err::create_dir_all(parent) .into_diagnostic() .wrap_err(format!( "failed to create directories in '{}'", parent.display() ))?; - fs::write(to, contents) + fs_err::write(to, contents) .into_diagnostic() .wrap_err(format!("failed to write config to '{}'", to.display())) } diff --git a/crates/pixi_glob/Cargo.toml b/crates/pixi_glob/Cargo.toml index 5349323b8..ecc8766e2 100644 --- a/crates/pixi_glob/Cargo.toml +++ b/crates/pixi_glob/Cargo.toml @@ -11,6 +11,7 @@ version = "0.1.0" [dependencies] dashmap = { workspace = true } +fs-err = { workspace = true } itertools = { workspace = true } memchr = { workspace = true } rattler_digest = { workspace = true } diff --git a/crates/pixi_glob/src/glob_set.rs b/crates/pixi_glob/src/glob_set.rs index bba77bf6a..2d70e97ae 100644 --- a/crates/pixi_glob/src/glob_set.rs +++ b/crates/pixi_glob/src/glob_set.rs @@ -96,10 +96,8 @@ impl<'t> GlobSet<'t> { #[cfg(test)] mod tests { use super::GlobSet; - use std::{ - fs::{create_dir, File}, - path::PathBuf, - }; + use fs_err::File; + use std::path::PathBuf; use tempfile::tempdir; #[test] @@ -111,7 +109,7 @@ mod tests { File::create(root_path.join("include1.txt")).unwrap(); File::create(root_path.join("include2.log")).unwrap(); File::create(root_path.join("exclude.txt")).unwrap(); - create_dir(root_path.join("subdir")).unwrap(); + fs_err::create_dir(root_path.join("subdir")).unwrap(); File::create(root_path.join("subdir/include_subdir.txt")).unwrap(); // Test globs: include all .txt but exclude exclude.txt diff --git a/crates/pixi_manifest/Cargo.toml b/crates/pixi_manifest/Cargo.toml index a29ed8e3e..cc7841d86 100644 --- a/crates/pixi_manifest/Cargo.toml +++ b/crates/pixi_manifest/Cargo.toml @@ -11,6 +11,7 @@ version = "0.1.0" [dependencies] dunce = { workspace = true } fancy_display = { workspace = true } +fs-err = { workspace = true } indexmap = { workspace = true } itertools = { workspace = true } pep440_rs = { workspace = true } diff --git a/crates/pixi_manifest/src/manifests/manifest.rs b/crates/pixi_manifest/src/manifests/manifest.rs index 56e2d986f..1d4fa89dc 100644 --- a/crates/pixi_manifest/src/manifests/manifest.rs +++ b/crates/pixi_manifest/src/manifests/manifest.rs @@ -84,7 +84,7 @@ impl Manifest { /// Create a new manifest from a path pub fn from_path(path: impl AsRef) -> miette::Result { let manifest_path = dunce::canonicalize(path.as_ref()).into_diagnostic()?; - let contents = std::fs::read_to_string(path.as_ref()).into_diagnostic()?; + let contents = fs_err::read_to_string(path.as_ref()).into_diagnostic()?; Self::from_str(manifest_path.as_ref(), contents) } @@ -162,7 +162,7 @@ impl Manifest { /// Save the manifest to the file and update the contents pub fn save(&mut self) -> miette::Result<()> { let contents = self.document.to_string(); - std::fs::write(&self.path, &contents).into_diagnostic()?; + fs_err::write(&self.path, &contents).into_diagnostic()?; self.contents = Some(contents); Ok(()) } @@ -801,7 +801,7 @@ mod tests { // Test the toml from a path let dir = tempdir().unwrap(); let path = dir.path().join("pixi.toml"); - std::fs::write(&path, PROJECT_BOILERPLATE).unwrap(); + fs_err::write(&path, PROJECT_BOILERPLATE).unwrap(); // From &PathBuf let _manifest = Manifest::from_path(&path).unwrap(); // From &Path @@ -2321,7 +2321,7 @@ bar = "*" for entry in glob(location).unwrap() { match entry { Ok(path) => { - let contents = std::fs::read_to_string(path).unwrap(); + let contents = fs_err::read_to_string(path).unwrap(); let _manifest = Manifest::from_str(Path::new("pixi.toml"), contents).unwrap(); } Err(e) => println!("{:?}", e), diff --git a/crates/pixi_manifest/src/pyproject.rs b/crates/pixi_manifest/src/pyproject.rs index ccb491cb2..3388a5370 100644 --- a/crates/pixi_manifest/src/pyproject.rs +++ b/crates/pixi_manifest/src/pyproject.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, fs, path::PathBuf, str::FromStr}; +use std::{collections::HashMap, path::PathBuf, str::FromStr}; use indexmap::IndexMap; use miette::{Diagnostic, IntoDiagnostic, Report, WrapErr}; @@ -58,7 +58,7 @@ impl PyProjectManifest { /// Parses a `pyproject.toml` file into a PyProjectManifest pub fn from_path(path: &PathBuf) -> Result { - let source = fs::read_to_string(path) + let source = fs_err::read_to_string(path) .into_diagnostic() .wrap_err_with(|| format!("Failed to read file: {:?}", path))?; Self::from_toml_str(&source).into_diagnostic() diff --git a/crates/pixi_trampoline/Cargo.lock b/crates/pixi_trampoline/Cargo.lock index f391a0d6d..0315f8119 100644 --- a/crates/pixi_trampoline/Cargo.lock +++ b/crates/pixi_trampoline/Cargo.lock @@ -2303,6 +2303,7 @@ dependencies = [ "clap", "console", "dirs", + "fs-err 2.11.0", "itertools 0.13.0", "miette", "pixi_consts", @@ -2333,6 +2334,7 @@ name = "pixi_trampoline" version = "0.1.0" dependencies = [ "ctrlc", + "fs-err 3.0.0", "miette", "pixi_utils", "serde", @@ -2344,6 +2346,7 @@ name = "pixi_utils" version = "0.1.0" dependencies = [ "fd-lock", + "fs-err 2.11.0", "indicatif", "itertools 0.13.0", "miette", diff --git a/crates/pixi_trampoline/Cargo.toml b/crates/pixi_trampoline/Cargo.toml index f45311e3f..860bc3dcd 100644 --- a/crates/pixi_trampoline/Cargo.toml +++ b/crates/pixi_trampoline/Cargo.toml @@ -25,7 +25,8 @@ strip = true [dependencies] ctrlc = "3.4" -miette = "7.2.0" +fs-err = "3.0.0" +miette = "7.4.0" pixi_utils = { path = "../pixi_utils" } serde = { version = "1.0.210", features = ["derive"] } serde_json = "1.0.128" diff --git a/crates/pixi_trampoline/src/main.rs b/crates/pixi_trampoline/src/main.rs index 1bab2f9ac..8b2d13323 100644 --- a/crates/pixi_trampoline/src/main.rs +++ b/crates/pixi_trampoline/src/main.rs @@ -1,9 +1,9 @@ +use fs_err::File; use miette::{Context, IntoDiagnostic}; use pixi_utils::executable_from_path; use serde::Deserialize; use std::collections::HashMap; use std::env; -use std::fs::File; use std::ops::Not; #[cfg(target_family = "unix")] use std::os::unix::process::CommandExt; diff --git a/crates/pixi_utils/Cargo.toml b/crates/pixi_utils/Cargo.toml index 774dfed8f..308f6a02d 100644 --- a/crates/pixi_utils/Cargo.toml +++ b/crates/pixi_utils/Cargo.toml @@ -25,6 +25,7 @@ rustls-tls = [ [dependencies] fd-lock = { workspace = true } +fs-err = { workspace = true } indicatif = { workspace = true } itertools = { workspace = true } miette = { workspace = true } diff --git a/crates/pixi_utils/src/conda_environment_file.rs b/crates/pixi_utils/src/conda_environment_file.rs index 4e70d03df..807491a28 100644 --- a/crates/pixi_utils/src/conda_environment_file.rs +++ b/crates/pixi_utils/src/conda_environment_file.rs @@ -85,7 +85,7 @@ impl CondaEnvFile { } pub fn from_path(path: &Path) -> miette::Result { - let file = std::fs::File::open(path).into_diagnostic()?; + let file = fs_err::File::open(path).into_diagnostic()?; let reader = std::io::BufReader::new(file); let lines = reader @@ -187,7 +187,7 @@ fn parse_channels(channels: Vec) -> Vec { #[cfg(test)] mod tests { - use std::{fs, io::Write, path::Path, str::FromStr}; + use std::{io::Write, path::Path, str::FromStr}; use rattler_conda_types::{MatchSpec, ParseStrictness::Strict}; @@ -271,7 +271,7 @@ mod tests { .join("tests") .join("environment_yamls"); - let entries = match fs::read_dir(test_files_path) { + let entries = match fs_err::read_dir(test_files_path) { Ok(entries) => entries, Err(e) => panic!("Failed to read directory: {}", e), }; @@ -317,7 +317,7 @@ mod tests { let f = tempfile::NamedTempFile::new().unwrap(); let path = f.path(); - let mut file = std::fs::File::create(path).unwrap(); + let mut file = fs_err::File::create(path).unwrap(); file.write_all(example_conda_env_file.as_bytes()).unwrap(); let conda_env_file_data = CondaEnvFile::from_path(path).unwrap(); diff --git a/crates/pixi_utils/src/prefix_guard.rs b/crates/pixi_utils/src/prefix_guard.rs index 400c769b9..9ca68ead6 100644 --- a/crates/pixi_utils/src/prefix_guard.rs +++ b/crates/pixi_utils/src/prefix_guard.rs @@ -81,7 +81,7 @@ impl PrefixGuard { let guard_path = prefix.join(GUARD_PATH); // Ensure that the directory exists - std::fs::create_dir_all(guard_path.parent().unwrap())?; + fs_err::create_dir_all(guard_path.parent().unwrap())?; // Open the file Ok(Self { diff --git a/crates/pypi_mapping/Cargo.toml b/crates/pypi_mapping/Cargo.toml index 2800b5dc8..b2bc69e14 100644 --- a/crates/pypi_mapping/Cargo.toml +++ b/crates/pypi_mapping/Cargo.toml @@ -11,6 +11,7 @@ version = "0.1.0" [dependencies] async-once-cell = { workspace = true } +fs-err = { workspace = true } futures = { workspace = true } http-cache-reqwest = { workspace = true } itertools = { workspace = true } diff --git a/crates/pypi_mapping/src/custom_pypi_mapping.rs b/crates/pypi_mapping/src/custom_pypi_mapping.rs index 522ce87ea..bed1531c3 100644 --- a/crates/pypi_mapping/src/custom_pypi_mapping.rs +++ b/crates/pypi_mapping/src/custom_pypi_mapping.rs @@ -46,7 +46,7 @@ pub async fn fetch_mapping_from_url( } pub fn fetch_mapping_from_path(path: &Path) -> miette::Result { - let file = std::fs::File::open(path) + let file = fs_err::File::open(path) .into_diagnostic() .context(format!("failed to open file {}", path.display()))?; let reader = std::io::BufReader::new(file); diff --git a/src/cli/build.rs b/src/cli/build.rs index 461f89696..ea3cbd567 100644 --- a/src/cli/build.rs +++ b/src/cli/build.rs @@ -174,7 +174,7 @@ pub async fn execute(args: Args) -> miette::Result<()> { // Move the built packages to the output directory. let output_dir = args.output_dir; for package in result.packages { - std::fs::create_dir_all(&output_dir) + fs_err::create_dir_all(&output_dir) .into_diagnostic() .with_context(|| { format!( diff --git a/src/cli/info.rs b/src/cli/info.rs index a39c7b350..82b905f00 100644 --- a/src/cli/info.rs +++ b/src/cli/info.rs @@ -1,4 +1,4 @@ -use std::{fmt::Display, fs, path::PathBuf}; +use std::{fmt::Display, path::PathBuf}; use chrono::{DateTime, Local}; use clap::Parser; @@ -316,24 +316,26 @@ impl Display for Info { /// Returns the size of a directory fn dir_size(path: impl Into) -> miette::Result { - fn dir_size(mut dir: fs::ReadDir) -> miette::Result { + fn dir_size(mut dir: fs_err::ReadDir) -> miette::Result { dir.try_fold(0, |acc, file| { let file = file.into_diagnostic()?; let size = match file.metadata().into_diagnostic()? { - data if data.is_dir() => dir_size(fs::read_dir(file.path()).into_diagnostic()?)?, + data if data.is_dir() => { + dir_size(fs_err::read_dir(file.path()).into_diagnostic()?)? + } data => data.len(), }; Ok(acc + size) }) } - let size = dir_size(fs::read_dir(path.into()).into_diagnostic()?)?; + let size = dir_size(fs_err::read_dir(path.into()).into_diagnostic()?)?; Ok(format!("{} MiB", size / 1024 / 1024)) } /// Returns last update time of file, formatted: DD-MM-YYYY H:M:S fn last_updated(path: impl Into) -> miette::Result { - let time = fs::metadata(path.into()) + let time = fs_err::metadata(path.into()) .into_diagnostic()? .modified() .into_diagnostic()?; diff --git a/src/cli/init.rs b/src/cli/init.rs index d7a948968..900bafb93 100644 --- a/src/cli/init.rs +++ b/src/cli/init.rs @@ -199,7 +199,7 @@ pub async fn execute(args: Args) -> miette::Result<()> { } // Fail silently if the directory already exists or cannot be created. - fs::create_dir_all(&dir).ok(); + fs_err::create_dir_all(&dir).ok(); let default_name = get_name_from_dir(&dir).unwrap_or_else(|_| String::from("new_project")); let version = "0.1.0"; @@ -484,7 +484,7 @@ fn render_project( /// Save the rendered template to a file, and print a message to the user. fn save_manifest_file(path: &Path, content: String) -> miette::Result<()> { - fs::write(path, content).into_diagnostic()?; + fs_err::write(path, content).into_diagnostic()?; eprintln!( "{}Created {}", console::style(console::Emoji("✔ ", "")).green(), @@ -510,7 +510,7 @@ fn get_name_from_dir(path: &Path) -> miette::Result { // When the specific template is not in the file or the file does not exist. // Make the file and append the template to the file. fn create_or_append_file(path: &Path, template: &str) -> std::io::Result<()> { - let file = fs::read_to_string(path).unwrap_or_default(); + let file = fs_err::read_to_string(path).unwrap_or_default(); if !file.contains(template) { fs::OpenOptions::new() @@ -585,7 +585,7 @@ mod tests { let template = "Test Template"; fn read_file_content(path: &Path) -> String { - let mut file = std::fs::File::open(path).unwrap(); + let mut file = fs_err::File::open(path).unwrap(); let mut content = String::new(); file.read_to_string(&mut content).unwrap(); content diff --git a/src/cli/list.rs b/src/cli/list.rs index fc9817975..bd660fe80 100644 --- a/src/cli/list.rs +++ b/src/cli/list.rs @@ -96,7 +96,7 @@ where let mut result = 0; if path.as_ref().is_dir() { - for entry in std::fs::read_dir(&path)? { + for entry in fs_err::read_dir(path.as_ref())? { let _path = entry?.path(); if _path.is_file() { result += _path.metadata()?.len(); diff --git a/src/cli/project/export/conda_explicit_spec.rs b/src/cli/project/export/conda_explicit_spec.rs index fdbea28fc..87954ff41 100644 --- a/src/cli/project/export/conda_explicit_spec.rs +++ b/src/cli/project/export/conda_explicit_spec.rs @@ -1,6 +1,5 @@ use std::{ collections::HashSet, - fs, path::{Path, PathBuf}, }; @@ -87,7 +86,7 @@ fn render_explicit_spec( environment.push_str("# Generated by `pixi project export`\n"); environment.push_str(exp_env_spec.to_spec_string().as_str()); - fs::write(target, environment) + fs_err::write(target, environment) .into_diagnostic() .with_context(|| format!("failed to write environment file: {}", target.display()))?; @@ -212,7 +211,7 @@ pub async fn execute(args: Args) -> miette::Result<()> { } } - fs::create_dir_all(&args.output_dir).ok(); + fs_err::create_dir_all(&args.output_dir).ok(); for (env_name, env, plat) in env_platform { render_env_platform( @@ -259,7 +258,7 @@ mod tests { .join(format!("{}_{}_conda_spec.txt", env_name, platform)); insta::assert_snapshot!( format!("test_render_conda_explicit_spec_{}_{}", env_name, platform), - fs::read_to_string(file_path).unwrap() + fs_err::read_to_string(file_path).unwrap() ); } } diff --git a/src/environment.rs b/src/environment.rs index f508570fd..9eee95d4e 100644 --- a/src/environment.rs +++ b/src/environment.rs @@ -61,7 +61,7 @@ pub async fn verify_prefix_location_unchanged(environment_dir: &Path) -> miette: prefix_file.display() ); - match std::fs::read_to_string(prefix_file.clone()) { + match fs_err::read_to_string(prefix_file.clone()) { // Not found is fine as it can be new or backwards compatible. Err(e) if e.kind() == ErrorKind::NotFound => Ok(()), // Scream the error if we don't know it. @@ -146,7 +146,7 @@ fn create_prefix_location_file(environment_dir: &Path) -> miette::Result<()> { // Read existing contents to determine if an update is necessary if prefix_file_path.exists() { - let existing_contents = fs::read_to_string(&prefix_file_path).into_diagnostic()?; + let existing_contents = fs_err::read_to_string(&prefix_file_path).into_diagnostic()?; if existing_contents == contents { tracing::info!("No update needed for the prefix file."); return Ok(()); @@ -240,11 +240,11 @@ pub(crate) fn write_environment_file( .parent() .expect("There should already be a conda-meta folder"); - match std::fs::create_dir_all(parent).into_diagnostic() { + match fs_err::create_dir_all(parent).into_diagnostic() { Ok(_) => { // Using json as it's easier to machine read it. let contents = serde_json::to_string_pretty(&env_file).into_diagnostic()?; - match std::fs::write(&path, contents).into_diagnostic() { + match fs_err::write(&path, contents).into_diagnostic() { Ok(_) => { tracing::debug!("Wrote environment file to: {:?}", path); } @@ -270,7 +270,7 @@ pub(crate) fn read_environment_file( ) -> miette::Result> { let path = environment_file_path(environment_dir); - let contents = match std::fs::read_to_string(&path) { + let contents = match fs_err::read_to_string(&path) { Ok(contents) => contents, Err(e) if e.kind() == ErrorKind::NotFound => { tracing::debug!("Environment file not yet found at: {:?}", path); @@ -282,7 +282,7 @@ pub(crate) fn read_environment_file( path, e ); - let _ = std::fs::remove_file(&path); + let _ = fs_err::remove_file(&path); return Err(e).into_diagnostic(); } }; @@ -294,7 +294,7 @@ pub(crate) fn read_environment_file( path, e ); - let _ = std::fs::remove_file(&path); + let _ = fs_err::remove_file(&path); return Ok(None); } }; @@ -526,7 +526,7 @@ pub async fn update_prefix_pypi( async fn uninstall_outdated_site_packages(site_packages: &Path) -> miette::Result<()> { // Check if the old interpreter is outdated let mut installed = vec![]; - for entry in std::fs::read_dir(site_packages).into_diagnostic()? { + for entry in fs_err::read_dir(site_packages).into_diagnostic()? { let entry = entry.into_diagnostic()?; if entry.file_type().into_diagnostic()?.is_dir() { let path = entry.path(); diff --git a/src/global/common.rs b/src/global/common.rs index d04d08fc2..4cf6d4e3f 100644 --- a/src/global/common.rs +++ b/src/global/common.rs @@ -39,7 +39,7 @@ impl BinDir { #[cfg(test)] pub fn new(root: PathBuf) -> miette::Result { let path = root.join("bin"); - std::fs::create_dir_all(&path).into_diagnostic()?; + fs_err::create_dir_all(&path).into_diagnostic()?; Ok(Self(path)) } @@ -107,7 +107,7 @@ impl EnvRoot { #[cfg(test)] pub fn new(root: PathBuf) -> miette::Result { let path = root.join("envs"); - std::fs::create_dir_all(&path).into_diagnostic()?; + fs_err::create_dir_all(&path).into_diagnostic()?; Ok(Self(path)) } diff --git a/src/global/install.rs b/src/global/install.rs index d8897dc1d..d9b00ee85 100644 --- a/src/global/install.rs +++ b/src/global/install.rs @@ -472,7 +472,6 @@ mod tests { #[tokio::test] async fn test_extract_executable_from_script_windows() { use crate::global::trampoline::GlobalExecutable; - use std::fs; use std::path::Path; let script_without_quote = r#" @SET "PATH=C:\Users\USER\.pixi/envs\hyperfine\bin:%PATH%" @@ -482,7 +481,7 @@ mod tests { let script_path = Path::new("hyperfine.bat"); let tempdir = tempfile::tempdir().unwrap(); let script_path = tempdir.path().join(script_path); - fs::write(&script_path, script_without_quote).unwrap(); + fs_err::write(&script_path, script_without_quote).unwrap(); let script_global_bin = GlobalExecutable::Script(script_path); let executable_path = script_global_bin.executable().await.unwrap(); assert_eq!( @@ -497,7 +496,7 @@ mod tests { "#; let script_path = Path::new("pydoc.bat"); let script_path = tempdir.path().join(script_path); - fs::write(&script_path, script_with_quote).unwrap(); + fs_err::write(&script_path, script_with_quote).unwrap(); let executable_path = script_global_bin.executable().await.unwrap(); assert_eq!( executable_path, @@ -508,7 +507,7 @@ mod tests { #[cfg(unix)] #[tokio::test] async fn test_extract_executable_from_script_unix() { - use std::{fs, path::Path}; + use std::path::Path; use crate::global::trampoline::GlobalExecutable; @@ -520,7 +519,7 @@ export CONDA_PREFIX="/home/user/.pixi/envs/nushell" let script_path = Path::new("nu"); let tempdir = tempfile::tempdir().unwrap(); let script_path = tempdir.path().join(script_path); - fs::write(&script_path, script).unwrap(); + fs_err::write(&script_path, script).unwrap(); let script_global_bin = GlobalExecutable::Script(script_path); let executable_path = script_global_bin.executable().await.unwrap(); assert_eq!( diff --git a/src/global/project/manifest.rs b/src/global/project/manifest.rs index 5974b0c64..fb2b55adf 100644 --- a/src/global/project/manifest.rs +++ b/src/global/project/manifest.rs @@ -3,7 +3,6 @@ use std::path::{Path, PathBuf}; use std::str::FromStr; use fancy_display::FancyDisplay; -use fs_err as fs; use fs_err::tokio as tokio_fs; use indexmap::IndexSet; use miette::IntoDiagnostic; @@ -41,7 +40,7 @@ impl Manifest { /// Creates a new manifest from a path pub fn from_path(path: impl AsRef) -> miette::Result { let manifest_path = dunce::canonicalize(path.as_ref()).into_diagnostic()?; - let contents = fs::read_to_string(path.as_ref()).into_diagnostic()?; + let contents = fs_err::read_to_string(path.as_ref()).into_diagnostic()?; Self::from_str(manifest_path.as_ref(), contents) } diff --git a/src/install_pypi/install_wheel.rs b/src/install_pypi/install_wheel.rs index 66fb7b414..f19400398 100644 --- a/src/install_pypi/install_wheel.rs +++ b/src/install_pypi/install_wheel.rs @@ -37,7 +37,7 @@ pub(crate) fn get_wheel_info( /// See: fn find_dist_info(path: impl AsRef) -> miette::Result { // Iterate over `path` to find the `.dist-info` directory. It should be at the top-level. - let Some(dist_info) = fs::read_dir(path.as_ref()) + let Some(dist_info) = fs_err::read_dir(path.as_ref()) .into_diagnostic()? .find_map(|entry| { let entry = entry.ok()?; @@ -92,14 +92,14 @@ pub(crate) fn get_wheel_kind( // > 1.a Parse distribution-1.0.dist-info/WHEEL. // > 1.b Check that installer is compatible with Wheel-Version. Warn if minor version is greater, abort if major version is greater. let wheel_file_path = wheel_path.join(format!("{dist_info_prefix}.dist-info/WHEEL")); - let wheel_text = fs::read_to_string(wheel_file_path).into_diagnostic()?; + let wheel_text = fs_err::read_to_string(wheel_file_path).into_diagnostic()?; let lib_kind = parse_wheel_file(&wheel_text)?; Ok(lib_kind) } use std::{ collections::HashMap, - fs::{self, File}, + fs::File, io::{BufRead, BufReader, Read}, path::{Path, PathBuf}, }; diff --git a/src/lock_file/resolve/uv_resolution_context.rs b/src/lock_file/resolve/uv_resolution_context.rs index 0b0d8c59f..7155ae19c 100644 --- a/src/lock_file/resolve/uv_resolution_context.rs +++ b/src/lock_file/resolve/uv_resolution_context.rs @@ -30,7 +30,7 @@ impl UvResolutionContext { pub(crate) fn from_project(project: &Project) -> miette::Result { let uv_cache = get_cache_dir()?.join(consts::PYPI_CACHE_DIR); if !uv_cache.exists() { - std::fs::create_dir_all(&uv_cache) + fs_err::create_dir_all(&uv_cache) .into_diagnostic() .context("failed to create uv cache directory")?; } diff --git a/src/prefix.rs b/src/prefix.rs index e17d93d2c..db1d549e0 100644 --- a/src/prefix.rs +++ b/src/prefix.rs @@ -56,7 +56,7 @@ impl Prefix { let concurrency_limit = concurrency_limit.unwrap_or(100); let mut meta_futures = FuturesUnordered::>>::new(); let mut result = Vec::new(); - for entry in std::fs::read_dir(self.root.join("conda-meta")) + for entry in fs_err::read_dir(self.root.join("conda-meta")) .into_iter() .flatten() { diff --git a/src/project/environment.rs b/src/project/environment.rs index 2ff1e2425..3b78db4f2 100644 --- a/src/project/environment.rs +++ b/src/project/environment.rs @@ -1,7 +1,6 @@ use std::{ collections::{HashMap, HashSet}, fmt::Debug, - fs, hash::{Hash, Hasher}, sync::Once, }; @@ -133,8 +132,8 @@ impl<'p> Environment<'p> { "osx-arm64 (Apple Silicon) is not supported by the pixi.toml, falling back to osx-64 (emulated with Rosetta)" ); // Create a file to prevent the warning from showing up multiple times. Also ignore the result. - fs::create_dir_all(warn_folder).and_then(|_| { - std::fs::File::create(emulation_warn) + fs_err::create_dir_all(warn_folder).and_then(|_| { + fs_err::File::create(emulation_warn) }).ok(); } }); @@ -152,8 +151,8 @@ impl<'p> Environment<'p> { "win-arm64 is not supported by the pixi.toml, falling back to win-64 (emulation)" ); // Create a file to prevent the warning from showing up multiple times. Also ignore the result. - fs::create_dir_all(warn_folder).and_then(|_| { - std::fs::File::create(emulation_warn) + fs_err::create_dir_all(warn_folder).and_then(|_| { + fs_err::File::create(emulation_warn) }).ok(); } }); diff --git a/src/project/mod.rs b/src/project/mod.rs index f1e2f0df7..a27ef18c0 100644 --- a/src/project/mod.rs +++ b/src/project/mod.rs @@ -1043,7 +1043,7 @@ pub(crate) fn find_project_manifest(current_dir: PathBuf) -> Option { match *manifest { consts::PROJECT_MANIFEST => return Some(path), consts::PYPROJECT_MANIFEST => { - if let Ok(content) = std::fs::read_to_string(&path) { + if let Ok(content) = fs_err::read_to_string(&path) { if content.contains("[tool.pixi") { return Some(path); } @@ -1523,13 +1523,13 @@ mod tests { writeln!(file, "[project]").unwrap(); // Pixi child manifest is pyproject.toml with pixi tool - std::fs::create_dir_all(&pixi_child_dir).unwrap(); + fs_err::create_dir_all(&pixi_child_dir).unwrap(); let mut file = File::create(&manifest_path_pixi_child).unwrap(); writeln!(file, "[project]").unwrap(); writeln!(file, "[tool.pixi.project]").unwrap(); // Non pixi child manifest is pyproject.toml without pixi tool - std::fs::create_dir_all(&non_pixi_child_dir).unwrap(); + fs_err::create_dir_all(&non_pixi_child_dir).unwrap(); let mut file = File::create(&manifest_path_non_pixi_child).unwrap(); writeln!(file, "[project]").unwrap(); diff --git a/src/task/executable_task.rs b/src/task/executable_task.rs index e28001bf8..bde9a100f 100644 --- a/src/task/executable_task.rs +++ b/src/task/executable_task.rs @@ -21,6 +21,7 @@ use crate::{ task::task_graph::{TaskGraph, TaskId}, Project, }; +use fs_err::tokio as tokio_fs; use pixi_consts::consts; use crate::activation::CurrentEnvVarBehavior; @@ -252,7 +253,7 @@ impl<'p> ExecutableTask<'p> { let cache_name = self.cache_name(); let cache_file = self.project().task_cache_folder().join(cache_name); if cache_file.exists() { - let cache = tokio::fs::read_to_string(&cache_file).await?; + let cache = tokio_fs::read_to_string(&cache_file).await?; let cache: TaskCache = serde_json::from_str(&cache)?; let hash = TaskHash::from_task(self, lock_file).await; if let Ok(Some(hash)) = hash { diff --git a/src/task/file_hashes.rs b/src/task/file_hashes.rs index 0fb2fbbac..b31782943 100644 --- a/src/task/file_hashes.rs +++ b/src/task/file_hashes.rs @@ -177,7 +177,7 @@ fn compute_file_hash(path: &Path) -> Result { mod test { use super::*; use assert_matches::assert_matches; - use std::fs::{create_dir, write}; + use fs_err::{create_dir, write}; use tempfile::tempdir; #[tokio::test] diff --git a/src/utils.rs b/src/utils.rs index 0c076e29e..bfaa2397c 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -24,10 +24,10 @@ const EXDEV: i32 = 17; /// the file if possible and otherwise copying the file and removing the /// original. pub(crate) fn move_file(from: &Path, to: &Path) -> Result<(), MoveError> { - if let Err(e) = std::fs::rename(from, to) { + if let Err(e) = fs_err::rename(from, to) { if e.raw_os_error() == Some(EXDEV) { - std::fs::copy(from, to).map_err(MoveError::CopyFailed)?; - std::fs::remove_file(from).map_err(MoveError::FailedToRemove)? + fs_err::copy(from, to).map_err(MoveError::CopyFailed)?; + fs_err::remove_file(from).map_err(MoveError::FailedToRemove)? } else { return Err(MoveError::MoveFailed(e)); } diff --git a/tests/integration_rust/common/mod.rs b/tests/integration_rust/common/mod.rs index 1973947ad..55df5e3e6 100644 --- a/tests/integration_rust/common/mod.rs +++ b/tests/integration_rust/common/mod.rs @@ -217,8 +217,8 @@ impl PixiControl { // Add default project config let pixi_path = tempdir.path().join(".pixi"); - std::fs::create_dir_all(&pixi_path).unwrap(); - std::fs::write(pixi_path.join("config.toml"), DEFAULT_PROJECT_CONFIG).unwrap(); + fs_err::create_dir_all(&pixi_path).unwrap(); + fs_err::write(pixi_path.join("config.toml"), DEFAULT_PROJECT_CONFIG).unwrap(); // Hide the progress bars for the tests // Otherwise the override the test output @@ -229,7 +229,7 @@ impl PixiControl { /// Creates a new PixiControl instance from an existing manifest pub fn from_manifest(manifest: &str) -> miette::Result { let pixi = Self::new()?; - std::fs::write(pixi.manifest_path(), manifest) + fs_err::write(pixi.manifest_path(), manifest) .into_diagnostic() .context("failed to write pixi.toml")?; Ok(pixi) @@ -237,7 +237,7 @@ impl PixiControl { /// Updates the complete manifest pub fn update_manifest(&self, manifest: &str) -> miette::Result<()> { - std::fs::write(self.manifest_path(), manifest) + fs_err::write(self.manifest_path(), manifest) .into_diagnostic() .context("failed to write pixi.toml")?; Ok(()) @@ -278,7 +278,7 @@ impl PixiControl { /// Get the manifest contents pub fn manifest_contents(&self) -> miette::Result { - std::fs::read_to_string(self.manifest_path()) + fs_err::read_to_string(self.manifest_path()) .into_diagnostic() .context("failed to read manifest") } diff --git a/tests/integration_rust/init_tests.rs b/tests/integration_rust/init_tests.rs index 235e5330f..e43ed34f9 100644 --- a/tests/integration_rust/init_tests.rs +++ b/tests/integration_rust/init_tests.rs @@ -64,7 +64,7 @@ async fn init_from_existing_pyproject_toml() { let project_path = pixi.project_path(); let pyproject_toml = project_path.join("pyproject.toml"); let pyproject_toml_contents = include_str!("../data/pixi_tomls/pyproject_no_pixi.toml"); - std::fs::write(&pyproject_toml, pyproject_toml_contents).unwrap(); + fs_err::write(&pyproject_toml, pyproject_toml_contents).unwrap(); // Init a new project pixi.init() diff --git a/tests/integration_rust/install_tests.rs b/tests/integration_rust/install_tests.rs index b70f767fd..f11ac9567 100644 --- a/tests/integration_rust/install_tests.rs +++ b/tests/integration_rust/install_tests.rs @@ -3,6 +3,7 @@ use crate::common::{ package_database::{Package, PackageDatabase}, }; use crate::common::{LockFileExt, PixiControl}; +use fs_err::tokio as tokio_fs; use pixi::cli::cli_config::{PrefixUpdateConfig, ProjectConfig}; use pixi::cli::{run, run::Args, LockFileUsageArgs}; use pixi::environment::LockFileUsage; @@ -13,7 +14,7 @@ use pixi_consts::consts; use pixi_manifest::{FeatureName, FeaturesExt}; use rattler_conda_types::Platform; use std::{ - fs::{create_dir_all, File}, + fs::File, io::Write, path::{Path, PathBuf}, str::FromStr, @@ -159,10 +160,10 @@ async fn install_locked_with_config() { let mut config = Config::default(); let target_dir = pixi.project_path().join("target"); config.detached_environments = Some(DetachedEnvironments::Path(target_dir.clone())); - create_dir_all(target_dir.clone()).unwrap(); + fs_err::create_dir_all(target_dir.clone()).unwrap(); let config_path = pixi.project().unwrap().pixi_dir().join("config.toml"); - create_dir_all(config_path.parent().unwrap()).unwrap(); + fs_err::create_dir_all(config_path.parent().unwrap()).unwrap(); let mut file = File::create(config_path).unwrap(); file.write_all(toml_edit::ser::to_string(&config).unwrap().as_bytes()) @@ -527,12 +528,12 @@ async fn test_installer_name() { // Check that installer name is uv-pixi assert!(dist_info.exists(), "{dist_info:?} does not exist"); let installer = dist_info.join("INSTALLER"); - let installer = std::fs::read_to_string(installer).unwrap(); + let installer = fs_err::read_to_string(installer).unwrap(); assert_eq!(installer, consts::PIXI_UV_INSTALLER); // Write a new installer name to the INSTALLER file // so that we fake that it is not installed by pixi - std::fs::write(dist_info.join("INSTALLER"), "not-pixi").unwrap(); + fs_err::write(dist_info.join("INSTALLER"), "not-pixi").unwrap(); pixi.remove("click==8.0.0") .with_install(true) .set_type(pixi::DependencyType::PypiDependency) @@ -544,7 +545,7 @@ async fn test_installer_name() { // we know that pixi did not touch the package assert!(dist_info.exists()); let installer = dist_info.join("INSTALLER"); - let installer = std::fs::read_to_string(installer).unwrap(); + let installer = fs_err::read_to_string(installer).unwrap(); assert_eq!(installer, "not-pixi"); // re-manage the package by adding it, this should cause a reinstall @@ -554,7 +555,7 @@ async fn test_installer_name() { .await .unwrap(); let installer = dist_info.join("INSTALLER"); - let installer = std::fs::read_to_string(installer).unwrap(); + let installer = fs_err::read_to_string(installer).unwrap(); assert_eq!(installer, consts::PIXI_UV_INSTALLER); } @@ -565,7 +566,7 @@ async fn test_installer_name() { /// installed. async fn test_old_lock_install() { let lock_str = - std::fs::read_to_string("tests/data/satisfiability/old_lock_file/pixi.lock").unwrap(); + fs_err::read_to_string("tests/data/satisfiability/old_lock_file/pixi.lock").unwrap(); let project = Project::from_path(Path::new( "tests/data/satisfiability/old_lock_file/pyproject.toml", )) @@ -583,7 +584,7 @@ async fn test_old_lock_install() { .unwrap(); assert_eq!( lock_str, - std::fs::read_to_string("tests/data/satisfiability/old_lock_file/pixi.lock").unwrap() + fs_err::read_to_string("tests/data/satisfiability/old_lock_file/pixi.lock").unwrap() ); } @@ -645,8 +646,8 @@ setup( let project_path = pixi.project_path(); // Write setup.py to a my-pkg folder let my_pkg = project_path.join("my-pkg"); - std::fs::create_dir_all(&my_pkg).unwrap(); - std::fs::write(my_pkg.join("setup.py"), setup_py).unwrap(); + fs_err::create_dir_all(&my_pkg).unwrap(); + fs_err::write(my_pkg.join("setup.py"), setup_py).unwrap(); let has_pkg = pixi .project() @@ -726,7 +727,7 @@ async fn test_ensure_gitignore_file_creation() { gitignore_path.exists(), ".pixi/.gitignore file was not created" ); - let contents = tokio::fs::read_to_string(&gitignore_path).await.unwrap(); + let contents = tokio_fs::read_to_string(&gitignore_path).await.unwrap(); assert_eq!( contents, "*\n", ".pixi/.gitignore file does not contain the expected content" @@ -737,7 +738,7 @@ async fn test_ensure_gitignore_file_creation() { .await .unwrap(); pixi.install().await.unwrap(); - let contents = tokio::fs::read_to_string(&gitignore_path).await.unwrap(); + let contents = tokio_fs::read_to_string(&gitignore_path).await.unwrap(); assert_eq!( contents, "*\nsome_file\n", ".pixi/.gitignore file does not contain the expected content" @@ -754,7 +755,7 @@ async fn test_ensure_gitignore_file_creation() { gitignore_path.exists(), ".pixi/.gitignore file was not recreated" ); - let contents = tokio::fs::read_to_string(&gitignore_path).await.unwrap(); + let contents = tokio_fs::read_to_string(&gitignore_path).await.unwrap(); assert_eq!( contents, "*\n", ".pixi/.gitignore file does not contain the expected content" diff --git a/tests/integration_rust/project_tests.rs b/tests/integration_rust/project_tests.rs index 6da6e6173..856d2d343 100644 --- a/tests/integration_rust/project_tests.rs +++ b/tests/integration_rust/project_tests.rs @@ -104,11 +104,11 @@ async fn parse_project() { async fn parse_valid_schema_projects() { // Test all files in the schema/examples/valid directory let schema_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("schema/examples/valid"); - for entry in std::fs::read_dir(schema_dir).unwrap() { + for entry in fs_err::read_dir(schema_dir).unwrap() { let entry = entry.unwrap(); let path = entry.path(); if path.extension().map(|ext| ext == "toml").unwrap_or(false) { - let pixi_toml = std::fs::read_to_string(&path).unwrap(); + let pixi_toml = fs_err::read_to_string(&path).unwrap(); let _project = Project::from_str(&PathBuf::from("pixi.toml"), &pixi_toml).unwrap(); } } @@ -118,11 +118,11 @@ async fn parse_valid_schema_projects() { fn parse_valid_docs_manifests() { // Test all files in the docs/source_files/pixi_tomls directory let schema_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("docs/source_files/pixi_tomls"); - for entry in std::fs::read_dir(schema_dir).unwrap() { + for entry in fs_err::read_dir(schema_dir).unwrap() { let entry = entry.unwrap(); let path = entry.path(); if path.extension().map(|ext| ext == "toml").unwrap_or(false) { - let pixi_toml = std::fs::read_to_string(&path).unwrap(); + let pixi_toml = fs_err::read_to_string(&path).unwrap(); let _project = Project::from_str(&PathBuf::from("pixi.toml"), &pixi_toml).unwrap(); } } @@ -133,11 +133,11 @@ fn parse_valid_docs_configs() { // Test all files in the docs/source_files/pixi_config_tomls directory let schema_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("docs/source_files/pixi_config_tomls"); - for entry in std::fs::read_dir(schema_dir).unwrap() { + for entry in fs_err::read_dir(schema_dir).unwrap() { let entry = entry.unwrap(); let path = entry.path(); if path.extension().map(|ext| ext == "toml").unwrap_or(false) { - let toml = std::fs::read_to_string(&path).unwrap(); + let toml = fs_err::read_to_string(&path).unwrap(); let (_config, unused_keys) = Config::from_toml(&toml).unwrap(); assert_eq!( unused_keys, diff --git a/tests/integration_rust/solve_group_tests.rs b/tests/integration_rust/solve_group_tests.rs index 26a7d38b1..5f945bfd3 100644 --- a/tests/integration_rust/solve_group_tests.rs +++ b/tests/integration_rust/solve_group_tests.rs @@ -619,7 +619,7 @@ async fn test_file_url_as_mapping_location() { let tmp_dir = tempfile::tempdir().unwrap(); let mapping_file = tmp_dir.path().join("custom_mapping.json"); - let _ = std::fs::write( + let _ = fs_err::write( &mapping_file, r#" { diff --git a/tests/integration_rust/task_tests.rs b/tests/integration_rust/task_tests.rs index b8d2e706a..d3ca73d03 100644 --- a/tests/integration_rust/task_tests.rs +++ b/tests/integration_rust/task_tests.rs @@ -5,7 +5,6 @@ use pixi::task::TaskName; use pixi_manifest::task::CmdArgs; use pixi_manifest::{FeatureName, Task}; use rattler_conda_types::Platform; -use std::fs; use std::path::PathBuf; #[tokio::test] @@ -174,7 +173,7 @@ async fn test_cwd() { pixi.init().without_channels().await.unwrap(); // Create test dir - fs::create_dir(pixi.project_path().join("test")).unwrap(); + fs_err::create_dir(pixi.project_path().join("test")).unwrap(); pixi.tasks() .add("pwd-test".into(), None, FeatureName::Default)