Initial commit
This commit is contained in:
parent
a75681ff11
commit
21f3205989
|
@ -1 +1,3 @@
|
|||
/target
|
||||
build
|
||||
Cargo.lock
|
||||
|
|
|
@ -6,3 +6,5 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
chrono = "0.4"
|
||||
atom_syndication = "0.11"
|
||||
|
|
351
src/main.rs
351
src/main.rs
|
@ -1,3 +1,350 @@
|
|||
fn main() {
|
||||
println!("Hello, world!");
|
||||
use std::{
|
||||
env,
|
||||
fs::{self, copy, create_dir, read_to_string, write},
|
||||
io,
|
||||
io::{Error, ErrorKind},
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use chrono::{DateTime, FixedOffset, Local, NaiveDate, TimeZone};
|
||||
|
||||
use atom_syndication::{Entry, Feed, Link, Person};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
struct GemEntry {
|
||||
date: NaiveDate,
|
||||
title: String,
|
||||
dir: PathBuf,
|
||||
olddir: PathBuf,
|
||||
}
|
||||
|
||||
impl GemEntry {
|
||||
fn linkline(&self) -> String {
|
||||
return format!("=> {} {}", self.getlink(), self.title.replace("_", " "));
|
||||
}
|
||||
|
||||
fn getlink(&self) -> String {
|
||||
let p = &self.dir;
|
||||
let q: PathBuf = p.iter().skip(1).collect();
|
||||
let tmp = q.into_os_string().into_string().unwrap();
|
||||
|
||||
tmp
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Nonentry {
|
||||
dir: PathBuf,
|
||||
olddir: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Index {
|
||||
dir: PathBuf,
|
||||
content: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Gemdir {
|
||||
root: PathBuf, // current dir
|
||||
index: Option<Index>, // has a index.gmi file
|
||||
curentries: Vec<GemEntry>, // .gmi files in current folder that needs to be indexed
|
||||
curfolder: Vec<Nonentry>, // .gmi files that must be copied without indexing
|
||||
subfolders: Vec<Gemdir>, // .subfolders
|
||||
}
|
||||
|
||||
impl Gemdir {
|
||||
/// Changes the root dir of a Gemdir.
|
||||
pub fn changeroot(&mut self, dir: &Path) {
|
||||
let old = &self.root.clone();
|
||||
|
||||
self.chanrgerootrecurse(dir, old);
|
||||
}
|
||||
|
||||
fn chanrgerootrecurse(&mut self, dir: &Path, old: &PathBuf) {
|
||||
let p = self.root.strip_prefix(old).unwrap();
|
||||
self.root = dir.join(p);
|
||||
|
||||
if let Some(p) = &self.index {
|
||||
let t = p.dir.strip_prefix(old).unwrap();
|
||||
let mut p2 = p.clone();
|
||||
p2.dir = dir.join(t);
|
||||
self.index = Some(p2);
|
||||
}
|
||||
|
||||
for i in 0..self.curentries.len() {
|
||||
let p = self.curentries[i].dir.strip_prefix(old).unwrap().clone();
|
||||
self.curentries[i].dir = dir.join(p);
|
||||
}
|
||||
|
||||
for i in 0..self.curfolder.len() {
|
||||
let p = self.curfolder[i].dir.strip_prefix(old).unwrap().clone();
|
||||
self.curfolder[i].dir = dir.join(p);
|
||||
}
|
||||
|
||||
for i in 0..self.subfolders.len() {
|
||||
self.subfolders[i].chanrgerootrecurse(dir, old);
|
||||
}
|
||||
}
|
||||
|
||||
fn getsubfiles(&self) -> Vec<GemEntry> {
|
||||
let mut res = self.curentries.clone();
|
||||
|
||||
for sdir in &self.subfolders {
|
||||
let mut v2 = sdir.getsubfiles();
|
||||
|
||||
res.append(&mut v2);
|
||||
}
|
||||
|
||||
res.sort();
|
||||
res.reverse();
|
||||
return res;
|
||||
}
|
||||
|
||||
fn indexallsubs(&self) -> String {
|
||||
let list: Vec<GemEntry> = self.getsubfiles();
|
||||
let lines: Vec<String> = list.into_iter().map(|x| x.linkline()).collect();
|
||||
lines.join("\n")
|
||||
}
|
||||
|
||||
fn indexsubfolders(&self) -> String {
|
||||
let mut res = vec![];
|
||||
|
||||
for fold in &self.subfolders {
|
||||
let q: PathBuf = (&fold.root).iter().skip(1).collect();
|
||||
let p = q.into_os_string().into_string().unwrap();
|
||||
let links: String = (&fold.curentries)
|
||||
.into_iter()
|
||||
.map(|x| x.linkline())
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n");
|
||||
|
||||
if let Some(ind) = &fold.index {
|
||||
let k: PathBuf = (&ind.dir).iter().skip(1).collect();
|
||||
let indlink = k.into_os_string().into_string().unwrap();
|
||||
let indline = format!("=> {} Index of {}", indlink, p);
|
||||
res.push(format!("### {}\n{}\n\n{}", p, indline, links));
|
||||
} else {
|
||||
// println!("branch 2");
|
||||
res.push(format!("### {}\n\n{}", p, links));
|
||||
}
|
||||
}
|
||||
|
||||
res.join("\n----------------------------\n")
|
||||
}
|
||||
|
||||
fn refactorindex(&mut self) {
|
||||
if let Some(ind) = &self.index {
|
||||
let mut k = ind.clone();
|
||||
let c1 = k.content.replace("{{ full-list }}", &self.indexallsubs());
|
||||
let c2 = c1.replace("{{ folders }}", &self.indexsubfolders());
|
||||
k.content = c2;
|
||||
self.index = Some(k);
|
||||
}
|
||||
|
||||
for sub in &mut self.subfolders {
|
||||
sub.refactorindex();
|
||||
}
|
||||
}
|
||||
|
||||
fn writetodisk(&self) -> io::Result<()> {
|
||||
create_dir(self.root.clone())?;
|
||||
|
||||
if let Some(ind) = &self.index {
|
||||
write(ind.dir.clone(), ind.content.clone())?;
|
||||
}
|
||||
|
||||
for e in &self.curentries {
|
||||
copy(e.olddir.clone(), e.dir.clone())?;
|
||||
}
|
||||
|
||||
for ne in &self.curfolder {
|
||||
copy(ne.olddir.clone(), ne.dir.clone())?;
|
||||
}
|
||||
|
||||
for sub in &self.subfolders {
|
||||
sub.writetodisk()?
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_dirs(dir: &Path) -> io::Result<Gemdir> {
|
||||
if dir.is_dir() {
|
||||
let mut cdir = Gemdir {
|
||||
root: dir.to_path_buf(),
|
||||
index: None,
|
||||
curfolder: vec![],
|
||||
curentries: vec![],
|
||||
subfolders: vec![],
|
||||
};
|
||||
|
||||
for entry in fs::read_dir(dir)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
|
||||
println!("found : {:?}", path);
|
||||
|
||||
if path.is_dir() {
|
||||
cdir.subfolders.push(visit_dirs(&path)?);
|
||||
} else {
|
||||
let f = path.file_name().expect("File has no name?");
|
||||
|
||||
if f == "index.gmi" || f == "index.gemini" {
|
||||
// println!("filename: {:?}", e);
|
||||
let i = Index {
|
||||
dir: path.to_path_buf(),
|
||||
content: read_to_string(path)?,
|
||||
};
|
||||
|
||||
cdir.index = Some(i);
|
||||
} else if let Some(e) = path.extension() {
|
||||
if e == "gmi" || e == "gemini" {
|
||||
if let Some(e) = parse_entry(&path) {
|
||||
cdir.curentries.push(e);
|
||||
} else {
|
||||
cdir.curfolder.push(Nonentry {
|
||||
dir: path.to_path_buf(),
|
||||
olddir: path.to_path_buf(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cdir.curentries.sort();
|
||||
|
||||
return Ok(cdir);
|
||||
}
|
||||
Err(Error::from(ErrorKind::NotFound))
|
||||
}
|
||||
|
||||
fn parse_entry(dir: &Path) -> Option<GemEntry> {
|
||||
let t = dir.file_name().unwrap();
|
||||
|
||||
let f = t.to_os_string().into_string().unwrap();
|
||||
let filename = f.clone();
|
||||
|
||||
let (title, rest) = split_once(&filename)?;
|
||||
|
||||
// println!("{}", title);
|
||||
// println!("{:?}", rest);
|
||||
|
||||
let date;
|
||||
|
||||
if let Ok(d) = NaiveDate::parse_from_str(rest, "%Y-%m-%d.gmi") {
|
||||
date = d;
|
||||
} else if let Ok(d) = NaiveDate::parse_from_str(rest, "%Y-%m-%d.gemini") {
|
||||
date = d;
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
|
||||
let e = GemEntry {
|
||||
title: title.to_string(),
|
||||
dir: dir.to_path_buf(),
|
||||
olddir: dir.to_path_buf(),
|
||||
date,
|
||||
};
|
||||
Some(e)
|
||||
}
|
||||
|
||||
// found on stackoverflow
|
||||
fn split_once(in_string: &str) -> Option<(&str, &str)> {
|
||||
let mut splitter = in_string.splitn(2, '-');
|
||||
let first = splitter.next()?;
|
||||
let second = splitter.next()?;
|
||||
Some((first, second))
|
||||
}
|
||||
|
||||
fn writefeed(g: &Gemdir, title: String, url: String, author: String) -> io::Result<()> {
|
||||
let k = Path::new("atom.xml");
|
||||
let p = g.root.clone().join(&k);
|
||||
|
||||
let mut feed = Feed::default();
|
||||
|
||||
feed.set_base(url.clone());
|
||||
feed.set_title(title);
|
||||
feed.set_id(url.clone());
|
||||
|
||||
let posts = g.getsubfiles();
|
||||
|
||||
let lastupdatenaive = posts[0].date;
|
||||
|
||||
let lastupdate = getfixeddate(lastupdatenaive);
|
||||
feed.set_updated(lastupdate);
|
||||
|
||||
let mut entries = vec![];
|
||||
|
||||
for p in posts {
|
||||
let mut e = Entry::default();
|
||||
|
||||
e.set_updated(getfixeddate(p.date));
|
||||
e.set_title(p.title.replace("_", " "));
|
||||
|
||||
let mut auth = Person::default();
|
||||
auth.set_name(author.clone());
|
||||
|
||||
e.set_authors(vec![auth]);
|
||||
|
||||
let url = format!("{}/{}", url.clone(), p.getlink());
|
||||
|
||||
let mut link = Link::default();
|
||||
|
||||
link.set_href(url.clone());
|
||||
|
||||
e.set_links(vec![link]);
|
||||
|
||||
e.set_id(url);
|
||||
|
||||
entries.push(e);
|
||||
}
|
||||
|
||||
feed.set_entries(entries);
|
||||
|
||||
write(p, feed.to_string())
|
||||
}
|
||||
|
||||
fn getfixeddate(d: NaiveDate) -> DateTime<FixedOffset> {
|
||||
let naivedatetime = d.and_hms(0, 0, 0);
|
||||
let curtime = Local::now();
|
||||
let offset = curtime.offset();
|
||||
|
||||
offset.from_local_datetime(&naivedatetime).unwrap()
|
||||
}
|
||||
|
||||
fn buildsite(
|
||||
dir: &Path,
|
||||
g: &mut Gemdir,
|
||||
title: String,
|
||||
url: String,
|
||||
author: String,
|
||||
) -> io::Result<()> {
|
||||
g.changeroot(dir);
|
||||
g.refactorindex();
|
||||
|
||||
g.writetodisk()?;
|
||||
writefeed(g, title, url, author)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
// let dir = Path::new("/home/raphy/Documents/Projects/Rust/rugem/testsite/");
|
||||
let dir = Path::new(&args[1]);
|
||||
let dst = Path::new(&args[2]);
|
||||
let title = &args[3];
|
||||
let url = &args[4];
|
||||
let auth = &args[5];
|
||||
let mut k = visit_dirs(&dir).unwrap();
|
||||
|
||||
buildsite(
|
||||
dst,
|
||||
&mut k,
|
||||
title.to_string(),
|
||||
url.to_string(),
|
||||
auth.to_string(),
|
||||
);
|
||||
// print!("{:?}", k)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue