From 7e12223344238ece92a1f703d22a89c705afc70a Mon Sep 17 00:00:00 2001 From: 2Shirt <2xShirt@gmail.com> Date: Sat, 8 Nov 2025 16:17:34 -0800 Subject: [PATCH] Use separate State structs per app --- boot_diags/src/app.rs | 67 ++++++++++++++++++++-------------------- boot_diags/src/main.rs | 1 + boot_diags/src/scan.rs | 12 ++++---- boot_diags/src/state.rs | 42 +++++++++++++++++++++++++ core/src/state.rs | 32 ------------------- deja_vu/src/app.rs | 68 +++++++++++++++++++++-------------------- deja_vu/src/main.rs | 1 + deja_vu/src/state.rs | 47 ++++++++++++++++++++++++++++ 8 files changed, 166 insertions(+), 104 deletions(-) create mode 100644 boot_diags/src/state.rs create mode 100644 deja_vu/src/state.rs diff --git a/boot_diags/src/app.rs b/boot_diags/src/app.rs index 16f095f..dc68ffb 100644 --- a/boot_diags/src/app.rs +++ b/boot_diags/src/app.rs @@ -26,7 +26,7 @@ use core::{ }, config::Config, line::{DVLine, get_disk_description_right, get_part_description}, - state::{CloneSettings, Mode}, + state::Mode, system::{ boot::{self, SafeMode, configure_disk}, cpu::get_cpu_name, @@ -57,6 +57,7 @@ use crate::{ parse_dism, parse_registry_hives, parse_system_files, }, scan, + state::State, }; pub struct App { @@ -71,13 +72,13 @@ pub struct App { should_suspend: bool, tick_rate: f64, // App - clone: CloneSettings, cur_mode: Mode, diag_groups: Arc>>, list: StatefulList, boot_modes: Vec, setup_modes: Vec, selections: Vec>, + state: State, system32: String, tasks: Tasks, } @@ -117,7 +118,7 @@ impl App { should_suspend: false, tick_rate, // App - clone: CloneSettings::new(disk_list_arc), + state: State::new(disk_list_arc), cur_mode: Mode::Home, diag_groups: diag_groups_arc, list, @@ -130,12 +131,12 @@ impl App { } pub fn inject_driver(&mut self, index: usize) { - if let Some(driver) = self.clone.driver_list.get(index) - && let Some(disk_index) = self.clone.disk_index_dest + if let Some(driver) = self.state.driver_list.get(index) + && let Some(disk_index) = self.state.disk_index_dest { - let disk_list = self.clone.disk_list.lock().unwrap(); + let disk_list = self.state.disk_list.lock().unwrap(); if let Some(disk) = disk_list.get(disk_index) - && let Some(os_index) = self.clone.part_index_os + && let Some(os_index) = self.state.part_index_os && let Ok(task) = boot::inject_driver( driver, disk.get_part_letter(os_index).as_str(), @@ -171,10 +172,10 @@ impl App { SafeMode::Enable => "Safe Mode (minimal)", }; info!("Setting boot mode to: {new_mode}"); - let disk_list = self.clone.disk_list.lock().unwrap(); - if let Some(disk_index) = self.clone.disk_index_dest + let disk_list = self.state.disk_list.lock().unwrap(); + if let Some(disk_index) = self.state.disk_index_dest && let Some(disk) = disk_list.get(disk_index) - && let Some(boot_index) = self.clone.part_index_boot + && let Some(boot_index) = self.state.part_index_boot && let Ok(task) = boot::set_mode( disk.get_part_letter(boot_index).as_str(), &boot_mode, @@ -202,13 +203,13 @@ impl App { ))?; scan::queue_boot_scan_tasks( self.action_tx.clone(), - &self.clone, self.diag_groups.clone(), + &self.state, self.system32.clone(), &mut self.tasks, )?; } - Mode::InjectDrivers | Mode::InstallDrivers => self.clone.scan_drivers(), + Mode::InjectDrivers | Mode::InstallDrivers => self.state.scan_drivers(), Mode::Process => { self.action_tx .send(Action::DisplayPopup(popup::Type::Info, String::from("...")))?; @@ -383,10 +384,10 @@ impl App { } Mode::InstallDrivers => { if let Some(index) = one - && let Some(driver) = self.clone.driver_list.get(index).cloned() + && let Some(driver) = self.state.driver_list.get(index).cloned() { drivers::load(&driver.inf_paths); - self.clone.driver = Some(driver); + self.state.driver = Some(driver); } } Mode::BootSetup => { @@ -398,11 +399,11 @@ impl App { } } Mode::SelectDisks => { - self.clone.disk_index_dest = one; + self.state.disk_index_dest = one; } Mode::SelectParts => { - self.clone.part_index_boot = one; - self.clone.part_index_os = two; + self.state.part_index_boot = one; + self.state.part_index_os = two; } Mode::SetBootMode => { if let Some(index) = one @@ -683,7 +684,7 @@ fn build_left_items(app: &App) -> Action { Mode::InstallDrivers => { select_type = SelectionType::One; title = String::from("Install Drivers"); - app.clone + app.state .driver_list .iter() .for_each(|driver| items.push(driver.to_string())); @@ -691,7 +692,7 @@ fn build_left_items(app: &App) -> Action { Mode::InjectDrivers => { select_type = SelectionType::One; title = String::from("Select Drivers"); - app.clone + app.state .driver_list .iter() .for_each(|driver| items.push(driver.to_string())); @@ -699,7 +700,7 @@ fn build_left_items(app: &App) -> Action { Mode::SelectDisks => { select_type = SelectionType::One; title = String::from("Select Disk"); - let disk_list = app.clone.disk_list.lock().unwrap(); + let disk_list = app.state.disk_list.lock().unwrap(); disk_list .iter() .for_each(|disk| items.push(disk.description.to_string())); @@ -713,8 +714,8 @@ fn build_left_items(app: &App) -> Action { title = String::from("Select Boot and OS Partitions"); labels[0] = String::from("boot"); labels[1] = String::from("os"); - let disk_list = app.clone.disk_list.lock().unwrap(); - if let Some(index) = app.clone.disk_index_dest + let disk_list = app.state.disk_list.lock().unwrap(); + if let Some(index) = app.state.disk_index_dest && let Some(disk) = disk_list.get(index) { disk.get_parts().iter().for_each(|part| { @@ -854,7 +855,7 @@ fn build_right_items(app: &App) -> Action { line_colors: vec![Color::Cyan], }; labels.push(vec![dest_dv_line]); - let disk_list = app.clone.disk_list.lock().unwrap(); + let disk_list = app.state.disk_list.lock().unwrap(); disk_list .iter() .for_each(|disk| items.push(get_disk_description_right(disk, &None))); @@ -866,9 +867,9 @@ fn build_right_items(app: &App) -> Action { line_colors: vec![Color::Cyan], }]) }); - if let Some(index) = app.clone.disk_index_dest { + if let Some(index) = app.state.disk_index_dest { start_index += 1; - let disk_list = app.clone.disk_list.lock().unwrap(); + let disk_list = app.state.disk_list.lock().unwrap(); if let Some(disk) = disk_list.get(index) { // Disk Details items.push(get_disk_description_right(disk, &None)); @@ -897,11 +898,11 @@ fn build_right_items(app: &App) -> Action { fn create_boot_files(app: &mut App, safe_mode: SafeMode) { let mut tasks: Vec = Vec::new(); - if let Some(index) = app.clone.disk_index_dest { - let disk_list = app.clone.disk_list.lock().unwrap(); + if let Some(index) = app.state.disk_index_dest { + let disk_list = app.state.disk_list.lock().unwrap(); if let Some(disk) = disk_list.get(index) { - let letter_boot = disk.get_part_letter(app.clone.part_index_boot.unwrap()); - let letter_os = disk.get_part_letter(app.clone.part_index_os.unwrap()); + let letter_boot = disk.get_part_letter(app.state.part_index_boot.unwrap()); + let letter_os = disk.get_part_letter(app.state.part_index_os.unwrap()); tasks = configure_disk( &letter_boot, &letter_os, @@ -918,14 +919,14 @@ fn create_boot_files(app: &mut App, safe_mode: SafeMode) { fn get_disk_header(app: &App) -> Vec { let mut header_lines: Vec = Vec::new(); - if let Some(index) = app.clone.disk_index_dest { - let disk_list = app.clone.disk_list.lock().unwrap(); + if let Some(index) = app.state.disk_index_dest { + let disk_list = app.state.disk_list.lock().unwrap(); if let Some(disk) = disk_list.get(index) { let mut parts: Vec = Vec::new(); - if let Some(index) = app.clone.part_index_boot { + if let Some(index) = app.state.part_index_boot { parts.push(index); } - if let Some(index) = app.clone.part_index_os { + if let Some(index) = app.state.part_index_os { parts.push(index); } header_lines.append(&mut get_disk_description_right(disk, &Some(parts))); diff --git a/boot_diags/src/main.rs b/boot_diags/src/main.rs index b71a458..5b8974b 100644 --- a/boot_diags/src/main.rs +++ b/boot_diags/src/main.rs @@ -22,6 +22,7 @@ mod app; mod components; mod diags; mod scan; +mod state; #[tokio::main] async fn main() -> Result<()> { diff --git a/boot_diags/src/scan.rs b/boot_diags/src/scan.rs index df98f02..7d9354b 100644 --- a/boot_diags/src/scan.rs +++ b/boot_diags/src/scan.rs @@ -1,5 +1,4 @@ use color_eyre::Result; -use core::state::CloneSettings; use core::system::disk::PartitionTableType; use core::tasks::Tasks; use core::{action::Action, tasks::TaskType}; @@ -8,24 +7,25 @@ use std::sync::{Arc, Mutex}; use tokio::sync::mpsc; use crate::diags::{DiagGroup, Type as DiagType}; +use crate::state::State; pub fn queue_boot_scan_tasks( action_tx: mpsc::UnboundedSender, - clone: &CloneSettings, diag_groups: Arc>>, + state: &State, system32: String, tasks: &mut Tasks, ) -> Result<()> { if let Ok(mut diag_groups) = diag_groups.lock() { diag_groups.clear(); } - let disk_list = clone.disk_list.lock().unwrap(); - if let Some(disk_index) = clone.disk_index_dest + let disk_list = state.disk_list.lock().unwrap(); + if let Some(disk_index) = state.disk_index_dest && let Some(disk) = disk_list.get(disk_index) { let table_type = disk.part_type.clone(); - let letter_boot = disk.get_part_letter(clone.part_index_boot.unwrap()); - let letter_os = disk.get_part_letter(clone.part_index_os.unwrap()); + let letter_boot = disk.get_part_letter(state.part_index_boot.unwrap()); + let letter_os = disk.get_part_letter(state.part_index_os.unwrap()); // Safety check if letter_os.is_empty() { diff --git a/boot_diags/src/state.rs b/boot_diags/src/state.rs new file mode 100644 index 0000000..00383b5 --- /dev/null +++ b/boot_diags/src/state.rs @@ -0,0 +1,42 @@ +// This file is part of Deja-Vu. +// +// Deja-Vu is free software: you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Deja-Vu is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Deja-Vu. If not, see . +// + +use std::sync::{Arc, Mutex}; + +use core::system::{disk::Disk, drivers}; + +#[derive(Debug, Default)] +pub struct State { + pub disk_index_dest: Option, + pub disk_list: Arc>>, + pub driver_list: Vec, + pub part_index_boot: Option, + pub part_index_os: Option, + pub driver: Option, +} + +impl State { + pub fn new(disk_list: Arc>>) -> Self { + State { + disk_list, + ..Default::default() + } + } + + pub fn scan_drivers(&mut self) { + self.driver_list = drivers::scan(); + } +} diff --git a/core/src/state.rs b/core/src/state.rs index 1992a2b..d05eaf5 100644 --- a/core/src/state.rs +++ b/core/src/state.rs @@ -14,15 +14,8 @@ // along with Deja-Vu. If not, see . // -use std::sync::{Arc, Mutex}; - use serde::{Deserialize, Serialize}; -use crate::system::{ - disk::{Disk, PartitionTableType}, - drivers, -}; - #[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Mode { // Core @@ -52,28 +45,3 @@ pub enum Mode { // WinPE PEMenu, } - -#[derive(Debug, Default)] -pub struct CloneSettings { - pub disk_index_dest: Option, - pub disk_index_source: Option, - pub disk_list: Arc>>, - pub driver_list: Vec, - pub part_index_boot: Option, - pub part_index_os: Option, - pub driver: Option, - pub table_type: Option, -} - -impl CloneSettings { - pub fn new(disk_list: Arc>>) -> Self { - CloneSettings { - disk_list, - ..Default::default() - } - } - - pub fn scan_drivers(&mut self) { - self.driver_list = drivers::scan(); - } -} diff --git a/deja_vu/src/app.rs b/deja_vu/src/app.rs index 5fc447f..34afb20 100644 --- a/deja_vu/src/app.rs +++ b/deja_vu/src/app.rs @@ -26,7 +26,7 @@ use core::{ }, config::Config, line::{DVLine, get_disk_description_right, get_part_description}, - state::{CloneSettings, Mode}, + state::Mode, system::{ boot, cpu::get_cpu_name, disk::PartitionTableType, diskpart::build_dest_format_script, drivers, @@ -51,6 +51,8 @@ use ratatui::{ use tokio::sync::mpsc; use tracing::{debug, info}; +use crate::state::State; + pub struct App { // TUI action_rx: mpsc::UnboundedReceiver, @@ -63,11 +65,11 @@ pub struct App { should_suspend: bool, tick_rate: f64, // App - clone: CloneSettings, cur_mode: Mode, list: StatefulList, prev_mode: Mode, selections: Vec>, + state: State, tasks: Tasks, } @@ -94,7 +96,7 @@ impl App { should_suspend: false, tick_rate, // App - clone: CloneSettings::new(disk_list_arc), + state: State::new(disk_list_arc), cur_mode: Mode::default(), list: StatefulList::default(), prev_mode: Mode::default(), @@ -167,7 +169,7 @@ impl App { info!("Setting mode to {new_mode:?}"); self.cur_mode = new_mode; match new_mode { - Mode::InstallDrivers => self.clone.scan_drivers(), + Mode::InstallDrivers => self.state.scan_drivers(), Mode::ScanDisks => { self.prev_mode = self.cur_mode; if self.tasks.idle() { @@ -194,11 +196,11 @@ impl App { )); // Build Diskpart script to format destination disk - let disk_list = self.clone.disk_list.lock().unwrap(); - if let Some(disk_index) = self.clone.disk_index_dest + let disk_list = self.state.disk_list.lock().unwrap(); + if let Some(disk_index) = self.state.disk_index_dest && let Some(disk) = disk_list.get(disk_index) { - let table_type = self.clone.table_type.clone().unwrap(); + let table_type = self.state.table_type.clone().unwrap(); let diskpart_script = build_dest_format_script(disk.id, &table_type); self.tasks.add(TaskType::Diskpart(diskpart_script)); } @@ -212,7 +214,7 @@ impl App { self.config.clone_app_path.clone(), Vec::new(), )); - if let Some(dest_index) = self.clone.disk_index_dest { + if let Some(dest_index) = self.state.disk_index_dest { self.tasks.add(TaskType::UpdateDestDisk(dest_index)); } } @@ -226,13 +228,13 @@ impl App { let system32 = get_system32_path(&self.action_tx); // Add actions - let disk_list = self.clone.disk_list.lock().unwrap(); - if let Some(disk_index) = self.clone.disk_index_dest + let disk_list = self.state.disk_list.lock().unwrap(); + if let Some(disk_index) = self.state.disk_index_dest && let Some(disk) = disk_list.get(disk_index) { - let table_type = self.clone.table_type.clone().unwrap(); - let letter_boot = disk.get_part_letter(self.clone.part_index_boot.unwrap()); - let letter_os = disk.get_part_letter(self.clone.part_index_os.unwrap()); + let table_type = self.state.table_type.clone().unwrap(); + let letter_boot = disk.get_part_letter(self.state.part_index_boot.unwrap()); + let letter_os = disk.get_part_letter(self.state.part_index_os.unwrap()); // Safety check if letter_boot.is_empty() || letter_os.is_empty() { @@ -254,7 +256,7 @@ impl App { } // Inject driver(s) (if selected) - if let Some(driver) = &self.clone.driver { + if let Some(driver) = &self.state.driver { if let Ok(task) = boot::inject_driver(driver, &letter_os, &system32) { self.tasks.add(task); } else { @@ -414,22 +416,22 @@ impl App { match self.cur_mode { Mode::InstallDrivers => { if let Some(index) = one - && let Some(driver) = self.clone.driver_list.get(index).cloned() + && let Some(driver) = self.state.driver_list.get(index).cloned() { drivers::load(&driver.inf_paths); - self.clone.driver = Some(driver); + self.state.driver = Some(driver); } } Mode::SelectDisks => { - self.clone.disk_index_source = one; - self.clone.disk_index_dest = two; + self.state.disk_index_source = one; + self.state.disk_index_dest = two; } Mode::SelectParts => { - self.clone.part_index_boot = one; - self.clone.part_index_os = two; + self.state.part_index_boot = one; + self.state.part_index_os = two; } Mode::SelectTableType => { - self.clone.table_type = { + self.state.table_type = { if let Some(index) = one { match index { 0 => Some(PartitionTableType::Guid), @@ -452,7 +454,7 @@ impl App { // Clear TableType selection match new_mode { Mode::SelectDisks | Mode::SelectTableType => { - self.clone.table_type = None; + self.state.table_type = None; } _ => {} } @@ -466,8 +468,8 @@ impl App { Mode::SelectTableType | Mode::Confirm => { // Select source/dest disks self.action_tx.send(Action::SelectRight( - self.clone.disk_index_source, - self.clone.disk_index_dest, + self.state.disk_index_source, + self.state.disk_index_dest, ))?; } Mode::SelectParts => { @@ -475,7 +477,7 @@ impl App { self.action_tx.send(Action::Select(Some(0), None))?; // Highlight 2nd or 3rd partition as OS partition - let index = if let Some(table_type) = &self.clone.table_type { + let index = if let Some(table_type) = &self.state.table_type { match table_type { PartitionTableType::Guid => 2, PartitionTableType::Legacy => 1, @@ -649,7 +651,7 @@ fn build_left_items(app: &App, cur_mode: Mode) -> Action { Mode::InstallDrivers => { select_type = SelectionType::One; title = String::from("Install Drivers"); - app.clone + app.state .driver_list .iter() .for_each(|driver| items.push(driver.to_string())); @@ -659,7 +661,7 @@ fn build_left_items(app: &App, cur_mode: Mode) -> Action { title = String::from("Select Source and Destination Disks"); labels.push(String::from("source")); labels.push(String::from("dest")); - let disk_list = app.clone.disk_list.lock().unwrap(); + let disk_list = app.state.disk_list.lock().unwrap(); disk_list .iter() .for_each(|disk| items.push(disk.description.to_string())); @@ -683,8 +685,8 @@ fn build_left_items(app: &App, cur_mode: Mode) -> Action { title = String::from("Select Boot and OS Partitions"); labels.push(String::from("boot")); labels.push(String::from("os")); - let disk_list = app.clone.disk_list.lock().unwrap(); - if let Some(index) = app.clone.disk_index_dest + let disk_list = app.state.disk_list.lock().unwrap(); + if let Some(index) = app.state.disk_index_dest && let Some(disk) = disk_list.get(index) { disk.get_parts().iter().for_each(|part| { @@ -739,7 +741,7 @@ fn build_right_items(app: &App, cur_mode: Mode) -> Action { ], line_colors: vec![Color::Cyan, Color::Red], }; - if let Some(table_type) = &app.clone.table_type { + if let Some(table_type) = &app.state.table_type { // Show table type let type_str = match table_type { PartitionTableType::Guid => "GPT", @@ -755,7 +757,7 @@ fn build_right_items(app: &App, cur_mode: Mode) -> Action { } else { labels.push(vec![dest_dv_line]); } - let disk_list = app.clone.disk_list.lock().unwrap(); + let disk_list = app.state.disk_list.lock().unwrap(); disk_list .iter() .for_each(|disk| items.push(get_disk_description_right(disk, &None))); @@ -767,9 +769,9 @@ fn build_right_items(app: &App, cur_mode: Mode) -> Action { line_colors: vec![Color::Cyan], }]); } - if let Some(index) = app.clone.disk_index_dest { + if let Some(index) = app.state.disk_index_dest { start_index = 1; - let disk_list = app.clone.disk_list.lock().unwrap(); + let disk_list = app.state.disk_list.lock().unwrap(); if let Some(disk) = disk_list.get(index) { // Disk Details items.push(get_disk_description_right(disk, &None)); diff --git a/deja_vu/src/main.rs b/deja_vu/src/main.rs index 1aa1772..8048d12 100644 --- a/deja_vu/src/main.rs +++ b/deja_vu/src/main.rs @@ -19,6 +19,7 @@ use color_eyre::Result; use crate::app::App; mod app; +mod state; #[tokio::main] async fn main() -> Result<()> { diff --git a/deja_vu/src/state.rs b/deja_vu/src/state.rs new file mode 100644 index 0000000..60bae71 --- /dev/null +++ b/deja_vu/src/state.rs @@ -0,0 +1,47 @@ +// This file is part of Deja-Vu. +// +// Deja-Vu is free software: you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Deja-Vu is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Deja-Vu. If not, see . +// + +use std::sync::{Arc, Mutex}; + +use core::system::{ + disk::{Disk, PartitionTableType}, + drivers, +}; + +#[derive(Debug, Default)] +pub struct State { + pub disk_index_dest: Option, + pub disk_index_source: Option, + pub disk_list: Arc>>, + pub driver_list: Vec, + pub part_index_boot: Option, + pub part_index_os: Option, + pub driver: Option, + pub table_type: Option, +} + +impl State { + pub fn new(disk_list: Arc>>) -> Self { + State { + disk_list, + ..Default::default() + } + } + + pub fn scan_drivers(&mut self) { + self.driver_list = drivers::scan(); + } +}