From 91edae0ff627e47b0267a1679527029f3f5af81e Mon Sep 17 00:00:00 2001 From: Sophie Herold Date: Wed, 19 Oct 2022 23:01:30 +0200 Subject: [PATCH 1/8] Revert "overview: Add upcoming markdown formatted strings" This reverts commit 3c8c2a5bbbe8b9e35a402f3915e0293561f98e79. --- website/src/gettext_strings.rs | 14 -------------- website/templates/overview.html | 11 ----------- 2 files changed, 25 deletions(-) diff --git a/website/src/gettext_strings.rs b/website/src/gettext_strings.rs index bbc387a..cba8ab6 100644 --- a/website/src/gettext_strings.rs +++ b/website/src/gettext_strings.rs @@ -43,13 +43,6 @@ pub fn strings() -> Vec<(&'static str, String)> { r###"Apps featured in this curated overview are all built with the GNOME philosophy in mind. They are easy to understand and simple to use, feature a consistent and polished design and provide a noticeable attention to details. Naturally, they are free software and have committed to being part of a welcoming and friendly community. These apps will perfectly integrate with your GNOME Desktop."###, ), ), - ( - r###"Apps featured in this curated overview are all built with the GNOME philosophy in mind. They are easy to understand and simple to use, feature a consistent and polished design and provide a noticeable attention to details. Naturally, they are [free software](https://fsfe.org/freesoftware/) and have committed to being part of a [welcoming and friendly community](https://wiki.gnome.org/Foundation/CodeOfConduct). These apps will perfectly integrate with your [GNOME Desktop](https://www.gnome.org/)."###, - // Translators: NEW main page introductiory text using markdown - gettextrs::gettext( - r###"Apps featured in this curated overview are all built with the GNOME philosophy in mind. They are easy to understand and simple to use, feature a consistent and polished design and provide a noticeable attention to details. Naturally, they are [free software](https://fsfe.org/freesoftware/) and have committed to being part of a [welcoming and friendly community](https://wiki.gnome.org/Foundation/CodeOfConduct). These apps will perfectly integrate with your [GNOME Desktop](https://www.gnome.org/)."###, - ), - ), ( r###"App supports mobile devices"###, gettextrs::gettext(r###"App supports mobile devices"###), @@ -84,13 +77,6 @@ pub fn strings() -> Vec<(&'static str, String)> { r###"GNOME Circle contains applications extending the GNOME ecosystem. It champions the great additional software that is available for the GNOME platform. Learn more about GNOME Circle."###, ), ), - ( - r###"GNOME Circle contains applications extending the GNOME ecosystem. It champions the great additional software that is available for the GNOME platform. [Learn more about GNOME Circle.](https://circle.gnome.org/)"###, - // Translators: NEW App list section text using markdown - gettextrs::gettext( - r###"GNOME Circle contains applications extending the GNOME ecosystem. It champions the great additional software that is available for the GNOME platform. [Learn more about GNOME Circle.](https://circle.gnome.org/)"###, - ), - ), ( r###"Development Tools"###, // Translators: App list section heading diff --git a/website/templates/overview.html b/website/templates/overview.html index 2a17e27..07f319f 100644 --- a/website/templates/overview.html +++ b/website/templates/overview.html @@ -55,12 +55,6 @@ {# Translators: Main page introductiory text #}

{{ str["Apps featured in this curated overview are all built with the GNOME philosophy in mind. They are easy to understand and simple to use, feature a consistent and polished design and provide a noticeable attention to details. Naturally, they are free software and have committed to being part of a welcoming and friendly community. These apps will perfectly integrate with your GNOME Desktop."] | safe }}

- -

{{ str[ {{ str["Apps supported on GNOME mobile devices are marked with the mobile icon."] | safe }}

@@ -88,11 +82,6 @@

{{ str["Circle Apps"] }}

{# Translators: App list section text #} {{ str["GNOME Circle contains applications extending the GNOME ecosystem. It champions the great additional software that is available for the GNOME platform. Learn more about GNOME Circle."] | safe }} - -- GitLab From 785d858795744f8f4ee94ff3f49a74bb4a222e6b Mon Sep 17 00:00:00 2001 From: Sophie Herold Date: Tue, 18 Oct 2022 17:46:48 +0200 Subject: [PATCH 2/8] generate: Structure code --- aussi/src/output.rs | 21 +++- website/src/error.rs | 21 ++++ website/src/generate.rs | 184 +++++++--------------------- website/src/generate/card_icons.rs | 33 +++++ website/src/generate/screenshots.rs | 65 ++++++++++ website/src/generate/sitemap.rs | 20 +++ 6 files changed, 203 insertions(+), 141 deletions(-) create mode 100644 website/src/generate/card_icons.rs create mode 100644 website/src/generate/screenshots.rs create mode 100644 website/src/generate/sitemap.rs diff --git a/aussi/src/output.rs b/aussi/src/output.rs index e9982ec..a5eb076 100644 --- a/aussi/src/output.rs +++ b/aussi/src/output.rs @@ -2,7 +2,7 @@ use askama::Template; use std::path::{Path, PathBuf}; -pub const TMP_DIR: &str = "tmp-out"; +pub const TMP_DIR: &str = "public.new"; pub const TARGET_DIR: &str = "public"; pub trait Output { @@ -44,6 +44,25 @@ impl OutputSimple for Dir { } } +pub struct File(PathBuf); + +impl> From for File { + fn from(path: T) -> Self { + Self(path.as_ref().to_path_buf()) + } +} + +impl OutputSimple for File { + fn output(&self, path: impl AsRef) { + let mut tmp_dest = PathBuf::from(TMP_DIR); + tmp_dest.push(path); + + std::fs::create_dir_all(&tmp_dest.parent().unwrap()).unwrap(); + + std::fs::copy(&self.0, tmp_dest).unwrap(); + } +} + pub struct Scss(PathBuf); impl> From for Scss { fn from(path: T) -> Self { diff --git a/website/src/error.rs b/website/src/error.rs index 6dcebe8..5fbab96 100644 --- a/website/src/error.rs +++ b/website/src/error.rs @@ -4,6 +4,7 @@ use std::fmt::Display; use std::sync::Mutex; pub static LOG: Lazy>>> = Lazy::new(Default::default); +pub static TIMED: Lazy>> = Lazy::new(Default::default); pub fn add_log_entry(app_id: impl Display, level: &str, msg: impl Display) { LOG.lock() @@ -25,6 +26,26 @@ macro_rules! log_warn { }) } +#[macro_export] +macro_rules! timed_info { + ($($arg:tt)+) => ({ + let msg = format!($($arg)+); + if let Some(x) = *$crate::error::TIMED.lock().unwrap() { + info!("{} ms needed for completion", x.elapsed().as_millis()); + } + *$crate::error::TIMED.lock().unwrap() = Some(std::time::Instant::now()); + info!("{}", msg); + }) +} + +pub fn timed_info(msg: &str) { + if let Some(x) = *TIMED.lock().unwrap() { + info!("Completed in {} ms", x.elapsed().as_millis()); + } + *TIMED.lock().unwrap() = Some(std::time::Instant::now()); + info!("{}", msg); +} + pub trait LogError { fn warn(self, context: C) -> Self where diff --git a/website/src/generate.rs b/website/src/generate.rs index 05b0e59..76f6804 100644 --- a/website/src/generate.rs +++ b/website/src/generate.rs @@ -1,22 +1,24 @@ +mod card_icons; mod redirects; +mod screenshots; +mod sitemap; use crate::collect::*; use crate::context::*; -use crate::{cli, config, flathub, l10n, lists, output, sitemap, svg, utils}; +use crate::{cli, config, flathub, l10n, lists, output, svg, utils}; use appstream::AppId; -use futures::stream::TryStreamExt; +use aussi::output::{Dir, File, OutputSimple, Scss}; use rust_icu::sys::UDateFormatStyle; use std::sync::Arc; use tera::Tera; -use tokio_util::compat::FuturesAsyncReadCompatExt; use flatpak::prelude::*; use gio::prelude::*; use std::io::prelude::*; -use crate::log_warn; +use crate::{log_warn, timed_info}; lazy_static! { pub static ref TEMPLATES: Tera = Tera::new("templates/**/*").unwrap(); @@ -30,7 +32,7 @@ pub async fn generate() -> Result<(), Box> { let mut app_ids = Vec::new(); if !opt.dev { - info!("Loading core utitilies apps list"); + timed_info!("Loading core utitilies apps list"); let mut core_ids = lists::gnome_app_ids("utilities").await?; core_ids.push("org.gnome.Settings".into()); @@ -44,7 +46,7 @@ pub async fn generate() -> Result<(), Box> { .collect(), ); - info!("Loading circle apps list"); + timed_info!("Loading circle apps list"); app_ids.append( &mut lists::circle_apps() .await? @@ -54,7 +56,7 @@ pub async fn generate() -> Result<(), Box> { ); } - info!("Loading core developer tools apps list"); + timed_info!("Loading core developer tools apps list"); let mut dev_ids = lists::gnome_app_ids("developer-tools").await?; dev_ids.push("org.gnome.design.AppIconPreview".into()); dev_ids.push("org.gnome.design.Contrast".into()); @@ -75,7 +77,7 @@ pub async fn generate() -> Result<(), Box> { app_ids.retain(|(id, _, _)| &id.to_string() == app); } - info!("Loading appdata file"); + timed_info!("Loading appdata file"); let installation = flathub::installation()?; installation.update_appstream_sync("afg-flathub", None, gio::Cancellable::NONE)?; @@ -85,7 +87,7 @@ pub async fn generate() -> Result<(), Box> { let mut collection = appstream::Collection::from_path(appstream_path.path().unwrap())?; - info!("Installing Flathub data"); + timed_info!("Installing Flathub data"); let flathub_app_ids = app_ids .iter() .map(|(app_id, _, _)| app_id) @@ -93,7 +95,7 @@ pub async fn generate() -> Result<(), Box> { .collect::>(); flathub::install_data(&flathub_app_ids)?; - info!("Adding appstream components not available on Flathub"); + timed_info!("Adding appstream components not available on Flathub"); if let Ok(entries) = std::fs::read_dir("non-flatpak/metainfo/") { for entry in entries { let entry = entry?; @@ -112,7 +114,7 @@ pub async fn generate() -> Result<(), Box> { error!("Non-flatpak data not available. Use `./download-non-flatpaked.py` to get them."); } - info!("Copying app icons"); + timed_info!("Copying app icons"); std::fs::create_dir_all("public.new/icons/scalable")?; std::fs::create_dir_all("public.new/icons/symbolic")?; for (app_id, _, _) in &app_ids { @@ -146,7 +148,7 @@ pub async fn generate() -> Result<(), Box> { } } - info!("Retriving nightly infos"); + timed_info!("Retriving nightly infos"); installation.update_appstream_sync("afg-gnome-nightly", None, gio::Cancellable::NONE)?; let nightly_app_ids = Arc::new( installation @@ -158,7 +160,7 @@ pub async fn generate() -> Result<(), Box> { .collect::>(), ); - info!("stats"); + timed_info!("Download stats"); let date: chrono::NaiveDate = chrono::Utc::now().date().naive_local() - chrono::Duration::days(6 * 30); let mut tasks = Vec::new(); @@ -172,7 +174,7 @@ pub async fn generate() -> Result<(), Box> { } let stats = Arc::new(stats); - info!("Extracting and retrieving relevant data"); + timed_info!("Extracting and retrieving relevant data"); let collection = Arc::new(collection); let mut apps_future = Vec::new(); for (app_id, gnome_line, circle) in app_ids { @@ -196,7 +198,7 @@ pub async fn generate() -> Result<(), Box> { } } - info!("Preparing languages"); + timed_info!("Preparing languages"); let mut tasks = Vec::new(); let mut languages = if opt.dev { vec![ @@ -218,14 +220,14 @@ pub async fn generate() -> Result<(), Box> { }; // remove unused languages - info!("Languages available in d-l: {}", languages.len()); + debug!("Languages available in d-l: {}", languages.len()); languages.retain(|lang| { apps.iter() .any(|app| app.appstream.name.get_for_locale(&lang.name).is_some() || lang.name == "en") }); - info!("Languages kept as active: {}", languages.len()); + debug!("Languages kept as active: {}", languages.len()); - info!("Generating pages"); + timed_info!("Generating pages"); let datetime = chrono::Utc::now(); for lang in languages.iter().map(|x| &x.name).chain([&String::new()]) { debug!("Language: {}", lang); @@ -282,7 +284,11 @@ pub async fn generate() -> Result<(), Box> { } } - info!("Language selector"); + for task in tasks { + task.await.unwrap(); + } + + timed_info!("Language selector"); let mut context = tera::Context::new(); context.insert("base", ".."); @@ -294,13 +300,13 @@ pub async fn generate() -> Result<(), Box> { let result = TEMPLATES.render("languages.html", &context)?; write_site("languages/index.html", &result, "")?; - debug!("Generating 404 error page ..."); + timed_info!("Generating 404 error page ..."); context.insert("base", config::ABSOLUTE_BASE_URL); let result = TEMPLATES.render("404.html", &context)?; write_site("404.html", &result, "")?; - info!("Generate language js"); + timed_info!("Generate language js"); let mut context = tera::Context::new(); context.insert( "languages_json", @@ -309,135 +315,33 @@ pub async fn generate() -> Result<(), Box> { let result = TEMPLATES.render("script.js", &context)?; write_site("assets/script.js", &result, "")?; - for task in tasks { - task.await.unwrap(); - } + timed_info!("Generating card icons"); + card_icons::generate(&apps).unwrap(); - info!("Generating card icons"); - std::fs::create_dir_all("public.new/icons/16")?; - std::fs::create_dir_all("public.new/icons/32")?; - std::fs::create_dir_all("public.new/icons/64")?; - std::fs::create_dir_all("public.new/icons/128")?; - std::fs::create_dir_all("public.new/icons/twitter")?; - for app in &apps { - for size in [64, 128] { - svg::card(&app.id.to_string(), size, &app.background_color); - } + timed_info!("Copying screenshots"); + screenshots::generate(&apps).await; - svg::twitter(&app.id.to_string(), &app.background_color, &app.project); - - for (scheme, shade) in [("-light", 0.), ("-dark", 1.)] { - let path = format!("public.new/icons/symbolic/{}.svg", app.id); - if std::path::Path::new(&path).exists() { - for size in [16, 32] { - svg::generate_icon( - &path, - size, - shade, - &format!("public.new/icons/{}/{}{}.png", size, app.id, scheme), - ) - } - } - } - } + timed_info!("Copying assets"); + Dir::from("assets/").output("assets/"); + File::from("data/google7ed0380f213cfb6e.html").output("google7ed0380f213cfb6e.html"); + File::from("data/robots.txt").output("robots.txt"); - info!("Copying screenshots"); - let mut tasks = Vec::new(); - for app in &apps { - for screenshot in &app.appstream.screenshots { - let image = screenshot - .images - .iter() - .find(|x| x.kind == appstream::enums::ImageKind::Source); - if let Some(image) = image { - debug!("Screenshot: {}", image.url.as_str()); - let img_url = image.url.clone(); - let app_id = app.id.to_string(); - tasks.push(tokio::task::spawn(async move { - debug!("ASYNC CALL"); - match reqwest::get(img_url.clone()).await { - Ok(img_data) => { - let content_type = img_data.headers().get("Content-Type"); - if content_type.map(|x| x.as_bytes()) != Some(b"image/png") { - log_warn!( - app_id, - "Wrong content type `{:?}` for screenshot: {}", - content_type, - img_url - ); - } else { - let filename = - img_url.path_segments().and_then(|x| x.last()).unwrap(); - let mut file = new_file_tokio(format!( - "assets/screenshots/{}/{}", - app_id, filename - )) - .await - .unwrap(); - let mut data = img_data - .bytes_stream() - .map_err(|e| { - futures::io::Error::new(futures::io::ErrorKind::Other, e) - }) - .into_async_read() - .compat(); - - //copy_to - tokio::io::copy(&mut data, &mut file).await.unwrap(); - } - } - Err(_) => { - log_warn!(app_id, "Screenshot not available: {}", img_url) - } - } - })); - } - } - } - - info!("Copying assets"); - fs_extra::dir::copy("assets", "public.new/", &Default::default())?; - std::fs::copy( - "data/google7ed0380f213cfb6e.html", - "public.new/google7ed0380f213cfb6e.html", - )?; - std::fs::copy("data/robots.txt", "public.new/robots.txt")?; - - info!("Compiling sass"); - let css = sass_rs::compile_file("scss/style.scss", Default::default())?; - write_site("assets/style.css", &css, "")?; + timed_info!("Compiling sass"); + Scss::from("scss/style.scss").output("assets/style.css"); - for task in tasks { - task.await.unwrap(); - } - - info!("Generating sitemap"); - - for lang in &languages { - let sitemap = sitemap::generate(&apps, lang, &languages); - sitemap.write_to(&format!("public.new/sitemap_{}.xml.gz", lang.ietf())); - } - - let mut sitemap_index = sitemap::SitemapIndex::new(); - for lang in &languages { - sitemap_index.push_sitemap(sitemap::Sitemap::new(&format!( - "{}/sitemap_{}.xml.gz", - config::ABSOLUTE_BASE_URL, - lang.ietf() - ))); - } - sitemap_index.write_to("public.new/sitemap.xml"); + timed_info!("Generating sitemap"); + sitemap::generate(&apps, &languages); - info!("Generating redirects"); + timed_info!("Generating redirects"); redirects::generate(&languages)?; - info!("Generating json api"); + timed_info!("Generating json api"); output::json::generate(&apps).await?; - info!("Copying finalized data"); - let _ignore = std::fs::remove_dir_all("public"); - std::fs::rename("public.new", "public")?; + timed_info!("Copying finalized data"); + aussi::output::complete().unwrap(); + timed_info!("Page generation completed"); Ok(()) } diff --git a/website/src/generate/card_icons.rs b/website/src/generate/card_icons.rs new file mode 100644 index 0000000..5eaed0c --- /dev/null +++ b/website/src/generate/card_icons.rs @@ -0,0 +1,33 @@ +use crate::collect::App; +use crate::svg; + +pub fn generate(apps: &[App]) -> Result<(), Box> { + std::fs::create_dir_all("public.new/icons/16")?; + std::fs::create_dir_all("public.new/icons/32")?; + std::fs::create_dir_all("public.new/icons/64")?; + std::fs::create_dir_all("public.new/icons/128")?; + std::fs::create_dir_all("public.new/icons/twitter")?; + for app in apps { + for size in [64, 128] { + svg::card(&app.id.to_string(), size, &app.background_color); + } + + svg::twitter(&app.id.to_string(), &app.background_color, &app.project); + + for (scheme, shade) in [("-light", 0.), ("-dark", 1.)] { + let path = format!("public.new/icons/symbolic/{}.svg", app.id); + if std::path::Path::new(&path).exists() { + for size in [16, 32] { + svg::generate_icon( + &path, + size, + shade, + &format!("public.new/icons/{}/{}{}.png", size, app.id, scheme), + ) + } + } + } + } + + Ok(()) +} diff --git a/website/src/generate/screenshots.rs b/website/src/generate/screenshots.rs new file mode 100644 index 0000000..e462f55 --- /dev/null +++ b/website/src/generate/screenshots.rs @@ -0,0 +1,65 @@ +use super::new_file_tokio; +use crate::collect::App; +use crate::log_warn; + +use futures::prelude::*; +use tokio_util::compat::FuturesAsyncReadCompatExt; + +pub async fn generate(apps: &[App]) { + let mut tasks = Vec::new(); + for app in apps.iter() { + for screenshot in &app.appstream.screenshots { + let image = screenshot + .images + .iter() + .find(|x| x.kind == appstream::enums::ImageKind::Source); + if let Some(image) = image { + debug!("Screenshot: {}", image.url.as_str()); + let img_url = image.url.clone(); + let app_id = app.id.to_string(); + tasks.push(tokio::task::spawn(async move { + debug!("ASYNC CALL"); + match reqwest::get(img_url.clone()).await { + Ok(img_data) => { + let content_type = img_data.headers().get("Content-Type"); + if content_type.map(|x| x.as_bytes()) != Some(b"image/png") { + log_warn!( + app_id, + "Wrong content type `{:?}` for screenshot: {}", + content_type, + img_url + ); + } else { + let filename = + img_url.path_segments().and_then(|x| x.last()).unwrap(); + let mut file = new_file_tokio(format!( + "assets/screenshots/{}/{}", + app_id, filename + )) + .await + .unwrap(); + let mut data = img_data + .bytes_stream() + .map_err(|e| { + futures::io::Error::new(futures::io::ErrorKind::Other, e) + }) + .into_async_read() + .compat(); + + //copy_to + tokio::io::copy(&mut data, &mut file).await.unwrap(); + } + } + Err(_) => { + log_warn!(app_id, "Screenshot not available: {}", img_url) + } + } + })); + } + } + } + + for task in tasks { + task.await.unwrap(); + } +} diff --git a/website/src/generate/sitemap.rs b/website/src/generate/sitemap.rs new file mode 100644 index 0000000..413d903 --- /dev/null +++ b/website/src/generate/sitemap.rs @@ -0,0 +1,20 @@ +use crate::collect::App; +use crate::collect::Language; +use crate::{config, sitemap}; + +pub fn generate(apps: &[App], languages: &[Language]) { + for lang in languages { + let sitemap = sitemap::generate(apps, lang, languages); + sitemap.write_to(&format!("public.new/sitemap_{}.xml.gz", lang.ietf())); + } + + let mut sitemap_index = sitemap::SitemapIndex::new(); + for lang in languages { + sitemap_index.push_sitemap(sitemap::Sitemap::new(&format!( + "{}/sitemap_{}.xml.gz", + config::ABSOLUTE_BASE_URL, + lang.ietf() + ))); + } + sitemap_index.write_to("public.new/sitemap.xml"); +} -- GitLab From 532f259a8a992df6b8fbdbc67f4270b653e56828 Mon Sep 17 00:00:00 2001 From: Sophie Herold Date: Tue, 18 Oct 2022 18:26:21 +0200 Subject: [PATCH 3/8] cargo: Optimize image crates in devel --- .gitlab-ci.yml | 2 +- website/Cargo.toml | 6 ++++++ website/src/cli.rs | 2 ++ website/src/generate.rs | 22 ++++++++++++---------- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5c6ef7f..b269b92 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -26,7 +26,7 @@ pages: test: script: - - RUST_LOG=debug cargo run --release + - RUST_LOG=debug cargo run - mv public ../ artifacts: paths: diff --git a/website/Cargo.toml b/website/Cargo.toml index 6be3b9d..67f5d30 100644 --- a/website/Cargo.toml +++ b/website/Cargo.toml @@ -3,6 +3,12 @@ name = "malamute" version = "0.1.0" edition = "2021" +[profile.dev.package.tiny-skia] +opt-level = 3 + +[profile.dev.package.png] +opt-level = 3 + [dependencies] aussi = { version = "*", path = "../aussi" } appstream = "0.2.2" diff --git a/website/src/cli.rs b/website/src/cli.rs index a02a860..165f1d3 100644 --- a/website/src/cli.rs +++ b/website/src/cli.rs @@ -11,6 +11,8 @@ pub struct Opt { pub github_token: Option, #[structopt(long)] pub gitlab_token: Option>, + #[structopt(long)] + pub no_stats: bool, } pub fn args() -> Opt { diff --git a/website/src/generate.rs b/website/src/generate.rs index 76f6804..bd3593a 100644 --- a/website/src/generate.rs +++ b/website/src/generate.rs @@ -160,17 +160,19 @@ pub async fn generate() -> Result<(), Box> { .collect::>(), ); - timed_info!("Download stats"); - let date: chrono::NaiveDate = - chrono::Utc::now().date().naive_local() - chrono::Duration::days(6 * 30); - let mut tasks = Vec::new(); - for day in date.iter_days().take(6 * 30) { - tasks.push(tokio::task::spawn(flathub::Stats::download(day))); - } - let mut stats = flathub::Stats::default(); - for task in tasks { - stats = stats.clone() + task.await?; + if !opt.no_stats { + timed_info!("Download stats"); + let date: chrono::NaiveDate = + chrono::Utc::now().date().naive_local() - chrono::Duration::days(6 * 30); + let mut tasks = Vec::new(); + for day in date.iter_days().take(6 * 30) { + tasks.push(tokio::task::spawn(flathub::Stats::download(day))); + } + + for task in tasks { + stats = stats.clone() + task.await?; + } } let stats = Arc::new(stats); -- GitLab From 00e3f889645540cb2e30a1d3e3396d86aba2b684 Mon Sep 17 00:00:00 2001 From: Sophie Herold Date: Tue, 18 Oct 2022 21:44:54 +0200 Subject: [PATCH 4/8] Use askama instead of tera for templates --- .gitlab-ci.yml | 7 +- aussi/Cargo.lock | 558 +++++++++++++++++- aussi/Cargo.toml | 3 + aussi/src/data/app.rs | 29 +- aussi/src/filters.rs | 26 +- aussi/src/i18n.rs | 24 +- aussi/src/lib.rs | 1 + aussi/src/output.rs | 21 +- aussi/src/site.rs | 21 +- aussi/src/utils.rs | 24 + meson.build | 5 - po/apps-for-gnome.pot | 182 ++++++ website/.gitignore | 1 + website/Cargo.lock | 335 +++-------- website/Cargo.toml | 8 +- website/extract_gettext.py | 43 -- website/meson.build | 5 + website/src/cli.rs | 4 + website/src/collect.rs | 10 +- website/src/context.rs | 10 +- website/src/error.rs | 8 - website/src/filters.rs | 2 + website/src/flathub.rs | 4 +- website/src/generate.rs | 187 ++---- website/src/generate/pages.rs | 29 + website/src/gettext_strings.rs | 270 --------- website/src/l10n.rs | 19 - website/src/lib.rs | 36 +- website/src/lists.rs | 17 +- website/src/pages.rs | 46 ++ website/src/utils.rs | 25 - website/templates/app.html | 185 +++--- website/templates/base.html | 57 +- .../templates/{404.html => error-404.html} | 2 +- website/templates/languages.html | 10 +- website/templates/macros.html | 199 +++---- website/templates/overview.html | 69 +-- website/templates/releases.html | 10 +- website/templates/script.js | 11 +- 39 files changed, 1352 insertions(+), 1151 deletions(-) create mode 100644 aussi/src/utils.rs delete mode 100644 meson.build create mode 100644 po/apps-for-gnome.pot delete mode 100755 website/extract_gettext.py create mode 100644 website/src/filters.rs create mode 100644 website/src/generate/pages.rs delete mode 100644 website/src/gettext_strings.rs delete mode 100644 website/src/l10n.rs create mode 100644 website/src/pages.rs rename website/templates/{404.html => error-404.html} (81%) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b269b92..f09967d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,9 +1,12 @@ image: 'registry.fedoraproject.org/fedora:35' +variables: + ABSOLUTE_BASE_URL: https://apps.gnome.org + before_script: - dnf install -y rust cargo gcc-c++ openssl-devel gettext-devel libicu-devel clang-devel flatpak meson glibc-all-langpacks git glib2-devel desktop-file-utils gtk-update-icon-cache appstream flatpak-devel - cd website - - meson --prefix `pwd`/out builddir .. + - meson builddir - ninja install -C builddir - ./download-non-flatpaked.py @@ -26,7 +29,7 @@ pages: test: script: - - RUST_LOG=debug cargo run + - RUST_LOG=malamute=debug cargo run --release - mv public ../ artifacts: paths: diff --git a/aussi/Cargo.lock b/aussi/Cargo.lock index bb24bab..27c7bf8 100644 --- a/aussi/Cargo.lock +++ b/aussi/Cargo.lock @@ -46,6 +46,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "anyhow" +version = "1.0.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602" + [[package]] name = "appstream" version = "0.2.2" @@ -62,6 +68,12 @@ dependencies = [ "xmltree", ] +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + [[package]] name = "askama" version = "0.11.1" @@ -101,7 +113,7 @@ dependencies = [ "humansize", "mime", "mime_guess", - "nom", + "nom 7.1.1", "num-traits", "percent-encoding", "proc-macro2", @@ -134,9 +146,12 @@ dependencies = [ "fs_extra", "gettext-rs", "grass", + "indexmap", "log", + "minify-html", "once_cell", "reqwest", + "rust_icu", "serde", "serde_json", ] @@ -168,6 +183,30 @@ dependencies = [ "serde", ] +[[package]] +name = "bindgen" +version = "0.53.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c72a978d268b1d70b0e963217e60fdabd9523a941457a6c42a7315d15c7e89e5" +dependencies = [ + "bitflags", + "cexpr", + "cfg-if 0.1.10", + "clang-sys", + "clap", + "env_logger", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "which", +] + [[package]] name = "bit-set" version = "0.5.3" @@ -189,6 +228,18 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitvec" +version = "0.19.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55f93d0ef3363c364d5976646a38f04cf67cfe1d4c8d160cdea02cab2c116b33" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "block" version = "0.1.6" @@ -222,6 +273,21 @@ version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +[[package]] +name = "cexpr" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" +dependencies = [ + "nom 5.1.2", +] + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + [[package]] name = "cfg-if" version = "1.0.0" @@ -244,6 +310,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "clang-sys" +version = "0.29.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe6837df1d5cba2397b835c8530f51723267e16abbf83892e9e5af4f0e5dd10a" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "clap" version = "2.34.0" @@ -313,6 +390,12 @@ dependencies = [ "xdg", ] +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + [[package]] name = "core-foundation" version = "0.9.3" @@ -344,7 +427,7 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -357,6 +440,17 @@ dependencies = [ "typenum", ] +[[package]] +name = "css-minify" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692b185e3b7c9af96b3195f3021f53a931d896968ed2ad3fb1cdb6558b30c9ab" +dependencies = [ + "derive_more", + "indexmap", + "nom 6.1.2", +] + [[package]] name = "cxx" version = "1.0.79" @@ -401,6 +495,19 @@ dependencies = [ "syn", ] +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn", +] + [[package]] name = "digest" version = "0.10.5" @@ -451,7 +558,7 @@ version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -460,6 +567,19 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca" +[[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + [[package]] name = "erased-serde" version = "0.3.23" @@ -534,6 +654,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" +[[package]] +name = "funty" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" + [[package]] name = "futures-channel" version = "0.3.24" @@ -598,7 +724,7 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "wasi 0.11.0+wasi-snapshot-preview1", ] @@ -623,6 +749,12 @@ dependencies = [ "temp-dir", ] +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + [[package]] name = "grass" version = "0.11.2" @@ -734,6 +866,15 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02296996cb8796d7c6e3bc2d9211b7802812d36999a51bb754123ead7d37d026" +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error", +] + [[package]] name = "hyper" version = "0.14.20" @@ -813,6 +954,7 @@ checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", "hashbrown 0.12.3", + "serde", ] [[package]] @@ -821,7 +963,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -866,12 +1008,35 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +[[package]] +name = "lexical-core" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" +dependencies = [ + "arrayvec", + "bitflags", + "cfg-if 1.0.0", + "ryu", + "static_assertions", +] + [[package]] name = "libc" version = "0.2.135" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c" +[[package]] +name = "libloading" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" +dependencies = [ + "cc", + "winapi", +] + [[package]] name = "line-wrap" version = "0.1.1" @@ -915,7 +1080,7 @@ version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -949,6 +1114,29 @@ dependencies = [ "unicase", ] +[[package]] +name = "minify-html" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16321f124e57bed2916c6e28ef67b94c9a9d85f234b4c33ac2882eaacd8736c" +dependencies = [ + "aho-corasick", + "css-minify", + "lazy_static", + "memchr", + "minify-js", +] + +[[package]] +name = "minify-js" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe033709f5a1159736cf7e22748518ffb75af26f3a6264d52ecc8bb38c68c36" +dependencies = [ + "lazy_static", + "parse-js", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -994,6 +1182,29 @@ dependencies = [ "tempfile", ] +[[package]] +name = "nom" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" +dependencies = [ + "memchr", + "version_check", +] + +[[package]] +name = "nom" +version = "6.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2" +dependencies = [ + "bitvec", + "funty", + "lexical-core", + "memchr", + "version_check", +] + [[package]] name = "nom" version = "7.1.1" @@ -1129,7 +1340,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12fc0523e3bd51a692c8850d075d74dc062ccf251c0110668cbd921917118a13" dependencies = [ "bitflags", - "cfg-if", + "cfg-if 1.0.0", "foreign-types", "libc", "once_cell", @@ -1167,6 +1378,29 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "parse-js" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66bb85ec60d22b9e6d4adac1e3dbdaf3903a4485f476c5f4dd7ed1285cbf4dad" +dependencies = [ + "aho-corasick", + "lazy_static", + "memchr", +] + +[[package]] +name = "paste" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + [[package]] name = "percent-encoding" version = "2.2.0" @@ -1314,6 +1548,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quote" version = "1.0.21" @@ -1323,6 +1563,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" + [[package]] name = "rand" version = "0.8.5" @@ -1436,6 +1682,255 @@ dependencies = [ "winreg", ] +[[package]] +name = "rust_icu" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e95a32c975f48a8ecdf2bae94b1af07e5183a6444bb1d7c7e5fa38fa4d9f4603" +dependencies = [ + "anyhow", + "log", + "paste", + "rust_icu_common", + "rust_icu_sys", + "rust_icu_ubrk", + "rust_icu_ucal", + "rust_icu_ucol", + "rust_icu_udat", + "rust_icu_udata", + "rust_icu_uenum", + "rust_icu_ulistformatter", + "rust_icu_uloc", + "rust_icu_umsg", + "rust_icu_unorm2", + "rust_icu_ustring", + "rust_icu_utext", + "rust_icu_utrans", + "thiserror", +] + +[[package]] +name = "rust_icu_common" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b08406df3a1168150c8bac41ce90691b8957a3f6759676f296e3e85caa840d82" +dependencies = [ + "anyhow", + "rust_icu_sys", + "thiserror", +] + +[[package]] +name = "rust_icu_sys" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "934d041adaf09531e60b8dd254087f3a80f1557e08d21a95640840f48bee4652" +dependencies = [ + "anyhow", + "bindgen", + "lazy_static", + "libc", + "paste", +] + +[[package]] +name = "rust_icu_ubrk" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c60f4a2c75313e2714774b401004b616b98d6bb8f09eeeb0f52f0086af9775eb" +dependencies = [ + "log", + "paste", + "rust_icu_common", + "rust_icu_sys", + "rust_icu_uloc", + "rust_icu_ustring", +] + +[[package]] +name = "rust_icu_ucal" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "272a6cb370222fe0be84e9ec2795cc139110f041a601fb899319ce64f38e18b2" +dependencies = [ + "log", + "paste", + "rust_icu_common", + "rust_icu_sys", + "rust_icu_uenum", + "rust_icu_ustring", +] + +[[package]] +name = "rust_icu_ucol" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "833a1734c1cfe0875f9bcdbdba0c8e4f4ee433da79ec54704783abac53bc23a5" +dependencies = [ + "anyhow", + "log", + "paste", + "rust_icu_common", + "rust_icu_sys", + "rust_icu_uenum", + "rust_icu_ustring", +] + +[[package]] +name = "rust_icu_udat" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c79fa5f32849682f5fa393078a63db401c131aa62d1d58d99b5b649b5c5036" +dependencies = [ + "anyhow", + "log", + "paste", + "rust_icu_common", + "rust_icu_sys", + "rust_icu_ucal", + "rust_icu_uenum", + "rust_icu_uloc", + "rust_icu_ustring", +] + +[[package]] +name = "rust_icu_udata" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fb44eddf05eb6c55ddce28c6406ba5d6dc1210b68fb957b2d770a361ade907f" +dependencies = [ + "log", + "paste", + "rust_icu_common", + "rust_icu_sys", +] + +[[package]] +name = "rust_icu_uenum" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f8256fd37fcf535e29d9a30444af0583c92e0b0b77aa4179fe7793c1aef84d4" +dependencies = [ + "paste", + "rust_icu_common", + "rust_icu_sys", +] + +[[package]] +name = "rust_icu_ulistformatter" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a67c4ad37d21b0768d3a080fb7a5c97f74596e4bdfbef98e814ae1efe2ed8727" +dependencies = [ + "anyhow", + "log", + "paste", + "rust_icu_common", + "rust_icu_sys", + "rust_icu_ustring", +] + +[[package]] +name = "rust_icu_uloc" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b8454315a4865f7686bcc59d0e738b91ab31ff539aa1cd436214025cc50cce3" +dependencies = [ + "anyhow", + "log", + "paste", + "rust_icu_common", + "rust_icu_sys", + "rust_icu_uenum", + "rust_icu_ustring", +] + +[[package]] +name = "rust_icu_umsg" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21e8565b0cc4e14804d91da0801e490d37c2c563cc810fdfb3ae9a0b0ff2d475" +dependencies = [ + "anyhow", + "log", + "paste", + "rust_icu_common", + "rust_icu_sys", + "rust_icu_uloc", + "rust_icu_ustring", + "thiserror", +] + +[[package]] +name = "rust_icu_unorm2" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be35db3f9bfc5dfadfd95e006af0641d06fd4b57b2524e20c99ada38a3d73506" +dependencies = [ + "anyhow", + "log", + "paste", + "rust_icu_common", + "rust_icu_sys", + "rust_icu_ucal", + "rust_icu_uenum", + "rust_icu_uloc", + "rust_icu_ustring", +] + +[[package]] +name = "rust_icu_ustring" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f32dd5e7d9ba4670d293c65c488b22f3989d6bcb5ade0ff6505bb8988ee185a" +dependencies = [ + "log", + "paste", + "rust_icu_common", + "rust_icu_sys", +] + +[[package]] +name = "rust_icu_utext" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c75f7beecd9c2dbc04ad1a23f6e9baefe151f32094a56a43effb432576b2b37" +dependencies = [ + "paste", + "rust_icu_common", + "rust_icu_sys", +] + +[[package]] +name = "rust_icu_utrans" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07dbb8292ceb650011c79f978603d3cafb6bd297df6f24b21c9ba212e98b5bc4" +dependencies = [ + "anyhow", + "log", + "paste", + "rust_icu_common", + "rust_icu_sys", + "rust_icu_uenum", + "rust_icu_ustring", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + [[package]] name = "rustversion" version = "1.0.9" @@ -1502,6 +1997,12 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" + [[package]] name = "serde" version = "1.0.145" @@ -1551,7 +2052,7 @@ version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cpufeatures", "digest", ] @@ -1562,6 +2063,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" +[[package]] +name = "shlex" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" + [[package]] name = "siphasher" version = "0.3.10" @@ -1587,6 +2094,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strsim" version = "0.8.0" @@ -1646,6 +2159,12 @@ dependencies = [ "yaml-rust", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "temp-dir" version = "0.1.11" @@ -1658,7 +2177,7 @@ version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "fastrand", "libc", "redox_syscall", @@ -1803,7 +2322,7 @@ version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "pin-project-lite", "tracing-core", ] @@ -1974,7 +2493,7 @@ version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "wasm-bindgen-macro", ] @@ -1999,7 +2518,7 @@ version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "js-sys", "wasm-bindgen", "web-sys", @@ -2044,6 +2563,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "which" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724" +dependencies = [ + "libc", +] + [[package]] name = "winapi" version = "0.3.9" @@ -2127,6 +2655,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "wyz" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" + [[package]] name = "xdg" version = "2.4.1" diff --git a/aussi/Cargo.toml b/aussi/Cargo.toml index 63dbf90..78b8a4e 100644 --- a/aussi/Cargo.toml +++ b/aussi/Cargo.toml @@ -13,8 +13,11 @@ dynfmt = { version = "0.1.5", features = ["curly"] } fs_extra = "1.2" gettext-rs = { version= "0.7", features = ["gettext-system"]} grass = "0.11" +indexmap = { version = "1.9", features = ["serde-1"] } log = "0.4" +minify-html = "0.10" once_cell = "1.12" reqwest = { version = "0.11", features = ["blocking", "json"] } +rust_icu = "2.0" serde = "1.0" serde_json = "1.0" diff --git a/aussi/src/data/app.rs b/aussi/src/data/app.rs index a72ad52..4b79736 100644 --- a/aussi/src/data/app.rs +++ b/aussi/src/data/app.rs @@ -1,5 +1,5 @@ +use indexmap::IndexMap; use serde::{Deserialize, Serialize}; -use std::collections::HashMap; use std::fs::File; use std::io::BufReader; use std::path::Path; @@ -47,7 +47,11 @@ pub struct App { impl App { pub fn stable_releases(&self) -> Vec { - self.releases.iter().filter(|x| x.kind == "stable").cloned().collect() + self.releases + .iter() + .filter(|x| x.kind == "stable") + .cloned() + .collect() } } @@ -71,7 +75,7 @@ impl From<&App> for BasicApp { } #[derive(Debug, Serialize, Deserialize)] -pub struct Apps(HashMap); +pub struct Apps(IndexMap); impl Apps { pub fn from_json_file>(path: P) -> Result> { @@ -92,9 +96,7 @@ impl Apps { let list: Vec = reqwest::blocking::get("https://apps.gnome.org/_api/apps.json")?.json()?; - let map: HashMap = - list.into_iter().map(|x| (x.id.to_string(), x)).collect(); - let apps = Self(map); + let apps = Self::from(list); std::fs::write(APPS_CACHE, serde_json::to_string(&apps)?)?; Ok(apps) @@ -106,16 +108,23 @@ impl Apps { } } -impl AsRef> for Apps { - fn as_ref(&self) -> &HashMap { +impl AsRef> for Apps { + fn as_ref(&self) -> &IndexMap { &self.0 } } impl std::ops::Deref for Apps { - type Target = HashMap; + type Target = IndexMap; - fn deref(&self) -> &HashMap { + fn deref(&self) -> &IndexMap { self.as_ref() } } + +impl From> for Apps { + fn from(apps: Vec) -> Self { + let map: IndexMap = apps.into_iter().map(|x| (x.id.to_string(), x)).collect(); + Self(map) + } +} diff --git a/aussi/src/filters.rs b/aussi/src/filters.rs index 3c0003d..4780f2d 100644 --- a/aussi/src/filters.rs +++ b/aussi/src/filters.rs @@ -5,10 +5,12 @@ use crate::{data, i18n}; /// Translate string pub fn t(s: &str) -> askama::Result { - i18n::TRANSLATABLE_STRINGS - .lock() - .unwrap() - .insert(s.to_string(), Default::default()); + i18n::add_string(s, Default::default()); + Ok(i18n::translate(s)) +} + +pub fn tc(s: &str, comment: &str) -> askama::Result { + i18n::add_string_with_comment(s, comment); Ok(i18n::translate(s)) } @@ -80,3 +82,19 @@ pub fn replace( ) -> askama::Result { Ok(s.as_ref().replace(from.as_ref(), to.as_ref())) } + +pub fn striptags(input: &str) -> askama::Result { + Ok(input + .chars() + .fold((String::new(), false), |(mut s, in_tag), c| { + if c == '>' { + (s, false) + } else if c == '<' || in_tag { + (s, true) + } else { + s.push(c); + (s, in_tag) + } + }) + .0) +} diff --git a/aussi/src/i18n.rs b/aussi/src/i18n.rs index 6869aa5..686ad33 100644 --- a/aussi/src/i18n.rs +++ b/aussi/src/i18n.rs @@ -1,11 +1,12 @@ +use indexmap::{IndexMap, IndexSet}; use once_cell::sync::Lazy; -use std::collections::{HashMap, HashSet}; use std::io::prelude::*; use std::path::{Path, PathBuf}; use std::sync::Mutex; -pub static TRANSLATABLE_STRINGS: Lazy>>> = - Lazy::new(|| Mutex::new(Default::default())); +pub static TRANSLATABLE_STRINGS: Lazy< + Mutex, IndexSet)>>, +> = Lazy::new(|| Mutex::new(Default::default())); #[derive(Default, Hash, Eq, PartialEq)] pub struct StringDetail { @@ -45,16 +46,27 @@ pub fn add_string(s: &str, detail: StringDetail) { .unwrap() .entry(s.to_string()) .or_default() + .0 .insert(detail); } +pub fn add_string_with_comment(s: &str, comment: &str) { + TRANSLATABLE_STRINGS + .lock() + .unwrap() + .entry(s.to_string()) + .or_default() + .1 + .insert(comment.to_string()); +} + pub fn write_pot_file(path: impl AsRef) -> std::io::Result<()> { let mut pot = String::new(); for (msgid, details) in TRANSLATABLE_STRINGS.lock().unwrap().iter() { let msgid_escaped = msgid.replace('\n', r"\n"); - for detail in details { + for detail in &details.0 { if let Some(path) = &detail.path { pot.push_str(&format!(r"#: {}", path.display())); if let Some(line) = detail.line { @@ -64,6 +76,10 @@ pub fn write_pot_file(path: impl AsRef) -> std::io::Result<()> { } } + for comment in &details.1 { + pot.push_str(&format!("#. Translators: {}\n", comment)); + } + pot.push_str(&format!(r#"msgid "{msgid_escaped}""#)); pot.push('\n'); pot.push_str(r#"msgstr """#); diff --git a/aussi/src/lib.rs b/aussi/src/lib.rs index abb2875..e948e02 100644 --- a/aussi/src/lib.rs +++ b/aussi/src/lib.rs @@ -4,6 +4,7 @@ pub mod i18n; pub mod markdown; pub mod output; pub mod site; +pub mod utils; pub use data::*; pub use site::Site; diff --git a/aussi/src/output.rs b/aussi/src/output.rs index a5eb076..3494d55 100644 --- a/aussi/src/output.rs +++ b/aussi/src/output.rs @@ -17,11 +17,26 @@ pub trait OutputSimple { impl Output for T { fn output_localized(&self, path: impl AsRef, lang: &str) { let content = self.render().unwrap(); - write_l10n(path, lang, content).unwrap(); + + if path.as_ref().extension().unwrap_or_default() == "html" { + let binary = + minify_html::minify(content.as_bytes(), &minify_html::Cfg::spec_compliant()); + write_l10n(path, lang, binary).unwrap(); + } else { + write_l10n(path, lang, content).unwrap(); + } } + fn output(&self, path: impl AsRef) { let content = self.render().unwrap(); - write(path, content).unwrap(); + + if path.as_ref().extension().unwrap_or_default() == "html" { + let binary = + minify_html::minify(content.as_bytes(), &minify_html::Cfg::spec_compliant()); + write(path, binary).unwrap(); + } else { + write(path, content).unwrap(); + } } } @@ -116,7 +131,7 @@ fn write_l10n( content: impl AsRef<[u8]>, ) -> Result<(), Box> { let mut tmp_path = PathBuf::from(TMP_DIR); - tmp_path.push(lang); + tmp_path.push(lang.replace("_", "-")); tmp_path.push(path); std::fs::create_dir_all(tmp_path.parent().unwrap())?; diff --git a/aussi/src/site.rs b/aussi/src/site.rs index 7af7940..46805b3 100644 --- a/aussi/src/site.rs +++ b/aussi/src/site.rs @@ -1,15 +1,19 @@ +use crate::utils; + pub struct Site { pub base_url: String, + pub absolute_base_url: String, pub lang_base_url: String, pub assets_url: String, pub document_language: String, + pub now_localized: String, } impl Site { pub fn new(lang: &str) -> Self { - let base_url = option_env!("BASE_URL") - .map(|x| x.to_string()) - .unwrap_or_default(); + let lang = lang.replace("_", "-"); + + let base_url = std::env::var("BASE_URL").unwrap_or_default(); let mut lang_base_url = base_url.clone(); @@ -25,11 +29,22 @@ impl Site { lang.to_string() }; + let now_localized = utils::localized_datetime( + &chrono::Utc::now(), + &utils::string_to_loc(&lang), + rust_icu::sys::UDateFormatStyle::UDAT_SHORT, + rust_icu::sys::UDateFormatStyle::UDAT_MEDIUM, + ); + + let absolute_base_url = std::env::var("ABSOLUTE_BASE_URL").unwrap_or_default(); + Self { base_url, lang_base_url, assets_url, document_language, + now_localized, + absolute_base_url, } } } diff --git a/aussi/src/utils.rs b/aussi/src/utils.rs new file mode 100644 index 0000000..be62342 --- /dev/null +++ b/aussi/src/utils.rs @@ -0,0 +1,24 @@ +use rust_icu::sys::*; + +pub fn localized_datetime( + datetime: &chrono::DateTime, + loc: &rust_icu::loc::ULoc, + time_format: UDateFormatStyle, + date_format: UDateFormatStyle, +) -> String { + rust_icu::dat::UDateFormat::new_with_styles( + time_format, + date_format, + loc, + &rust_icu::string::UChar::try_from("utc").unwrap(), + ) + .unwrap() + .format(datetime.timestamp_millis() as f64) + .unwrap() +} + +pub fn string_to_loc(lang: &str) -> rust_icu::loc::ULoc { + let lang = if lang.is_empty() { "en" } else { lang }; + + rust_icu::loc::ULoc::for_language_tag(&lang.replace('_', "-")).unwrap() +} diff --git a/meson.build b/meson.build deleted file mode 100644 index be31a2c..0000000 --- a/meson.build +++ /dev/null @@ -1,5 +0,0 @@ -project('apps-for-gnome') - -i18n = import ('i18n') - -subdir('website') \ No newline at end of file diff --git a/po/apps-for-gnome.pot b/po/apps-for-gnome.pot new file mode 100644 index 0000000..6a8a55d --- /dev/null +++ b/po/apps-for-gnome.pot @@ -0,0 +1,182 @@ +#. Translators: Page title and main heading +msgid "Apps for GNOME" +msgstr "" + +msgid "Discover the best Apps for GNOME" +msgstr "" + +#. Translators: Page subtitle +msgid "Discover the best applications in the GNOME ecosystem and learn how to get involved." +msgstr "" + +msgid "Overview" +msgstr "" + +#. Translators: Short for 'GNOME Core apps.' Navigation link to app section. +msgid "Core" +msgstr "" + +#. Translators: Short for 'GNOME Circle apps.' Navigation link to app section. +msgid "Circle" +msgstr "" + +#. Translators: Short for 'GNOME Development tools.' Navigation link to app section. +msgid "Development" +msgstr "" + +msgid "Switch Language" +msgstr "" + +#. Translators: Main page introductory text (markdown formatted) +msgid "Apps featured in this curated overview are all built with the GNOME philosophy in mind. They are easy to understand and simple to use, feature a consistent and polished design and provide a noticeable attention to details. Naturally, they are [free software](https://fsfe.org/freesoftware/) and have committed to being part of a [welcoming and friendly community](https://wiki.gnome.org/Foundation/CodeOfConduct). These apps will perfectly integrate with your [GNOME Desktop](https://www.gnome.org/)." +msgstr "" + +msgid "App supports mobile devices" +msgstr "" + +msgid "Apps supported on GNOME mobile devices are marked with the mobile icon." +msgstr "" + +#. Translators: App list section heading +msgid "Core Apps" +msgstr "" + +#. Translators: App list section text +msgid "GNOME Core apps cover ordinary tasks on the GNOME desktop. They are usually pre-installed on your GNOME system." +msgstr "" + +#. Translators: App list section heading +msgid "Circle Apps" +msgstr "" + +#. Translators: App list section text (markdown formatted) +msgid "GNOME Circle contains applications extending the GNOME ecosystem. It champions the great additional software that is available for the GNOME platform. [Learn more about GNOME Circle.](https://circle.gnome.org/)" +msgstr "" + +#. Translators: App list section heading +msgid "Development Tools" +msgstr "" + +#. Translators: App list section text +msgid "GNOME Development tools help develop and design new apps and make it easy to contribute to existing ones." +msgstr "" + +msgid "The GNOME Project" +msgstr "" + +msgid "Contact Us" +msgstr "" + +msgid "About Us" +msgstr "" + +msgid "Privacy" +msgstr "" + +msgid "This website is available in many languages" +msgstr "" + +msgid "Page Software" +msgstr "" + +msgid "© The “Apps for GNOME” contributors" +msgstr "" + +msgid "Page generated" +msgstr "" + +#. Translators: App details section headings +msgid "Get involved" +msgstr "" + +msgid "Give feedback" +msgstr "" + +msgid "Contribute your ideas or report issues on the apps issue tracker." +msgstr "" + +#. Translators: App details section headings +msgid "Explore the interface" +msgstr "" + +#. Translators: App details section heading +msgid "Get to know us" +msgstr "" + +msgid "Maintainer" +msgstr "" + +msgid "GitLab account" +msgstr "" + +#. Translators: App details section heading +msgid "More Information" +msgstr "" + +msgid "Project homepage" +msgstr "" + +msgid "Visit the dedicated homepage for this project." +msgstr "" + +#. Translators: This is a template string. You can move a pair of curly braces with the keyword in between around. But do not change or translate the keyword in between the braces. +msgid "Latest version { version_name } released on { date }." +msgstr "" + +msgid "Newest Release" +msgstr "" + +msgid "App specific content © The respective app contributors" +msgstr "" + +msgid "Releases" +msgstr "" + +msgid "Get the app" +msgstr "" + +msgid "Install the latest version from Flathub." +msgstr "" + +msgid "Donate money" +msgstr "" + +msgid "Learn how you can donate to the developers of this project." +msgstr "" + +msgid "Donate to the GNOME Foundation to support this project." +msgstr "" + +msgid "Help translating" +msgstr "" + +msgid "Help translate this app into your language." +msgstr "" + +msgid "Learn more" +msgstr "" + +msgid "Visit the online help page for this app." +msgstr "" + +msgid "GitHub account" +msgstr "" + +msgid "Twitter account" +msgstr "" + +msgid "Website" +msgstr "" + +msgid "Get in touch" +msgstr "" + +msgid "Just chat with the app's community or get help when you are stuck." +msgstr "" + +msgid "FAQ" +msgstr "" + +msgid "Find answers to the most frequently asked questions." +msgstr "" + diff --git a/website/.gitignore b/website/.gitignore index 3c6ad5a..9aa0d37 100644 --- a/website/.gitignore +++ b/website/.gitignore @@ -3,6 +3,7 @@ builddir/ flathub-installation/ non-flatpak/ out/ +install/ public.new/ public/ target/ diff --git a/website/Cargo.lock b/website/Cargo.lock index 4aadbd2..d3c4e93 100644 --- a/website/Cargo.lock +++ b/website/Cargo.lock @@ -184,9 +184,12 @@ dependencies = [ "fs_extra", "gettext-rs", "grass", + "indexmap", "log", + "minify-html", "once_cell", "reqwest", + "rust_icu", "serde", "serde_json", ] @@ -290,15 +293,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "bstr" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" -dependencies = [ - "memchr", -] - [[package]] name = "bumpalo" version = "3.11.0" @@ -375,28 +369,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "chrono-tz" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c39203181991a7dd4343b8005bd804e7a9a37afb8ac070e43771e8c820bbde" -dependencies = [ - "chrono", - "chrono-tz-build", - "phf 0.11.1", -] - -[[package]] -name = "chrono-tz-build" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f509c3a87b33437b05e2458750a0700e5bdd6956176773e6c7d6dd15a283a0c" -dependencies = [ - "parse-zoneinfo", - "phf 0.11.1", - "phf_codegen", -] - [[package]] name = "clang-sys" version = "0.29.3" @@ -536,15 +508,6 @@ dependencies = [ "cfg-if 1.0.0", ] -[[package]] -name = "crossbeam-utils" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac" -dependencies = [ - "cfg-if 1.0.0", -] - [[package]] name = "crypto-common" version = "0.1.6" @@ -698,12 +661,6 @@ dependencies = [ "syn", ] -[[package]] -name = "deunicode" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "850878694b7933ca4c9569d30a34b55031b9b139ee1fc7b94a527c4ef960d690" - [[package]] name = "digest" version = "0.10.5" @@ -1181,30 +1138,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" -[[package]] -name = "globset" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" -dependencies = [ - "aho-corasick", - "bstr", - "fnv", - "log", - "regex", -] - -[[package]] -name = "globwalk" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" -dependencies = [ - "bitflags", - "ignore", - "walkdir", -] - [[package]] name = "gobject-sys" version = "0.15.10" @@ -1493,24 +1426,6 @@ dependencies = [ "unicode-normalization", ] -[[package]] -name = "ignore" -version = "0.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d" -dependencies = [ - "crossbeam-utils", - "globset", - "lazy_static", - "log", - "memchr", - "regex", - "same-file", - "thread_local", - "walkdir", - "winapi-util", -] - [[package]] name = "indexmap" version = "1.9.1" @@ -1519,6 +1434,7 @@ checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", "hashbrown 0.12.3", + "serde", ] [[package]] @@ -1735,9 +1651,10 @@ dependencies = [ [[package]] name = "malamute" -version = "0.1.0" +version = "0.2.0" dependencies = [ "appstream", + "askama", "aussi", "chrono", "dominant_color", @@ -1754,23 +1671,19 @@ dependencies = [ "lazy_static", "libflatpak", "log", - "minify-html", "once_cell", "palette", "paste", "pretty_env_logger", - "rctree 0.5.0", "reqwest", "resvg", "rust_icu", - "sass-rs", "serde", "serde-xml-rs", "serde_json", "serde_yaml", "structopt", "svgcleaner", - "tera", "tiny-skia", "tokio", "tokio-util", @@ -1872,7 +1785,7 @@ dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "windows-sys 0.36.1", ] [[package]] @@ -2147,15 +2060,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" dependencies = [ "cfg-if 1.0.0", "libc", "redox_syscall", "smallvec", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -2169,15 +2082,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "parse-zoneinfo" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c705f256449c60da65e11ff6626e0c16a0a0b96aaa348de61376b249bc340f41" -dependencies = [ - "regex", -] - [[package]] name = "paste" version = "1.0.9" @@ -2270,16 +2174,6 @@ dependencies = [ "phf_shared 0.11.1", ] -[[package]] -name = "phf_codegen" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56ac890c5e3ca598bbdeaa99964edb5b0258a583a9eb6ef4e89fc85d9224770" -dependencies = [ - "phf_generator 0.11.1", - "phf_shared 0.11.1", -] - [[package]] name = "phf_generator" version = "0.9.1" @@ -2352,7 +2246,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" dependencies = [ "siphasher 0.3.10", - "uncased", ] [[package]] @@ -2528,12 +2421,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ae028b272a6e99d9f8260ceefa3caa09300a8d6c8d2b2001316474bc52122e9" -[[package]] -name = "rctree" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b42e27ef78c35d3998403c1d26f3efd9e135d3e5121b0a4845cc5cc27547f4f" - [[package]] name = "redox_syscall" version = "0.2.16" @@ -2671,7 +2558,7 @@ version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "921904a62e410e37e215c40381b7117f830d9d89ba60ab5236170541dd25646b" dependencies = [ - "xmlparser 0.13.3", + "xmlparser 0.13.5", ] [[package]] @@ -2925,9 +2812,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.20.6" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033" +checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c" dependencies = [ "log", "ring", @@ -2996,28 +2883,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "sass-rs" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cabcf7c6e55053f359911187ac401409aad2dc14338cae972dec266fee486abd" -dependencies = [ - "libc", - "sass-sys", -] - -[[package]] -name = "sass-sys" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "933bca23b402377f0ab71e79732a826deffc748013746ac3314f6abc7f9fc51c" -dependencies = [ - "cc", - "libc", - "num_cpus", - "pkg-config", -] - [[package]] name = "schannel" version = "0.1.20" @@ -3025,7 +2890,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" dependencies = [ "lazy_static", - "windows-sys", + "windows-sys 0.36.1", ] [[package]] @@ -3215,15 +3080,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "slug" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373" -dependencies = [ - "deunicode", -] - [[package]] name = "smallvec" version = "1.10.0" @@ -3437,28 +3293,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "tera" -version = "1.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3df578c295f9ec044ff1c829daf31bb7581d5b3c2a7a3d87419afe1f2531438c" -dependencies = [ - "chrono", - "chrono-tz", - "globwalk", - "humansize", - "lazy_static", - "percent-encoding", - "pest", - "pest_derive", - "rand", - "regex", - "serde", - "serde_json", - "slug", - "unic-segment", -] - [[package]] name = "termcolor" version = "1.1.3" @@ -3497,15 +3331,6 @@ dependencies = [ "syn", ] -[[package]] -name = "thread_local" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" -dependencies = [ - "once_cell", -] - [[package]] name = "time" version = "0.1.44" @@ -3702,71 +3527,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" -[[package]] -name = "uncased" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b01702b0fd0b3fadcf98e098780badda8742d4f4a7676615cad90e8ac73622" -dependencies = [ - "version_check", -] - [[package]] name = "unchecked-index" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eeba86d422ce181a719445e51872fa30f1f7413b62becb52e95ec91aa262d85c" -[[package]] -name = "unic-char-property" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" -dependencies = [ - "unic-char-range", -] - -[[package]] -name = "unic-char-range" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" - -[[package]] -name = "unic-common" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" - -[[package]] -name = "unic-segment" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ed5d26be57f84f176157270c112ef57b86debac9cd21daaabbe56db0f88f23" -dependencies = [ - "unic-ucd-segment", -] - -[[package]] -name = "unic-ucd-segment" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2079c122a62205b421f499da10f3ee0f7697f012f55b675e002483c73ea34700" -dependencies = [ - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] - -[[package]] -name = "unic-ucd-version" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" -dependencies = [ - "unic-common", -] - [[package]] name = "unicase" version = "2.6.0" @@ -3892,7 +3658,7 @@ dependencies = [ "kurbo", "log", "pico-args", - "rctree 0.4.0", + "rctree", "roxmltree", "rustybuzz", "simplecss 0.2.1", @@ -4115,43 +3881,100 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" dependencies = [ - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_msvc", + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", ] +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc 0.42.0", + "windows_i686_gnu 0.42.0", + "windows_i686_msvc 0.42.0", + "windows_x86_64_gnu 0.42.0", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc 0.42.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" + [[package]] name = "windows_aarch64_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" + [[package]] name = "windows_i686_gnu" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" +[[package]] +name = "windows_i686_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" + [[package]] name = "windows_i686_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" +[[package]] +name = "windows_i686_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" + [[package]] name = "windows_x86_64_gnu" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" + [[package]] name = "windows_x86_64_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" + [[package]] name = "winreg" version = "0.10.1" @@ -4194,9 +4017,9 @@ dependencies = [ [[package]] name = "xmlparser" -version = "0.13.3" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "114ba2b24d2167ef6d67d7d04c8cc86522b87f490025f39f0303b7db5bf5e3d8" +checksum = "4d25c75bf9ea12c4040a97f829154768bbbce366287e2dc044af160cd79a13fd" [[package]] name = "xmltree" diff --git a/website/Cargo.toml b/website/Cargo.toml index 67f5d30..ad393eb 100644 --- a/website/Cargo.toml +++ b/website/Cargo.toml @@ -1,7 +1,8 @@ [package] name = "malamute" -version = "0.1.0" +version = "0.2.0" edition = "2021" +resolver = "1" [profile.dev.package.tiny-skia] opt-level = 3 @@ -10,6 +11,7 @@ opt-level = 3 opt-level = 3 [dependencies] +askama = { version = "0.11.1", features = ["markdown"] } aussi = { version = "*", path = "../aussi" } appstream = "0.2.2" chrono = { version = "0.4", features = ["serde"] } @@ -27,23 +29,19 @@ itertools = "0.10" lazy-regex = "2.2" lazy_static = "1.4" log = "0.4" -minify-html = "0.10" once_cell = "1.3" palette = "0.6.1" paste = "1.0" pretty_env_logger = "0.4" -rctree = "0.5" reqwest = { version = "0.11", features = ["json", "stream"] } resvg = "0.23" rust_icu = "2.0" -sass-rs = "0.2" serde = "1.0" serde-xml-rs = "0.6" serde_json = "1.0" serde_yaml = "0.9" structopt = "0.3" svgcleaner = "0.9" -tera = "1.15" tiny-skia = "0.6" tokio = { version = "1", features = ["full"] } tokio-util = { version = "0.7", features = ["full"] } diff --git a/website/extract_gettext.py b/website/extract_gettext.py deleted file mode 100755 index 34cc4b1..0000000 --- a/website/extract_gettext.py +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/env python3 - -import glob -import re -from itertools import chain - -pattern1 = re.compile(r"str\['(.*?)'\]") -pattern2 = re.compile(r'str\["(.*?)"\]') - -comment_pattern = re.compile(r'{#\s+(Translators:.*)\s+#}') - -strings = {} - -for file in glob.iglob("templates/**/*.html", recursive=True): - last_line = "" - for line in open(file): - comment_match = re.search(comment_pattern, last_line) - if comment_match is not None: - comment = comment_match[1] - else: - comment = "" - - for match in chain(re.finditer(pattern1, line), re.finditer(pattern2, line)): - string = match[1] - if not strings.get(string, ""): - strings[string] = comment - - last_line = line - -with open("src/gettext_strings.rs", "w") as f: - f.write('pub fn strings() -> Vec<(&\'static str, String)> {\n'); - f.write(' vec![\n') - for s, c in strings.items(): - f.write(f' (\n') - f.write(f' r###"{ s }"###,\n') - if c: - f.write(f' // { c }\n') - f.write(f' gettextrs::gettext(r###"{ s }"###),\n') - f.write(f' ),\n') - f.write(' ]\n') - f.write('}\n') - -print(f"Wrote { len(strings) } strings.") diff --git a/website/meson.build b/website/meson.build index 219cff3..0000d26 100644 --- a/website/meson.build +++ b/website/meson.build @@ -1 +1,6 @@ +project('apps-for-gnome', default_options: ['prefix=' + meson.current_source_dir() + '/install']) + +i18n = import ('i18n') + subdir('po') + \ No newline at end of file diff --git a/website/src/cli.rs b/website/src/cli.rs index 165f1d3..2df88e5 100644 --- a/website/src/cli.rs +++ b/website/src/cli.rs @@ -12,6 +12,10 @@ pub struct Opt { #[structopt(long)] pub gitlab_token: Option>, #[structopt(long)] + pub no_images: bool, + #[structopt(long)] + pub no_log_warn: bool, + #[structopt(long)] pub no_stats: bool, } diff --git a/website/src/collect.rs b/website/src/collect.rs index ffd0548..5f52a43 100644 --- a/website/src/collect.rs +++ b/website/src/collect.rs @@ -112,18 +112,18 @@ impl App { None } } - - pub fn background_color(&self) {} } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Language { - pub name: String, - pub description: String, + #[serde(rename = "name")] + pub tag: String, + #[serde(rename = "description")] + pub local_name: String, } impl Language { pub fn ietf(&self) -> String { - self.name.replace('_', "-") + self.tag.replace('_', "-") } } diff --git a/website/src/context.rs b/website/src/context.rs index e633ae7..382bdb3 100644 --- a/website/src/context.rs +++ b/website/src/context.rs @@ -1,5 +1,4 @@ use super::collect::*; -use crate::utils; use appstream::AppId; use serde::{Deserialize, Serialize}; use std::convert::TryFrom; @@ -192,9 +191,14 @@ impl Out for appstream::Release { fn out(&self, lang: &str) -> ReleaseOut { let lang = if lang.is_empty() { "en" } else { lang }; - let loc = utils::string_to_loc(lang); + let loc = aussi::utils::string_to_loc(lang); let date_fmt = |date: chrono::DateTime, fmt| { - utils::localized_datetime(&date, &loc, rust_icu::sys::UDateFormatStyle::UDAT_NONE, fmt) + aussi::utils::localized_datetime( + &date, + &loc, + rust_icu::sys::UDateFormatStyle::UDAT_NONE, + fmt, + ) }; ReleaseOut { diff --git a/website/src/error.rs b/website/src/error.rs index 5fbab96..94ffb56 100644 --- a/website/src/error.rs +++ b/website/src/error.rs @@ -38,14 +38,6 @@ macro_rules! timed_info { }) } -pub fn timed_info(msg: &str) { - if let Some(x) = *TIMED.lock().unwrap() { - info!("Completed in {} ms", x.elapsed().as_millis()); - } - *TIMED.lock().unwrap() = Some(std::time::Instant::now()); - info!("{}", msg); -} - pub trait LogError { fn warn(self, context: C) -> Self where diff --git a/website/src/filters.rs b/website/src/filters.rs new file mode 100644 index 0000000..15e0f73 --- /dev/null +++ b/website/src/filters.rs @@ -0,0 +1,2 @@ +//! Filters available in templates +pub use aussi::filters::*; diff --git a/website/src/flathub.rs b/website/src/flathub.rs index fffbd8d..949a1f8 100644 --- a/website/src/flathub.rs +++ b/website/src/flathub.rs @@ -12,7 +12,7 @@ pub async fn exists(app_id: &AppId) -> bool { .is_success(); if !exists { - info!("App not on flathub: {}", app_id.to_string()); + debug!("App not on flathub: {}", app_id.to_string()); } exists @@ -110,6 +110,7 @@ impl Arches { total } + #[allow(dead_code)] pub fn updates(&self) -> u64 { self.total().updates() } @@ -136,6 +137,7 @@ impl std::ops::Add for Arches { pub struct Point(u64, u64); impl Point { + #[allow(dead_code)] pub fn updates(&self) -> u64 { self.1 } diff --git a/website/src/generate.rs b/website/src/generate.rs index bd3593a..bcd03c2 100644 --- a/website/src/generate.rs +++ b/website/src/generate.rs @@ -1,31 +1,26 @@ mod card_icons; +mod pages; mod redirects; mod screenshots; mod sitemap; use crate::collect::*; use crate::context::*; - -use crate::{cli, config, flathub, l10n, lists, output, svg, utils}; +use crate::{cli, flathub, lists, output, svg}; use appstream::AppId; +use aussi::output::Output; use aussi::output::{Dir, File, OutputSimple, Scss}; -use rust_icu::sys::UDateFormatStyle; use std::sync::Arc; -use tera::Tera; use flatpak::prelude::*; use gio::prelude::*; -use std::io::prelude::*; use crate::{log_warn, timed_info}; -lazy_static! { - pub static ref TEMPLATES: Tera = Tera::new("templates/**/*").unwrap(); -} - pub async fn generate() -> Result<(), Box> { - let _ignore = std::fs::remove_dir_all("public.new"); + aussi::i18n::init("apps-for-gnome"); + aussi::output::prepare(); let opt = Arc::new(cli::args()); @@ -201,133 +196,52 @@ pub async fn generate() -> Result<(), Box> { } timed_info!("Preparing languages"); - let mut tasks = Vec::new(); - let mut languages = if opt.dev { - vec![ - Language { - name: "de".to_string(), - description: "German".to_string(), - }, - Language { - name: "ar".to_string(), - description: "Arabic".to_string(), - }, - Language { - name: "en_GB".to_string(), - description: "British".to_string(), - }, - ] - } else { - lists::dl_languages().await? - }; - - // remove unused languages - debug!("Languages available in d-l: {}", languages.len()); - languages.retain(|lang| { - apps.iter() - .any(|app| app.appstream.name.get_for_locale(&lang.name).is_some() || lang.name == "en") - }); - debug!("Languages kept as active: {}", languages.len()); + let mut languages = lists::dl_languages().await?; - timed_info!("Generating pages"); - let datetime = chrono::Utc::now(); - for lang in languages.iter().map(|x| &x.name).chain([&String::new()]) { - debug!("Language: {}", lang); - debug!("Generating index page"); - let app_outs: Vec = apps.out(lang); - - let mut context = tera::Context::from_serialize(&MyContext { apps: app_outs })?; - context.insert("base", "."); - context.insert("lang", lang); - context.insert("languages", &languages); - context.insert("str", &l10n::strings(lang)); - context.insert("logical_url", ""); - context.insert("absolute_base_url", config::ABSOLUTE_BASE_URL); - context.insert( - "generated_datetime", - &utils::localized_datetime( - &datetime, - &utils::string_to_loc(lang), - UDateFormatStyle::UDAT_SHORT, - UDateFormatStyle::UDAT_MEDIUM, - ), - ); - - let mut buffer = Vec::new(); - TEMPLATES.render_to("overview.html", &context, &mut buffer)?; - write_html("index.html", &mut buffer, lang)?; - - debug!("Generating app pages"); - for app in &apps { - debug!("App: {:?}", app.id); - let mut app_context = context.clone(); - app_context.insert("app_id", &app.id.to_string()); - app_context.insert("base", "../.."); - let app_id = app.id.to_string(); - let lang = lang.clone(); - - tasks.push(tokio::task::spawn(async move { - let url = format!("app/{}/", app_id); - app_context.insert("logical_url", &url); - let mut buffer = Vec::new(); - TEMPLATES - .render_to("app.html", &app_context, &mut buffer) - .unwrap(); - write_html(&format!("{}index.html", url), &mut buffer, &lang).unwrap(); - - let url = format!("app/{}/releases.html", app_id); - app_context.insert("logical_url", &url); - let mut buffer = Vec::new(); - TEMPLATES - .render_to("releases.html", &app_context, &mut buffer) - .unwrap(); - write_html(&url, &mut buffer, &lang).unwrap(); - })); - } + if opt.dev { + languages.retain(|lang| ["de", "he", "en_GB"].contains(&lang.tag.as_str())); } - for task in tasks { - task.await.unwrap(); + timed_info!("Generating pages"); + for lang in languages.iter().map(|x| &x.tag).chain([&String::new()]) { + let apps = aussi::Apps::from(apps.out(lang)); + pages::generate(&apps, lang); } timed_info!("Language selector"); - - let mut context = tera::Context::new(); - context.insert("base", ".."); - context.insert("lang", ""); - context.insert("languages", &languages); - context.insert("str", &l10n::strings("")); - context.insert("logical_url", ""); - - let result = TEMPLATES.render("languages.html", &context)?; - write_site("languages/index.html", &result, "")?; - - timed_info!("Generating 404 error page ..."); - - context.insert("base", config::ABSOLUTE_BASE_URL); - let result = TEMPLATES.render("404.html", &context)?; - write_site("404.html", &result, "")?; + crate::pages::Languages { + site: &aussi::Site::new(""), + languages: &languages, + } + .output("languages/index.html"); timed_info!("Generate language js"); - let mut context = tera::Context::new(); - context.insert( - "languages_json", - &serde_json::to_string(&languages.iter().map(|x| x.ietf()).collect::>())?, - ); - let result = TEMPLATES.render("script.js", &context)?; - write_site("assets/script.js", &result, "")?; - - timed_info!("Generating card icons"); - card_icons::generate(&apps).unwrap(); + crate::pages::Script { + languages_json: serde_json::to_string( + &languages.iter().map(|x| x.ietf()).collect::>(), + )?, + } + .output("assets/script.js"); - timed_info!("Copying screenshots"); - screenshots::generate(&apps).await; + timed_info!("Generating 404 error page ..."); + crate::pages::Error404 { + site: &aussi::Site::new(""), + } + .output("404.html"); timed_info!("Copying assets"); Dir::from("assets/").output("assets/"); File::from("data/google7ed0380f213cfb6e.html").output("google7ed0380f213cfb6e.html"); File::from("data/robots.txt").output("robots.txt"); + if !opt.no_images { + timed_info!("Generating card icons"); + card_icons::generate(&apps).unwrap(); + + timed_info!("Copying screenshots"); + screenshots::generate(&apps).await; + } + timed_info!("Compiling sass"); Scss::from("scss/style.scss").output("assets/style.css"); @@ -340,9 +254,11 @@ pub async fn generate() -> Result<(), Box> { timed_info!("Generating json api"); output::json::generate(&apps).await?; - timed_info!("Copying finalized data"); + timed_info!("Moving finalized data"); aussi::output::complete().unwrap(); + aussi::i18n::write_pot_file("po/apps-for-gnome.pot").unwrap(); + timed_info!("Page generation completed"); Ok(()) } @@ -376,28 +292,3 @@ pub async fn new_file_tokio>( Ok(file) } - -fn write_site(path: &str, content: &str, lang: &str) -> Result<(), Box> { - let mut full_path = std::path::PathBuf::new(); - if !lang.is_empty() { - full_path.push(lang.replace('_', "-")); - } - full_path.push(path); - - let mut file = new_file(&full_path)?; - file.write_all(content.as_bytes())?; - - Ok(()) -} - -fn write_html( - path: &str, - content: &mut [u8], - lang: &str, -) -> Result<(), Box> { - let result = minify_html::minify(content, &minify_html::Cfg::spec_compliant()); - - write_site(path, std::str::from_utf8(&result)?, lang)?; - - Ok(()) -} diff --git a/website/src/generate/pages.rs b/website/src/generate/pages.rs new file mode 100644 index 0000000..cb649cb --- /dev/null +++ b/website/src/generate/pages.rs @@ -0,0 +1,29 @@ +use crate::pages; +use aussi::{i18n, output::Output, Apps, Site}; + +pub fn generate(apps: &Apps, lang: &str) { + i18n::set_lang(lang); + + let site = Site::new(lang); + + let index = pages::Overview { + site: &site, + apps: &apps, + }; + index.output_localized("index.html", lang); + + for app in apps.values() { + debug!("App ({lang}): {}", app.id); + let app_page = pages::App { + site: &site, + app: &app, + }; + app_page.output_localized(format!("app/{}/index.html", app.id), lang); + + let releases_page = pages::Releases { + site: &site, + app: &app, + }; + releases_page.output_localized(format!("app/{}/releases.html", app.id), lang); + } +} diff --git a/website/src/gettext_strings.rs b/website/src/gettext_strings.rs deleted file mode 100644 index cba8ab6..0000000 --- a/website/src/gettext_strings.rs +++ /dev/null @@ -1,270 +0,0 @@ -pub fn strings() -> Vec<(&'static str, String)> { - vec![ - ( - r###"Apps for GNOME"###, - // Translators: Page title and main heading - gettextrs::gettext(r###"Apps for GNOME"###), - ), - ( - r###"Discover the best Apps for GNOME"###, - gettextrs::gettext(r###"Discover the best Apps for GNOME"###), - ), - ( - r###"Discover the best applications in the GNOME ecosystem and learn how to get involved."###, - // Translators: Page subtitle - gettextrs::gettext( - r###"Discover the best applications in the GNOME ecosystem and learn how to get involved."###, - ), - ), - (r###"Overview"###, gettextrs::gettext(r###"Overview"###)), - ( - r###"Core"###, - // Translators: Short for "GNOME Core apps." Navigation link to app section. - gettextrs::gettext(r###"Core"###), - ), - ( - r###"Circle"###, - // Translators: Short for "GNOME Circle apps." Navigation link to app section. - gettextrs::gettext(r###"Circle"###), - ), - ( - r###"Development"###, - // Translators: Short for "GNOME Development tools." Navigation link to app section. - gettextrs::gettext(r###"Development"###), - ), - ( - r###"Switch Language"###, - gettextrs::gettext(r###"Switch Language"###), - ), - ( - r###"Apps featured in this curated overview are all built with the GNOME philosophy in mind. They are easy to understand and simple to use, feature a consistent and polished design and provide a noticeable attention to details. Naturally, they are free software and have committed to being part of a welcoming and friendly community. These apps will perfectly integrate with your GNOME Desktop."###, - // Translators: Main page introductiory text - gettextrs::gettext( - r###"Apps featured in this curated overview are all built with the GNOME philosophy in mind. They are easy to understand and simple to use, feature a consistent and polished design and provide a noticeable attention to details. Naturally, they are free software and have committed to being part of a welcoming and friendly community. These apps will perfectly integrate with your GNOME Desktop."###, - ), - ), - ( - r###"App supports mobile devices"###, - gettextrs::gettext(r###"App supports mobile devices"###), - ), - ( - r###"Apps supported on GNOME mobile devices are marked with the mobile icon."###, - gettextrs::gettext( - r###"Apps supported on GNOME mobile devices are marked with the mobile icon."###, - ), - ), - ( - r###"Core Apps"###, - // Translators: App list section heading - gettextrs::gettext(r###"Core Apps"###), - ), - ( - r###"GNOME Core apps cover ordinary tasks on the GNOME desktop. They are usually pre-installed on your GNOME system."###, - // Translators: App list section text - gettextrs::gettext( - r###"GNOME Core apps cover ordinary tasks on the GNOME desktop. They are usually pre-installed on your GNOME system."###, - ), - ), - ( - r###"Circle Apps"###, - // Translators: App list section heading - gettextrs::gettext(r###"Circle Apps"###), - ), - ( - r###"GNOME Circle contains applications extending the GNOME ecosystem. It champions the great additional software that is available for the GNOME platform. Learn more about GNOME Circle."###, - // Translators: App list section text - gettextrs::gettext( - r###"GNOME Circle contains applications extending the GNOME ecosystem. It champions the great additional software that is available for the GNOME platform. Learn more about GNOME Circle."###, - ), - ), - ( - r###"Development Tools"###, - // Translators: App list section heading - gettextrs::gettext(r###"Development Tools"###), - ), - ( - r###"GNOME Development tools help develop and design new apps and make it easy to contribute to existing ones."###, - // Translators: App list section text - gettextrs::gettext( - r###"GNOME Development tools help develop and design new apps and make it easy to contribute to existing ones."###, - ), - ), - ( - r###"Donate money"###, - gettextrs::gettext(r###"Donate money"###), - ), - ( - r###"Donate to the GNOME Foundation to support this project."###, - gettextrs::gettext(r###"Donate to the GNOME Foundation to support this project."###), - ), - ( - r###"Learn how you can donate to the developers of this project."###, - gettextrs::gettext( - r###"Learn how you can donate to the developers of this project."###, - ), - ), - ( - r###"Give feedback"###, - gettextrs::gettext(r###"Give feedback"###), - ), - ( - r###"Contribute your ideas or report issues on the apps issue tracker."###, - gettextrs::gettext( - r###"Contribute your ideas or report issues on the apps issue tracker."###, - ), - ), - (r###"Learn more"###, gettextrs::gettext(r###"Learn more"###)), - ( - r###"Visit the online help page for this app."###, - gettextrs::gettext(r###"Visit the online help page for this app."###), - ), - ( - r###"Project homepage"###, - gettextrs::gettext(r###"Project homepage"###), - ), - ( - r###"Visit the dedicated homepage for this project."###, - gettextrs::gettext(r###"Visit the dedicated homepage for this project."###), - ), - ( - r###"Help translating"###, - gettextrs::gettext(r###"Help translating"###), - ), - ( - r###"Help translate this app into your language."###, - gettextrs::gettext(r###"Help translate this app into your language."###), - ), - (r###"FAQ"###, gettextrs::gettext(r###"FAQ"###)), - ( - r###"Find answers to the most frequently asked questions."###, - gettextrs::gettext(r###"Find answers to the most frequently asked questions."###), - ), - ( - r###"Get in touch"###, - gettextrs::gettext(r###"Get in touch"###), - ), - ( - r###"Just chat with the app's community or get help when you are stuck."###, - gettextrs::gettext( - r###"Just chat with the app's community or get help when you are stuck."###, - ), - ), - ( - r###"Learn how you can contact the project."###, - gettextrs::gettext(r###"Learn how you can contact the project."###), - ), - ( - r###"The GNOME Project"###, - gettextrs::gettext(r###"The GNOME Project"###), - ), - (r###"Contact Us"###, gettextrs::gettext(r###"Contact Us"###)), - (r###"About Us"###, gettextrs::gettext(r###"About Us"###)), - (r###"Privacy"###, gettextrs::gettext(r###"Privacy"###)), - ( - r###"This website is available in many languages"###, - gettextrs::gettext(r###"This website is available in many languages"###), - ), - ( - r###"Page Software"###, - gettextrs::gettext(r###"Page Software"###), - ), - ( - r###"© The “Apps for GNOME” contributors"###, - gettextrs::gettext(r###"© The “Apps for GNOME” contributors"###), - ), - ( - r###"Page generated"###, - gettextrs::gettext(r###"Page generated"###), - ), - (r###"Releases"###, gettextrs::gettext(r###"Releases"###)), - ( - r###"Get involved"###, - // Translators: App details section headings - gettextrs::gettext(r###"Get involved"###), - ), - ( - r###"Get the app"###, - gettextrs::gettext(r###"Get the app"###), - ), - ( - r###"Install the latest version from Flathub."###, - gettextrs::gettext(r###"Install the latest version from Flathub."###), - ), - ( - r###"Explore the interface"###, - // Translators: App details section headings - gettextrs::gettext(r###"Explore the interface"###), - ), - ( - r###"Get to know us"###, - // Translators: App details section heading - gettextrs::gettext(r###"Get to know us"###), - ), - (r###"Maintainer"###, gettextrs::gettext(r###"Maintainer"###)), - ( - r###"GitHub account"###, - gettextrs::gettext(r###"GitHub account"###), - ), - ( - r###"GitLab account"###, - gettextrs::gettext(r###"GitLab account"###), - ), - ( - r###"Twitter account"###, - gettextrs::gettext(r###"Twitter account"###), - ), - (r###"Website"###, gettextrs::gettext(r###"Website"###)), - ( - r###"More Information"###, - // Translators: App details section heading - gettextrs::gettext(r###"More Information"###), - ), - ( - r###"Latest version { version_name } released on { date }."###, - // Translators: This is a template string. You can move a pair of curly braces with the keyword in between around. But do not change or translate the keyword in between the braces. - gettextrs::gettext(r###"Latest version { version_name } released on { date }."###), - ), - ( - r###"Newest Release"###, - gettextrs::gettext(r###"Newest Release"###), - ), - ( - r###"App is translated"###, - gettextrs::gettext(r###"App is translated"###), - ), - ( - r###"This app is available in your language."###, - gettextrs::gettext(r###"This app is available in your language."###), - ), - ( - r###"Partially translated"###, - gettextrs::gettext(r###"Partially translated"###), - ), - ( - r###"Some parts of this app are available in your language."###, - gettextrs::gettext(r###"Some parts of this app are available in your language."###), - ), - ( - r###"Sparsely translated"###, - gettextrs::gettext(r###"Sparsely translated"###), - ), - ( - r###"Only a small part of this app is available in your language."###, - gettextrs::gettext( - r###"Only a small part of this app is available in your language."###, - ), - ), - ( - r###"Not translated"###, - gettextrs::gettext(r###"Not translated"###), - ), - ( - r###"This app is not available in your language."###, - gettextrs::gettext(r###"This app is not available in your language."###), - ), - ( - r###"App specific content © The respective app contributors"###, - gettextrs::gettext(r###"App specific content © The respective app contributors"###), - ), - ] -} diff --git a/website/src/l10n.rs b/website/src/l10n.rs deleted file mode 100644 index ddd9ba3..0000000 --- a/website/src/l10n.rs +++ /dev/null @@ -1,19 +0,0 @@ -use std::collections::HashMap; - -pub fn strings(lang: &str) -> HashMap { - // We have to set this to something to keep gettext happy - std::env::set_var("LANG", "en_US.utf-8"); - std::env::set_var("LANGUAGE", lang); - gettextrs::setlocale(gettextrs::LocaleCategory::LcAll, ""); - - gettextrs::bindtextdomain("apps-for-gnome", "out/share/locale").unwrap(); - gettextrs::textdomain("apps-for-gnome").unwrap(); - gettextrs::bind_textdomain_codeset("apps-for-gnome", "UTF-8").unwrap(); - - let strings = super::gettext_strings::strings(); - - strings - .into_iter() - .map(|(k, v)| (k.to_string(), v)) - .collect() -} diff --git a/website/src/lib.rs b/website/src/lib.rs index 38503aa..58e16f7 100644 --- a/website/src/lib.rs +++ b/website/src/lib.rs @@ -8,24 +8,24 @@ extern crate lazy_regex; #[macro_use] extern crate log; -pub mod cli; -pub mod collect; -pub mod config; -pub mod context; -pub mod damned_lies; -pub mod doap; -pub mod error; -pub mod flathub; -pub mod generate; -pub mod gettext_strings; -pub mod git; -pub mod gnomeid; -pub mod l10n; -pub mod lists; -pub mod output; -pub mod sitemap; -pub mod svg; -pub mod utils; +mod cli; +mod collect; +mod config; +mod context; +mod damned_lies; +mod doap; +mod error; +mod filters; +mod flathub; +mod generate; +mod git; +mod gnomeid; +mod lists; +mod output; +mod pages; +mod sitemap; +mod svg; +mod utils; pub fn main() -> Result<(), Box> { once_cell::sync::Lazy::force(&lists::LDAP_TO_GITLAB); diff --git a/website/src/lists.rs b/website/src/lists.rs index e972051..63cb210 100644 --- a/website/src/lists.rs +++ b/website/src/lists.rs @@ -25,32 +25,27 @@ pub async fn dl_languages() -> Result, reqwest::Error> { let mut languages: Vec = existing_languages .into_iter() - .filter(|x| used_languages.contains(&x.name)) + .filter(|x| used_languages.contains(&x.tag)) .collect(); languages.push(Language { - name: "en".to_string(), - description: "English".to_string(), + tag: "en".to_string(), + local_name: "English".to_string(), }); for language in languages.iter_mut() { - if let Ok(locale) = rust_icu::loc::ULoc::for_language_tag(&language.name.replace('_', "-")) - { + if let Ok(locale) = rust_icu::loc::ULoc::for_language_tag(&language.tag.replace('_', "-")) { if let Ok(display) = crate::utils::display_language(&locale) { // 'und' seems to mean undefined if display != "und" { - language.description = display; + language.local_name = display; } } } } let collator = rust_icu::col::UCollator::try_from("en").unwrap(); - languages.sort_by(|a, b| { - collator - .strcoll_utf8(&a.description, &b.description) - .unwrap() - }); + languages.sort_by(|a, b| collator.strcoll_utf8(&a.local_name, &b.local_name).unwrap()); Ok(languages) } diff --git a/website/src/pages.rs b/website/src/pages.rs new file mode 100644 index 0000000..b2bb041 --- /dev/null +++ b/website/src/pages.rs @@ -0,0 +1,46 @@ +use askama::Template; +use aussi::{Apps, Site}; + +// used in templates +use crate::filters; +//use std::ops::Deref; + +#[derive(Template)] +#[template(path = "error-404.html")] +pub struct Error404<'a> { + pub site: &'a Site, +} + +#[derive(Template)] +#[template(path = "overview.html")] +pub struct Overview<'a> { + pub site: &'a Site, + pub apps: &'a Apps, +} + +#[derive(Template)] +#[template(path = "app.html")] +pub struct App<'a> { + pub site: &'a Site, + pub app: &'a aussi::App, +} + +#[derive(Template)] +#[template(path = "releases.html")] +pub struct Releases<'a> { + pub site: &'a Site, + pub app: &'a aussi::App, +} + +#[derive(Template)] +#[template(path = "languages.html")] +pub struct Languages<'a> { + pub site: &'a Site, + pub languages: &'a Vec, +} + +#[derive(Template)] +#[template(path = "script.js", escape = "none")] +pub struct Script { + pub languages_json: String, +} diff --git a/website/src/utils.rs b/website/src/utils.rs index 0c410cc..d69e447 100644 --- a/website/src/utils.rs +++ b/website/src/utils.rs @@ -1,7 +1,5 @@ use rust_icu::sys::*; -use std::convert::TryFrom; - const LOCALE_CAPACITY: usize = 255; pub fn display_language(locale: &rust_icu::loc::ULoc) -> Result { @@ -66,26 +64,3 @@ pub fn to_css_color(color: &palette::Srgb) -> String { format!("#{:08X}", css_color.color)[0..7].to_string() } - -pub fn localized_datetime( - datetime: &chrono::DateTime, - loc: &rust_icu::loc::ULoc, - time_format: UDateFormatStyle, - date_format: UDateFormatStyle, -) -> String { - rust_icu::dat::UDateFormat::new_with_styles( - time_format, - date_format, - loc, - &rust_icu::string::UChar::try_from("utc").unwrap(), - ) - .unwrap() - .format(datetime.timestamp_millis() as f64) - .unwrap() -} - -pub fn string_to_loc(lang: &str) -> rust_icu::loc::ULoc { - let lang = if lang.is_empty() { "en" } else { lang }; - - rust_icu::loc::ULoc::for_language_tag(&lang.replace('_', "-")).unwrap() -} diff --git a/website/templates/app.html b/website/templates/app.html index 56ed744..c9f5008 100644 --- a/website/templates/app.html +++ b/website/templates/app.html @@ -2,28 +2,29 @@ {% import "macros.html" as macros %} {% block class %}app{% endblock class %} -{% block title %}{{ app.name }} – {{ str["Apps for GNOME"] }}{% endblock title %} +{% block title %}{{ app.name }} – {{ "Apps for GNOME"|t }}{% endblock title %} {% block head %} - - {% set abstract = app.description | replace(from="

", to="

") | safe | striptags | truncate(length=200) %} - {{ macros::cards( - title=app.name, - desc=app.summary ~ " – " ~ abstract, - url=absolute_base_url ~ "/" ~ doc_lang ~ "/" ~ logical_url, - img=absolute_base_url ~ "/icons/128/" ~ app.id ~ ".png", - twitter_img=absolute_base_url ~ "/icons/twitter/" ~ app.id ~ ".png", - theme=app.background_color_v2, + {# #} + + {% set abstract = app.description.clone()|replace("

", "

")|striptags|truncate(200) %} + + {% call macros::cards( + app.name, + "{} – {}"|format(app.summary, abstract), + "{}/icons/128/{}.png"|format(site.absolute_base_url, app.id), + "{}/icons/twitter/{}.png"|format(site.absolute_base_url, app.id), + app.background_color_v2 ) - }} + %} - - + + - - - - + + + + {% endblock head %} {% block header %} @@ -43,7 +44,7 @@
-