Compare commits
4 commits
83b01a1230
...
de7520324b
| Author | SHA1 | Date | |
|---|---|---|---|
| de7520324b | |||
| b2b90bb946 | |||
| 1ce7f76229 | |||
| aa4ac8d5e8 |
8 changed files with 314 additions and 93 deletions
|
|
@ -22,11 +22,16 @@ use core::{
|
||||||
config::Config,
|
config::Config,
|
||||||
line::{get_disk_description_right, get_part_description, DVLine},
|
line::{get_disk_description_right, get_part_description, DVLine},
|
||||||
state::{CloneSettings, Mode},
|
state::{CloneSettings, Mode},
|
||||||
system::{cpu::get_cpu_name, drivers},
|
system::{
|
||||||
|
boot::{self, SafeMode},
|
||||||
|
cpu::get_cpu_name,
|
||||||
|
drivers,
|
||||||
|
},
|
||||||
tasks::{Task, Tasks},
|
tasks::{Task, Tasks},
|
||||||
tui::{Event, Tui},
|
tui::{Event, Tui},
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
|
env,
|
||||||
iter::zip,
|
iter::zip,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
@ -56,7 +61,9 @@ pub struct App {
|
||||||
clone: CloneSettings,
|
clone: CloneSettings,
|
||||||
cur_mode: Mode,
|
cur_mode: Mode,
|
||||||
list: StatefulList<Mode>,
|
list: StatefulList<Mode>,
|
||||||
|
boot_modes: Vec<SafeMode>,
|
||||||
selections: Vec<Option<usize>>,
|
selections: Vec<Option<usize>>,
|
||||||
|
system32: String,
|
||||||
tasks: Tasks,
|
tasks: Tasks,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -70,7 +77,7 @@ impl App {
|
||||||
Mode::BootDiags,
|
Mode::BootDiags,
|
||||||
Mode::BootSetup,
|
Mode::BootSetup,
|
||||||
Mode::InjectDrivers,
|
Mode::InjectDrivers,
|
||||||
Mode::ToggleSafeMode,
|
Mode::SetBootMode,
|
||||||
]);
|
]);
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
// TUI
|
// TUI
|
||||||
|
|
@ -94,11 +101,32 @@ impl App {
|
||||||
clone: CloneSettings::new(disk_list_arc),
|
clone: CloneSettings::new(disk_list_arc),
|
||||||
cur_mode: Mode::Home,
|
cur_mode: Mode::Home,
|
||||||
list,
|
list,
|
||||||
|
boot_modes: vec![SafeMode::Enable, SafeMode::Disable],
|
||||||
|
system32: String::new(),
|
||||||
selections: vec![None, None],
|
selections: vec![None, None],
|
||||||
tasks,
|
tasks,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn inject_driver(&mut self, index: usize) {
|
||||||
|
if let Some(driver) = self.clone.driver_list.get(index) {
|
||||||
|
if let Some(disk_index) = self.clone.disk_index_dest {
|
||||||
|
let disk_list = self.clone.disk_list.lock().unwrap();
|
||||||
|
if let Some(disk) = disk_list.get(disk_index) {
|
||||||
|
if let Some(boot_index) = self.clone.part_index_boot {
|
||||||
|
if let Ok(task) = boot::inject_driver(
|
||||||
|
driver,
|
||||||
|
disk.get_part_letter(boot_index).as_str(),
|
||||||
|
&self.system32,
|
||||||
|
) {
|
||||||
|
self.tasks.add(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn next_mode(&mut self) -> Mode {
|
pub fn next_mode(&mut self) -> Mode {
|
||||||
match self.cur_mode {
|
match self.cur_mode {
|
||||||
Mode::Home => Mode::ScanDisks,
|
Mode::Home => Mode::ScanDisks,
|
||||||
|
|
@ -106,13 +134,8 @@ impl App {
|
||||||
Mode::ScanDisks => Mode::SelectDisks,
|
Mode::ScanDisks => Mode::SelectDisks,
|
||||||
Mode::SelectDisks => Mode::SelectParts,
|
Mode::SelectDisks => Mode::SelectParts,
|
||||||
Mode::SelectParts => Mode::DiagMenu,
|
Mode::SelectParts => Mode::DiagMenu,
|
||||||
Mode::DiagMenu => {
|
Mode::BootDiags | Mode::BootSetup | Mode::InjectDrivers | Mode::SetBootMode => {
|
||||||
// Use highlighted entry
|
Mode::DiagMenu
|
||||||
if let Some(new_mode) = self.list.get_selected() {
|
|
||||||
new_mode
|
|
||||||
} else {
|
|
||||||
self.cur_mode
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Mode::Failed => Mode::Failed,
|
Mode::Failed => Mode::Failed,
|
||||||
// Default to current mode
|
// Default to current mode
|
||||||
|
|
@ -120,10 +143,34 @@ impl App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_boot_mode(&mut self, boot_mode: SafeMode) {
|
||||||
|
info!("Setting boot mode to: {:?}", boot_mode);
|
||||||
|
let disk_list = self.clone.disk_list.lock().unwrap();
|
||||||
|
if let Some(disk_index) = self.clone.disk_index_dest {
|
||||||
|
if let Some(disk) = disk_list.get(disk_index) {
|
||||||
|
if let Some(boot_index) = self.clone.part_index_boot {
|
||||||
|
if let Ok(task) = boot::set_mode(
|
||||||
|
disk.get_part_letter(boot_index).as_str(),
|
||||||
|
boot_mode,
|
||||||
|
&self.system32,
|
||||||
|
&disk.part_type,
|
||||||
|
) {
|
||||||
|
self.tasks.add(task);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_mode(&mut self, new_mode: Mode) -> Result<()> {
|
pub fn set_mode(&mut self, new_mode: Mode) -> Result<()> {
|
||||||
info!("Setting mode to {new_mode:?}");
|
info!("Setting mode to {new_mode:?}");
|
||||||
self.cur_mode = new_mode;
|
self.cur_mode = new_mode;
|
||||||
match new_mode {
|
match new_mode {
|
||||||
|
Mode::DiagMenu => {
|
||||||
|
self.selections[0] = None;
|
||||||
|
self.selections[1] = None;
|
||||||
|
self.list.select_first_item();
|
||||||
|
}
|
||||||
Mode::InjectDrivers | Mode::InstallDrivers => self.clone.scan_drivers(),
|
Mode::InjectDrivers | Mode::InstallDrivers => self.clone.scan_drivers(),
|
||||||
Mode::ScanDisks => {
|
Mode::ScanDisks => {
|
||||||
if self.tasks.idle() {
|
if self.tasks.idle() {
|
||||||
|
|
@ -157,7 +204,22 @@ impl App {
|
||||||
}
|
}
|
||||||
|
|
||||||
let action_tx = self.action_tx.clone();
|
let action_tx = self.action_tx.clone();
|
||||||
|
|
||||||
|
// Late init
|
||||||
|
self.system32 = if cfg!(windows) {
|
||||||
|
if let Ok(path) = env::var("SYSTEMROOT") {
|
||||||
|
format!("{path}/System32")
|
||||||
|
} else {
|
||||||
|
self.action_tx.send(Action::Error(String::from(
|
||||||
|
"ERROR\n\n\nFailed to find SYSTEMROOT",
|
||||||
|
)))?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String::from(".")
|
||||||
|
};
|
||||||
action_tx.send(Action::SetMode(Mode::ScanDisks))?;
|
action_tx.send(Action::SetMode(Mode::ScanDisks))?;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
self.handle_events(&mut tui).await?;
|
self.handle_events(&mut tui).await?;
|
||||||
self.handle_actions(&mut tui)?;
|
self.handle_actions(&mut tui)?;
|
||||||
|
|
@ -247,8 +309,23 @@ impl App {
|
||||||
.send(Action::DisplayPopup(popup::Type::Error, msg.clone()))?;
|
.send(Action::DisplayPopup(popup::Type::Error, msg.clone()))?;
|
||||||
self.action_tx.send(Action::SetMode(Mode::Failed))?;
|
self.action_tx.send(Action::SetMode(Mode::Failed))?;
|
||||||
}
|
}
|
||||||
|
Action::InstallDriver => {
|
||||||
|
self.action_tx.send(Action::SetMode(Mode::InstallDrivers))?;
|
||||||
|
}
|
||||||
|
Action::NextScreen => {
|
||||||
|
let next_mode = self.next_mode();
|
||||||
|
self.cur_mode = next_mode;
|
||||||
|
self.action_tx.send(Action::DismissPopup)?;
|
||||||
|
self.action_tx.send(Action::SetMode(next_mode))?;
|
||||||
|
}
|
||||||
Action::Process => match self.cur_mode {
|
Action::Process => match self.cur_mode {
|
||||||
Mode::DiagMenu => {
|
Mode::DiagMenu => {
|
||||||
|
// Use highlighted entry
|
||||||
|
if let Some(new_mode) = self.list.get_selected() {
|
||||||
|
self.action_tx.send(Action::SetMode(new_mode))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Mode::BootDiags | Mode::BootSetup => {
|
||||||
let new_mode = self.next_mode();
|
let new_mode = self.next_mode();
|
||||||
self.action_tx.send(Action::SetMode(new_mode))?;
|
self.action_tx.send(Action::SetMode(new_mode))?;
|
||||||
}
|
}
|
||||||
|
|
@ -257,8 +334,12 @@ impl App {
|
||||||
Action::Resize(w, h) => self.handle_resize(tui, w, h)?,
|
Action::Resize(w, h) => self.handle_resize(tui, w, h)?,
|
||||||
Action::Render => self.render(tui)?,
|
Action::Render => self.render(tui)?,
|
||||||
Action::ScanDisks => self.action_tx.send(Action::SetMode(Mode::ScanDisks))?,
|
Action::ScanDisks => self.action_tx.send(Action::SetMode(Mode::ScanDisks))?,
|
||||||
Action::Select(one, two) => {
|
Action::Select(one, two) => match self.cur_mode {
|
||||||
match self.cur_mode {
|
Mode::InjectDrivers => {
|
||||||
|
if let Some(index) = one {
|
||||||
|
self.inject_driver(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
Mode::InstallDrivers => {
|
Mode::InstallDrivers => {
|
||||||
if let Some(index) = one {
|
if let Some(index) = one {
|
||||||
if let Some(driver) = self.clone.driver_list.get(index).cloned() {
|
if let Some(driver) = self.clone.driver_list.get(index).cloned() {
|
||||||
|
|
@ -274,13 +355,16 @@ impl App {
|
||||||
self.clone.part_index_boot = one;
|
self.clone.part_index_boot = one;
|
||||||
self.clone.part_index_os = two;
|
self.clone.part_index_os = two;
|
||||||
}
|
}
|
||||||
|
Mode::SetBootMode => {
|
||||||
|
if let Some(index) = one {
|
||||||
|
if let Some(boot_mode) = self.boot_modes.get(index) {
|
||||||
|
self.set_boot_mode(boot_mode.to_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
},
|
||||||
self.selections[0] = one;
|
|
||||||
self.selections[1] = two;
|
|
||||||
}
|
|
||||||
Action::SetMode(new_mode) => {
|
Action::SetMode(new_mode) => {
|
||||||
self.cur_mode = new_mode;
|
|
||||||
self.set_mode(new_mode)?;
|
self.set_mode(new_mode)?;
|
||||||
self.action_tx
|
self.action_tx
|
||||||
.send(Action::UpdateFooter(build_footer_string(self.cur_mode)))?;
|
.send(Action::UpdateFooter(build_footer_string(self.cur_mode)))?;
|
||||||
|
|
@ -382,23 +466,28 @@ fn get_chunks(r: Rect) -> Vec<Rect> {
|
||||||
|
|
||||||
fn build_footer_string(cur_mode: Mode) -> String {
|
fn build_footer_string(cur_mode: Mode) -> String {
|
||||||
match cur_mode {
|
match cur_mode {
|
||||||
// Boot Diags
|
Mode::BootDiags | Mode::BootSetup | Mode::Home | Mode::PEMenu | Mode::ScanDisks => {
|
||||||
Mode::BootSetup
|
String::from("(q) to quit")
|
||||||
| Mode::DiagMenu
|
}
|
||||||
| Mode::InjectDrivers
|
Mode::InstallDrivers | Mode::InjectDrivers | Mode::SetBootMode => {
|
||||||
| Mode::PEMenu
|
String::from("(Enter) to select / (q) to quit")
|
||||||
| Mode::ToggleSafeMode => String::from("(Enter) or (q) to quit"),
|
}
|
||||||
// Copied from Clone
|
Mode::DiagMenu | Mode::SelectParts => {
|
||||||
Mode::Home | Mode::ScanDisks | Mode::BootDiags => String::from("(q) to quit"),
|
String::from("(Enter) to select / (s) to start over / (q) to quit")
|
||||||
Mode::SelectParts => String::from("(Enter) to select / (s) to start over / (q) to quit"),
|
}
|
||||||
Mode::SelectDisks => String::from(
|
Mode::SelectDisks => String::from(
|
||||||
"(Enter) to select / / (i) to install driver / (r) to rescan / (q) to quit",
|
"(Enter) to select / / (i) to install driver / (r) to rescan / (q) to quit",
|
||||||
),
|
),
|
||||||
Mode::SelectTableType => String::from("(Enter) to select / (b) to go back / (q) to quit"),
|
Mode::Failed => String::from("(Enter) or (q) to quit"),
|
||||||
Mode::Confirm => String::from("(Enter) to confirm / (b) to go back / (q) to quit"),
|
|
||||||
Mode::Done | Mode::Failed | Mode::InstallDrivers => String::from("(Enter) or (q) to quit"),
|
|
||||||
// Invalid states
|
// Invalid states
|
||||||
Mode::Clone | Mode::PreClone | Mode::PostClone => panic!("This shouldn't happen?"),
|
Mode::Confirm
|
||||||
|
| Mode::Clone
|
||||||
|
| Mode::PreClone
|
||||||
|
| Mode::PostClone
|
||||||
|
| Mode::Done
|
||||||
|
| Mode::SelectTableType => {
|
||||||
|
panic!("This shouldn't happen?")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -451,8 +540,8 @@ fn build_left_items(app: &App) -> Action {
|
||||||
Mode::SelectParts => {
|
Mode::SelectParts => {
|
||||||
select_num = 2;
|
select_num = 2;
|
||||||
title = String::from("Select Boot and OS Partitions");
|
title = String::from("Select Boot and OS Partitions");
|
||||||
labels.push(String::from("boot"));
|
labels[0] = String::from("boot");
|
||||||
labels.push(String::from("os"));
|
labels[1] = String::from("os");
|
||||||
let disk_list = app.clone.disk_list.lock().unwrap();
|
let disk_list = app.clone.disk_list.lock().unwrap();
|
||||||
if let Some(index) = app.clone.disk_index_dest {
|
if let Some(index) = app.clone.disk_index_dest {
|
||||||
if let Some(disk) = disk_list.get(index) {
|
if let Some(disk) = disk_list.get(index) {
|
||||||
|
|
@ -462,11 +551,18 @@ fn build_left_items(app: &App) -> Action {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Mode::BootDiags | Mode::BootSetup | Mode::ToggleSafeMode => {
|
Mode::BootDiags | Mode::BootSetup => {
|
||||||
select_num = 0;
|
select_num = 0;
|
||||||
let (new_title, _) = get_mode_strings(app.cur_mode);
|
let (new_title, _) = get_mode_strings(app.cur_mode);
|
||||||
title = new_title;
|
title = new_title;
|
||||||
}
|
}
|
||||||
|
Mode::SetBootMode => {
|
||||||
|
select_num = 1;
|
||||||
|
title = String::from("Set Boot Mode");
|
||||||
|
app.boot_modes.iter().for_each(|entry| {
|
||||||
|
items.push(format!("{:?} Safe Mode", entry));
|
||||||
|
});
|
||||||
|
}
|
||||||
Mode::Done | Mode::Failed => {
|
Mode::Done | Mode::Failed => {
|
||||||
select_num = 0;
|
select_num = 0;
|
||||||
title = String::from("Done");
|
title = String::from("Done");
|
||||||
|
|
@ -485,11 +581,72 @@ fn build_left_items(app: &App) -> Action {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_right_items(app: &App) -> Action {
|
fn build_right_items(app: &App) -> Action {
|
||||||
let mut items = Vec::new();
|
let mut items: Vec<Vec<DVLine>> = Vec::new();
|
||||||
let mut labels: Vec<Vec<DVLine>> = Vec::new();
|
let mut labels: Vec<Vec<DVLine>> = Vec::new();
|
||||||
let mut start_index = 0;
|
let mut start_index = 0;
|
||||||
|
// TODO: DELETE THIS SECTION
|
||||||
|
start_index = 1;
|
||||||
|
items.push(vec![
|
||||||
|
DVLine {
|
||||||
|
line_parts: vec![format!("Mode: {:?}", app.cur_mode)],
|
||||||
|
line_colors: vec![Color::Reset],
|
||||||
|
},
|
||||||
|
DVLine {
|
||||||
|
line_parts: vec![format!(
|
||||||
|
"Parts: {:?} // {:?}",
|
||||||
|
app.clone.part_index_boot, app.clone.part_index_os
|
||||||
|
)],
|
||||||
|
line_colors: vec![Color::Reset],
|
||||||
|
},
|
||||||
|
DVLine {
|
||||||
|
line_parts: vec![format!(
|
||||||
|
"Selected: {:?} // {:?}",
|
||||||
|
app.list.selected(),
|
||||||
|
app.list.get_selected(),
|
||||||
|
)],
|
||||||
|
line_colors: vec![Color::Reset],
|
||||||
|
},
|
||||||
|
DVLine {
|
||||||
|
line_parts: vec![String::from("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")],
|
||||||
|
line_colors: vec![Color::Reset],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
// TODO: DELETE THIS SECTION
|
||||||
match app.cur_mode {
|
match app.cur_mode {
|
||||||
Mode::DiagMenu => {
|
Mode::DiagMenu => {
|
||||||
|
let mut header_lines: Vec<DVLine> = Vec::new();
|
||||||
|
if let Some(index) = app.clone.disk_index_dest {
|
||||||
|
let disk_list = app.clone.disk_list.lock().unwrap();
|
||||||
|
if let Some(disk) = disk_list.get(index) {
|
||||||
|
let mut parts: Vec<usize> = Vec::new();
|
||||||
|
if let Some(index) = app.clone.part_index_boot {
|
||||||
|
parts.push(index);
|
||||||
|
}
|
||||||
|
if let Some(index) = app.clone.part_index_os {
|
||||||
|
parts.push(index);
|
||||||
|
}
|
||||||
|
// Disk Details
|
||||||
|
header_lines.append(&mut vec![
|
||||||
|
DVLine {
|
||||||
|
line_parts: vec![String::from("Disk")],
|
||||||
|
line_colors: vec![Color::Cyan],
|
||||||
|
},
|
||||||
|
DVLine {
|
||||||
|
line_parts: vec![String::new()],
|
||||||
|
line_colors: vec![Color::Reset],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
header_lines.append(&mut get_disk_description_right(&disk, Some(parts)));
|
||||||
|
|
||||||
|
// Add header
|
||||||
|
if !header_lines.is_empty() {
|
||||||
|
items[0].append(&mut header_lines);
|
||||||
|
// TODO: Replace line above with lines below
|
||||||
|
// items.push(header_lines);
|
||||||
|
// start_index = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
app.list.items.iter().for_each(|mode| {
|
app.list.items.iter().for_each(|mode| {
|
||||||
let (name, description) = get_mode_strings(*mode);
|
let (name, description) = get_mode_strings(*mode);
|
||||||
items.push(vec![
|
items.push(vec![
|
||||||
|
|
@ -522,13 +679,13 @@ fn build_right_items(app: &App) -> Action {
|
||||||
Mode::SelectDisks => {
|
Mode::SelectDisks => {
|
||||||
let dest_dv_line = DVLine {
|
let dest_dv_line = DVLine {
|
||||||
line_parts: vec![String::from("Disk")],
|
line_parts: vec![String::from("Disk")],
|
||||||
line_colors: vec![Color::Cyan, Color::Red],
|
line_colors: vec![Color::Cyan],
|
||||||
};
|
};
|
||||||
labels.push(vec![dest_dv_line]);
|
labels.push(vec![dest_dv_line]);
|
||||||
let disk_list = app.clone.disk_list.lock().unwrap();
|
let disk_list = app.clone.disk_list.lock().unwrap();
|
||||||
disk_list
|
disk_list
|
||||||
.iter()
|
.iter()
|
||||||
.for_each(|disk| items.push(get_disk_description_right(&disk)));
|
.for_each(|disk| items.push(get_disk_description_right(&disk, None)));
|
||||||
}
|
}
|
||||||
Mode::SelectParts => {
|
Mode::SelectParts => {
|
||||||
vec!["Boot", "OS"].iter().for_each(|s| {
|
vec!["Boot", "OS"].iter().for_each(|s| {
|
||||||
|
|
@ -542,7 +699,7 @@ fn build_right_items(app: &App) -> Action {
|
||||||
let disk_list = app.clone.disk_list.lock().unwrap();
|
let disk_list = app.clone.disk_list.lock().unwrap();
|
||||||
if let Some(disk) = disk_list.get(index) {
|
if let Some(disk) = disk_list.get(index) {
|
||||||
// Disk Details
|
// Disk Details
|
||||||
items.push(get_disk_description_right(&disk));
|
items.push(get_disk_description_right(&disk, None));
|
||||||
|
|
||||||
// Partition Details
|
// Partition Details
|
||||||
disk.parts
|
disk.parts
|
||||||
|
|
@ -551,6 +708,24 @@ fn build_right_items(app: &App) -> Action {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Mode::SetBootMode => {
|
||||||
|
app.boot_modes.iter().for_each(|mode| {
|
||||||
|
match mode {
|
||||||
|
SafeMode::Disable => {
|
||||||
|
items.push(vec![DVLine {
|
||||||
|
line_parts: vec![String::from("Disable Safe Mode")],
|
||||||
|
line_colors: vec![Color::Reset],
|
||||||
|
}]);
|
||||||
|
}
|
||||||
|
SafeMode::Enable => {
|
||||||
|
items.push(vec![DVLine {
|
||||||
|
line_parts: vec![String::from("Enable Safe Mode (minimal)")],
|
||||||
|
line_colors: vec![Color::Reset],
|
||||||
|
}]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
Action::UpdateRight(labels, start_index, items)
|
Action::UpdateRight(labels, start_index, items)
|
||||||
|
|
@ -570,7 +745,7 @@ fn get_mode_strings(mode: Mode) -> (String, String) {
|
||||||
String::from("Inject Drivers"),
|
String::from("Inject Drivers"),
|
||||||
String::from("Inject drivers into existing Windows environment"),
|
String::from("Inject drivers into existing Windows environment"),
|
||||||
),
|
),
|
||||||
Mode::ToggleSafeMode => (
|
Mode::SetBootMode => (
|
||||||
String::from("Toggle Safe Mode"),
|
String::from("Toggle Safe Mode"),
|
||||||
String::from("Enable or disable safe mode"),
|
String::from("Enable or disable safe mode"),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,7 @@
|
||||||
"<Enter>": "Process",
|
"<Enter>": "Process",
|
||||||
"<Up>": "KeyUp",
|
"<Up>": "KeyUp",
|
||||||
"<Down>": "KeyDown",
|
"<Down>": "KeyDown",
|
||||||
|
"<s>": "ScanDisks",
|
||||||
"<q>": "Quit",
|
"<q>": "Quit",
|
||||||
"<Ctrl-d>": "Quit",
|
"<Ctrl-d>": "Quit",
|
||||||
"<Ctrl-c>": "Quit",
|
"<Ctrl-c>": "Quit",
|
||||||
|
|
@ -131,7 +132,7 @@
|
||||||
"<Ctrl-c>": "Quit",
|
"<Ctrl-c>": "Quit",
|
||||||
"<Ctrl-z>": "Suspend"
|
"<Ctrl-z>": "Suspend"
|
||||||
},
|
},
|
||||||
"ToggleSafeMode": {
|
"SetBootMode": {
|
||||||
"<Enter>": "Process",
|
"<Enter>": "Process",
|
||||||
"<Up>": "KeyUp",
|
"<Up>": "KeyUp",
|
||||||
"<Down>": "KeyDown",
|
"<Down>": "KeyDown",
|
||||||
|
|
|
||||||
|
|
@ -138,13 +138,9 @@ impl Component for Left {
|
||||||
.areas(area);
|
.areas(area);
|
||||||
|
|
||||||
// Title
|
// Title
|
||||||
let title_text = if self.selections[1].is_some() || self.select_num == 1 {
|
let title = Paragraph::new(
|
||||||
"Confirm Selections"
|
Line::from(Span::styled(self.title_text.as_str(), Style::default())).centered(),
|
||||||
} else {
|
)
|
||||||
self.title_text.as_str()
|
|
||||||
};
|
|
||||||
let title =
|
|
||||||
Paragraph::new(Line::from(Span::styled(title_text, Style::default())).centered())
|
|
||||||
.block(Block::default().borders(Borders::NONE));
|
.block(Block::default().borders(Borders::NONE));
|
||||||
frame.render_widget(title, title_area);
|
frame.render_widget(title, title_area);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ impl<T: Clone> StatefulList<T> {
|
||||||
self.state.selected()
|
self.state.selected()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select_first_item(&mut self) {
|
pub fn select_first_item(&mut self) {
|
||||||
if self.items.is_empty() {
|
if self.items.is_empty() {
|
||||||
self.state.select(None);
|
self.state.select(None);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,10 @@ impl DVLine {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_disk_description_right(disk: &Disk) -> Vec<DVLine> {
|
pub fn get_disk_description_right(
|
||||||
|
disk: &Disk,
|
||||||
|
boot_os_indicies: Option<Vec<usize>>,
|
||||||
|
) -> Vec<DVLine> {
|
||||||
let mut description: Vec<DVLine> = vec![
|
let mut description: Vec<DVLine> = vec![
|
||||||
DVLine {
|
DVLine {
|
||||||
line_parts: vec![format!(
|
line_parts: vec![format!(
|
||||||
|
|
@ -67,12 +70,29 @@ pub fn get_disk_description_right(disk: &Disk) -> Vec<DVLine> {
|
||||||
line_colors: vec![Color::Blue],
|
line_colors: vec![Color::Blue],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
for line in &disk.parts_description {
|
disk.parts_description
|
||||||
description.push(DVLine {
|
.iter()
|
||||||
line_parts: vec![line.clone()],
|
.enumerate()
|
||||||
line_colors: vec![Color::Reset],
|
.for_each(|(index, line)| {
|
||||||
});
|
let mut line_parts = vec![line.clone()];
|
||||||
|
let mut line_colors = vec![Color::Reset];
|
||||||
|
if let Some(indicies) = &boot_os_indicies {
|
||||||
|
let boot_index = indicies.get(0);
|
||||||
|
if boot_index.is_some_and(|i| i == &index) {
|
||||||
|
line_parts.push(String::from(" <-- Boot Partition"));
|
||||||
|
line_colors.push(Color::Cyan);
|
||||||
}
|
}
|
||||||
|
let boot_index = indicies.get(1);
|
||||||
|
if boot_index.is_some_and(|i| i == &index) {
|
||||||
|
line_parts.push(String::from(" <-- OS Partition"));
|
||||||
|
line_colors.push(Color::Cyan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
description.push(DVLine {
|
||||||
|
line_parts,
|
||||||
|
line_colors,
|
||||||
|
});
|
||||||
|
});
|
||||||
description
|
description
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ pub enum Mode {
|
||||||
BootDiags,
|
BootDiags,
|
||||||
BootSetup,
|
BootSetup,
|
||||||
InjectDrivers,
|
InjectDrivers,
|
||||||
ToggleSafeMode,
|
SetBootMode,
|
||||||
// Clone
|
// Clone
|
||||||
ScanDisks,
|
ScanDisks,
|
||||||
InstallDrivers,
|
InstallDrivers,
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,13 @@ use crate::tasks::Task;
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
pub enum SafeMode {
|
||||||
|
#[default]
|
||||||
|
Disable,
|
||||||
|
Enable,
|
||||||
|
}
|
||||||
|
|
||||||
pub fn configure_disk(
|
pub fn configure_disk(
|
||||||
letter_boot: &str,
|
letter_boot: &str,
|
||||||
letter_os: &str,
|
letter_os: &str,
|
||||||
|
|
@ -55,25 +62,10 @@ pub fn configure_disk(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock in safe mode
|
// Lock in safe mode
|
||||||
let bcd_path = match table_type {
|
tasks.push(
|
||||||
PartitionTableType::Guid => {
|
set_mode(letter_boot, SafeMode::Enable, system32, &table_type)
|
||||||
format!("{letter_boot}:\\EFI\\Microsoft\\Boot\\BCD")
|
.expect("Failed to create set_mode task."),
|
||||||
}
|
);
|
||||||
PartitionTableType::Legacy => {
|
|
||||||
format!("{letter_boot}:\\Boot\\BCD")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
tasks.push(Task::Command(
|
|
||||||
PathBuf::from(format!("{system32}/bcdedit.exe")),
|
|
||||||
vec![
|
|
||||||
String::from("/store"),
|
|
||||||
bcd_path,
|
|
||||||
String::from("/set"),
|
|
||||||
String::from("{default}"),
|
|
||||||
String::from("safeboot"),
|
|
||||||
String::from("minimal"),
|
|
||||||
],
|
|
||||||
));
|
|
||||||
|
|
||||||
// Done
|
// Done
|
||||||
tasks
|
tasks
|
||||||
|
|
@ -92,3 +84,39 @@ pub fn inject_driver(driver: &Driver, letter_os: &str, system32: &str) -> Result
|
||||||
],
|
],
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_mode(
|
||||||
|
letter_boot: &str,
|
||||||
|
mode: SafeMode,
|
||||||
|
system32: &str,
|
||||||
|
table_type: &PartitionTableType,
|
||||||
|
) -> Result<Task> {
|
||||||
|
let bcd_path = match table_type {
|
||||||
|
PartitionTableType::Guid => {
|
||||||
|
format!("{letter_boot}:\\EFI\\Microsoft\\Boot\\BCD")
|
||||||
|
}
|
||||||
|
PartitionTableType::Legacy => {
|
||||||
|
format!("{letter_boot}:\\Boot\\BCD")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Build Command
|
||||||
|
let mut cmd_args = vec![String::from("/store"), bcd_path];
|
||||||
|
match mode {
|
||||||
|
SafeMode::Disable => {
|
||||||
|
cmd_args.push(String::from("/deletevalue"));
|
||||||
|
cmd_args.push(String::from("{default}"));
|
||||||
|
cmd_args.push(String::from("safeboot"));
|
||||||
|
}
|
||||||
|
SafeMode::Enable => {
|
||||||
|
cmd_args.push(String::from("/set"));
|
||||||
|
cmd_args.push(String::from("{default}"));
|
||||||
|
cmd_args.push(String::from("safeboot"));
|
||||||
|
cmd_args.push(String::from("minimal"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Task::Command(
|
||||||
|
PathBuf::from(format!("{system32}/bcdedit.exe")),
|
||||||
|
cmd_args,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ impl App {
|
||||||
| Mode::DiagMenu
|
| Mode::DiagMenu
|
||||||
| Mode::InjectDrivers
|
| Mode::InjectDrivers
|
||||||
| Mode::PEMenu
|
| Mode::PEMenu
|
||||||
| Mode::ToggleSafeMode => panic!("This shouldn't happen?"),
|
| Mode::SetBootMode => panic!("This shouldn't happen?"),
|
||||||
};
|
};
|
||||||
new_mode
|
new_mode
|
||||||
}
|
}
|
||||||
|
|
@ -144,7 +144,7 @@ impl App {
|
||||||
| Mode::DiagMenu
|
| Mode::DiagMenu
|
||||||
| Mode::InjectDrivers
|
| Mode::InjectDrivers
|
||||||
| Mode::PEMenu
|
| Mode::PEMenu
|
||||||
| Mode::ToggleSafeMode => panic!("This shouldn't happen?"),
|
| Mode::SetBootMode => panic!("This shouldn't happen?"),
|
||||||
};
|
};
|
||||||
|
|
||||||
if new_mode == self.cur_mode {
|
if new_mode == self.cur_mode {
|
||||||
|
|
@ -576,19 +576,20 @@ fn build_footer_string(cur_mode: Mode) -> String {
|
||||||
String::from("(q) to quit")
|
String::from("(q) to quit")
|
||||||
}
|
}
|
||||||
Mode::SelectParts => String::from("(Enter) to select / (s) to start over / (q) to quit"),
|
Mode::SelectParts => String::from("(Enter) to select / (s) to start over / (q) to quit"),
|
||||||
|
Mode::InstallDrivers => String::from("(Enter) to select / (q) to quit"),
|
||||||
Mode::SelectDisks => String::from(
|
Mode::SelectDisks => String::from(
|
||||||
"(Enter) to select / / (i) to install driver / (r) to rescan / (q) to quit",
|
"(Enter) to select / / (i) to install driver / (r) to rescan / (q) to quit",
|
||||||
),
|
),
|
||||||
Mode::SelectTableType => String::from("(Enter) to select / (b) to go back / (q) to quit"),
|
Mode::SelectTableType => String::from("(Enter) to select / (b) to go back / (q) to quit"),
|
||||||
Mode::Confirm => String::from("(Enter) to confirm / (b) to go back / (q) to quit"),
|
Mode::Confirm => String::from("(Enter) to confirm / (b) to go back / (q) to quit"),
|
||||||
Mode::Done | Mode::Failed | Mode::InstallDrivers => String::from("(Enter) or (q) to quit"),
|
Mode::Done | Mode::Failed => String::from("(Enter) or (q) to quit"),
|
||||||
// Invalid states
|
// Invalid states
|
||||||
Mode::BootDiags
|
Mode::BootDiags
|
||||||
| Mode::BootSetup
|
| Mode::BootSetup
|
||||||
| Mode::DiagMenu
|
| Mode::DiagMenu
|
||||||
| Mode::InjectDrivers
|
| Mode::InjectDrivers
|
||||||
| Mode::PEMenu
|
| Mode::PEMenu
|
||||||
| Mode::ToggleSafeMode => panic!("This shouldn't happen?"),
|
| Mode::SetBootMode => panic!("This shouldn't happen?"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -658,7 +659,7 @@ fn build_left_items(app: &App, cur_mode: Mode) -> Action {
|
||||||
| Mode::DiagMenu
|
| Mode::DiagMenu
|
||||||
| Mode::InjectDrivers
|
| Mode::InjectDrivers
|
||||||
| Mode::PEMenu
|
| Mode::PEMenu
|
||||||
| Mode::ToggleSafeMode => panic!("This shouldn't happen?"),
|
| Mode::SetBootMode => panic!("This shouldn't happen?"),
|
||||||
};
|
};
|
||||||
Action::UpdateLeft(title, labels, items, select_num)
|
Action::UpdateLeft(title, labels, items, select_num)
|
||||||
}
|
}
|
||||||
|
|
@ -711,7 +712,7 @@ fn build_right_items(app: &App, cur_mode: Mode) -> Action {
|
||||||
let disk_list = app.clone.disk_list.lock().unwrap();
|
let disk_list = app.clone.disk_list.lock().unwrap();
|
||||||
disk_list
|
disk_list
|
||||||
.iter()
|
.iter()
|
||||||
.for_each(|disk| items.push(get_disk_description_right(&disk)));
|
.for_each(|disk| items.push(get_disk_description_right(&disk, None)));
|
||||||
}
|
}
|
||||||
Mode::SelectParts => {
|
Mode::SelectParts => {
|
||||||
vec!["Boot", "OS"].iter().for_each(|s| {
|
vec!["Boot", "OS"].iter().for_each(|s| {
|
||||||
|
|
@ -725,7 +726,7 @@ fn build_right_items(app: &App, cur_mode: Mode) -> Action {
|
||||||
let disk_list = app.clone.disk_list.lock().unwrap();
|
let disk_list = app.clone.disk_list.lock().unwrap();
|
||||||
if let Some(disk) = disk_list.get(index) {
|
if let Some(disk) = disk_list.get(index) {
|
||||||
// Disk Details
|
// Disk Details
|
||||||
items.push(get_disk_description_right(&disk));
|
items.push(get_disk_description_right(&disk, None));
|
||||||
|
|
||||||
// Partition Details
|
// Partition Details
|
||||||
disk.parts
|
disk.parts
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue