Files
el/ui/crates/el-publish/src/metadata.rs
T

123 lines
3.5 KiB
Rust

//! Store metadata — reads title.txt, description.txt, whats-new.txt, etc.
//!
//! Directory structure (mirrors Fastlane's metadata format):
//! ```text
//! store/
//! en-US/
//! title.txt
//! description.txt
//! whats-new.txt
//! keywords.txt
//! promotional-text.txt
//! de-DE/
//! title.txt
//! ...
//! ```
use crate::{PublishError, PublishResult};
use std::collections::HashMap;
use std::path::Path;
/// Metadata for a single locale.
#[derive(Debug, Clone, Default)]
pub struct LocaleMetadata {
pub title: String,
pub description: String,
pub whats_new: String,
pub keywords: Vec<String>,
pub promotional_text: String,
}
impl LocaleMetadata {
pub fn new(title: impl Into<String>, description: impl Into<String>) -> Self {
Self {
title: title.into(),
description: description.into(),
..Default::default()
}
}
pub fn with_whats_new(mut self, whats_new: impl Into<String>) -> Self {
self.whats_new = whats_new.into();
self
}
}
/// Complete store metadata across all locales.
#[derive(Debug, Clone, Default)]
pub struct StoreMetadata {
pub locales: HashMap<String, LocaleMetadata>,
}
impl StoreMetadata {
pub fn new() -> Self {
Self::default()
}
pub fn add_locale(mut self, locale: impl Into<String>, metadata: LocaleMetadata) -> Self {
self.locales.insert(locale.into(), metadata);
self
}
/// Get metadata for a specific locale, falling back to `en-US`.
pub fn for_locale(&self, locale: &str) -> Option<&LocaleMetadata> {
self.locales.get(locale).or_else(|| self.locales.get("en-US"))
}
/// Load metadata from the directory structure.
///
/// Falls back gracefully: if the metadata directory doesn't exist,
/// returns empty metadata (don't fail the publish for missing store copy).
pub fn load_from_dir(dir: &str) -> PublishResult<Self> {
let path = Path::new(dir);
if !path.exists() {
// Warn but don't fail — metadata is optional for internal/alpha builds.
return Ok(Self::new());
}
let mut metadata = Self::new();
let read_dir = std::fs::read_dir(path).map_err(|e| {
PublishError::Metadata(format!("failed to read metadata dir {}: {}", dir, e))
})?;
for entry in read_dir.flatten() {
let locale_path = entry.path();
if !locale_path.is_dir() {
continue;
}
let locale = locale_path
.file_name()
.and_then(|n| n.to_str())
.unwrap_or("")
.to_string();
if locale.is_empty() {
continue;
}
let locale_meta = LocaleMetadata {
title: read_file(&locale_path, "title.txt"),
description: read_file(&locale_path, "description.txt"),
whats_new: read_file(&locale_path, "whats-new.txt"),
keywords: read_file(&locale_path, "keywords.txt")
.split(',')
.map(|k| k.trim().to_string())
.filter(|k| !k.is_empty())
.collect(),
promotional_text: read_file(&locale_path, "promotional-text.txt"),
};
metadata.locales.insert(locale, locale_meta);
}
Ok(metadata)
}
}
fn read_file(dir: &Path, filename: &str) -> String {
std::fs::read_to_string(dir.join(filename))
.unwrap_or_default()
.trim()
.to_string()
}