Skip to content

Commit

Permalink
localization: only-lang flag (#815)
Browse files Browse the repository at this point in the history
* localization: only-lang flag

* help shows the correct command
  • Loading branch information
BrettMayson authored Oct 25, 2024
1 parent 5f4524d commit 6003851
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 104 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 10 additions & 3 deletions bin/src/commands/localization/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use clap::{ArgMatches, Command};
use clap::{ArgAction, ArgMatches, Command};

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

Expand All @@ -11,7 +11,14 @@ pub fn cli() -> Command {
.visible_alias("ln")
.about("Manage localization stringtables")
.subcommand(Command::new("coverage").about("Check the coverage of localization"))
.subcommand(Command::new("sort").about("Sort the stringtables"))
.subcommand(
Command::new("sort").about("Sort the stringtables").arg(
clap::Arg::new("only-lang")
.long("only-lang")
.help("Sort only the languages")
.action(ArgAction::SetTrue),
),
)
}

/// Execute the localization command
Expand All @@ -24,7 +31,7 @@ pub fn cli() -> Command {
pub fn execute(matches: &ArgMatches) -> Result<Report, Error> {
match matches.subcommand() {
Some(("coverage", _)) => coverage::coverage(),
Some(("sort", _)) => sort::sort(),
Some(("sort", matches)) => sort::sort(matches),
_ => {
cli().print_help().expect("Failed to print help");
Ok(Report::new())
Expand Down
9 changes: 7 additions & 2 deletions bin/src/commands/localization/sort.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
use std::io::BufReader;

use clap::ArgMatches;
use hemtt_stringtable::Project;

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

pub fn sort() -> Result<Report, Error> {
pub fn sort(matches: &ArgMatches) -> Result<Report, Error> {
let ctx = Context::new(None, crate::context::PreservePrevious::Remove, true)?;

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

for addon in ctx.addons() {
let stringtable_path = ctx
.workspace_path()
Expand All @@ -15,7 +18,9 @@ pub fn sort() -> Result<Report, Error> {
if stringtable_path.exists()? {
match Project::from_reader(BufReader::new(stringtable_path.open_file()?)) {
Ok(mut project) => {
project.sort();
if !only_lang {
project.sort();
}
let out_path = ctx
.project_folder()
.join(addon.folder_pathbuf())
Expand Down
91 changes: 85 additions & 6 deletions bin/src/modules/stringtables/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
use hemtt_stringtable::analyze::{lint_addons, lint_check};
use std::{io::BufReader, sync::Arc};

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

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

Expand Down Expand Up @@ -26,11 +32,84 @@ impl Module for Stringtables {

fn pre_build(&self, ctx: &Context) -> Result<Report, Error> {
let mut report = Report::new();
report.extend(lint_addons(
ctx.workspace_path().to_owned(),
&ctx.addons().to_vec(),
Some(ctx.config()),
));

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");
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)),
Err(e) => {
debug!("Failed to parse stringtable for {}: {}", addon.folder(), e);
report.push(Arc::new(CodeStringtableInvalid::new(
addon.folder(),
e.to_string(),
)));
None
}
}
} else {
None
}
})
.collect::<Vec<_>>();

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

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

Ok(report)
}
}

#[allow(clippy::module_name_repetitions)]
pub struct CodeStringtableInvalid {
addon: String,
reason: String,
diagnostic: Option<Diagnostic>,
}

impl Code for CodeStringtableInvalid {
fn ident(&self) -> &'static str {
"INVALID-STRINGTABLE"
}

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

fn note(&self) -> Option<String> {
Some(self.reason.clone())
}

fn diagnostic(&self) -> Option<Diagnostic> {
self.diagnostic.clone()
}
}

impl CodeStringtableInvalid {
#[must_use]
pub fn new(addon: String, reason: String) -> Self {
Self {
addon,
reason,
diagnostic: None,
}
.generate_processed()
}

fn generate_processed(mut self) -> Self {
self.diagnostic = Some(Diagnostic::from_code(&self));
self
}
}
1 change: 1 addition & 0 deletions libs/stringtable/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ linkme = { workspace = true }
paste = { workspace = true }
quick-xml = { version = "0.36.2", features = ["serialize"] }
serde = { workspace = true, features = ["derive"] }
toml = { workspace = true }
tracing = { workspace = true }

[dev-dependencies]
Expand Down
93 changes: 28 additions & 65 deletions libs/stringtable/src/analyze/lints/01_sorted.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use std::{io::BufReader, sync::Arc};
use std::sync::Arc;

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

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

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

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

pub struct Runner;
impl LintRunner<SqfLintData> for Runner {
type Target = Vec<Addon>;
type Target = Vec<StringtableData>;
fn run(
&self,
_project: Option<&hemtt_common::config::ProjectConfig>,
config: &hemtt_common::config::LintConfig,
_processed: Option<&hemtt_workspace::reporting::Processed>,
target: &Vec<Addon>,
data: &SqfLintData,
target: &Vec<StringtableData>,
_data: &SqfLintData,
) -> Codes {
let mut unsorted = Vec::new();
let mut codes: Codes = Vec::new();
for addon in target {
let stringtable_path = data.workspace()
.join(addon.folder()).expect("vfs issue")
.join("stringtable.xml").expect("vfs issue");
if stringtable_path.exists().expect("vfs issue") {
let existing = stringtable_path.read_to_string().expect("vfs issue");
match Project::from_reader(BufReader::new(existing.as_bytes())) {
Ok(mut project) => {
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);
}
if writer != existing {
unsorted.push(addon.folder().to_string());
}
}
Err(e) => {
debug!("Failed to parse stringtable for {}: {}", addon.folder(), e);
codes.push(Arc::new(CodeStringtableInvalid::new(addon.folder())));
}
}
let only_lang = matches!(config.option("only-lang"), Some(toml::Value::Boolean(true)));
for (project, addon, 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);
}
if &writer != existing {
unsorted.push(addon.folder().to_string());
}
}
if unsorted.len() <= 3 {
for addon in unsorted {
codes.push(Arc::new(CodeStringtableNotSorted::new(
Unsorted::Addon(addon),
only_lang,
config.severity(),
)));
}
} else {
codes.push(Arc::new(CodeStringtableNotSorted::new(
Unsorted::Addons(unsorted),
only_lang,
config.severity(),
)));
}
Expand All @@ -96,6 +89,7 @@ pub enum Unsorted {
#[allow(clippy::module_name_repetitions)]
pub struct CodeStringtableNotSorted {
unsorted: Unsorted,
only_lang: bool,
severity: Severity,
diagnostic: Option<Diagnostic>,
}
Expand All @@ -119,7 +113,11 @@ impl Code for CodeStringtableNotSorted {
}

fn help(&self) -> Option<String> {
Some("Run `hemtt ln sort` to sort the stringtable".to_string())
if self.only_lang {
Some("Run `hemtt ln sort --only-lang` to sort the stringtable".to_string())
} else {
Some("Run `hemtt ln sort` to sort the stringtable".to_string())
}
}

fn diagnostic(&self) -> Option<Diagnostic> {
Expand All @@ -129,9 +127,10 @@ impl Code for CodeStringtableNotSorted {

impl CodeStringtableNotSorted {
#[must_use]
pub fn new(unsorted: Unsorted, severity: Severity) -> Self {
pub fn new(unsorted: Unsorted, only_lang: bool, severity: Severity) -> Self {
Self {
unsorted,
only_lang,
severity,
diagnostic: None,
}
Expand All @@ -143,39 +142,3 @@ impl CodeStringtableNotSorted {
self
}
}

#[allow(clippy::module_name_repetitions)]
pub struct CodeStringtableInvalid {
addon: String,
diagnostic: Option<Diagnostic>,
}

impl Code for CodeStringtableInvalid {
fn ident(&self) -> &'static str {
"L-L02"
}

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

fn diagnostic(&self) -> Option<Diagnostic> {
self.diagnostic.clone()
}
}

impl CodeStringtableInvalid {
#[must_use]
pub fn new(addon: String) -> Self {
Self {
addon,
diagnostic: None,
}
.generate_processed()
}

fn generate_processed(mut self) -> Self {
self.diagnostic = Some(Diagnostic::from_code(&self));
self
}
}
32 changes: 7 additions & 25 deletions libs/stringtable/src/analyze/mod.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,16 @@
use hemtt_common::config::ProjectConfig;
use hemtt_workspace::{
addons::Addon, lint::LintManager, lint_manager, reporting::Codes, WorkspacePath,
};
use hemtt_workspace::{lint::LintManager, lint_manager, reporting::Codes};
use lints::_01_sorted::StringtableData;

pub mod lints {
automod::dir!(pub "src/analyze/lints");
}

lint_manager!(stringtable, vec![]);

pub struct SqfLintData {
workspace: WorkspacePath,
}

impl SqfLintData {
#[must_use]
pub const fn workspace(&self) -> &WorkspacePath {
&self.workspace
}
}
pub struct SqfLintData {}

pub fn lint_addon(
workspace: WorkspacePath,
addon: &Addon,
project: Option<&ProjectConfig>,
) -> Codes {
pub fn lint_addon(addon: &StringtableData, project: Option<&ProjectConfig>) -> Codes {
let mut manager = LintManager::new(project.map_or_else(Default::default, |project| {
project.lints().stringtables().clone()
}));
Expand All @@ -36,15 +22,11 @@ pub fn lint_addon(
) {
return e;
}
manager.run(&SqfLintData { workspace }, project, None, addon)
manager.run(&SqfLintData {}, project, None, addon)
}

#[allow(clippy::ptr_arg)] // Needed for &Vec for &dyn Any
pub fn lint_addons(
workspace: WorkspacePath,
addons: &Vec<Addon>,
project: Option<&ProjectConfig>,
) -> Codes {
pub fn lint_addons(addons: &Vec<StringtableData>, project: Option<&ProjectConfig>) -> Codes {
let mut manager = LintManager::new(project.map_or_else(Default::default, |project| {
project.lints().stringtables().clone()
}));
Expand All @@ -56,5 +38,5 @@ pub fn lint_addons(
) {
return e;
}
manager.run(&SqfLintData { workspace }, project, None, addons)
manager.run(&SqfLintData {}, project, None, addons)
}
Loading

0 comments on commit 6003851

Please sign in to comment.