Archived
el-ui v2: universal platform, service bindings, AOP, auth, publish pipeline
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
//! 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()
|
||||
}
|
||||
Reference in New Issue
Block a user