113 lines
2.8 KiB
Rust
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()
|
|
}
|