mirror of
https://github.com/storytold/wordcraft.git
synced 2026-11-10 12:20:12 -06:00
craft-i18n's first Language pack release is published (https://github.com/storytold/craft-i18n/releases/tag/language-packs-1, 61 packs, built from craft-i18n main 4504e288). PACK_INDEX now pins its index.json sha256 instead of the all-zero placeholder. Docs say which languages it covers and which wait on craft-proof (compounding) or are excluded on licence grounds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
105 lines
4.0 KiB
Rust
105 lines
4.0 KiB
Rust
//! The font store as the packs [`Backend`](super::Backend): its folder, its consent setting, the
|
|
//! pinned pack index and verified installs (craft-libs `craft-font-store`, kind `language-pack`).
|
|
|
|
use std::path::PathBuf;
|
|
use std::sync::{Mutex, PoisonError};
|
|
|
|
use craft_font_catalog::FontEnv;
|
|
use craft_font_store::{FontStore, Network, PackEntry, PackIndex, PackIndexPin};
|
|
|
|
use super::{Cancel, Pack};
|
|
|
|
/// The pack index this build trusts: craft-i18n's first Language pack release, language-packs-1
|
|
/// (61 packs, built from craft-i18n `4504e288`), pinned by the sha256 of its `index.json`.
|
|
/// `CRAFT_LANGUAGE_PACK_INDEX` (read by the font store itself) points WordCraft at a local or test
|
|
/// index instead, for trying packs before they are released.
|
|
pub const PACK_INDEX: PackIndexPin = PackIndexPin {
|
|
url: "https://github.com/storytold/craft-i18n/releases/download/language-packs-1/index.json",
|
|
sha256: "531465b50126d0594bb89a9c4512f7ae67d581259636040a410190641ec1428c",
|
|
};
|
|
|
|
pub(super) struct FontStoreBackend {
|
|
store: FontStore,
|
|
/// The index last read or fetched; installs take their entry (url, size, sha256) from it.
|
|
index: Mutex<Option<PackIndex>>,
|
|
}
|
|
|
|
impl FontStoreBackend {
|
|
pub(super) fn new(user: bool) -> Option<Self> {
|
|
let env = FontEnv::from_process();
|
|
let store = if user { FontStore::for_user(&env)? } else { FontStore::for_agent(&env)? };
|
|
Some(Self { store, index: Mutex::new(None) })
|
|
}
|
|
|
|
/// A store in `dir`.
|
|
pub(super) fn in_dir(dir: PathBuf, user: bool) -> Self {
|
|
let caller = if user { craft_font_store::Caller::User } else { craft_font_store::Caller::Agent };
|
|
Self { store: FontStore::new(dir, caller), index: Mutex::new(None) }
|
|
}
|
|
|
|
fn keep(&self, index: PackIndex) -> Vec<Pack> {
|
|
let packs = index.packs.iter().map(pack).collect();
|
|
*self.index.lock().unwrap_or_else(PoisonError::into_inner) = Some(index);
|
|
packs
|
|
}
|
|
}
|
|
|
|
fn pack(e: &PackEntry) -> Pack {
|
|
Pack {
|
|
locale: e.locale.clone(),
|
|
name: e.name.clone(),
|
|
version: e.version.clone(),
|
|
url: e.url.clone(),
|
|
// TODO(CP4): the index's optional `source` once craft-font-store's PackEntry carries it.
|
|
source: None,
|
|
size: e.size,
|
|
licence: e.licence.clone(),
|
|
class: e.class.clone(),
|
|
spelling: e.spelling,
|
|
hyphenation: e.hyphenation,
|
|
}
|
|
}
|
|
|
|
impl super::Backend for FontStoreBackend {
|
|
fn index(&self) -> Result<Vec<Pack>, String> {
|
|
Ok(self.store.cached_language_pack_index(&PACK_INDEX).map(|i| self.keep(i)).unwrap_or_default())
|
|
}
|
|
|
|
fn fetch_index(&self, cancel: &Cancel) -> Result<Vec<Pack>, String> {
|
|
let index = self.store.fetch_language_pack_index(&PACK_INDEX, &cancel.0).map_err(|e| e.to_string())?;
|
|
Ok(self.keep(index))
|
|
}
|
|
|
|
fn network_on(&self) -> bool {
|
|
self.store.network() == Network::On
|
|
}
|
|
|
|
fn enable_network(&self) -> Result<(), String> {
|
|
self.store.enable_network().map_err(|e| e.to_string())
|
|
}
|
|
|
|
fn install(&self, pack: &Pack, cancel: &Cancel, progress: &mut dyn FnMut(u64, u64)) -> Result<(), String> {
|
|
let index = {
|
|
let held = self.index.lock().unwrap_or_else(PoisonError::into_inner).clone();
|
|
match held {
|
|
Some(i) => i,
|
|
None => self.store.cached_language_pack_index(&PACK_INDEX).ok_or("the list of Language packs hasn't been fetched")?,
|
|
}
|
|
};
|
|
let entry = index.pack(&pack.locale).ok_or_else(|| format!("there is no language pack for {}", pack.locale))?.clone();
|
|
self.store.install_language_pack(&index, &entry, &cancel.0, &mut |p| progress(p.done, p.total)).map(|_| ()).map_err(|e| e.to_string())
|
|
}
|
|
|
|
fn remove(&self, locale: &str) -> Result<(), String> {
|
|
self.store.remove_language_pack(locale).map_err(|e| e.to_string())
|
|
}
|
|
|
|
fn index_override(&self) -> Option<String> {
|
|
craft_font_store::language_pack_index_overridden()
|
|
}
|
|
|
|
fn packs_dir(&self) -> Option<PathBuf> {
|
|
Some(self.store.language_packs_dir())
|
|
}
|
|
}
|