Skip to content

Commit

Permalink
localization: handle subaddons (#820)
Browse files Browse the repository at this point in the history
* localization: handle subaddons

* handle no optionals
  • Loading branch information
BrettMayson authored Nov 1, 2024
1 parent eef86bc commit 6d92452
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 73 deletions.
70 changes: 41 additions & 29 deletions bin/src/commands/localization/sort.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::io::BufReader;
use std::{io::BufReader, path::PathBuf};

use clap::ArgMatches;
use hemtt_stringtable::Project;
Expand All @@ -10,39 +10,51 @@ pub fn sort(matches: &ArgMatches) -> Result<Report, Error> {

let only_lang = matches.get_flag("only-lang");

for addon in ctx.addons() {
let stringtable_path = ctx
.workspace_path()
.join(addon.folder())?
.join("stringtable.xml")?;
if stringtable_path.exists()? {
match Project::from_reader(BufReader::new(stringtable_path.open_file()?)) {
Ok(mut project) => {
if !only_lang {
project.sort();
for root in ["addons", "optionals"] {
if !ctx.project_folder().join(root).exists() {
continue;
}
let paths: Vec<PathBuf> = walkdir::WalkDir::new(ctx.project_folder().join(root))
.into_iter()
.filter_map(|p| {
p.map(|p| {
if p.file_name() == "stringtable.xml" {
Some(p.path().to_path_buf())
} else {
None
}
let out_path = ctx
.project_folder()
.join(addon.folder_pathbuf())
.join("stringtable.xml");
let mut writer = String::new();
if let Err(e) = project.to_writer(&mut writer) {
error!("Failed to write stringtable for {}", addon.folder());
error!("{:?}", e);
return Ok(Report::new());
})
.ok()
.flatten()
})
.collect::<Vec<_>>();
for path in paths {
if path.exists() {
let mut file = std::fs::File::open(&path)?;
match Project::from_reader(BufReader::new(&mut file)) {
Ok(mut project) => {
if !only_lang {
project.sort();
}
let mut writer = String::new();
if let Err(e) = project.to_writer(&mut writer) {
error!("Failed to write stringtable for {}", path.display());
error!("{:?}", e);
return Ok(Report::new());
}
if let Err(e) = std::fs::write(&path, writer) {
error!("Failed to write stringtable for {}", path.display());
error!("{:?}", e);
return Ok(Report::new());
}
}
if let Err(e) = std::fs::write(out_path, writer) {
error!("Failed to write stringtable for {}", addon.folder());
Err(e) => {
error!("Failed to read stringtable for {}", path.display());
error!("{:?}", e);
return Ok(Report::new());
}
}
Err(e) => {
error!("Failed to read stringtable for {}", addon.folder());
error!("{:?}", e);
return Ok(Report::new());
}
};
};
}
}
}
Ok(Report::new())
Expand Down
60 changes: 31 additions & 29 deletions bin/src/modules/stringtables/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use std::{io::BufReader, sync::Arc};

use hemtt_stringtable::{
analyze::{lint_addon, lint_addons, lint_check},
analyze::{lint_all, lint_check, lint_one},
Project,
};
use hemtt_workspace::reporting::{Code, Diagnostic};
use hemtt_workspace::{
reporting::{Code, Diagnostic},
WorkspacePath,
};

use crate::{context::Context, report::Report, Error};

Expand Down Expand Up @@ -33,39 +36,38 @@ impl Module for Stringtables {
fn pre_build(&self, ctx: &Context) -> Result<Report, Error> {
let mut report = Report::new();

let stringtables = ctx
.addons()
.iter()
.filter_map(|addon| {
let path = ctx
.workspace_path()
.join(addon.folder())
.expect("vfs issue")
.join("stringtable.xml")
.expect("vfs issue");
let mut stringtables = Vec::new();
for root in ["addons", "optionals"] {
if !ctx.workspace_path().join(root)?.exists()? {
continue;
}
let paths = ctx
.workspace_path()
.join(root)
.expect("vfs issue")
.walk_dir()
.expect("vfs issue")
.into_iter()
.filter(|p| p.filename() == "stringtable.xml")
.collect::<Vec<_>>();
for path in paths {
if path.exists().expect("vfs issue") {
let existing = path.read_to_string().expect("vfs issue");
match Project::from_reader(BufReader::new(existing.as_bytes())) {
Ok(project) => Some((project, addon.clone(), existing)),
Ok(project) => stringtables.push((project, path, existing)),
Err(e) => {
debug!("Failed to parse stringtable for {}: {}", addon.folder(), e);
report.push(Arc::new(CodeStringtableInvalid::new(
addon.folder(),
e.to_string(),
)));
None
debug!("Failed to parse stringtable for {}: {}", path, e);
report.push(Arc::new(CodeStringtableInvalid::new(path, e.to_string())));
}
}
} else {
None
}
})
.collect::<Vec<_>>();
}
}

report.extend(lint_addons(&stringtables, Some(ctx.config())));
report.extend(lint_all(&stringtables, Some(ctx.config())));

for stringtable in stringtables {
report.extend(lint_addon(&stringtable, Some(ctx.config())));
report.extend(lint_one(&stringtable, Some(ctx.config())));
}

Ok(report)
Expand All @@ -74,7 +76,7 @@ impl Module for Stringtables {

#[allow(clippy::module_name_repetitions)]
pub struct CodeStringtableInvalid {
addon: String,
path: WorkspacePath,
reason: String,
diagnostic: Option<Diagnostic>,
}
Expand All @@ -85,7 +87,7 @@ impl Code for CodeStringtableInvalid {
}

fn message(&self) -> String {
format!("Stringtable in `{}` is invalid", self.addon)
format!("Stringtable at `{}` is invalid", self.path)
}

fn note(&self) -> Option<String> {
Expand All @@ -99,9 +101,9 @@ impl Code for CodeStringtableInvalid {

impl CodeStringtableInvalid {
#[must_use]
pub fn new(addon: String, reason: String) -> Self {
pub fn new(path: WorkspacePath, reason: String) -> Self {
Self {
addon,
path,
reason,
diagnostic: None,
}
Expand Down
26 changes: 13 additions & 13 deletions libs/stringtable/src/analyze/lints/01_sorted.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::sync::Arc;

use hemtt_common::config::LintConfig;
use hemtt_workspace::{addons::Addon, lint::{AnyLintRunner, Lint, LintRunner}, reporting::{Code, Codes, Diagnostic, Severity}};
use hemtt_workspace::{lint::{AnyLintRunner, Lint, LintRunner}, reporting::{Code, Codes, Diagnostic, Severity}, WorkspacePath};

use crate::{analyze::SqfLintData, Project};

Expand Down Expand Up @@ -33,7 +33,7 @@ impl Lint<SqfLintData> for LintL01Sorted {
}
}

pub type StringtableData = (Project, Addon, String);
pub type StringtableData = (Project, WorkspacePath, String);

pub struct Runner;
impl LintRunner<SqfLintData> for Runner {
Expand All @@ -49,30 +49,30 @@ impl LintRunner<SqfLintData> for Runner {
let mut unsorted = Vec::new();
let mut codes: Codes = Vec::new();
let only_lang = matches!(config.option("only-lang"), Some(toml::Value::Boolean(true)));
for (project, addon, existing) in target {
for (project, path, existing) in target {
let mut project = project.clone();
if !only_lang {
project.sort();
}
let mut writer = String::new();
if let Err(e) = project.to_writer(&mut writer) {
panic!("Failed to write stringtable for {}: {}", addon.folder(), e);
panic!("Failed to write stringtable for {path}: {e}");
}
if &writer != existing {
unsorted.push(addon.folder().to_string());
unsorted.push(path.as_str().to_string());
}
}
if unsorted.len() <= 3 {
for addon in unsorted {
for path in unsorted {
codes.push(Arc::new(CodeStringtableNotSorted::new(
Unsorted::Addon(addon),
Unsorted::Path(path),
only_lang,
config.severity(),
)));
}
} else {
codes.push(Arc::new(CodeStringtableNotSorted::new(
Unsorted::Addons(unsorted),
Unsorted::Paths(unsorted),
only_lang,
config.severity(),
)));
Expand All @@ -82,8 +82,8 @@ impl LintRunner<SqfLintData> for Runner {
}

pub enum Unsorted {
Addon(String),
Addons(Vec<String>),
Path(String),
Paths(Vec<String>),
}

#[allow(clippy::module_name_repetitions)]
Expand All @@ -105,9 +105,9 @@ impl Code for CodeStringtableNotSorted {

fn message(&self) -> String {
match &self.unsorted {
Unsorted::Addon(addon) => format!("Stringtable in `{addon}` is not sorted"),
Unsorted::Addons(addons) => {
format!("Stringtables in {} addons are not sorted", addons.len())
Unsorted::Path(path) => format!("Stringtable at `{path}` is not sorted"),
Unsorted::Paths(paths) => {
format!("{} stringtables are not sorted", paths.len())
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions libs/stringtable/src/analyze/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ lint_manager!(stringtable, vec![]);

pub struct SqfLintData {}

pub fn lint_addon(addon: &StringtableData, project: Option<&ProjectConfig>) -> Codes {
pub fn lint_one(addon: &StringtableData, project: Option<&ProjectConfig>) -> Codes {
let mut manager = LintManager::new(project.map_or_else(Default::default, |project| {
project.lints().stringtables().clone()
}));
Expand All @@ -26,7 +26,7 @@ pub fn lint_addon(addon: &StringtableData, project: Option<&ProjectConfig>) -> C
}

#[allow(clippy::ptr_arg)] // Needed for &Vec for &dyn Any
pub fn lint_addons(addons: &Vec<StringtableData>, project: Option<&ProjectConfig>) -> Codes {
pub fn lint_all(addons: &Vec<StringtableData>, project: Option<&ProjectConfig>) -> Codes {
let mut manager = LintManager::new(project.map_or_else(Default::default, |project| {
project.lints().stringtables().clone()
}));
Expand Down

0 comments on commit 6d92452

Please sign in to comment.