diff --git a/packages/zpm-config/src/fns.rs b/packages/zpm-config/src/fns.rs index 756a8dd3..96c54e15 100644 --- a/packages/zpm-config/src/fns.rs +++ b/packages/zpm-config/src/fns.rs @@ -4,7 +4,7 @@ pub fn check_tsconfig(context: &ConfigurationContext) -> bool { if let Some(project_cwd) = &context.project_cwd { let root_has_tsconfig = project_cwd .with_join_str("tsconfig.json") - .fs_exists(); + .fs_exists_blocking(); if root_has_tsconfig { return true; @@ -14,7 +14,7 @@ pub fn check_tsconfig(context: &ConfigurationContext) -> bool { if let Some(package_cwd) = &context.package_cwd { let package_has_tsconfig = package_cwd .with_join_str("tsconfig.json") - .fs_exists(); + .fs_exists_blocking(); if package_has_tsconfig { return true; diff --git a/packages/zpm-formats/src/lib.rs b/packages/zpm-formats/src/lib.rs index f78b070b..39f7e52f 100644 --- a/packages/zpm-formats/src/lib.rs +++ b/packages/zpm-formats/src/lib.rs @@ -114,8 +114,8 @@ impl<'a> Entry<'a> { pub fn entries_to_disk<'a>(entries: &[Entry<'a>], base: &Path) -> Result<(), Error> { for entry in entries { base.with_join(&entry.name) - .fs_create_parent()? - .fs_change(&entry.data, entry.mode & 0o111 == 0o111)?; + .fs_create_parent_blocking()? + .fs_change_blocking(&entry.data, entry.mode & 0o111 == 0o111)?; } Ok(()) @@ -126,7 +126,7 @@ pub fn entries_from_folder<'a>(path: &Path) -> Result>, Error> { let mut process_queue = vec![path.clone()]; while let Some(path) = process_queue.pop() { - let listing = path.fs_read_dir()?; + let listing = path.fs_read_dir_blocking()?; for entry in listing { let entry = entry?; @@ -138,7 +138,7 @@ pub fn entries_from_folder<'a>(path: &Path) -> Result>, Error> { } let name = Path::try_from(entry.file_name().into_string()?)?; - let data = path.fs_read()?; + let data = path.fs_read_blocking()?; let metadata = path.fs_metadata()?; let is_exec = metadata.permissions().mode() & 0o111 != 0; @@ -164,7 +164,7 @@ pub fn entries_from_files<'a>(base: &Path, files: &[Path]) -> Result { - Ok(self.fs_read_text_prealloc()?) + Ok(self.fs_read_text_prealloc_blocking()?) }, pnp::fs::VPath::Virtual(info) => { let file_data = Path::try_from(info.physical_base_path()).unwrap() - .fs_read_text_prealloc()?; + .fs_read_text_prealloc_blocking()?; Ok(file_data) }, @@ -196,7 +196,7 @@ impl ZipSupport for Path { pnp::fs::VPath::Zip(info) => { let zip_data = Path::try_from(info.physical_base_path()).unwrap() - .fs_read_prealloc()?; + .fs_read_prealloc_blocking()?; let file_data = Path::try_from(info.zip_path)? .fs_read_text_from_zip_buffer(&zip_data)?; diff --git a/packages/zpm-switch/src/cache.rs b/packages/zpm-switch/src/cache.rs index d0d1c58e..523c5800 100644 --- a/packages/zpm-switch/src/cache.rs +++ b/packages/zpm-switch/src/cache.rs @@ -53,7 +53,7 @@ pub fn cache_dir() -> Result { pub fn cache_metadata(p: &Path) -> Result { let key_string = p .with_join_str("meta.json") - .fs_read_text()?; + .fs_read_text_blocking()?; let key_data: CacheKey = JsonDocument::hydrate_from_str(&key_string)?; @@ -116,7 +116,7 @@ async fn pretty_download>>(key_data: &Cache result } -fn access(key_data: &CacheKey) -> Result<(Path, bool), Error> { +async fn access(key_data: &CacheKey) -> Result<(Path, bool), Error> { let key_string = JsonDocument::to_string(key_data)?; let key_hash @@ -130,28 +130,42 @@ fn access(key_data: &CacheKey) -> Result<(Path, bool), Error> { let ready_path = cache_path .with_join_str(".ready"); - Ok((cache_path, ready_path.fs_exists())) + Ok((cache_path, ready_path.fs_exists().await)) } -pub fn check(key_data: &CacheKey) -> Result { - Ok(access(key_data)?.1) +pub async fn check(key_data: &CacheKey) -> Result { + Ok(access(key_data).await?.1) +} + +fn touch_ready_sync(ready_path: Path) -> Result<(), Error> { + ready_path + .fs_set_modified(std::time::SystemTime::now())?; + Ok(()) +} + +fn move_cache_sync(temp_dir: Path, cache_path: Path) -> Result<(), Error> { + temp_dir + .fs_concurrent_move(&cache_path)?; + Ok(()) } pub async fn ensure>, F: FnOnce(Path) -> R>(key_data: &CacheKey, f: F) -> Result { - match access(key_data)? { + match access(key_data).await? { (cache_path, true) => { let ready_path = cache_path .with_join_str(".ready"); // Not a big deal if this fails, which may happen on filesystems // with limited permissions (read-only ones) - let _ = ready_path - .fs_set_modified(std::time::SystemTime::now()); + let _ = tokio::task::spawn_blocking(move || touch_ready_sync(ready_path)).await; Ok(cache_path) }, (cache_path, false) => { + let cache_path_for_move + = cache_path.clone(); + pretty_download(key_data, async { let temp_dir = Path::temp_dir()?; @@ -163,17 +177,18 @@ pub async fn ensure>, F: FnOnce(Path) -> R> temp_dir .with_join_str("meta.json") - .fs_write(&meta_content)?; + .fs_write(&meta_content).await?; temp_dir .with_join_str(".ready") - .fs_write([])?; + .fs_write([]).await?; cache_path - .fs_create_parent()?; + .fs_create_parent().await?; - temp_dir - .fs_concurrent_move(&cache_path)?; + tokio::task::spawn_blocking(move || { + move_cache_sync(temp_dir, cache_path_for_move) + }).await??; Ok(()) }).await?; diff --git a/packages/zpm-switch/src/commands/switch/cache_check.rs b/packages/zpm-switch/src/commands/switch/cache_check.rs index 366f616f..00ec7c5f 100644 --- a/packages/zpm-switch/src/commands/switch/cache_check.rs +++ b/packages/zpm-switch/src/commands/switch/cache_check.rs @@ -24,7 +24,7 @@ impl CacheCheckCommand { platform: get_system_string().to_string(), }; - if !cache::check(&cache_key)? { + if !cache::check(&cache_key).await? { return Err(Error::CacheNotFound(version.clone())); } } diff --git a/packages/zpm-switch/src/commands/switch/cache_clear.rs b/packages/zpm-switch/src/commands/switch/cache_clear.rs index cb4acc61..09caa836 100644 --- a/packages/zpm-switch/src/commands/switch/cache_clear.rs +++ b/packages/zpm-switch/src/commands/switch/cache_clear.rs @@ -23,13 +23,12 @@ impl CacheClearCommand { = cache::cache_dir()?; if self.old { - let Some(cache_entries) = cache_dir.fs_read_dir().ok_missing()? else { - return Ok(()); + let mut cache_entries = match cache_dir.fs_read_dir().await.ok_missing()? { + Some(cache_entries) => cache_entries, + None => return Ok(()), }; - for entry in cache_entries { - let entry - = entry?; + while let Some(entry) = cache_entries.next_entry().await? { let entry_path = Path::try_from(entry.path())?; @@ -41,12 +40,13 @@ impl CacheClearCommand { }; if entry_last_used.elapsed().unwrap() > std::time::Duration::from_secs(60 * 60 * 24 * 7) { - entry_path.fs_rm().ok_missing()?; + entry_path.fs_rm().await.ok_missing()?; } } } else { cache_dir .fs_rm() + .await .ok_missing()?; } diff --git a/packages/zpm-switch/src/commands/switch/cache_list.rs b/packages/zpm-switch/src/commands/switch/cache_list.rs index 47562677..664f0d6f 100644 --- a/packages/zpm-switch/src/commands/switch/cache_list.rs +++ b/packages/zpm-switch/src/commands/switch/cache_list.rs @@ -19,13 +19,12 @@ impl CacheListCommand { let cache_dir = cache::cache_dir()?; - let Some(cache_entries) = cache_dir.fs_read_dir().ok_missing()? else { - return Ok(()); + let mut cache_entries = match cache_dir.fs_read_dir().await.ok_missing()? { + Some(cache_entries) => cache_entries, + None => return Ok(()), }; - for entry in cache_entries { - let entry - = entry?; + while let Some(entry) = cache_entries.next_entry().await? { let entry_path = Path::try_from(entry.path())?; diff --git a/packages/zpm-switch/src/commands/switch/link.rs b/packages/zpm-switch/src/commands/switch/link.rs index 04bbacde..6140dabd 100644 --- a/packages/zpm-switch/src/commands/switch/link.rs +++ b/packages/zpm-switch/src/commands/switch/link.rs @@ -26,7 +26,7 @@ impl LinkCommand { set_link(&Link { project_cwd: detected_root_path.clone(), - link_target: LinkTarget::Local {bin_path: self.path.fs_canonicalize()?}, + link_target: LinkTarget::Local {bin_path: self.path.fs_canonicalize().await?}, })?; println!( diff --git a/packages/zpm-switch/src/commands/switch/links_clear.rs b/packages/zpm-switch/src/commands/switch/links_clear.rs index 670c2bf9..3daf1eda 100644 --- a/packages/zpm-switch/src/commands/switch/links_clear.rs +++ b/packages/zpm-switch/src/commands/switch/links_clear.rs @@ -20,6 +20,7 @@ impl LinksClearCommand { links_dir .fs_rm() + .await .ok_missing()?; Ok(()) diff --git a/packages/zpm-switch/src/commands/switch/postinstall.rs b/packages/zpm-switch/src/commands/switch/postinstall.rs index 9aa763b6..d43cf8d4 100644 --- a/packages/zpm-switch/src/commands/switch/postinstall.rs +++ b/packages/zpm-switch/src/commands/switch/postinstall.rs @@ -93,7 +93,7 @@ impl PostinstallCommand { fn write_profile(&self, bin_dir: &Path, profile: &ShellProfile) { let profile_content = profile.rc_file - .fs_read_text_prealloc() + .fs_read_text_prealloc_blocking() .ok_missing(); if let Ok(maybe_profile_content) = profile_content { @@ -128,8 +128,8 @@ impl PostinstallCommand { fn write_env(&self, env_file: &Path, env_line: &str) -> Result<(), Error> { env_file - .fs_create_parent()? - .fs_write_text(env_line)?; + .fs_create_parent_blocking()? + .fs_write_text_blocking(env_line)?; Ok(()) } @@ -153,8 +153,8 @@ impl PostinstallCommand { .push_str(&rc_line); rc_file - .fs_create_parent()? - .fs_write_text(&rc_content)?; + .fs_create_parent_blocking()? + .fs_write_text_blocking(&rc_content)?; Ok(()) } @@ -168,7 +168,7 @@ impl PostinstallCommand { = Path::from_str(&github_path).unwrap(); let github_path_file_write_result = github_path_file - .fs_append_text(format!("{}\n", bin_dir.to_file_string())); + .fs_append_text_blocking(format!("{}\n", bin_dir.to_file_string())); if github_path_file_write_result.is_err() { Note::Warning(format!(" @@ -239,7 +239,7 @@ impl PostinstallCommand { .with_join_str("../../../../user/platform.json"); let mut volta_platform_content = volta_platform_path - .fs_read_prealloc()?; + .fs_read_prealloc_blocking()?; if volta_platform_content.is_empty() { volta_platform_content = "{}".as_bytes().to_vec(); @@ -254,7 +254,7 @@ impl PostinstallCommand { )?; volta_platform_path - .fs_write(&document.input)?; + .fs_write_blocking(&document.input)?; Ok(()) } diff --git a/packages/zpm-switch/src/commands/switch/update.rs b/packages/zpm-switch/src/commands/switch/update.rs index dba20c1f..62b9b78b 100644 --- a/packages/zpm-switch/src/commands/switch/update.rs +++ b/packages/zpm-switch/src/commands/switch/update.rs @@ -26,7 +26,8 @@ impl UpdateCommand { .with_join_str("yarn-install-script.sh"); install_script_path - .fs_write(install_script)?; + .fs_write(install_script) + .await?; Command::new("bash") .arg(install_script_path.to_path_buf()) diff --git a/packages/zpm-switch/src/install.rs b/packages/zpm-switch/src/install.rs index f1527c7e..817f490a 100644 --- a/packages/zpm-switch/src/install.rs +++ b/packages/zpm-switch/src/install.rs @@ -104,7 +104,7 @@ async fn install_native_from_zpm(source: &cache::CacheKey, binary_name: &Path) - async fn install_node_js_from_url(source: &cache::CacheKey) -> Result { let cache_path = cache::ensure(source, |p| async move { - p.with_join_str("bin.js").fs_write(fetch(&source.to_url()).await?)?; + p.with_join_str("bin.js").fs_write(fetch(&source.to_url()).await?).await?; Ok(()) }).await?; diff --git a/packages/zpm-switch/src/links.rs b/packages/zpm-switch/src/links.rs index 806ee11c..1172c114 100644 --- a/packages/zpm-switch/src/links.rs +++ b/packages/zpm-switch/src/links.rs @@ -52,8 +52,8 @@ pub fn set_link(link: &Link) -> Result<(), Error> { .with_join_str(format!("{}.json", hash.short())); link_path - .fs_create_parent()? - .fs_write(JsonDocument::to_string(link)?)?; + .fs_create_parent_blocking()? + .fs_write_blocking(JsonDocument::to_string(link)?)?; Ok(()) } @@ -66,7 +66,7 @@ pub fn unset_link(project_cwd: &Path) -> Result<(), Error> { .with_join_str(format!("{}.json", hash.short())); link_path - .fs_rm()?; + .fs_rm_blocking()?; Ok(()) } @@ -75,7 +75,7 @@ pub fn list_links() -> Result, Error> { let links_dir = links_dir()?; - let Some(dir_entries) = links_dir.fs_read_dir().ok_missing()? else { + let Some(dir_entries) = links_dir.fs_read_dir_blocking().ok_missing()? else { return Ok(BTreeSet::new()); }; @@ -83,7 +83,7 @@ pub fn list_links() -> Result, Error> { .filter_map(|entry| entry.ok()) .filter(|entry| entry.file_type().map_or(false, |f| f.is_file())) .filter_map(|link_path| Path::try_from(link_path.path()).ok()) - .filter_map(|link_path| link_path.fs_read_text().ok()) + .filter_map(|link_path| link_path.fs_read_text_blocking().ok()) .filter_map(|contents| JsonDocument::hydrate_from_str::(&contents).ok()) .collect::>(); @@ -98,7 +98,7 @@ pub fn get_link(path: &Path) -> Result, Error> { .with_join_str(format!("{}.json", hash.short())); let link = link_path - .fs_read_text() + .fs_read_text_blocking() .ok_missing()? .and_then(|link| JsonDocument::hydrate_from_str::(&link).ok()); diff --git a/packages/zpm-switch/src/manifest.rs b/packages/zpm-switch/src/manifest.rs index 61627fe7..a51eb472 100644 --- a/packages/zpm-switch/src/manifest.rs +++ b/packages/zpm-switch/src/manifest.rs @@ -137,7 +137,7 @@ pub fn find_closest_package_manager(path: &Path) -> Result { .with_join_str("package.json"); let manifest = manifest_path - .fs_read_text() + .fs_read_text_blocking() .ok_missing()?; if let Some(manifest) = &manifest { @@ -157,7 +157,7 @@ pub fn find_closest_package_manager(path: &Path) -> Result { let root_file_path = parent .with_join_str(root_file); - if root_file_path.fs_exists() { + if root_file_path.fs_exists_blocking() { return Ok(FindResult { detected_root_path: Some(parent), detected_package_manager: None, diff --git a/packages/zpm-switch/src/yarn.rs b/packages/zpm-switch/src/yarn.rs index 8e05ff75..956fd6d2 100644 --- a/packages/zpm-switch/src/yarn.rs +++ b/packages/zpm-switch/src/yarn.rs @@ -85,7 +85,7 @@ pub async fn resolve_channel_selector(channel_selector: &ChannelSelector) -> Res = Path::temp_root_dir()? .with_join_str(&format!("yswitch-{}-{}-{}", release_line, channel, today.format("%Y%m%d"))); - if let Ok(version_str) = channel_path.fs_read_text_async().await { + if let Ok(version_str) = channel_path.fs_read_text().await { let version = Version::from_str(&version_str)?; @@ -106,7 +106,8 @@ pub async fn resolve_channel_selector(channel_selector: &ChannelSelector) -> Res = Version::from_str(version_str)?; channel_path - .fs_write_text(&version_str)?; + .fs_write_text(&version_str) + .await?; Ok(version) } diff --git a/packages/zpm-switch/tests/postinstall.rs b/packages/zpm-switch/tests/postinstall.rs index 82018efc..79ab5bf8 100644 --- a/packages/zpm-switch/tests/postinstall.rs +++ b/packages/zpm-switch/tests/postinstall.rs @@ -37,7 +37,7 @@ fn empty_profile_file() -> Result<(), Box> { let profile_content = tmp_dir .with_join_str(".profile") - .fs_read_text_prealloc() + .fs_read_text_prealloc_blocking() .expect("Failed to read .profile"); assert_eq!(profile_content, format!(". \"{}/.yarn/switch/env\"\n", tmp_dir.to_file_string())); @@ -54,7 +54,7 @@ fn profile_file_with_existing_path() -> Result<(), Box> { tmp_dir .with_join_str(".profile") - .fs_write_text("# Hello world!\n") + .fs_write_text_blocking("# Hello world!\n") .expect("Failed to write .profile"); cmd.args(vec!["switch", "postinstall", "--home-dir", tmp_dir.as_str()]); @@ -65,7 +65,7 @@ fn profile_file_with_existing_path() -> Result<(), Box> { let profile_content = tmp_dir .with_join_str(".profile") - .fs_read_text_prealloc() + .fs_read_text_prealloc_blocking() .expect("Failed to read .profile"); assert_eq!(profile_content, format!("# Hello world!\n. \"{}/.yarn/switch/env\"\n", tmp_dir.to_file_string())); @@ -85,7 +85,7 @@ fn profile_file_with_duplicate_path() -> Result<(), Box> tmp_dir .with_join_str(".profile") - .fs_write_text(&initial_profile_content) + .fs_write_text_blocking(&initial_profile_content) .expect("Failed to write .profile"); cmd.args(vec!["switch", "postinstall", "--home-dir", tmp_dir.as_str()]); @@ -96,7 +96,7 @@ fn profile_file_with_duplicate_path() -> Result<(), Box> let profile_content = tmp_dir .with_join_str(".profile") - .fs_read_text_prealloc() + .fs_read_text_prealloc_blocking() .expect("Failed to read .profile"); assert_eq!(profile_content, initial_profile_content); diff --git a/packages/zpm-sync/src/lib.rs b/packages/zpm-sync/src/lib.rs index bc6300cd..6e565cba 100644 --- a/packages/zpm-sync/src/lib.rs +++ b/packages/zpm-sync/src/lib.rs @@ -314,7 +314,7 @@ impl<'a> SyncTree<'a> { if self.dry_run { file_ops.push(FileOp::Delete(path.clone())); } else { - path.fs_rm()?; + path.fs_rm_blocking()?; } } @@ -337,7 +337,7 @@ impl<'a> SyncTree<'a> { match template { SyncTemplate::Zip {archive_path, inner_path} => { let zip_buffer - = archive_path.fs_read()?; + = archive_path.fs_read_blocking()?; let zip_entries = zpm_formats::zip::entries_from_zip(&zip_buffer)? @@ -364,7 +364,7 @@ impl<'a> SyncTree<'a> { } } else { if !check.must_create { - let extraneous_entries = path.fs_read_dir() + let extraneous_entries = path.fs_read_dir_blocking() .ok_missing()? .map(|read_dir| read_dir.collect::, _>>()) .transpose()? @@ -381,7 +381,7 @@ impl<'a> SyncTree<'a> { if self.dry_run { file_ops.push(FileOp::Delete(entry_path)); } else { - entry_path.fs_rm()?; + entry_path.fs_rm_blocking()?; } } } @@ -400,7 +400,7 @@ impl<'a> SyncTree<'a> { if self.dry_run { file_ops.push(FileOp::CreateFile(path.clone(), data[..data.len().min(20)].to_vec())); } else { - path.fs_write(data)?; + path.fs_write_blocking(data)?; } } diff --git a/packages/zpm-utils/src/path.rs b/packages/zpm-utils/src/path.rs index 0dccdd1e..32afdcfa 100644 --- a/packages/zpm-utils/src/path.rs +++ b/packages/zpm-utils/src/path.rs @@ -1,6 +1,7 @@ use std::{collections::BTreeMap, io::{Read, Write}, os::unix::ffi::OsStrExt, str::{FromStr, Split}}; use rkyv::Archive; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; use crate::{diff_data, impl_file_string_from_str, impl_file_string_serialization, path_resolve::resolve_path, DataType, FromFileString, IoResultExt, PathError, PathIterator, ToFileString, ToHumanString}; @@ -407,23 +408,40 @@ impl Path { Ok(()) } - pub fn fs_canonicalize(&self) -> Result { + pub fn fs_canonicalize_blocking(&self) -> Result { Ok(Path::try_from(std::fs::canonicalize(&self.path)?)?) } - pub fn fs_create_parent(&self) -> Result<&Self, PathError> { + pub async fn fs_canonicalize(&self) -> Result { + Ok(Path::try_from(tokio::fs::canonicalize(&self.path).await?)?) + } + + pub fn fs_create_parent_blocking(&self) -> Result<&Self, PathError> { if let Some(parent) = self.dirname() { - parent.fs_create_dir_all()?; + parent.fs_create_dir_all_blocking()?; } Ok(self) } - pub fn fs_create_dir_all(&self) -> Result<&Self, PathError> { + pub async fn fs_create_parent(&self) -> Result<&Self, PathError> { + if let Some(parent) = self.dirname() { + parent.fs_create_dir_all().await?; + } + + Ok(self) + } + + pub fn fs_create_dir_all_blocking(&self) -> Result<&Self, PathError> { std::fs::create_dir_all(&self.path)?; Ok(self) } + pub async fn fs_create_dir_all(&self) -> Result<&Self, PathError> { + tokio::fs::create_dir_all(&self.path).await?; + Ok(self) + } + pub fn fs_create_dir(&self) -> Result<&Self, PathError> { std::fs::create_dir(&self.path)?; Ok(self) @@ -442,10 +460,14 @@ impl Path { Ok(std::fs::metadata(&self.path)?) } - pub fn fs_exists(&self) -> bool { + pub fn fs_exists_blocking(&self) -> bool { self.fs_metadata().is_ok() } + pub async fn fs_exists(&self) -> bool { + tokio::fs::try_exists(&self.path).await.unwrap_or(false) + } + pub fn fs_is_symlink(&self) -> bool { self.fs_symlink_metadata().map(|m| m.file_type().is_symlink()).unwrap_or(false) } @@ -463,7 +485,7 @@ impl Path { } pub fn if_exists(&self) -> Option { - if self.fs_exists() { + if self.fs_exists_blocking() { Some(self.clone()) } else { None @@ -486,16 +508,33 @@ impl Path { } } - pub fn fs_read(&self) -> Result, PathError> { + pub fn fs_read_blocking(&self) -> Result, PathError> { Ok(std::fs::read(&self.to_path_buf())?) } - pub fn fs_read_prealloc(&self) -> Result, PathError> { + pub async fn fs_read(&self) -> Result, PathError> { + Ok(tokio::fs::read(self.to_path_buf()).await?) + } + + pub fn fs_read_prealloc_blocking(&self) -> Result, PathError> { let metadata = self.fs_metadata()?; Ok(self.fs_read_with_size(metadata.len())?) } + pub async fn fs_read_prealloc(&self) -> Result, PathError> { + let metadata + = tokio::fs::metadata(self.to_path_buf()).await?; + + let mut data = Vec::with_capacity(metadata.len() as usize); + + let mut file + = tokio::fs::File::open(self.to_path_buf()).await?; + file.read_to_end(&mut data).await?; + + Ok(data) + } + pub fn fs_read_with_size(&self, size: u64) -> Result, PathError> { let mut data = Vec::with_capacity(size as usize); @@ -505,16 +544,29 @@ impl Path { Ok(data) } - pub fn fs_read_text(&self) -> Result { + pub fn fs_read_text_blocking(&self) -> Result { Ok(std::fs::read_to_string(self.to_path_buf())?) } - pub fn fs_read_text_prealloc(&self) -> Result { + pub fn fs_read_text_prealloc_blocking(&self) -> Result { let metadata = self.fs_metadata()?; Ok(self.fs_read_text_with_size(metadata.len())?) } + pub async fn fs_read_text_prealloc(&self) -> Result { + let metadata + = tokio::fs::metadata(self.to_path_buf()).await?; + + let mut data = String::with_capacity(metadata.len() as usize); + + let mut file + = tokio::fs::File::open(self.to_path_buf()).await?; + file.read_to_string(&mut data).await?; + + Ok(data) + } + pub fn fs_read_text_with_size(&self, size: u64) -> Result { let mut data = String::with_capacity(size as usize); @@ -524,24 +576,38 @@ impl Path { Ok(data) } - pub async fn fs_read_text_async(&self) -> Result { + pub async fn fs_read_text(&self) -> Result { Ok(tokio::fs::read_to_string(self.to_path_buf()).await?) } - pub fn fs_read_dir(&self) -> Result { + pub fn fs_read_dir_blocking(&self) -> Result { Ok(std::fs::read_dir(&self.to_path_buf())?) } - pub fn fs_write>(&self, data: T) -> Result<&Self, PathError> { + pub async fn fs_read_dir(&self) -> Result { + Ok(tokio::fs::read_dir(&self.to_path_buf()).await?) + } + + pub fn fs_write_blocking>(&self, data: T) -> Result<&Self, PathError> { std::fs::write(self.to_path_buf(), data)?; Ok(self) } - pub fn fs_write_text>(&self, text: T) -> Result<&Self, PathError> { + pub async fn fs_write>(&self, data: T) -> Result<&Self, PathError> { + tokio::fs::write(self.to_path_buf(), data).await?; + Ok(self) + } + + pub fn fs_write_text_blocking>(&self, text: T) -> Result<&Self, PathError> { std::fs::write(self.to_path_buf(), text.as_ref())?; Ok(self) } + pub async fn fs_write_text>(&self, text: T) -> Result<&Self, PathError> { + tokio::fs::write(self.to_path_buf(), text.as_ref()).await?; + Ok(self) + } + pub fn fs_set_modified(&self, modified: std::time::SystemTime) -> Result<&Self, PathError> { let file = std::fs::File::open(self.to_path_buf())?; @@ -551,7 +617,7 @@ impl Path { Ok(self) } - pub fn fs_append>(&self, data: T) -> Result<&Self, PathError> { + pub fn fs_append_blocking>(&self, data: T) -> Result<&Self, PathError> { let mut file = std::fs::OpenOptions::new() .append(true) .create(true) @@ -562,8 +628,24 @@ impl Path { Ok(self) } - pub fn fs_append_text>(&self, text: T) -> Result<&Self, PathError> { - self.fs_append(text.as_ref()) + pub async fn fs_append>(&self, data: T) -> Result<&Self, PathError> { + let mut file = tokio::fs::OpenOptions::new() + .append(true) + .create(true) + .open(&self.to_path_buf()) + .await?; + + file.write_all(data.as_ref()).await?; + + Ok(self) + } + + pub fn fs_append_text_blocking>(&self, text: T) -> Result<&Self, PathError> { + self.fs_append_blocking(text.as_ref()) + } + + pub async fn fs_append_text>(&self, text: T) -> Result<&Self, PathError> { + self.fs_append(text.as_ref()).await } pub fn fs_sync_dir(&self, mut entries: BTreeMap) -> Result<&Self, SyncError> { @@ -606,7 +688,7 @@ impl Path { let path_abs = self.with_join(&path_rel); - for entry in path_abs.fs_read_dir()? { + for entry in path_abs.fs_read_dir_blocking()? { let entry = entry .map_err(PathError::from)?; @@ -621,7 +703,7 @@ impl Path { .with_join_str(&file_name); if entries.remove(&entry_rel_path).is_none() { - entry_abs_path.fs_rm()?; + entry_abs_path.fs_rm_blocking()?; continue; }; @@ -647,16 +729,16 @@ impl Path { => self.fs_symlink(&target), SyncEntryKind::File(data, is_exec) - => self.fs_change(&data, is_exec), + => self.fs_change_blocking(&data, is_exec), SyncEntryKind::Folder - => self.fs_create_dir_all(), + => self.fs_create_dir_all_blocking(), } } pub fn fs_expect>(&self, expected_data: T, is_exec: bool) -> Result<&Self, PathError> { let current_content - = self.fs_read() + = self.fs_read_blocking() .ok_missing()?; let update_content = current_content.as_ref() @@ -697,10 +779,10 @@ impl Path { Ok(self) } - pub fn fs_change>(&self, data: T, is_exec: bool) -> Result<&Self, PathError> { + pub fn fs_change_blocking>(&self, data: T, is_exec: bool) -> Result<&Self, PathError> { let path_buf = self.to_path_buf(); - let update_content = self.fs_read() + let update_content = self.fs_read_blocking() .ok_missing() .map(|current| current.map(|current| current.ne(data.as_ref())).unwrap_or(true))?; @@ -731,6 +813,40 @@ impl Path { Ok(self) } + pub async fn fs_change>(&self, data: T, is_exec: bool) -> Result<&Self, PathError> { + let path_buf = self.to_path_buf(); + + let update_content = self.fs_read().await + .ok_missing() + .map(|current| current.map(|current| current.ne(data.as_ref())).unwrap_or(true))?; + + if update_content { + tokio::fs::write(&path_buf, data).await?; + } + + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + + let current_mode + = tokio::fs::metadata(&path_buf).await? + .permissions() + .mode() & 0o666; + + let expected_mode + = current_mode | (if is_exec {0o111} else {0}); + + if current_mode != expected_mode { + let expected_permissions + = std::fs::Permissions::from_mode(expected_mode); + + tokio::fs::set_permissions(&path_buf, expected_permissions).await?; + } + } + + Ok(self) + } + /** * Rename a file or directory to a new location. * @@ -751,8 +867,8 @@ impl Path { pub fn fs_copy(&self, new_path: &Path) -> Result<&Self, PathError> { match self.fs_is_dir() { true => { - new_path.fs_create_dir_all()?; - for entry in self.fs_read_dir()? { + new_path.fs_create_dir_all_blocking()?; + for entry in self.fs_read_dir_blocking()? { let entry = entry?; let entry_path = Path::try_from(entry.path())?; @@ -782,7 +898,7 @@ impl Path { Ok(_) => Ok(self), Err(err) if err.kind() == std::io::ErrorKind::CrossesDevices => { self.fs_copy(new_path)?; - self.fs_rm() + self.fs_rm_blocking() }, Err(err) => Err(err.into()), } @@ -802,12 +918,17 @@ impl Path { .map(|_| self) } - pub fn fs_rm_file(&self) -> Result<&Self, PathError> { + pub fn fs_rm_file_blocking(&self) -> Result<&Self, PathError> { std::fs::remove_file(self.to_path_buf())?; Ok(self) } - pub fn fs_rm(&self) -> Result<&Self, PathError> { + pub async fn fs_rm_file(&self) -> Result<&Self, PathError> { + tokio::fs::remove_file(self.to_path_buf()).await?; + Ok(self) + } + + pub fn fs_rm_blocking(&self) -> Result<&Self, PathError> { match self.fs_is_real_dir() { true => std::fs::remove_dir_all(self.to_path_buf()), false => std::fs::remove_file(self.to_path_buf()), @@ -816,6 +937,19 @@ impl Path { Ok(self) } + pub async fn fs_rm(&self) -> Result<&Self, PathError> { + let metadata + = tokio::fs::symlink_metadata(self.to_path_buf()).await?; + + if metadata.is_dir() { + tokio::fs::remove_dir_all(self.to_path_buf()).await?; + } else { + tokio::fs::remove_file(self.to_path_buf()).await?; + } + + Ok(self) + } + pub fn fs_symlink(&self, target: &Path) -> Result<&Self, PathError> { std::os::unix::fs::symlink(&target.path, &self.path)?; Ok(self) diff --git a/packages/zpm-utils/src/system.rs b/packages/zpm-utils/src/system.rs index 04c58244..c6b79f3e 100644 --- a/packages/zpm-utils/src/system.rs +++ b/packages/zpm-utils/src/system.rs @@ -45,7 +45,7 @@ const LIBC: Option = None; fn detect_libc() -> Option { let ldd_contents = Path::from_str(LDD_PATH).unwrap() - .fs_read_text_prealloc() + .fs_read_text_prealloc_blocking() .ok(); if let Some(ldd_contents) = ldd_contents { diff --git a/packages/zpm/src/build.rs b/packages/zpm/src/build.rs index 49d894d3..b7293b25 100644 --- a/packages/zpm/src/build.rs +++ b/packages/zpm/src/build.rs @@ -124,11 +124,14 @@ impl BuildRequest { build_cache_folder .fs_rm() + .await .ok_missing()?; build_cache_folder - .fs_create_parent()? - .fs_write_text(format!("{:#?}", diff_list))?; + .fs_create_parent() + .await? + .fs_write_text(format!("{:#?}", diff_list)) + .await?; } Ok(ScriptResult::new_success()) @@ -183,7 +186,7 @@ impl BuildState { .build_state_path(); let build_state_text = build_state_path - .fs_read_text_async() + .fs_read_text() .await .unwrap_or_else(|_| "{}".to_owned()); @@ -196,13 +199,13 @@ impl BuildState { .build_state_path(); build_state_path - .fs_create_parent()?; + .fs_create_parent_blocking()?; let build_state_text = JsonDocument::to_string(self)?; build_state_path - .fs_change(build_state_text, false)?; + .fs_change_blocking(build_state_text, false)?; Ok(()) } diff --git a/packages/zpm/src/cache.rs b/packages/zpm/src/cache.rs index 999547f0..6233857a 100644 --- a/packages/zpm/src/cache.rs +++ b/packages/zpm/src/cache.rs @@ -1,10 +1,7 @@ -use std::fs::File; -use std::io::Write; use std::path::PathBuf; use std::sync::Arc; use std::collections::HashSet; use std::sync::Mutex; -use itertools::Itertools; use zpm_formats::{iter_ext::IterExt, zip::ToZip, Entry}; use zpm_macro_enum::zpm_enum; use zpm_primitives::Locator; @@ -348,29 +345,32 @@ impl DiskCache { let data = func().await?; - let mut file - = File::create(key_path.clone())?; - - file.write_all(&data)?; + tokio::fs::write(key_path, &data).await?; Ok(data) } pub async fn clean(&self) -> Result { - let accessed_files - = self.accessed_files.lock() - .map_err(|_| Error::Unsupported)?; + let accessed_files = self.accessed_files.lock() + .map_err(|_| Error::Unsupported)? + .clone(); + + let mut extraneous_cache_files = Vec::new(); + let mut cache_entries + = tokio::fs::read_dir(self.cache_path.to_path_buf()).await?; + + while let Some(entry) = cache_entries.next_entry().await? { + if !entry.file_type().await?.is_file() { + continue; + } - let cache_entries = self.cache_path - .fs_read_dir()? - .collect::, _>>()?; + let file + = entry.file_name().to_os_string().into_string().unwrap(); - let extraneous_cache_files = cache_entries - .iter() - .filter(|entry| entry.file_type().unwrap().is_file()) - .map(|entry| entry.file_name().to_os_string().into_string().unwrap()) - .filter(|file| !accessed_files.contains(file)) - .collect_vec(); + if !accessed_files.contains(&file) { + extraneous_cache_files.push(file); + } + } let extraneous_count = extraneous_cache_files.len(); @@ -380,9 +380,7 @@ impl DiskCache { } for file in extraneous_cache_files { - self.cache_path - .with_join_str(&file) - .fs_rm_file()?; + tokio::fs::remove_file(self.cache_path.with_join_str(&file).to_path_buf()).await?; } Ok(extraneous_count) diff --git a/packages/zpm/src/commands/add.rs b/packages/zpm/src/commands/add.rs index e463b4b9..c2a26023 100644 --- a/packages/zpm/src/commands/add.rs +++ b/packages/zpm/src/commands/add.rs @@ -266,7 +266,7 @@ impl Add { .with_join_str(project::MANIFEST_NAME); let manifest_content = manifest_path - .fs_read_prealloc()?; + .fs_read_prealloc().await?; let mut document = JsonDocument::new(manifest_content)?; @@ -318,7 +318,7 @@ impl Add { } manifest_path - .fs_change(&document.input, false)?; + .fs_change(&document.input, false).await?; let mut project = project::Project::new(None).await?; diff --git a/packages/zpm/src/commands/cache_clear.rs b/packages/zpm/src/commands/cache_clear.rs index 352e90ea..2d263efd 100644 --- a/packages/zpm/src/commands/cache_clear.rs +++ b/packages/zpm/src/commands/cache_clear.rs @@ -1,5 +1,4 @@ use clipanion::cli; -use itertools::Itertools; use zpm_utils::{DataType, IoResultExt, Path}; use crate::{error::Error, project, report::{StreamReport, StreamReportConfig, current_report, with_report_result}}; @@ -48,30 +47,36 @@ async fn clear_cache(old: bool) -> Result<(), Error> { }); with_report_result(report, async { - let cache_entries - = project.global_cache_path() - .fs_read_dir() - .ok_missing()?; - - let mut cleared_entries - = 0; - - if let Some(cache_entries) = cache_entries { - let cache_entries = cache_entries - .filter_map(|entry| entry.ok()) - .map(|entry| Path::try_from(entry.path())) - .filter_map(|entry| entry.ok()) - .filter(|entry| !old || age_filter(entry)) - .collect_vec(); - - cleared_entries - = cache_entries.len(); - - for entry in &cache_entries { - entry.fs_rm().ok_missing()?; + let cache_entries = match project.global_cache_path() + .fs_read_dir() + .await + .ok_missing()? + { + Some(cache_entries) => cache_entries, + None => { + current_report().await.as_ref().map(|report| { + report.info("No entries to clear from the cache.".to_string()); + }); + return Ok(()); + }, + }; + + let mut entries_to_delete = Vec::new(); + let mut cache_entries = cache_entries; + while let Some(entry) = cache_entries.next_entry().await? { + let entry = Path::try_from(entry.path())?; + + if !old || age_filter(&entry) { + entries_to_delete.push(entry); } } + let cleared_entries = entries_to_delete.len(); + + for entry in &entries_to_delete { + entry.fs_rm().await.ok_missing()?; + } + current_report().await.as_ref().map(|report| { if cleared_entries > 0 { report.info(format!("Cleared {} entries from the cache.", DataType::Number.colorize(&cleared_entries.to_string()))) diff --git a/packages/zpm/src/commands/config_set.rs b/packages/zpm/src/commands/config_set.rs index c9f667d1..e3d03453 100644 --- a/packages/zpm/src/commands/config_set.rs +++ b/packages/zpm/src/commands/config_set.rs @@ -49,7 +49,7 @@ impl ConfigSet { }; let document = document_path - .fs_read_text() + .fs_read_text().await .ok_missing()? .unwrap_or_default(); @@ -60,7 +60,7 @@ impl ConfigSet { )?; document_path - .fs_change(&updated_document, false)?; + .fs_change(&updated_document, false).await?; Ok(()) } diff --git a/packages/zpm/src/commands/constraints.rs b/packages/zpm/src/commands/constraints.rs index 79cfb991..46af86e3 100644 --- a/packages/zpm/src/commands/constraints.rs +++ b/packages/zpm/src/commands/constraints.rs @@ -55,7 +55,7 @@ impl Constraints { .with_join_str("package.json"); let manifest_content = manifest_path - .fs_read_prealloc()?; + .fs_read_prealloc().await?; let mut document = JsonDocument::new(manifest_content)?; @@ -75,7 +75,7 @@ impl Constraints { // Write the formatted result back manifest_path - .fs_change(&document.input, false)?; + .fs_change(&document.input, false).await?; } let should_break = false diff --git a/packages/zpm/src/commands/debug/bench.rs b/packages/zpm/src/commands/debug/bench.rs index fb811f39..c34b9b25 100644 --- a/packages/zpm/src/commands/debug/bench.rs +++ b/packages/zpm/src/commands/debug/bench.rs @@ -14,7 +14,7 @@ fn remove_list(list: &[&str]) -> Result<(), Error> { for path in list { current_dir .with_join_str(*path) - .fs_rm() + .fs_rm_blocking() .ok_missing()?; } @@ -89,9 +89,12 @@ impl BenchMode { .with_join_str(".yarnrc.yml"); yarnrc_yml - .fs_append_text(format!("globalFolder: '{}'\n", global_folder.to_file_string()))? - .fs_append_text("enableImmutableInstalls: false\n")? - .fs_append_text("enableScripts: false\n")?; + .fs_append_text(format!("globalFolder: '{}'\n", global_folder.to_file_string())) + .await? + .fs_append_text("enableImmutableInstalls: false\n") + .await? + .fs_append_text("enableScripts: false\n") + .await?; if self == &BenchMode::InstallReady { let dummy_pkg_json @@ -99,8 +102,10 @@ impl BenchMode { .with_join_str("dummy-pkg/package.json"); dummy_pkg_json - .fs_create_parent()? - .fs_write("{\"name\": \"dummy-pkg\"}")?; + .fs_create_parent() + .await? + .fs_write("{\"name\": \"dummy-pkg\"}") + .await?; } run_cli(&["install"]).await?; @@ -204,7 +209,8 @@ impl BenchPrepare { pub async fn execute(&self) -> Result<(), Error> { Path::current_dir()? .with_join_str("package.json") - .fs_write(&self.name.get_manifest())?; + .fs_write(&self.name.get_manifest()) + .await?; self.mode.prepare_folder().await?; diff --git a/packages/zpm/src/commands/debug/flamegraph.rs b/packages/zpm/src/commands/debug/flamegraph.rs index 5d84d75e..daa4fa86 100644 --- a/packages/zpm/src/commands/debug/flamegraph.rs +++ b/packages/zpm/src/commands/debug/flamegraph.rs @@ -18,7 +18,7 @@ impl Flamegraph { .ok_or(Error::HomeDirectoryNotFound)? .with_join_str(".cargo/bin/samply"); - if !samply_path.fs_exists() { + if !samply_path.fs_exists().await { return Err(Error::MissingSamply); } diff --git a/packages/zpm/src/commands/debug/iter_zip.rs b/packages/zpm/src/commands/debug/iter_zip.rs index d8548299..836c6321 100644 --- a/packages/zpm/src/commands/debug/iter_zip.rs +++ b/packages/zpm/src/commands/debug/iter_zip.rs @@ -12,7 +12,8 @@ pub struct IterZip { impl IterZip { pub async fn execute(&self) -> Result<(), Error> { let buffer = self.path - .fs_read()?; + .fs_read() + .await?; let entries = zpm_formats::zip::entries_from_zip(&buffer)?; diff --git a/packages/zpm/src/commands/debug/sync_fs.rs b/packages/zpm/src/commands/debug/sync_fs.rs index a4d30062..63082466 100644 --- a/packages/zpm/src/commands/debug/sync_fs.rs +++ b/packages/zpm/src/commands/debug/sync_fs.rs @@ -17,7 +17,7 @@ pub struct SyncFs { impl SyncFs { pub async fn execute(&self) -> Result<(), Error> { let definition_file_contents - = self.definition_file.fs_read_text()?; + = self.definition_file.fs_read_text().await?; let definition: BTreeMap> = JsonDocument::hydrate_from_str(&definition_file_contents)?; @@ -30,7 +30,7 @@ impl SyncFs { } let ops - = sync_tree.run(self.destination.fs_canonicalize()?)?; + = sync_tree.run(self.destination.fs_canonicalize().await?)?; for op in ops { println!("{}", op); diff --git a/packages/zpm/src/commands/dlx.rs b/packages/zpm/src/commands/dlx.rs index d89adeff..d1f6586c 100644 --- a/packages/zpm/src/commands/dlx.rs +++ b/packages/zpm/src/commands/dlx.rs @@ -129,11 +129,11 @@ pub async fn setup_project() -> Result { = Path::temp_dir_pattern("dlx-<>")?; temp_dir.with_join_str("package.json") - .fs_write_text("{}\n")?; + .fs_write_text("{}\n").await?; temp_dir.with_join_str("yarn.lock") - .fs_write_text("{}\n")?; + .fs_write_text("{}\n").await?; temp_dir.with_join_str(".yarnrc.yml") - .fs_write_text("enableGlobalCache: false\n")?; + .fs_write_text("enableGlobalCache: false\n").await?; let project = Project::new(Some(temp_dir)).await?; @@ -146,7 +146,7 @@ pub async fn install_dependencies(workspace_path: &Path, loose_resolutions: Vec< .with_join_str("package.json"); let manifest_content = manifest_path - .fs_read_prealloc()?; + .fs_read_prealloc().await?; let mut formatter = JsonDocument::new(manifest_content)?; @@ -159,7 +159,7 @@ pub async fn install_dependencies(workspace_path: &Path, loose_resolutions: Vec< } manifest_path - .fs_change(&formatter.input, false)?; + .fs_change(&formatter.input, false).await?; let mut project = Project::new(Some(workspace_path.clone())).await?; diff --git a/packages/zpm/src/commands/init.rs b/packages/zpm/src/commands/init.rs index c85d8062..e2c95b45 100644 --- a/packages/zpm/src/commands/init.rs +++ b/packages/zpm/src/commands/init.rs @@ -170,14 +170,14 @@ pub async fn init_project(init_cwd: &Path, params: InitParams) -> Result Result Result Result Result Result Result Result Result Result Result<(), Error> .with_join_str("package.json"); let manifest_content = manifest_path - .fs_read_prealloc()?; + .fs_read_prealloc_blocking()?; let mut document = JsonDocument::new(manifest_content)?; @@ -146,7 +146,7 @@ fn sort_workspace_dependencies(project: &project::Project) -> Result<(), Error> if any_sorted { manifest_path - .fs_change(&document.input, false)?; + .fs_change_blocking(&document.input, false)?; } } diff --git a/packages/zpm/src/commands/link.rs b/packages/zpm/src/commands/link.rs index 86907841..bbcc16a8 100644 --- a/packages/zpm/src/commands/link.rs +++ b/packages/zpm/src/commands/link.rs @@ -54,13 +54,13 @@ impl Link { let manifest_path = root_path.with_join_str(MANIFEST_NAME); let manifest_content - = manifest_path.fs_read_prealloc()?; + = manifest_path.fs_read_prealloc().await?; let mut document = JsonDocument::new(manifest_content)?; for destination in &self.destinations { let canonical_destination - = destination.fs_canonicalize()?; + = destination.fs_canonicalize().await?; // Prevent linking a project to itself if root_path.contains(&canonical_destination) || canonical_destination.contains(root_path) { @@ -100,7 +100,7 @@ impl Link { } } - manifest_path.fs_change(&document.input, false)?; + manifest_path.fs_change(&document.input, false).await?; Ok(()) } diff --git a/packages/zpm/src/commands/npm/login.rs b/packages/zpm/src/commands/npm/login.rs index b2bee3aa..e2454fbe 100644 --- a/packages/zpm/src/commands/npm/login.rs +++ b/packages/zpm/src/commands/npm/login.rs @@ -115,7 +115,7 @@ impl Login { }; let config_content = config_path - .fs_read_text() + .fs_read_text().await .ok_missing()? .unwrap_or_default(); @@ -140,7 +140,7 @@ impl Login { )?; config_path - .fs_write_text(&updated_content)?; + .fs_write_text(&updated_content).await?; current_report().await.as_ref().map(|report| { report.info("Successfully logged in".to_string()); diff --git a/packages/zpm/src/commands/npm/logout.rs b/packages/zpm/src/commands/npm/logout.rs index cee369d4..2a3ee9f8 100644 --- a/packages/zpm/src/commands/npm/logout.rs +++ b/packages/zpm/src/commands/npm/logout.rs @@ -44,7 +44,7 @@ impl Logout { }; let config_content = config_path - .fs_read_text()?; + .fs_read_text().await?; let updated_content = if let Some(scope) = &self.scope { let scope = scope.strip_prefix('@').unwrap_or(scope); @@ -107,7 +107,7 @@ impl Logout { }; config_path - .fs_write_text(&updated_content)?; + .fs_write_text(&updated_content).await?; Ok(()) }).await diff --git a/packages/zpm/src/commands/npm/logout_all.rs b/packages/zpm/src/commands/npm/logout_all.rs index eb53b19d..e39e20d9 100644 --- a/packages/zpm/src/commands/npm/logout_all.rs +++ b/packages/zpm/src/commands/npm/logout_all.rs @@ -30,7 +30,7 @@ impl LogoutAll { }; let config_content = config_path - .fs_read_text()?; + .fs_read_text().await?; let mut doc = DataDocument::new(config_content.into_bytes())?; @@ -54,7 +54,7 @@ impl LogoutAll { .expect("Document was originally valid UTF-8"); config_path - .fs_write_text(&updated_content)?; + .fs_write_text(&updated_content).await?; current_report().await.as_ref().map(|report| { report.info("Successfully logged out from all npm registries".to_string()); diff --git a/packages/zpm/src/commands/npm/publish.rs b/packages/zpm/src/commands/npm/publish.rs index 7610cefb..622d122b 100644 --- a/packages/zpm/src/commands/npm/publish.rs +++ b/packages/zpm/src/commands/npm/publish.rs @@ -201,7 +201,7 @@ impl Publish { let readme = published_workspace.path.with_join_str("README.md") - .fs_read_text() + .fs_read_text().await .ok_missing()? .unwrap_or_else(|| format!("# {}\n", ident.to_file_string())); diff --git a/packages/zpm/src/commands/pack.rs b/packages/zpm/src/commands/pack.rs index 9fd3a5c4..e0e7831f 100644 --- a/packages/zpm/src/commands/pack.rs +++ b/packages/zpm/src/commands/pack.rs @@ -78,8 +78,8 @@ impl Pack { )?; out_path - .fs_create_parent()? - .fs_write(&pack_result.pack_file)?; + .fs_create_parent().await? + .fs_write(&pack_result.pack_file).await?; } Ok(()) diff --git a/packages/zpm/src/commands/patch.rs b/packages/zpm/src/commands/patch.rs index 5cbbcb41..71681cbc 100644 --- a/packages/zpm/src/commands/patch.rs +++ b/packages/zpm/src/commands/patch.rs @@ -72,7 +72,7 @@ impl Patch { .with_join_str("user"); locator_path - .fs_write(original_locator.to_file_string())?; + .fs_write(original_locator.to_file_string()).await?; Self::unpack_package_to(&install_result, &original_locator, &original_path)?; Self::unpack_package_to(&install_result, &user_locator, &user_path)?; @@ -147,7 +147,7 @@ impl Patch { }; let archive_data = archive_path - .fs_read_prealloc()?; + .fs_read_prealloc_blocking()?; let package_subdir = package_directory @@ -161,7 +161,7 @@ impl Patch { .collect::>(); destination - .fs_create_dir_all()?; + .fs_create_dir_all_blocking()?; zpm_formats::entries_to_disk(&entries, &destination)?; diff --git a/packages/zpm/src/commands/patch_commit.rs b/packages/zpm/src/commands/patch_commit.rs index 06a4918c..656838f5 100644 --- a/packages/zpm/src/commands/patch_commit.rs +++ b/packages/zpm/src/commands/patch_commit.rs @@ -37,10 +37,17 @@ impl PatchCommit { let mut project = project::Project::new(None).await?; - let locator_path = self.source + let mut locator_path = None; + for path in self.source .iter_path() .map(|path| path.with_join_str(".locator")) - .find(|path| path.fs_exists()) + { + if path.fs_exists().await { + locator_path = Some(path); + break; + } + } + let locator_path = locator_path .ok_or_else(|| Error::NotAPatchFolder(self.source.clone()))?; let original_path = locator_path @@ -53,7 +60,7 @@ impl PatchCommit { .with_join_str("user"); let locator_str = locator_path - .fs_read_text()?; + .fs_read_text().await?; let locator = Locator::from_file_string(&locator_str)?; @@ -103,7 +110,7 @@ impl PatchCommit { if let Some(workspace) = project.try_workspace_by_locator(pkg_locator)? { let manifest_content = workspace.manifest_path() - .fs_read_prealloc()?; + .fs_read_prealloc().await?; let mut document = JsonDocument::new(manifest_content)?; @@ -124,7 +131,7 @@ impl PatchCommit { if document.changed { workspace.manifest_path() - .fs_write(&document.input)?; + .fs_write(&document.input).await?; } } else { for descriptor in resolution.dependencies.values() { @@ -151,7 +158,7 @@ impl PatchCommit { let top_level_manifest_path = project.manifest_path(); let top_level_manifest_content - = top_level_manifest_path.fs_read_prealloc()?; + = top_level_manifest_path.fs_read_prealloc().await?; let mut document = JsonDocument::new(top_level_manifest_content)?; @@ -165,14 +172,14 @@ impl PatchCommit { if document.changed { top_level_manifest_path - .fs_write(document.input)?; + .fs_write(document.input).await?; } } project.project_cwd .with_join(&patch_rel_path) - .fs_create_parent()? - .fs_write(&diff)?; + .fs_create_parent().await? + .fs_write(&diff).await?; Ok(()) } diff --git a/packages/zpm/src/commands/remove.rs b/packages/zpm/src/commands/remove.rs index 51d2c11c..6ed6be30 100644 --- a/packages/zpm/src/commands/remove.rs +++ b/packages/zpm/src/commands/remove.rs @@ -101,7 +101,7 @@ impl Remove { .with_join_str("package.json"); let manifest_content = manifest_path - .fs_read_prealloc()?; + .fs_read_prealloc_blocking()?; let mut document = JsonDocument::new(manifest_content)?; @@ -129,7 +129,7 @@ impl Remove { } manifest_path - .fs_change(&document.input, false)?; + .fs_change_blocking(&document.input, false)?; Ok(()) } diff --git a/packages/zpm/src/commands/set_version.rs b/packages/zpm/src/commands/set_version.rs index 97342a85..a7a549b5 100644 --- a/packages/zpm/src/commands/set_version.rs +++ b/packages/zpm/src/commands/set_version.rs @@ -32,7 +32,7 @@ impl SetVersion { .with_join_str("package.json"); let manifest_content = manifest_path - .fs_read_prealloc()?; + .fs_read_prealloc().await?; let mut document = JsonDocument::new(manifest_content)?; @@ -53,7 +53,7 @@ impl SetVersion { )?; manifest_path - .fs_change(&document.input, false)?; + .fs_change(&document.input, false).await?; println!("Switching to {}", resolved_version.to_print_string()); println!("Saved into {}", manifest_path.to_print_string()); diff --git a/packages/zpm/src/commands/set_version_from_sources.rs b/packages/zpm/src/commands/set_version_from_sources.rs index 63ff72ea..47fda08e 100644 --- a/packages/zpm/src/commands/set_version_from_sources.rs +++ b/packages/zpm/src/commands/set_version_from_sources.rs @@ -64,7 +64,7 @@ impl SetVersionFromSources { let bundle_path = target.with_join_str("target/release/yarn-bin"); - if !bundle_path.fs_exists() { + if !bundle_path.fs_exists().await { run_build(&target).await?; println!(); @@ -87,7 +87,7 @@ async fn prepare_repo(spec: &SetVersionFromSources, target: &Path) -> Result<(), let mut ready = false; - if !spec.force && target.with_join_str(".git").fs_exists() { + if !spec.force && target.with_join_str(".git").fs_exists().await { println!("Fetching the latest commits"); println!(); @@ -107,12 +107,12 @@ async fn prepare_repo(spec: &SetVersionFromSources, target: &Path) -> Result<(), println!("Cloning the remote repository"); println!(); - if target.fs_exists() { - target.fs_rm()?; + if target.fs_exists().await { + target.fs_rm().await?; } target - .fs_create_dir_all()?; + .fs_create_dir_all().await?; run_clone(spec, target).await?; } diff --git a/packages/zpm/src/commands/unlink.rs b/packages/zpm/src/commands/unlink.rs index 5cbaf2b1..8e403cf7 100644 --- a/packages/zpm/src/commands/unlink.rs +++ b/packages/zpm/src/commands/unlink.rs @@ -62,7 +62,7 @@ impl Unlink { let manifest_path = root_path.with_join_str(MANIFEST_NAME); let manifest_content - = manifest_path.fs_read_prealloc()?; + = manifest_path.fs_read_prealloc().await?; let mut document = JsonDocument::new(manifest_content)?; @@ -82,7 +82,7 @@ impl Unlink { match target { UnlinkTarget::Path(explicit_path) => { let canonical_path - = explicit_path.path.raw_path.path.fs_canonicalize()?; + = explicit_path.path.raw_path.path.fs_canonicalize().await?; if self.all { let target_workspace @@ -132,7 +132,7 @@ impl Unlink { )?; } - manifest_path.fs_change(&document.input, false)?; + manifest_path.fs_change(&document.input, false).await?; Ok(()) } diff --git a/packages/zpm/src/commands/unplug.rs b/packages/zpm/src/commands/unplug.rs index 76b87929..f4fdf74c 100644 --- a/packages/zpm/src/commands/unplug.rs +++ b/packages/zpm/src/commands/unplug.rs @@ -47,7 +47,7 @@ impl Unplug { .with_join_str(project::MANIFEST_NAME); let manifest_content = manifest_path - .fs_read_prealloc()?; + .fs_read_prealloc().await?; let mut document = JsonDocument::new(manifest_content)?; @@ -60,7 +60,7 @@ impl Unplug { } manifest_path - .fs_change(&document.input, false)?; + .fs_change(&document.input, false).await?; let mut project = project::Project::new(None).await?; diff --git a/packages/zpm/src/commands/up.rs b/packages/zpm/src/commands/up.rs index 1bf2bb71..db054b94 100644 --- a/packages/zpm/src/commands/up.rs +++ b/packages/zpm/src/commands/up.rs @@ -128,7 +128,7 @@ impl Up { .with_join_str("package.json"); let manifest_content = manifest_path - .fs_read_prealloc()?; + .fs_read_prealloc().await?; let mut document = JsonDocument::new(manifest_content)?; @@ -151,7 +151,7 @@ impl Up { } manifest_path - .fs_change(&document.input, false)?; + .fs_change(&document.input, false).await?; } let mut project diff --git a/packages/zpm/src/constraints/mod.rs b/packages/zpm/src/constraints/mod.rs index 2fbaf3c4..bf6eb3eb 100644 --- a/packages/zpm/src/constraints/mod.rs +++ b/packages/zpm/src/constraints/mod.rs @@ -29,11 +29,18 @@ pub async fn check_constraints(project: &Project, fix: bool) -> Result Result Result Result { let package_bytes - = archive_path.fs_read()?; + = archive_path.fs_read_blocking()?; let first_entry = zpm_formats::zip::first_entry_from_zip(&package_bytes)?; diff --git a/packages/zpm/src/descriptor_loose.rs b/packages/zpm/src/descriptor_loose.rs index 028686b8..ccc5ec9c 100644 --- a/packages/zpm/src/descriptor_loose.rs +++ b/packages/zpm/src/descriptor_loose.rs @@ -131,7 +131,9 @@ impl LooseDescriptor { = Path::try_from(¶ms_path)?; let tgz_content = path - .fs_read_prealloc()?; + .to_path_buf(); + let tgz_content + = std::fs::read(tgz_content)?; let tar_content = tar::unpack_tgz(&tgz_content)?; diff --git a/packages/zpm/src/diff_finder.rs b/packages/zpm/src/diff_finder.rs index 13cd0385..2adf9bbe 100644 --- a/packages/zpm/src/diff_finder.rs +++ b/packages/zpm/src/diff_finder.rs @@ -154,7 +154,7 @@ impl DiffFinder { let directory_entries = abs_path - .fs_read_dir()? + .fs_read_dir_blocking()? .into_iter() .collect::, _>>()?; diff --git a/packages/zpm/src/fetchers/patch.rs b/packages/zpm/src/fetchers/patch.rs index 6919aa1a..e5f5e3c2 100644 --- a/packages/zpm/src/fetchers/patch.rs +++ b/packages/zpm/src/fetchers/patch.rs @@ -9,6 +9,10 @@ use crate::{ use super::PackageData; +fn read_text_with_zip_sync(path: zpm_utils::Path) -> Result { + Ok(path.fs_read_text_with_zip()?) +} + const BUILTIN_PATCHES: &[(&str, &[u8])] = &[ ("fsevents", std::include_bytes!("../../patches/fsevents.brotli.dat")), ("resolve", std::include_bytes!("../../patches/resolve.brotli.dat")), @@ -58,18 +62,20 @@ pub async fn fetch_locator<'a>(context: &InstallContext<'a>, locator: &Locator, }, path if path.starts_with("~/") => { - project.project_cwd - .with_join_str(&path[2..]) - .fs_read_text_with_zip()? + tokio::task::spawn_blocking({ + let path = project.project_cwd.with_join_str(&path[2..]); + move || read_text_with_zip_sync(path) + }).await?? }, path => { let parent_data = parent_data.expect("Expected parent data to be fetched when the patchfile is relative to the parent package"); - parent_data.package_data.context_directory() - .with_join_str(path) - .fs_read_text_with_zip()? + tokio::task::spawn_blocking({ + let path = parent_data.package_data.context_directory().with_join_str(path); + move || read_text_with_zip_sync(path) + }).await?? }, }; @@ -100,7 +106,7 @@ pub async fn fetch_locator<'a>(context: &InstallContext<'a>, locator: &Locator, let cached_blob = package_cache.upsert_blob(locator.clone(), ".zip", || async { let original_bytes = match &original_data.package_data { - PackageData::Zip {archive_path, ..} => Some(archive_path.fs_read()?), + PackageData::Zip {archive_path, ..} => Some(archive_path.fs_read().await?), _ => None, }; diff --git a/packages/zpm/src/fetchers/tarball.rs b/packages/zpm/src/fetchers/tarball.rs index 1fc6b444..9868f8e7 100644 --- a/packages/zpm/src/fetchers/tarball.rs +++ b/packages/zpm/src/fetchers/tarball.rs @@ -40,7 +40,7 @@ pub async fn fetch_locator<'a>(context: &InstallContext<'a>, locator: &Locator, let cached_blob = package_cache.upsert_blob(locator.clone(), ".zip", || async { let tgz_data - = tarball_path.fs_read()?; + = tarball_path.fs_read().await?; let archive = tokio::task::spawn_blocking(move || -> Result, Error> { let tar_data diff --git a/packages/zpm/src/git_utils.rs b/packages/zpm/src/git_utils.rs index de5d1565..0279ad4f 100644 --- a/packages/zpm/src/git_utils.rs +++ b/packages/zpm/src/git_utils.rs @@ -14,7 +14,7 @@ pub fn find_root(initial_cwd: &Path) -> Result { let git_path = parent .with_join_str(".git"); - if git_path.fs_exists() { + if git_path.fs_exists_blocking() { return Ok(parent); } } diff --git a/packages/zpm/src/install.rs b/packages/zpm/src/install.rs index 75fcb97d..f9fb69b1 100644 --- a/packages/zpm/src/install.rs +++ b/packages/zpm/src/install.rs @@ -611,6 +611,7 @@ impl Install { project.ignore_path() .with_join_str(".gitignore") .fs_change("*", false) + .await .ok_missing()?; Ok(InstallResult { @@ -746,8 +747,8 @@ impl<'a> InstallManager<'a> { let late_checksums = missing_checksums.into_par_iter() .map(|(locator, archive_path)| -> Result<_, Error> { - let archive_data = archive_path - .fs_read_prealloc()?; + let archive_data + = std::fs::read(archive_path.to_path_buf())?; let checksum = Hash64::from_data(&archive_data); @@ -790,11 +791,14 @@ impl<'a> InstallManager<'a> { .with_ext("zip"); let data = archive_path - .fs_read_prealloc()?; + .fs_read() + .await?; quarantine_path - .fs_create_parent()? - .fs_write(&data)?; + .fs_create_parent() + .await? + .fs_write(&data) + .await?; } return Err(Error::ChecksumMismatch(entry.resolution.locator.clone())); diff --git a/packages/zpm/src/linker/helpers.rs b/packages/zpm/src/linker/helpers.rs index a50e6997..b5dbcf05 100644 --- a/packages/zpm/src/linker/helpers.rs +++ b/packages/zpm/src/linker/helpers.rs @@ -39,13 +39,13 @@ impl TopLevelConfiguration { pub fn from_project(project: &Project) -> Vec<(FilterDescriptor, PackageMeta)> { project.manifest_path() .if_exists() - .and_then(|path| path.fs_read_text().ok()).map(|data| JsonDocument::hydrate_from_str::(&data).unwrap().dependencies_meta) + .and_then(|path| path.fs_read_text_blocking().ok()).map(|data| JsonDocument::hydrate_from_str::(&data).unwrap().dependencies_meta) .unwrap_or_default() } } pub fn fs_remove_nm(nm_path: Path) -> Result<(), Error> { - let entries = nm_path.fs_read_dir(); + let entries = nm_path.fs_read_dir_blocking(); match entries { Err(PathError::IoError {inner, ..}) if inner.kind() == std::io::ErrorKind::NotFound @@ -69,12 +69,12 @@ pub fn fs_remove_nm(nm_path: Path) -> Result<(), Error> { continue; } - path.fs_rm() + path.fs_rm_blocking() .unwrap(); } if !has_dot_entries { - nm_path.fs_rm()?; + nm_path.fs_rm_blocking()?; } Ok(()) @@ -86,12 +86,12 @@ pub fn fs_extract_archive(destination: &Path, package_data: &PackageData) -> Res let ready_path = destination .with_join_str(".ready"); - if !ready_path.fs_exists() && !matches!(package_data, &PackageData::MissingZip {..}) { + if !ready_path.fs_exists_blocking() && !matches!(package_data, &PackageData::MissingZip {..}) { let package_subpath = package_data.package_subpath(); let package_bytes = match package_data { - PackageData::Zip {archive_path, ..} => archive_path.fs_read()?, + PackageData::Zip {archive_path, ..} => archive_path.fs_read_blocking()?, _ => panic!("Expected a zip archive"), }; @@ -106,13 +106,13 @@ pub fn fs_extract_archive(destination: &Path, package_data: &PackageData) -> Res .with_join(&entry.name); target_path - .fs_create_parent()? - .fs_write(&entry.data)? + .fs_create_parent_blocking()? + .fs_write_blocking(&entry.data)? .fs_set_permissions(Permissions::from_mode(entry.mode as u32))?; } ready_path - .fs_write(vec![])?; + .fs_write_blocking(vec![])?; Ok(true) } else { diff --git a/packages/zpm/src/linker/nm/mod.rs b/packages/zpm/src/linker/nm/mod.rs index 809863ce..568bff5b 100644 --- a/packages/zpm/src/linker/nm/mod.rs +++ b/packages/zpm/src/linker/nm/mod.rs @@ -79,7 +79,7 @@ fn register_workspace_bin_symlinks(workspace_nm_tree: &mut SyncTree, workspace_p = workspace_path .with_join(bin_path); - if !target_abs_path.fs_exists() { + if !target_abs_path.fs_exists_blocking() { continue; } diff --git a/packages/zpm/src/linker/pnp.rs b/packages/zpm/src/linker/pnp.rs index 8e2a3e1e..95408250 100644 --- a/packages/zpm/src/linker/pnp.rs +++ b/packages/zpm/src/linker/pnp.rs @@ -190,8 +190,8 @@ fn generate_inline_files(project: &Project, state: &PnpState) -> Result<(), Erro ].join(""); project.pnp_path() - .fs_create_parent()? - .fs_change(script, false)?; + .fs_create_parent_blocking()? + .fs_change_blocking(script, false)?; Ok(()) } @@ -213,16 +213,32 @@ fn generate_split_setup(project: &Project, state: &PnpState) -> Result<(), Error ].join(""); project.pnp_path() - .fs_create_parent()? - .fs_change(script, false)?; + .fs_create_parent_blocking()? + .fs_change_blocking(script, false)?; project.pnp_data_path() - .fs_create_parent()? - .fs_change(JsonDocument::to_string(&state)?, false)?; + .fs_create_parent_blocking()? + .fs_change_blocking(JsonDocument::to_string(&state)?, false)?; Ok(()) } +fn collect_unplugged_entries(path: Path) -> Result, Error> { + Ok(path.fs_read_dir_blocking() + .ok_missing()? + .into_iter() + .flatten() + .filter_map(|entry| entry.ok()) + .filter_map(|entry| Path::try_from(entry.path()).ok()) + .collect::>()) +} + +fn apply_node_modules_sync(path: Path, entries: BTreeMap) -> Result<(), Error> { + path.fs_sync_dir(entries) + .map_err(Error::from)?; + Ok(()) +} + pub async fn link_project_pnp<'a>(project: &'a Project, install: &'a Install) -> Result { let tree = &install.install_state.resolution_tree; @@ -256,14 +272,10 @@ pub async fn link_project_pnp<'a>(project: &'a Project, install: &'a Install) -> let unplugged_path = project.unplugged_path(); - let mut extraneous_unplugged_packages - = unplugged_path.fs_read_dir() - .ok_missing()? - .into_iter() - .flatten() - .filter_map(|entry| entry.ok()) - .filter_map(|entry| Path::try_from(entry.path()).ok()) - .collect::>(); + let mut extraneous_unplugged_packages = tokio::task::spawn_blocking({ + let unplugged_path = unplugged_path.clone(); + move || collect_unplugged_entries(unplugged_path) + }).await??; let mut concrete_unplugged_packages = BTreeMap::new(); @@ -406,7 +418,8 @@ pub async fn link_project_pnp<'a>(project: &'a Project, install: &'a Install) -> .with_join_str(format!("build/{}", locator.slug())); build_dir - .fs_create_dir_all()?; + .fs_create_dir_all() + .await?; build_dir.relative_to(&project.project_cwd) }, @@ -428,7 +441,7 @@ pub async fn link_project_pnp<'a>(project: &'a Project, install: &'a Install) -> } for path in extraneous_unplugged_packages { - path.fs_rm()?; + path.fs_rm().await?; } // Native dynamic libraries sometimes have runtime dependencies on other dynamic libraries. They @@ -466,11 +479,15 @@ pub async fn link_project_pnp<'a>(project: &'a Project, install: &'a Install) -> ); } - package_location_abs - .with_join_str("node_modules") - .fs_create_dir_all()? - .fs_sync_dir(symlinks_to_create) - .map_err(Error::from)?; + let node_modules_path = package_location_abs + .with_join_str("node_modules"); + node_modules_path + .fs_create_dir_all() + .await?; + + tokio::task::spawn_blocking(move || { + apply_node_modules_sync(node_modules_path, symlinks_to_create) + }).await??; } for descriptor in &install.roots { @@ -546,7 +563,7 @@ pub async fn link_project_pnp<'a>(project: &'a Project, install: &'a Install) -> } project.pnp_loader_path() - .fs_change(&misc::unpack_brotli_data(PNP_MJS_TEMPLATE)?, false)?; + .fs_change(&misc::unpack_brotli_data(PNP_MJS_TEMPLATE)?, false).await?; let package_build_dependencies = linker::helpers::populate_build_entry_dependencies( &package_build_entries, diff --git a/packages/zpm/src/linker/pnpm.rs b/packages/zpm/src/linker/pnpm.rs index 275d29af..3cbf8683 100644 --- a/packages/zpm/src/linker/pnpm.rs +++ b/packages/zpm/src/linker/pnpm.rs @@ -45,6 +45,17 @@ fn collect_hoistable_packages<'a>(tree: &'a ResolutionTree, patterns: &[IdentGlo hoistable } +fn create_symlink_entry(link_abs_path: &Path, symlink_target: &Path) -> Result<(), Error> { + link_abs_path + .fs_rm_file_blocking() + .ok_missing()? + .unwrap_or(link_abs_path) + .fs_create_parent_blocking()? + .fs_symlink(symlink_target)?; + + Ok(()) +} + pub async fn link_project_pnpm<'a>(project: &'a Project, install: &'a Install) -> Result { let tree = &install.install_state.resolution_tree; @@ -184,12 +195,9 @@ pub async fn link_project_pnpm<'a>(project: &'a Project, install: &'a Install) - let symlink_target = package_abs_path .relative_to(&link_abs_dirname); - link_abs_path - .fs_rm_file() - .ok_missing()? - .unwrap_or(&link_abs_path) - .fs_create_parent()? - .fs_symlink(&symlink_target)?; + tokio::task::spawn_blocking(move || { + create_symlink_entry(&link_abs_path, &symlink_target) + }).await??; } // Track which packages are direct dependencies of workspaces @@ -230,12 +238,9 @@ pub async fn link_project_pnpm<'a>(project: &'a Project, install: &'a Install) - = package_abs_path .relative_to(&link_abs_dirname); - link_abs_path - .fs_rm_file() - .ok_missing()? - .unwrap_or(&link_abs_path) - .fs_create_parent()? - .fs_symlink(&symlink_target)?; + tokio::task::spawn_blocking(move || { + create_symlink_entry(&link_abs_path, &symlink_target) + }).await??; } // Second pass: create symlinks in node_modules directories @@ -294,12 +299,9 @@ pub async fn link_project_pnpm<'a>(project: &'a Project, install: &'a Install) - = dep_abs_path .relative_to(&link_abs_dirname); - link_abs_path - .fs_rm_file() - .ok_missing()? - .unwrap_or(&link_abs_path) - .fs_create_parent()? - .fs_symlink(&symlink_target)?; + tokio::task::spawn_blocking(move || { + create_symlink_entry(&link_abs_path, &symlink_target) + }).await??; } } diff --git a/packages/zpm/src/lockfile.rs b/packages/zpm/src/lockfile.rs index b6eeb323..90be6482 100644 --- a/packages/zpm/src/lockfile.rs +++ b/packages/zpm/src/lockfile.rs @@ -349,7 +349,7 @@ pub fn from_pnpm_node_modules(project_cwd: &Path) -> Result { = project_cwd .with_join_str("node_modules/.pnpm"); - if !pnpm_dir.fs_exists() { + if !pnpm_dir.fs_exists_blocking() { return Ok(Lockfile::new()); } @@ -394,7 +394,7 @@ pub fn from_pnpm_node_modules(project_cwd: &Path) -> Result { let manifest: Option = package_path .with_join_str("package.json") - .fs_read_text() + .fs_read_text_blocking() .ok() .and_then(|content| JsonDocument::hydrate_from_str(&content).ok()); diff --git a/packages/zpm/src/manifest_finder.rs b/packages/zpm/src/manifest_finder.rs index 02a34621..21f2bbd4 100644 --- a/packages/zpm/src/manifest_finder.rs +++ b/packages/zpm/src/manifest_finder.rs @@ -35,7 +35,7 @@ impl CachedManifestFinder { let save_state = save_state_path - .fs_read_prealloc() + .fs_read_prealloc_blocking() .ok() .and_then(|save_data| CacheState::from_slice(&save_data).ok()) .unwrap_or_default(); @@ -58,8 +58,8 @@ impl CachedManifestFinder { fn save_state_file(&self, data: &[u8]) -> Result<(), Error> { self.save_state_path - .fs_create_parent()? - .fs_write(&data)?; + .fs_create_parent_blocking()? + .fs_write_blocking(&data)?; Ok(()) } diff --git a/packages/zpm/src/pack.rs b/packages/zpm/src/pack.rs index 558baf59..d213f0e3 100644 --- a/packages/zpm/src/pack.rs +++ b/packages/zpm/src/pack.rs @@ -160,7 +160,7 @@ impl PackList { let abs_path = self.root_path .with_join(rel_path); - let directory_entries = abs_path.fs_read_dir()? + let directory_entries = abs_path.fs_read_dir_blocking()? .into_iter() .collect::, _>>()?; @@ -220,7 +220,7 @@ impl PackList { let ignore_file = abs_glob_root .with_join_str(&ignore_name) - .fs_read_text_prealloc()?; + .fs_read_text_prealloc_blocking()?; let ignore_list = ignore_file .split('\n') @@ -368,7 +368,7 @@ pub fn pack_manifest(project: &Project, workspace: &Workspace, options: &PackOpt .with_join_str("package.json"); let manifest_content = manifest_path - .fs_read_prealloc()?; + .fs_read_prealloc_blocking()?; let manifest: Manifest = parse_manifest(&String::from_utf8_lossy(&manifest_content))?; diff --git a/packages/zpm/src/prepare.rs b/packages/zpm/src/prepare.rs index 419e73cf..47941ed6 100644 --- a/packages/zpm/src/prepare.rs +++ b/packages/zpm/src/prepare.rs @@ -46,7 +46,7 @@ pub async fn prepare_project(_locator: &Locator, folder_path: &Path, params: &Pr fn get_package_manager(folder_path: &Path) -> Result { let yarn_lock_path = folder_path .with_join_str("yarn.lock") - .fs_read_text(); + .fs_read_text_blocking(); if let Ok(yarn_lock) = yarn_lock_path { if yarn_lock.starts_with("{") { @@ -62,11 +62,11 @@ fn get_package_manager(folder_path: &Path) -> Result { } } - if folder_path.with_join_str("pnpm-lock.yaml").fs_exists() { + if folder_path.with_join_str("pnpm-lock.yaml").fs_exists_blocking() { return Ok(PackageManager::Pnpm); } - if folder_path.with_join_str("package-lock.json").fs_exists() { + if folder_path.with_join_str("package-lock.json").fs_exists_blocking() { return Ok(PackageManager::Npm); } @@ -144,7 +144,8 @@ async fn prepare_npm_project(folder_path: &Path, params: &PrepareParams) -> Resu let pack_tgz = folder_path .with_join_str(pack_file) - .fs_read()?; + .fs_read() + .await?; Ok(pack_tgz) } @@ -153,7 +154,8 @@ async fn prepare_yarn_classic_project(folder_path: &Path, params: &PrepareParams // Otherwise Yarn 1 will pack the .yarn directory :( folder_path .with_join_str(".npmignore") - .fs_append("/.yarn\n")?; + .fs_append("/.yarn\n") + .await?; let channel_selector = zpm_switch::ReleaseLine::Classic @@ -191,7 +193,7 @@ async fn prepare_yarn_classic_project(folder_path: &Path, params: &PrepareParams .ok()?; let pack_tgz - = pack_path.fs_read()?; + = pack_path.fs_read().await?; Ok(pack_tgz) } @@ -204,8 +206,8 @@ async fn prepare_yarn_modern_project(folder_path: &Path, params: &PrepareParams) let lockfile_path = folder_path .with_join_str("yarn.lock"); - if !lockfile_path.fs_exists() { - lockfile_path.fs_write(b"")?; + if !lockfile_path.fs_exists().await { + lockfile_path.fs_write(b"").await?; } let channel_selector @@ -256,7 +258,8 @@ async fn prepare_yarn_modern_project(folder_path: &Path, params: &PrepareParams) .ok()?; let pack_tgz = pack_path - .fs_read()?; + .fs_read() + .await?; Ok(pack_tgz) } @@ -279,7 +282,8 @@ async fn prepare_pnpm_project(folder_path: &Path, _params: &PrepareParams) -> Re let pack_tgz = folder_path .with_join_str(pack_file.trim()) - .fs_read()?; + .fs_read() + .await?; Ok(pack_tgz) } @@ -318,7 +322,8 @@ async fn prepare_yarn_zpm_project(folder_path: &Path, params: &PrepareParams) -> .ok()?; let pack_tgz = archive_path - .fs_read()?; + .fs_read() + .await?; Ok(pack_tgz) } diff --git a/packages/zpm/src/project.rs b/packages/zpm/src/project.rs index 28d8d5c8..e112be63 100644 --- a/packages/zpm/src/project.rs +++ b/packages/zpm/src/project.rs @@ -84,14 +84,14 @@ impl Project { let lock_p = p.with_join_str(LOCKFILE_NAME); - if lock_p.fs_exists() { + if lock_p.fs_exists_blocking() { return Ok((p.clone(), closest_pkg.unwrap_or(p))); } let pkg_p = p.with_join_str(MANIFEST_NAME); - if pkg_p.fs_exists() { + if pkg_p.fs_exists_blocking() { farthest_pkg = Some(p.clone()); if closest_pkg.is_none() { @@ -274,13 +274,13 @@ impl Project { } fn lockfile_from(lockfile_path: &Path) -> Result { - if !lockfile_path.fs_exists() { + if !lockfile_path.fs_exists_blocking() { // Check for pnpm node_modules in the same directory if let Some(project_cwd) = lockfile_path.dirname() { let pnpm_dir = project_cwd.with_join_str("node_modules/.pnpm"); - if pnpm_dir.fs_exists() { + if pnpm_dir.fs_exists_blocking() { return from_pnpm_node_modules(&project_cwd); } } @@ -289,7 +289,7 @@ impl Project { } let src = lockfile_path - .fs_read_text()?; + .fs_read_text_blocking()?; if src.is_empty() { return Ok(Lockfile::new()); @@ -310,12 +310,12 @@ impl Project { let install_state_path = self.install_state_path(); - if !install_state_path.fs_exists() { + if !install_state_path.fs_exists_blocking() { return Err(Error::InstallStateNotFound); } let src = install_state_path - .fs_read()?; + .fs_read_blocking()?; let install_state = rkyv::from_bytes::(&src) @@ -354,16 +354,16 @@ impl Project { // let re_parsed_formatted = format!("{:#?}", re_parsed); // Path::from("/tmp/zpm-install-state-before.json") - // .fs_write_text(install_state_formatted)?; + // .fs_write_text(install_state_formatted).await?; // Path::from("/tmp/zpm-install-state-after.json") - // .fs_write_text(re_parsed_formatted)?; + // .fs_write_text(re_parsed_formatted).await?; // panic!("The generated install state does not match the original install state. See /tmp/zpm-install-state-{{before,after}}.json for details."); // } link_info_path - .fs_create_parent()? - .fs_change(contents, false)?; + .fs_create_parent_blocking()? + .fs_change_blocking(contents, false)?; Ok(()) } @@ -378,7 +378,7 @@ impl Project { if self.config.settings.enable_immutable_installs.value { lockfile_path.fs_expect(contents, false)?; } else { - lockfile_path.fs_change(contents, false)?; + lockfile_path.fs_change_blocking(contents, false)?; } Ok(()) @@ -390,12 +390,12 @@ impl Project { let local_cache_path = self.local_cache_path(); - global_cache_path.fs_create_dir_all()?; + global_cache_path.fs_create_dir_all_blocking()?; if !self.config.settings.enable_global_cache.value { if !self.config.settings.enable_immutable_cache.value { - local_cache_path.fs_create_dir_all()?; - } else if !local_cache_path.fs_exists() { + local_cache_path.fs_create_dir_all_blocking()?; + } else if !local_cache_path.fs_exists_blocking() { return Err(Error::MissingCacheFolder(local_cache_path)); } } @@ -718,9 +718,9 @@ impl Project { }; let cache_exists = if self.config.settings.enable_global_cache.value { - self.global_cache_path().fs_exists() + self.global_cache_path().fs_exists().await } else { - self.local_cache_path().fs_exists() + self.local_cache_path().fs_exists().await }; if cache_exists { @@ -773,7 +773,8 @@ impl Project { = self.lockfile_path(); let lockfile_content = lockfile_path - .fs_read_text()?; + .fs_read_text() + .await?; if lockfile_content.contains("<<<<<<<") { if self.config.settings.enable_immutable_installs.value { diff --git a/packages/zpm/src/report.rs b/packages/zpm/src/report.rs index 01234b7f..b04d04f8 100644 --- a/packages/zpm/src/report.rs +++ b/packages/zpm/src/report.rs @@ -311,7 +311,7 @@ impl Reporter { for log_path in &self.log_paths { writeln!(writer, "\n{}\n", log_path.to_print_string()).unwrap(); - let log_content = log_path.fs_read_text().unwrap(); + let log_content = log_path.fs_read_text_blocking().unwrap(); writeln!(writer, "{}", log_content).unwrap(); } diff --git a/packages/zpm/src/script.rs b/packages/zpm/src/script.rs index 6a37013d..f93d4633 100644 --- a/packages/zpm/src/script.rs +++ b/packages/zpm/src/script.rs @@ -27,7 +27,7 @@ fn make_path_wrapper(bin_dir: &Path, name: &str, argv0: &str, args: &Vec bin_dir .with_join_str(format!("{}.cmd", name)) - .fs_write_text(&cmd_script)?; + .fs_write_text_blocking(&cmd_script)?; } else { let sh_script = format!( "#!/bin/sh\nexec \"{}\" {} \"$@\"\n", @@ -37,7 +37,7 @@ fn make_path_wrapper(bin_dir: &Path, name: &str, argv0: &str, args: &Vec bin_dir .with_join_str(name) - .fs_write_text(&sh_script)? + .fs_write_text_blocking(&sh_script)? .fs_set_permissions(Permissions::from_mode(0o755))?; } @@ -255,7 +255,7 @@ impl ScriptResult { // open a fd and write stdout/err into it let log_write = log_path - .fs_write_text(format!("=== COMMAND ===\n\n{}\n\n=== STDOUT ===\n\n{}\n=== STDERR ===\n\n{}", shell_line, stdout, stderr)); + .fs_write_text_blocking(format!("=== COMMAND ===\n\n{}\n\n=== STDOUT ===\n\n{}\n=== STDERR ===\n\n{}", shell_line, stdout, stderr)); if log_write.is_ok() { Err(Error::ChildProcessFailedWithLog(program, log_path)) @@ -501,19 +501,19 @@ impl ScriptEnvironment { .expect("Expected home directory") .with_join_str(&dir_name); - if !dir.fs_exists() { + if !dir.fs_exists_blocking() { let temp_dir = Path::temp_dir()?; temp_dir - .fs_create_dir_all()?; + .fs_create_dir_all_blocking()?; for binary in &self.binaries.binaries { make_path_wrapper(&temp_dir, &binary.name, &binary.argv0, &binary.args)?; } dir - .fs_create_parent()?; + .fs_create_parent_blocking()?; temp_dir .fs_concurrent_move(&dir)?; diff --git a/packages/zpm/src/versioning.rs b/packages/zpm/src/versioning.rs index 6c779934..ba1e6c91 100644 --- a/packages/zpm/src/versioning.rs +++ b/packages/zpm/src/versioning.rs @@ -136,7 +136,7 @@ impl<'a> Versioning<'a> { = self.project.versioning_path(); let versioning_files - = versioning_dir.fs_read_dir() + = versioning_dir.fs_read_dir_blocking() .ok_missing()?; let Some(versioning_files) = versioning_files else { @@ -152,7 +152,7 @@ impl<'a> Versioning<'a> { } let content - = path.fs_read_text_prealloc() + = path.fs_read_text_prealloc_blocking() .ok_missing()? .unwrap_or_else(|| "{}".to_string()); @@ -238,7 +238,7 @@ impl<'a> Versioning<'a> { = self.project.versioning_path(); let versioning_files - = versioning_dir.fs_read_dir()?; + = versioning_dir.fs_read_dir_blocking()?; for versioning_file in versioning_files { let versioning_file = versioning_file?; @@ -249,7 +249,7 @@ impl<'a> Versioning<'a> { } let content - = path.fs_read_text_prealloc() + = path.fs_read_text_prealloc_blocking() .ok_missing()? .unwrap_or_else(|| "{}".to_string()); @@ -262,14 +262,14 @@ impl<'a> Versioning<'a> { } if versioning_data.releases.is_empty() { - path.fs_rm_file()?; + path.fs_rm_file_blocking()?; continue; } let versioning_content = format!("{}\n", JsonDocument::to_string_pretty(&versioning_data)?); - path.fs_change(&versioning_content, false)?; + path.fs_change_blocking(&versioning_content, false)?; } Ok(()) @@ -281,7 +281,7 @@ impl<'a> Versioning<'a> { .manifest_path(); let manifest_content = manifest_path - .fs_read_prealloc()?; + .fs_read_prealloc_blocking()?; let mut document = JsonDocument::new(manifest_content)?; @@ -292,7 +292,7 @@ impl<'a> Versioning<'a> { )?; manifest_path - .fs_change(&document.input, false)?; + .fs_change_blocking(&document.input, false)?; Ok(()) } @@ -321,6 +321,7 @@ impl<'a> Versioning<'a> { let versioning_content = versioning_path.fs_read_text_prealloc() + .await .ok_missing()? .unwrap_or_else(|| "{}".to_string()); @@ -339,8 +340,10 @@ impl<'a> Versioning<'a> { = format!("{}\n", JsonDocument::to_string_pretty(&versioning_data)?); versioning_path - .fs_create_parent()? - .fs_change(&versioning_content, false)?; + .fs_create_parent() + .await? + .fs_change(&versioning_content, false) + .await?; Ok(()) }