Avarice_old/src/database/mod.rs

113 lines
2.8 KiB
Rust

use log::warn;
use serde_json;
use std::error::Error;
use std::fs;
use std::path;
extern crate custom_error;
use custom_error::custom_error;
custom_error! {DatabaseError
NotDirectory{path: String} = "Path to database should point at the directory: {path}",
}
struct File {
name: String,
contents: serde_json::Value,
}
struct Group {
name: String,
files: Vec<File>,
}
struct Category {
name: String,
groups: Vec<Group>,
}
pub struct Database {
storage: path::PathBuf,
contents: Vec<Category>,
}
impl Database {
pub fn new(storage: &path::Path) -> Result<Database, Box<dyn Error>> {
if !storage.is_dir() {
return Err(Box::new(DatabaseError::NotDirectory {
path: storage.display().to_string(),
}));
}
let mut contents = Vec::new();
for entry in fs::read_dir(storage)? {
let entry = entry?;
let path = entry.path();
if !path.is_dir() {
warn!(
r#"File {} found where only category directories are supposed to be"#,
path.display()
);
} else {
let category = load_category(&path)?;
contents.push(category);
}
}
Ok(Database {
storage: storage.to_path_buf(),
contents,
})
}
}
fn load_category(category_path: &path::Path) -> Result<Category, Box<dyn Error>> {
let mut groups = Vec::new();
for entry in fs::read_dir(category_path)? {
let entry = entry?;
let path = entry.path();
if !path.is_dir() {
warn!(
r#"File {} found where only group directories are supposed to be"#,
path.display()
);
} else {
let group = load_group(&path)?;
groups.push(group);
}
}
Ok(Category {
name: get_file_name(category_path),
groups,
})
}
fn load_group(group_path: &path::Path) -> Result<Group, Box<dyn Error>> {
let mut files = Vec::new();
for entry in fs::read_dir(group_path)? {
let entry = entry?;
let path = entry.path();
if path.is_dir() {
warn!(
r#"Directory {} found where only data files are supposed to be"#,
path.display()
);
} else {
let file_contents = fs::read_to_string(&path)?;
files.push(File {
name: get_file_name(path.as_path()),
contents: serde_json::from_str(&file_contents)?,
});
}
}
Ok(Group {
name: get_file_name(group_path),
files,
})
}
fn get_file_name(path: &path::Path) -> String {
path.file_stem()
.and_then(|x| x.to_str())
.unwrap_or_default()
.to_string()
}