From 189978b3f8be92324180686f58997313408722b8 Mon Sep 17 00:00:00 2001 From: Essien Ita Essien Date: Mon, 8 Jan 2024 10:41:07 +0000 Subject: [PATCH] cli: Refactor workspace root directory creation * Add file_util::create_or_reuse_dir() which is needed by all init functionality regardless of the backend. --- cli/src/commands/init.rs | 15 +++++---------- lib/src/file_util.rs | 15 ++++++++++++++- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/cli/src/commands/init.rs b/cli/src/commands/init.rs index 517bd90d90..80337808ec 100644 --- a/cli/src/commands/init.rs +++ b/cli/src/commands/init.rs @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::io; use std::io::Write; -use std::{fs, io}; use clap::ArgGroup; use itertools::Itertools as _; @@ -51,16 +51,11 @@ pub(crate) fn cmd_init( command: &CommandHelper, args: &InitArgs, ) -> Result<(), CommandError> { - let wc_path = command.cwd().join(&args.destination); - match fs::create_dir(&wc_path) { - Ok(()) => {} - Err(_) if wc_path.is_dir() => {} - Err(e) => return Err(user_error_with_message("Failed to create workspace", e)), - } - let wc_path = wc_path - .canonicalize() - .map_err(|e| user_error_with_message("Failed to create workspace", e))?; // raced? let cwd = command.cwd().canonicalize().unwrap(); + let wc_path = cwd.join(&args.destination); + let wc_path = file_util::create_or_reuse_dir(&wc_path) + .and_then(|_| wc_path.canonicalize()) + .map_err(|e| user_error_with_message("Failed to create workspace", e))?; let relative_wc_path = file_util::relative_path(&cwd, &wc_path); if let Some(git_store_str) = &args.git_repo { diff --git a/lib/src/file_util.rs b/lib/src/file_util.rs index d2b6c4820a..15b9b24a14 100644 --- a/lib/src/file_util.rs +++ b/lib/src/file_util.rs @@ -14,7 +14,7 @@ #![allow(missing_docs)] -use std::fs::File; +use std::fs::{self, File}; use std::path::{Component, Path, PathBuf}; use std::{io, iter}; @@ -42,6 +42,19 @@ impl IoResultExt for io::Result { } } +/// Creates a directory or does nothing if the directory already exists. +/// +/// Returns the underlying error if the directory can't be created. +/// The function will also fail if intermediate directories on the path do not +/// already exist. +pub fn create_or_reuse_dir(dirname: &Path) -> io::Result<()> { + match fs::create_dir(dirname) { + Ok(()) => Ok(()), + Err(_) if dirname.is_dir() => Ok(()), + Err(e) => Err(e), + } +} + /// Turns the given `to` path into relative path starting from the `from` path. /// /// Both `from` and `to` paths are supposed to be absolute and normalized in the