summaryrefslogtreecommitdiff
path: root/cli/util
diff options
context:
space:
mode:
authorDavid Sherret <dsherret@users.noreply.github.com>2024-05-14 14:26:48 -0400
committerGitHub <noreply@github.com>2024-05-14 14:26:48 -0400
commitf16b4d4df8bd03f2d0c5e5d6855e334fa768e828 (patch)
tree6b99b3a79486cd73c32145bca981e13fc626549b /cli/util
parentc0e3b6ed9d955bc59a8d88e177219b541881c63d (diff)
fix(npm): make tarball extraction more reliable (#23759)
1. Extracts to a directory beside the destination. 2. Renames to the destination with retries.
Diffstat (limited to 'cli/util')
-rw-r--r--cli/util/fs.rs12
-rw-r--r--cli/util/path.rs26
2 files changed, 28 insertions, 10 deletions
diff --git a/cli/util/fs.rs b/cli/util/fs.rs
index 92820ebe8..fdc7855e6 100644
--- a/cli/util/fs.rs
+++ b/cli/util/fs.rs
@@ -2,7 +2,6 @@
use std::collections::HashSet;
use std::env::current_dir;
-use std::fmt::Write as FmtWrite;
use std::fs::FileType;
use std::fs::OpenOptions;
use std::io::Error;
@@ -23,12 +22,12 @@ use deno_core::error::AnyError;
pub use deno_core::normalize_path;
use deno_core::unsync::spawn_blocking;
use deno_core::ModuleSpecifier;
-use deno_runtime::deno_crypto::rand;
use deno_runtime::deno_fs::FileSystem;
use deno_runtime::deno_node::PathClean;
use crate::util::gitignore::DirGitIgnores;
use crate::util::gitignore::GitIgnoreTree;
+use crate::util::path::get_atomic_file_path;
use crate::util::progress_bar::ProgressBar;
use crate::util::progress_bar::ProgressBarStyle;
use crate::util::progress_bar::ProgressMessagePrompt;
@@ -56,14 +55,7 @@ pub fn atomic_write_file<T: AsRef<[u8]>>(
}
fn inner(file_path: &Path, data: &[u8], mode: u32) -> std::io::Result<()> {
- let temp_file_path = {
- let rand: String = (0..4).fold(String::new(), |mut output, _| {
- let _ = write!(output, "{:02x}", rand::random::<u8>());
- output
- });
- let extension = format!("{rand}.tmp");
- file_path.with_extension(extension)
- };
+ let temp_file_path = get_atomic_file_path(file_path);
if let Err(write_err) =
atomic_write_file_raw(&temp_file_path, file_path, data, mode)
diff --git a/cli/util/path.rs b/cli/util/path.rs
index a3109ad04..3c848edea 100644
--- a/cli/util/path.rs
+++ b/cli/util/path.rs
@@ -42,6 +42,32 @@ pub fn get_extension(file_path: &Path) -> Option<String> {
.map(|e| e.to_lowercase());
}
+pub fn get_atomic_dir_path(file_path: &Path) -> PathBuf {
+ let rand = gen_rand_path_component();
+ let new_file_name = format!(
+ ".{}_{}",
+ file_path
+ .file_name()
+ .map(|f| f.to_string_lossy())
+ .unwrap_or(Cow::Borrowed("")),
+ rand
+ );
+ file_path.with_file_name(new_file_name)
+}
+
+pub fn get_atomic_file_path(file_path: &Path) -> PathBuf {
+ let rand = gen_rand_path_component();
+ let extension = format!("{rand}.tmp");
+ file_path.with_extension(extension)
+}
+
+fn gen_rand_path_component() -> String {
+ (0..4).fold(String::new(), |mut output, _| {
+ output.push_str(&format!("{:02x}", rand::random::<u8>()));
+ output
+ })
+}
+
/// TypeScript figures out the type of file based on the extension, but we take
/// other factors into account like the file headers. The hack here is to map the
/// specifier passed to TypeScript to a new specifier with the file extension.