summaryrefslogtreecommitdiff
path: root/cli/fs_util.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cli/fs_util.rs')
-rw-r--r--cli/fs_util.rs86
1 files changed, 85 insertions, 1 deletions
diff --git a/cli/fs_util.rs b/cli/fs_util.rs
index f3a4addc0..365c9b430 100644
--- a/cli/fs_util.rs
+++ b/cli/fs_util.rs
@@ -5,10 +5,11 @@ use deno_core::error::{uri_error, AnyError};
pub use deno_core::normalize_path;
use deno_core::ModuleSpecifier;
use deno_runtime::deno_crypto::rand;
+use deno_runtime::deno_node::PathClean;
use std::borrow::Cow;
use std::env::current_dir;
use std::fs::OpenOptions;
-use std::io::{Error, Write};
+use std::io::{Error, ErrorKind, Write};
use std::path::{Path, PathBuf};
use walkdir::WalkDir;
@@ -75,6 +76,35 @@ pub fn canonicalize_path(path: &Path) -> Result<PathBuf, Error> {
return Ok(path);
}
+/// Canonicalizes a path which might be non-existent by going up the
+/// ancestors until it finds a directory that exists, canonicalizes
+/// that path, then adds back the remaining path components.
+///
+/// Note: When using this, you should be aware that a symlink may
+/// subsequently be created along this path by some other code.
+pub fn canonicalize_path_maybe_not_exists(
+ path: &Path,
+) -> Result<PathBuf, Error> {
+ let path = path.to_path_buf().clean();
+ let mut path = path.as_path();
+ let mut names_stack = Vec::new();
+ loop {
+ match canonicalize_path(path) {
+ Ok(mut canonicalized_path) => {
+ for name in names_stack.into_iter().rev() {
+ canonicalized_path = canonicalized_path.join(name);
+ }
+ return Ok(canonicalized_path);
+ }
+ Err(err) if err.kind() == ErrorKind::NotFound => {
+ names_stack.push(path.file_name().unwrap());
+ path = path.parent().unwrap();
+ }
+ Err(err) => return Err(err),
+ }
+ }
+}
+
#[cfg(windows)]
fn strip_unc_prefix(path: PathBuf) -> PathBuf {
use std::path::Component;
@@ -294,6 +324,60 @@ pub async fn remove_dir_all_if_exists(path: &Path) -> std::io::Result<()> {
}
}
+/// Copies a directory to another directory.
+///
+/// Note: Does not handle symlinks.
+pub fn copy_dir_recursive(from: &Path, to: &Path) -> Result<(), AnyError> {
+ std::fs::create_dir_all(&to)
+ .with_context(|| format!("Creating {}", to.display()))?;
+ let read_dir = std::fs::read_dir(&from)
+ .with_context(|| format!("Reading {}", from.display()))?;
+
+ for entry in read_dir {
+ let entry = entry?;
+ let file_type = entry.file_type()?;
+ let new_from = from.join(entry.file_name());
+ let new_to = to.join(entry.file_name());
+
+ if file_type.is_dir() {
+ copy_dir_recursive(&new_from, &new_to).with_context(|| {
+ format!("Dir {} to {}", new_from.display(), new_to.display())
+ })?;
+ } else if file_type.is_file() {
+ std::fs::copy(&new_from, &new_to).with_context(|| {
+ format!("Copying {} to {}", new_from.display(), new_to.display())
+ })?;
+ }
+ }
+
+ Ok(())
+}
+
+pub fn symlink_dir(oldpath: &Path, newpath: &Path) -> Result<(), AnyError> {
+ let err_mapper = |err: Error| {
+ Error::new(
+ err.kind(),
+ format!(
+ "{}, symlink '{}' -> '{}'",
+ err,
+ oldpath.display(),
+ newpath.display()
+ ),
+ )
+ };
+ #[cfg(unix)]
+ {
+ use std::os::unix::fs::symlink;
+ symlink(&oldpath, &newpath).map_err(err_mapper)?;
+ }
+ #[cfg(not(unix))]
+ {
+ use std::os::windows::fs::symlink_dir;
+ symlink_dir(&oldpath, &newpath).map_err(err_mapper)?;
+ }
+ Ok(())
+}
+
/// Attempts to convert a specifier to a file path. By default, uses the Url
/// crate's `to_file_path()` method, but falls back to try and resolve unix-style
/// paths on Windows.