use super::{
file_system::{normalise_path_separator, upload_file_to_net},
metadata::FileMeta,
ProcessedFiles,
};
use crate::{api::app::consts::*, Error, Result, Safe};
use log::{debug, info};
use std::{collections::BTreeMap, fs, path::Path};
pub type FilesMap = BTreeMap<String, FileItem>;
pub type FileItem = BTreeMap<String, String>;
pub trait GetAttr {
fn getattr(&self, key: &str) -> Result<&str>;
}
impl GetAttr for FileItem {
fn getattr(&self, key: &str) -> Result<&str> {
match self.get(key) {
Some(v) => Ok(v),
None => Err(Error::EntryNotFound(format!("key not found: {}", key))),
}
}
}
#[allow(clippy::too_many_arguments)]
pub(crate) async fn add_or_update_file_item(
safe: &mut Safe,
file_name: &str,
file_name_for_map: &str,
file_path: &Path,
file_meta: &FileMeta,
file_link: Option<&str>,
name_exists: bool,
dry_run: bool,
files_map: &mut FilesMap,
processed_files: &mut ProcessedFiles,
) -> bool {
match gen_new_file_item(safe, file_path, file_meta, file_link, dry_run).await {
Ok(new_file_item) => {
let content_added_sign = if name_exists {
CONTENT_UPDATED_SIGN.to_string()
} else {
CONTENT_ADDED_SIGN.to_string()
};
debug!("New FileItem item: {:?}", new_file_item);
debug!("New FileItem item inserted as {:?}", file_name);
files_map.insert(file_name_for_map.to_string(), new_file_item.clone());
processed_files.insert(
file_name.to_string(),
(
content_added_sign,
new_file_item
.get(PREDICATE_LINK)
.unwrap_or(&String::default())
.to_string(),
),
);
true
}
Err(err) => {
processed_files.insert(
file_name.to_string(),
(CONTENT_ERROR_SIGN.to_string(), format!("<{}>", err)),
);
info!("Skipping file \"{}\": {:?}", file_link.unwrap_or(""), err);
false
}
}
}
async fn gen_new_file_item(
safe: &mut Safe,
file_path: &Path,
file_meta: &FileMeta,
link: Option<&str>, dry_run: bool,
) -> Result<FileItem> {
let mut file_item = file_meta.to_file_item();
if file_meta.is_file() {
let xorurl = match link {
None => upload_file_to_net(safe, file_path, dry_run).await?,
Some(link) => link.to_string(),
};
file_item.insert(PREDICATE_LINK.to_string(), xorurl);
} else if file_meta.is_symlink() {
let result = fs::metadata(&file_path);
let symlink_target_type = match result {
Ok(meta) => {
if meta.is_dir() {
"dir"
} else {
"file"
}
}
Err(_) => "unknown", };
let target_path = match link {
Some(target) => target.to_string(),
None => {
let target_path = fs::read_link(&file_path).map_err(|e| {
Error::FileSystemError(format!(
"Unable to read link: {}. {:#?}",
file_path.display(),
e
))
})?;
normalise_path_separator(&target_path.display().to_string())
}
};
file_item.insert("symlink_target".to_string(), target_path);
file_item.insert(
"symlink_target_type".to_string(),
symlink_target_type.to_string(),
);
}
Ok(file_item)
}