diff --git a/packages/desktop/src/common/fs_util.rs b/packages/desktop/src/common/fs_util.rs index 8e34363f..8e83f6e5 100644 --- a/packages/desktop/src/common/fs_util.rs +++ b/packages/desktop/src/common/fs_util.rs @@ -19,18 +19,35 @@ pub fn read_and_parse_json( Ok(parsed) } +/// Returns whether the given path is a JSON file. +pub fn is_json(path: &PathBuf) -> bool { + path.extension().and_then(|ext| ext.to_str()) == Some("json") +} + /// Recursively copies a directory and all its contents to a new file /// location. -pub fn copy_dir_all(src: &PathBuf, dest: &PathBuf) -> anyhow::Result<()> { - fs::create_dir_all(&dest)?; - - for entry in fs::read_dir(src)? { +/// +/// Optionally replaces existing files in the destination directory if +/// `override_existing` is `true`. +pub fn copy_dir_all( + src_dir: &PathBuf, + dest_dir: &PathBuf, + override_existing: bool, +) -> anyhow::Result<()> { + fs::create_dir_all(&dest_dir)?; + + for entry in fs::read_dir(src_dir)? { let entry = entry?; + let path = entry.path(); if entry.file_type()?.is_dir() { - copy_dir_all(&entry.path(), &dest.join(entry.file_name()))?; - } else { - fs::copy(entry.path(), dest.join(entry.file_name()))?; + copy_dir_all( + &path, + &dest_dir.join(entry.file_name()), + override_existing, + )?; + } else if override_existing || !path.exists() { + fs::copy(path, dest_dir.join(entry.file_name()))?; } } diff --git a/packages/desktop/src/config.rs b/packages/desktop/src/config.rs index fd09b0c2..811ed843 100644 --- a/packages/desktop/src/config.rs +++ b/packages/desktop/src/config.rs @@ -8,7 +8,9 @@ use serde::{Deserialize, Serialize}; use tauri::{path::BaseDirectory, AppHandle, Manager}; use tracing::{info, warn}; -use crate::common::{copy_dir_all, read_and_parse_json, LengthValue}; +use crate::common::{ + copy_dir_all, is_json, read_and_parse_json, LengthValue, +}; #[derive(Clone, Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] @@ -195,7 +197,7 @@ impl Config { if path.is_dir() { // Recursively aggregate configs in subdirectories. configs.extend(Self::read_window_configs(&path)?); - } else if Self::is_json(&path) { + } else if is_json(&path) { if let Ok(config) = read_and_parse_json(&path) { info!("Found valid window config at: {}", path.display()); @@ -213,11 +215,6 @@ impl Config { Ok(configs) } - /// Returns whether the given path is a JSON file. - fn is_json(path: &PathBuf) -> bool { - path.extension().and_then(|ext| ext.to_str()) == Some("json") - } - /// Initialize config at the given path from the starter resource. fn create_from_starter( app_handle: &AppHandle, @@ -226,14 +223,9 @@ impl Config { let starter_path = app_handle .path() .resolve("resources/config", BaseDirectory::Resource) - .context("Unable to resolve sample config resource.")?; - - // Create the destination directory. - fs::create_dir_all(&config_dir).with_context(|| { - format!("Unable to create directory {}.", &config_dir.display()) - })?; + .context("Unable to resolve starter config resource.")?; - copy_dir_all(&starter_path, config_dir)?; + copy_dir_all(&starter_path, config_dir, false)?; Ok(()) }