use std::path::Path; use crate::consts::*; pub fn build_folder_layout(root: impl AsRef) -> std::io::Result<()> { std::fs::create_dir_all( root.as_ref() .join(SETTING_FOLDER) .join(ID_FOLDER) )?; std::fs::create_dir_all( root.as_ref() .join(SETTING_FOLDER) .join(APP_ID_FOLDER) )?; std::fs::create_dir_all( root.as_ref() .join(SETTING_FOLDER) .join(USER_ID_FOLDER) )?; std::fs::create_dir_all( root.as_ref() .join(SETTING_FOLDER) .join(TAG_FOLDER) )?; Ok(()) } pub fn fix_symlinks(root: impl AsRef) -> std::io::Result<()> { log::info!("root setttings folder: {} aka {} (absolute)", root.as_ref().display(), root.as_ref().canonicalize()?.display()); for dir_entry in root.as_ref() .join(SETTING_FOLDER) .join(APP_ID_FOLDER) .read_dir()? { let dir_entry = dir_entry?; if dir_entry.file_type()?.is_dir() { make_symlinks_absolute_in_dir(root.as_ref(), dir_entry.path())?; } } for dir_entry in root.as_ref() .join(SETTING_FOLDER) .join(USER_ID_FOLDER) .read_dir()? { let dir_entry = dir_entry?; if dir_entry.file_type()?.is_dir() { make_symlinks_absolute_in_dir(root.as_ref(), dir_entry.path())?; } } for dir_entry in root.as_ref() .join(SETTING_FOLDER) .join(TAG_FOLDER).read_dir()? { let dir_entry = dir_entry?; if dir_entry.file_type()?.is_dir() { make_symlinks_absolute_in_dir(root.as_ref(), dir_entry.path())?; } } Ok(()) } fn make_symlinks_absolute_in_dir(root: impl AsRef, dir: impl AsRef) -> std::io::Result<()> { let abs_root = root.as_ref().canonicalize()?; assert!(abs_root.is_absolute()); for dir_entry in dir.as_ref() .read_dir()? { let dir_entry = dir_entry?; if dir_entry.file_type()?.is_symlink() { let path = dir_entry.path(); let link_path = path.read_link()?; if !link_path.is_absolute() { let new_link = abs_root.join( link_path.strip_prefix(&root).expect("Symlinked path does not begin with root settings folder") ); log::info!("Fixing {} -> {} to -> {}", path.display(), link_path.display(), new_link.display()); std::fs::remove_file(&path)?; #[cfg(target_family = "windows")] // NOTE: windows support is untested and unmaintained { std::os::windows::fs::symlink_file(new_link, &path)?; } #[cfg(target_family = "unix")] { std::os::unix::fs::symlink(new_link, &path)?; } }else { log::info!("Found already-absolute symlink {} -> {}", path.display(), link_path.display()); } } else { log::info!("Found non-symlink {}: {:?}", dir_entry.path().display(), dir_entry.file_type()?); } } Ok(()) } pub fn sync_ids(root: impl AsRef) -> std::io::Result<()> { for dir_entry in root.as_ref() .join(SETTING_FOLDER) .join(ID_FOLDER) .read_dir()? { let dir_entry = dir_entry?; let f_path = dir_entry.path(); if let Some(ext) = f_path.extension() { let id = f_path.file_stem().map(|os| os.to_string_lossy().to_string()).unwrap(); if ext == RON_EXTENSION { let reader = std::io::BufReader::new(std::fs::File::open(&f_path)?); let mut setting: community_settings_core::v1::Metadata = match ron::de::from_reader(reader) { Ok(x) => x, Err(e) => { log::debug!("Error while reading {}: {}", f_path.display(), e); let e_msg = format!("{}", e); return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, e_msg)); } }; if setting.id != id { setting.id = id; ron::ser::to_writer(std::fs::File::create(&f_path)?, &setting).unwrap(); } } else if ext == JSON_EXTENSION { let reader = std::io::BufReader::new(std::fs::File::open(&f_path)?); let mut setting: community_settings_core::v1::Metadata = match serde_json::from_reader(reader) { Ok(x) => x, Err(e) => { log::debug!("Error while reading {}: {}", f_path.display(), e); let e_msg = format!("{}", e); return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, e_msg)); } }; if setting.id != id { setting.id = id; serde_json::to_writer(std::fs::File::create(&f_path)?, &setting).unwrap(); } } } } Ok(()) } pub fn make_tag_subfolders(root: impl AsRef) -> std::io::Result<()> { for dir_entry in root.as_ref() .join(SETTING_FOLDER) .join(USER_ID_FOLDER) .read_dir()? { let dir_entry = dir_entry?; if dir_entry.metadata()?.is_dir() { let tag_folder = dir_entry.path().join(TAG_FOLDER); if !tag_folder.exists() { std::fs::create_dir(&tag_folder)?; } } } for dir_entry in root.as_ref() .join(SETTING_FOLDER) .join(APP_ID_FOLDER) .read_dir()? { let dir_entry = dir_entry?; if dir_entry.metadata()?.is_dir() { let tag_folder = dir_entry.path().join(TAG_FOLDER); if !tag_folder.exists() { std::fs::create_dir(&tag_folder)?; } } } // TODO populate folders Ok(()) }