summaryrefslogtreecommitdiff
path: root/src/blog/helper.rs
blob: 35396c0023a21172bfcccb8d776cc1159038d368 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
use anyhow::{anyhow, Context};
use futures::future::join_all;
use std::{
    path::{Path, PathBuf},
    process::Stdio,
};
use tokio::{
    fs::File,
    io::{AsyncBufReadExt, BufReader},
    process::Command,
};

#[derive(Clone)]
pub struct ArticleMeta {
    pub title: String,
    pub canonical_name: String,
    pub date: iso8601::Date,
}

pub async fn article_metadata(path: PathBuf) -> anyhow::Result<ArticleMeta> {
    let f = File::open(&path).await.context("article not found")?;
    let mut f = BufReader::new(f);
    let mut buf = String::new();
    f.read_line(&mut buf).await.context("cant read the file")?; // assume the 1st line has the title
    Ok(ArticleMeta {
        title: String::from(buf[2..].trim()),
        canonical_name: path
            .file_stem()
            .ok_or(anyhow!("no file stem"))?
            .to_str()
            .ok_or(anyhow!("this file's name is broken"))?
            .to_string(),
        date: iso8601::date(
            &path
                .file_name()
                .ok_or(anyhow!("file has no name"))?
                .to_str()
                .ok_or(anyhow!("this file's name is broken"))?[0..10],
        )
        .map_err(|e| anyhow!("file date wrong: {e}"))?,
    })
}

pub async fn get_articles(blog_root: &Path) -> anyhow::Result<Vec<ArticleMeta>> {
    let mut a = join_all(
        std::fs::read_dir(blog_root)?
            .map(|e| e.unwrap())
            .map(|e| article_metadata(e.path())),
    )
    .await
    .into_iter()
    .collect::<anyhow::Result<Vec<_>>>()?;
    a.sort_by_cached_key(|e| -match e.date {
        iso8601::Date::YMD { year, month, day } => day as i32 + month as i32 * 100 + year * 10000,
        _ => unreachable!(),
    });
    Ok(a)
}

// TODO use this somewhere
pub async fn file_history(filename: &str) -> String {
    String::from_utf8(
        Command::new("/usr/bin/git")
            .args(&["log", "--follow", "--pretty=tformat:%as %h %s", filename])
            .stdout(Stdio::piped())
            .output()
            .await
            .unwrap()
            .stdout,
    )
    .unwrap()
}