hennzau

21 commits
Updated 2026-04-25 12:39:37
hnz/src
hnz/src/front.rs
use std::{path::PathBuf, sync::Arc};

use jj_lib::{
    backend::TimestampOutOfRange,
    repo::{Repo, RepoLoaderError, StoreLoadError},
    revset::{RevsetEvaluationError, RevsetExpression, RevsetIteratorExt},
};

use crate::Help;

#[derive(Debug)]
#[allow(dead_code)]
pub enum GenFrontError {
    RepoPathNotValid,
    StoreLoad(StoreLoadError),
    RepoLoader(RepoLoaderError),
    RevsetEvaluation(RevsetEvaluationError),
    EmptyHead,
    TimestampOutOfRange(TimestampOutOfRange),
    IO(std::io::Error),
}

pub fn gen_front(help: Help) -> Result<(), GenFrontError> {
    let repo_path = help.get_one::<PathBuf>("REPO_PATH").expect("required");
    let output_path = help.get_one::<PathBuf>("OUTPUT").expect("required");

    let repo_name = repo_path
        .components()
        .last()
        .ok_or(GenFrontError::RepoPathNotValid)?
        .as_os_str();

    let repo = help
        .load(repo_path.join(".jj").join("repo"))
        .map_err(GenFrontError::StoreLoad)?
        .map_err(GenFrontError::RepoLoader)?;

    let expression = Arc::new(RevsetExpression::All);
    let revset = expression
        .evaluate(repo.as_ref())
        .map_err(GenFrontError::RevsetEvaluation)?;

    let commit_count = revset
        .count_estimate()
        .map_err(GenFrontError::RevsetEvaluation)?
        .0;

    let head = revset
        .iter()
        .commits(repo.store())
        .next()
        .ok_or(GenFrontError::EmptyHead)?
        .map_err(GenFrontError::RevsetEvaluation)?;

    let root = revset
        .iter()
        .commits(repo.store())
        .fold((None, None), |(_, prev), curr| (prev, Some(curr)))
        .0
        .transpose()
        .map_err(GenFrontError::RevsetEvaluation)?;

    let last_updated = head
        .author()
        .timestamp
        .to_datetime()
        .map(|dt| dt.format("%Y-%m-%d %H:%M:%S").to_string())
        .map_err(GenFrontError::TimestampOutOfRange)?;

    let description = root
        .map(|root| root.description().trim().to_string())
        .unwrap_or("<no_description>".to_string());

    let contents = format!(
        r#"+++
title = "{}"
template = "content/repo.html"

[extra]
commits = {}
last_updated = "{}"
description = "{}"
+++"#,
        repo_name.display(),
        commit_count,
        last_updated,
        description
    );

    Ok(
        std::fs::write(output_path.join(repo_name).with_extension("md"), contents)
            .map_err(GenFrontError::IO)?,
    )
}