217 lines
8.6 KiB
Rust
217 lines
8.6 KiB
Rust
use std::path::Path;
|
|
|
|
use crate::consts::*;
|
|
|
|
pub fn build_folder_layout(root: impl AsRef<Path>) -> 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 rebuild_symlinks(root: impl AsRef<Path>) -> std::io::Result<()> {
|
|
for dir_entry in root.as_ref()
|
|
.join(SETTING_FOLDER)
|
|
.join(ID_FOLDER)
|
|
.read_dir()? {
|
|
let dir_entry = dir_entry?;
|
|
if dir_entry.file_type()?.is_file() {
|
|
let f_path = dir_entry.path();
|
|
if let Some(ext) = f_path.extension() {
|
|
if ext == RON_EXTENSION {
|
|
let reader = std::io::BufReader::new(std::fs::File::open(&f_path)?);
|
|
let 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));
|
|
}
|
|
};
|
|
let to_symlink = crate::file_util::symlinks(&root, &setting)?;
|
|
let path_ron_canon = f_path.canonicalize()?;
|
|
let path_json_canon = crate::file_util::setting_path_by_id(&root, setting.get_id(), JSON_EXTENSION).canonicalize()?;
|
|
for ron_link in to_symlink.ron {
|
|
if ron_link.exists() { continue; }
|
|
log::info!("Rebuilding symlink {} -> {}", ron_link.display(), path_ron_canon.display());
|
|
#[cfg(target_family = "windows")] // NOTE: windows support is untested and unmaintained
|
|
{
|
|
std::os::windows::fs::symlink_file(&path_ron_canon, &ron_link)?;
|
|
}
|
|
#[cfg(target_family = "unix")]
|
|
{
|
|
std::os::unix::fs::symlink(&path_ron_canon, &ron_link)?;
|
|
}
|
|
}
|
|
for json_link in to_symlink.json {
|
|
if json_link.exists() { continue; }
|
|
log::info!("Rebuilding symlink {} -> {}", json_link.display(), path_json_canon.display());
|
|
#[cfg(target_family = "windows")] // NOTE: windows support is untested and unmaintained
|
|
{
|
|
std::os::windows::fs::symlink_file(&path_json_canon, json_link)?;
|
|
}
|
|
#[cfg(target_family = "unix")]
|
|
{
|
|
std::os::unix::fs::symlink(&path_json_canon, json_link)?;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
pub fn fix_symlinks(root: impl AsRef<Path>) -> 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<Path>, dir: impl AsRef<Path>) -> 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<Path>) -> 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<Path>) -> 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(())
|
|
}
|