1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use crate::lib::logic::{ConfigJob, ConfigManifest, IoConfig, JobEngine, JobMode, JobSpec, MX, RenderFlags};
/// Orchestrator zadań wsadowych.
/// Pobiera konfigurację z plików TOML, tłumaczy ją na silnie typowane obiekty
/// JobSpec i zleca ich wykonanie do rdzennego JobEngine.
pub struct DocEngineMultiple {
pub manifest: ConfigManifest,
}
impl DocEngineMultiple {
// ============================================================================
// LOADERY (Odczyt konfiguracji za pomocą IoConfig)
// ============================================================================
/// Wczytuje konfigurację z domyślnego pliku (np. ./.x-do.toml)
pub fn loader_default() -> Result<Self, String> {
let manifest = IoConfig::default_config_loader()?;
Ok(Self { manifest })
}
/// Wczytuje konfigurację ze wskazanej ścieżki
pub fn loader_from_toml(path: &str) -> Result<Self, String> {
let manifest = IoConfig::config_loader_from(path)?;
Ok(Self { manifest })
}
// ============================================================================
// PARSERY (Tłumaczenie ConfigJob z TOML na nasz domenowy JobSpec)
// ============================================================================
/// Parsuje pojedynczy surowy obiekt konfiguracji TOML na silnie typowany
/// JobSpec
pub fn parse(&self, cfg: &ConfigJob) -> Result<JobSpec, String> { JobSpec::from_config(cfg) }
/// Szuka zadania po ID i parsuje je do JobSpec (nie wykonując go)
pub fn parse_for(&self, id: &str) -> Result<JobSpec, String> {
let cfg_job = self
.manifest
.job
.iter()
.find(|j| j.id == id)
.ok_or_else(|| format!("❌ Nie znaleziono zadania o ID: '{}'", id))?;
JobSpec::from_config(cfg_job)
}
// ============================================================================
// EXECUTORY (Wykonywanie zadań za pomocą JobEngine)
// ============================================================================
/// Mapuje i wykonuje w pętli wszystkie zadania zdefiniowane w pliku TOML
pub fn jobs(&self) -> Result<(), String> {
for cfg_job in &self.manifest.job {
let spec = self.parse(cfg_job)?;
self.execute_spec(spec)?;
}
Ok(())
}
/// Wyszukuje zadanie po ID, mapuje na JobSpec i wykonuje je
pub fn job_id(&self, id: &str) -> Result<(), String> {
let spec = self.parse_for(id)?;
self.execute_spec(spec)?;
Ok(())
}
// ============================================================================
// SILNIK WYKONAWCZY (Delegacja do JobEngine)
// ============================================================================
/// Bierze gotowy i bezpieczny JobSpec, a następnie karmi nim JobEngine
fn execute_spec(&self, spec: JobSpec) -> Result<(), String> {
if !spec.quiet_work {
let name = spec.name.as_deref().unwrap_or("Brak nazwy");
println!("🚀 Uruchamianie zadania: {} ({})", spec.id, name);
}
// 1. Przekładamy JobMode na stare MX dla silnika renderującego
let mx_mode = match spec.mode {
JobMode::Matched => MX::Matched,
JobMode::Mismatched => MX::Mismatched,
};
// 2. Inicjujemy rdzewny JobEngine przekazując mu od razu obiekt ScanSpec i
// TabSpec
let mut engine = JobEngine::new(spec.scan.clone()).spec(spec.table.clone());
// 3. Widok w terminalu (lub cichy stan dla plików)
if !spec.quiet_work {
if let Some(size) = spec.table.trim_size {
let page = Some(spec.table.trim_page);
engine = engine.view_trimmed(mx_mode, spec.hide_stats, spec.hide_promo, size, page);
} else {
engine = engine.view(mx_mode, spec.hide_stats, spec.hide_promo);
}
} else {
// Nawet w trybie cichym zapisujemy konfigurację renderowania na wypadek zapisu
// do pliku
engine.last_render =
Some(RenderFlags { hide_stats: spec.hide_stats, hide_promo: spec.hide_promo, mode: mx_mode });
}
// 4. Eksport do plików (niezależnie od trybu quiet)
if let Some(sotc_path) = &spec.save_sotc_at {
engine = engine.save_structure_of_the_content(sotc_path, spec.title_sotc.as_deref());
}
if let Some(cots_path) = &spec.save_cots_at {
engine = engine.save_content_of_the_structure(cots_path, spec.title_cots.as_deref());
}
let _ = engine;
if !spec.quiet_work {
println!("✨ Ukończono zadanie: {}", spec.id);
}
Ok(())
}
}