use crate::cook::ident; use crate::recipe::SourceRecipe; use crate::web::get_category; use crate::{cook::tree::format_size, recipe::CookRecipe}; use pkg::Package; use std::collections::BTreeMap; use std::{fs, path::Path}; pub fn generate_html_pkg( package: &Package, recipe: &CookRecipe, dependents: &Vec, stage_files: &Option, html_path: &Path, config: &crate::web::CliWebConfig, ) { let name = &package.name; let version = &package.version; let target = &package.target; let category = &get_category(&recipe.dir); let description = recipe .recipe .package .description .as_ref() .map(|p| p.as_str()) .unwrap_or("-"); let desc_html = recipe .recipe .package .description .as_ref() .map(|desc| format!(r#"

{}

"#, desc)) .unwrap_or_default(); let repo_url = &config.repo_url; let deps_html = if package.depends.is_empty() { String::from("

None

") } else { let items: Vec = package .depends .iter() .map(|dep| format!(r#"
  • {dep}
  • "#)) .collect(); format!("
      \n{}\n
    ", items.join("\n")) }; let dependents_html = if dependents.is_empty() { String::from("

    None

    ") } else { let items: Vec = dependents .iter() .map(|dep| format!(r#"
  • {dep}
  • "#)) .collect(); format!("
      \n{}\n
    ", items.join("\n")) }; let mut source_html = match &recipe.recipe.source { Some(SourceRecipe::Git { git, .. }) => { let host = get_hostname(git); let tree_link = get_tree_url(git, host, &package.source_identifier, None); let short_commit = get_short_commit(&package.source_identifier); format!( r#"
    Git:{host}
    Commit:{short_commit}
    "# ) } Some(SourceRecipe::Tar { tar, .. }) => { let host = get_hostname(tar); format!( r#"
    Tarball:{host}
    "# ) } Some(SourceRecipe::SameAs { same_as }) => { let r = Path::new(same_as).file_name().unwrap().to_string_lossy(); format!( r#"
    Same as:{r}
    "# ) } _ => String::from(r#"

    No source specified.

    "#), }; let (files_html, files_count) = if let Some(stage_files) = stage_files { let count = stage_files .split('\n') .filter(|p| !p.ends_with('/') && !p.is_empty()) .count(); (format!("
    {stage_files}
    "), format!("{}", count)) } else { ( String::from(r#"

    No package files defined.

    "#), String::from("?"), ) }; { let host = get_hostname(&config.this_repo); let tree_link = get_tree_url( &config.this_repo, host, &package.commit_identifier, Some(&format!("recipes/{category}/{}/recipe.toml", name.name())), ); let short_commit = get_short_commit(&package.commit_identifier); source_html += &format!( r#"
    Build script:{short_commit}
    "# ); } let (arch, os) = { let target_split: Vec<&str> = package.target.split('-').collect(); ( target_split .get(0) .map(|s| s.to_string()) .unwrap_or("-".into()), target_split .get(2) .map(|s| s.to_string()) .unwrap_or("-".into()), ) }; let html = format!( r#" {name} - Red Bear OS Package
    ← Back to packages

    {name} {version}

    {desc_html}

    {description}

    $ pkg install {name}

    Dependencies

    {deps_html}

    Dependents

    {dependents_html}

    Package Files

    {files_html}
    Download

    Package Info

    OS{os}
    Architecture{arch}
    Category{category}
    Network Size{network_size}
    Storage Size{storage_size}
    File count{files_count}
    Published{published_short}
    Hash{blake3}

    Package Source

    {source_html}
    "#, network_size = format_size(package.network_size), storage_size = format_size(package.storage_size), published_short = &package.time_identifier[0..10], published = package.time_identifier, blake3 = package.blake3, ); fs::write(html_path, html).expect("Failed to write package HTML file"); } pub fn generate_html_index( grouped_packages: BTreeMap>, index_path: &Path, config: &crate::web::CliWebConfig, ) { let mut categories_html = Vec::new(); for (category, pkgs) in grouped_packages { let cards_html: Vec = pkgs .iter() .map(|(pkg, _recipe)| { let name = &pkg.name; format!( r#"

    {name}

    {version} {size}
    "#, name = name, version = pkg.version, size = format_size(pkg.network_size) ) }) .collect(); let category_block = format!( r#"

    {category}

    {cards}
    "#, category = category, cards = cards_html.join("\n") ); categories_html.push(category_block); } let html = format!( r#" Red Bear OS Package Repository

    Red Bear OS Package Repository

    Repository for {target}

    {category_sections}
    "#, target = redoxer::target(), category_sections = categories_html.join("\n\n"), commit_time = &ident::get_ident().time, commit_hash = get_short_commit(&ident::get_ident().commit), commit_tree = get_tree_url( &config.this_repo, get_hostname(&config.this_repo), &ident::get_ident().commit, None ), ); fs::write(index_path, html).expect("Failed to write index HTML file"); } fn get_hostname(url: &str) -> &str { url.split("://") .nth(1) .unwrap_or(url) .split('/') .next() .unwrap_or(url) .split(':') .next() .unwrap_or(url) } pub fn get_tree_url(git_url: &str, host: &str, commit: &str, folder: Option<&str>) -> String { let mut base_url = git_url.trim_end_matches(".git").to_string(); if let Some(ssh_path) = base_url.strip_prefix("git@") { // "git@github.com:user/repo" -> "https://github.com/user/repo" base_url = format!("https://{}", ssh_path.replace(':', "/")); } else if base_url.starts_with("git://") { // "git://github.com/user/repo" -> "https://github.com/user/repo" base_url = base_url.replacen("git://", "https://", 1); } let base_url = if host == "github.com" { format!("{}/tree/{}", base_url, commit) } else if host.contains("gitlab") { format!("{}/-/tree/{}", base_url, commit) } else { return format!("{}?commit={}", base_url, commit); }; match folder { Some(f) => format!("{base_url}/{f}"), None => base_url, } } fn get_short_commit(commit: &str) -> &str { commit.get(0..7).unwrap_or("?") }