es_fluent_cli/commands/
common.rs1use crate::core::{CliError, CrateInfo, GenerateResult, GenerationAction, WorkspaceInfo};
2use crate::utils::{count_ftl_resources, filter_crates_by_package, partition_by_lib_rs, ui};
3use clap::Args;
4use std::path::PathBuf;
5use std::time::Instant;
6
7#[derive(Args, Clone, Debug)]
8pub struct WorkspaceArgs {
9 #[arg(short, long)]
11 pub path: Option<PathBuf>,
12 #[arg(short = 'P', long)]
14 pub package: Option<String>,
15}
16
17#[derive(Args, Clone, Debug)]
21pub struct LocaleProcessingArgs {
22 #[arg(long)]
24 pub all: bool,
25
26 #[arg(long)]
28 pub dry_run: bool,
29}
30
31#[derive(Clone, Debug)]
33pub struct WorkspaceCrates {
34 pub path: PathBuf,
36 pub workspace_info: WorkspaceInfo,
38 pub crates: Vec<CrateInfo>,
40 pub valid: Vec<CrateInfo>,
42 pub skipped: Vec<CrateInfo>,
44}
45
46impl WorkspaceCrates {
47 pub fn discover(args: WorkspaceArgs) -> Result<Self, CliError> {
49 use crate::utils::discover_workspace;
50
51 let path = args.path.unwrap_or_else(|| PathBuf::from("."));
52 let workspace_info = discover_workspace(&path)?;
53 let crates = filter_crates_by_package(workspace_info.crates.clone(), args.package.as_ref());
54 let (valid_refs, skipped_refs) = partition_by_lib_rs(&crates);
55 let valid = valid_refs.into_iter().cloned().collect();
56 let skipped = skipped_refs.into_iter().cloned().collect();
57
58 Ok(Self {
59 path,
60 workspace_info,
61 crates,
62 valid,
63 skipped,
64 })
65 }
66
67 pub fn print_discovery(&self, header: impl Fn()) -> bool {
71 header();
72
73 if self.crates.is_empty() {
74 ui::print_discovered(&[]);
75 return false;
76 }
77
78 ui::print_discovered(&self.crates);
79
80 for krate in &self.skipped {
81 ui::print_missing_lib_rs(&krate.name);
82 }
83
84 true
85 }
86}
87
88fn read_changed_status(temp_dir: &std::path::Path, crate_name: &str) -> bool {
95 let result_json_path = temp_dir
96 .join("metadata")
97 .join(crate_name)
98 .join("result.json");
99
100 if !result_json_path.exists() {
101 return false;
102 }
103
104 match std::fs::read_to_string(&result_json_path) {
105 Ok(json_str) => match serde_json::from_str::<serde_json::Value>(&json_str) {
106 Ok(json) => json["changed"].as_bool().unwrap_or(false),
107 Err(_) => false,
108 },
109 Err(_) => false,
110 }
111}
112
113pub fn parallel_generate(
120 workspace: &WorkspaceInfo,
121 crates: &[CrateInfo],
122 action: &GenerationAction,
123 force_run: bool,
124) -> Vec<GenerateResult> {
125 use crate::generation::{generate_for_crate_monolithic, prepare_monolithic_runner_crate};
126
127 if let Err(e) = prepare_monolithic_runner_crate(workspace) {
129 return crates
131 .iter()
132 .map(|k| {
133 GenerateResult::failure(k.name.clone(), std::time::Duration::ZERO, e.to_string())
134 })
135 .collect();
136 }
137
138 let pb = ui::create_progress_bar(crates.len() as u64, "Processing crates...");
139
140 crates
143 .iter()
144 .map(|krate| {
145 let start = Instant::now();
146 let result = generate_for_crate_monolithic(krate, workspace, action, force_run);
147 let duration = start.elapsed();
148
149 pb.inc(1);
150
151 let resource_count = result
152 .as_ref()
153 .ok()
154 .map(|_| count_ftl_resources(&krate.ftl_output_dir, &krate.name))
155 .unwrap_or(0);
156
157 match result {
158 Ok(output) => {
159 let temp_dir = workspace.root_dir.join(".es-fluent");
161 let changed = read_changed_status(&temp_dir, &krate.name);
162
163 let output_opt = if output.is_empty() {
164 None
165 } else {
166 Some(output.to_string())
167 };
168
169 GenerateResult::success(
170 krate.name.clone(),
171 duration,
172 resource_count,
173 output_opt,
174 changed,
175 )
176 },
177 Err(e) => GenerateResult::failure(krate.name.clone(), duration, e.to_string()),
178 }
179 })
180 .collect()
181}
182
183pub fn render_generation_results(
187 results: &[GenerateResult],
188 on_success: impl Fn(&GenerateResult),
189 on_error: impl Fn(&GenerateResult),
190) -> bool {
191 let mut has_errors = false;
192
193 for result in results {
194 if result.error.is_some() {
195 has_errors = true;
196 on_error(result);
197 } else {
198 on_success(result);
199 }
200 }
201
202 has_errors
203}