122 lines
2.7 KiB
Rust
122 lines
2.7 KiB
Rust
use std::{collections::BTreeMap, iter::Peekable};
|
|
|
|
use log::warn;
|
|
use trillium_askama::Template;
|
|
|
|
#[derive(Template)]
|
|
#[template(path = "home.html")]
|
|
pub struct Home {}
|
|
|
|
#[derive(Template)]
|
|
#[template(path = "repo.html")]
|
|
pub struct Repo {
|
|
pub content: String,
|
|
pub root: Directory,
|
|
}
|
|
|
|
#[derive(Clone, Template)]
|
|
#[template(
|
|
source = r#"
|
|
{% match self %}
|
|
{% when Entry::Directory(dir) %}
|
|
<li class="tree-dir">
|
|
<details>
|
|
<summary><span class="filename">{{ dir.name|escape }}</span></summary>
|
|
<ul class="tree">
|
|
{% for entry in dir.entries.values() %}
|
|
{{ entry.render()? }}
|
|
{% endfor %}
|
|
</ul>
|
|
</details>
|
|
</li>
|
|
{% when Entry::File(file) %}
|
|
<li class="tree-file"><span class="filename">{{ file.name|escape }}</span></li>
|
|
{% endmatch %}
|
|
"#,
|
|
ext = "html",
|
|
escape = "none"
|
|
)]
|
|
pub enum Entry {
|
|
Directory(Directory),
|
|
File(File),
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct File {
|
|
pub name: String,
|
|
pub path: String,
|
|
pub hash: String,
|
|
}
|
|
|
|
#[derive(Clone, Default)]
|
|
pub struct Directory {
|
|
pub name: String,
|
|
pub path: String,
|
|
pub entries: BTreeMap<String, Entry>,
|
|
}
|
|
|
|
impl Entry {
|
|
fn name(&self) -> &str {
|
|
match self {
|
|
Entry::Directory(dir) => &dir.name,
|
|
Entry::File(file) => &file.name,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl PartialEq<Entry> for Entry {
|
|
fn eq(&self, other: &Entry) -> bool {
|
|
self.name() == other.name()
|
|
}
|
|
}
|
|
|
|
impl PartialOrd<Entry> for Entry {
|
|
fn partial_cmp(&self, other: &Entry) -> Option<std::cmp::Ordering> {
|
|
self.name().partial_cmp(other.name())
|
|
}
|
|
}
|
|
|
|
impl Directory {
|
|
/// Insert
|
|
pub fn insert<'a>(&mut self, entry: Entry, mut path: Peekable<impl Iterator<Item = &'a str>>) {
|
|
let Some(next_path_level) = path.next() else {
|
|
warn!("Cannot insert entry: no more path");
|
|
return;
|
|
};
|
|
if path.peek().is_some() {
|
|
// Directory
|
|
if let Some(parent) = self.entries.get_mut(next_path_level) {
|
|
// Directory exists
|
|
match parent {
|
|
Entry::Directory(dir) => dir.insert(entry, path),
|
|
Entry::File(_file) => {
|
|
warn!("Cannot insert entry: file");
|
|
}
|
|
}
|
|
} else {
|
|
//warn!("Cannot insert entry: not found");
|
|
// Need to create directory
|
|
let mut new_dir_path = self.path.clone();
|
|
new_dir_path.push_str(next_path_level);
|
|
let mut parent = Directory {
|
|
name: next_path_level.into(),
|
|
path: new_dir_path,
|
|
entries: BTreeMap::new(),
|
|
};
|
|
parent.insert(entry, path);
|
|
self.entries
|
|
.insert(next_path_level.into(), Entry::Directory(parent));
|
|
}
|
|
} else {
|
|
// File
|
|
self.entries.insert(entry.name().to_string(), entry);
|
|
}
|
|
}
|
|
|
|
pub fn find<'a>(&self, mut path: impl Iterator<Item = &'a str>) -> Option<&str> {
|
|
match self.entries.get(path.next()?)? {
|
|
Entry::Directory(directory) => directory.find(path),
|
|
Entry::File(file) => Some(&file.hash),
|
|
}
|
|
}
|
|
}
|