Major refactor around task groups
This commit is contained in:
parent
081fd22de1
commit
2296b8f274
8 changed files with 138 additions and 254 deletions
|
|
@ -39,7 +39,6 @@ use core::{
|
||||||
tui::{Event, Tui},
|
tui::{Event, Tui},
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
collections::VecDeque,
|
|
||||||
env,
|
env,
|
||||||
iter::zip,
|
iter::zip,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
|
|
@ -54,7 +53,7 @@ use ratatui::{
|
||||||
style::Color,
|
style::Color,
|
||||||
};
|
};
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
use tracing::{debug, info, warn};
|
use tracing::{debug, info};
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
// TUI
|
// TUI
|
||||||
|
|
@ -76,7 +75,6 @@ pub struct App {
|
||||||
selections: Vec<Option<usize>>,
|
selections: Vec<Option<usize>>,
|
||||||
system32: String,
|
system32: String,
|
||||||
tasks: Tasks,
|
tasks: Tasks,
|
||||||
task_groups: VecDeque<Option<String>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
|
|
@ -120,7 +118,6 @@ impl App {
|
||||||
system32: String::new(),
|
system32: String::new(),
|
||||||
selections: vec![None, None],
|
selections: vec![None, None],
|
||||||
tasks,
|
tasks,
|
||||||
task_groups: VecDeque::new(),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -401,20 +398,12 @@ impl App {
|
||||||
self.action_tx.send(Action::Select(None, None))?;
|
self.action_tx.send(Action::Select(None, None))?;
|
||||||
}
|
}
|
||||||
Action::TaskGroupStart(ref title) => {
|
Action::TaskGroupStart(ref title) => {
|
||||||
|
// TODO: Verify this isn't broken and/or unused
|
||||||
if self.cur_mode == Mode::BootScan {
|
if self.cur_mode == Mode::BootScan {
|
||||||
info!("TaskGroup: {:?}", self.task_groups.front());
|
self.action_tx.send(Action::DiagLineStart {
|
||||||
if self.task_groups.front().is_some() {
|
text: title.clone(),
|
||||||
if self.task_groups.front().unwrap().is_some() {
|
})?;
|
||||||
// None here means that we're in the middle of a group of tasks
|
self.diag_groups.start(title.to_owned());
|
||||||
// i.e. don't start a new diag line
|
|
||||||
self.action_tx.send(Action::DiagStartLine {
|
|
||||||
text: title.clone(),
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !self.diag_groups.contains(&title) {
|
|
||||||
self.diag_groups.update(title.to_owned(), None, None);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Action::TasksComplete => {
|
Action::TasksComplete => {
|
||||||
|
|
@ -443,70 +432,22 @@ impl App {
|
||||||
|
|
||||||
fn handle_task(&mut self, task: &Task) -> Result<()> {
|
fn handle_task(&mut self, task: &Task) -> Result<()> {
|
||||||
info!("Handling Task: {task:?}");
|
info!("Handling Task: {task:?}");
|
||||||
let title: Option<String>;
|
|
||||||
match self.cur_mode {
|
match self.cur_mode {
|
||||||
Mode::BootScan => {
|
Mode::BootScan => {
|
||||||
let task_group = self.task_groups.pop_front();
|
if let Some(result) = &task.result {
|
||||||
match &task.task_type {
|
let title = self.diag_groups.current_group();
|
||||||
TaskType::CommandWait(cmd_path, _cmd_args) => {
|
let passed: bool;
|
||||||
let mut cmd_name = "";
|
let info: String;
|
||||||
if let Some(path) = cmd_path.file_name() {
|
match result {
|
||||||
if let Some(cmd_str) = path.to_str() {
|
TaskResult::Error(msg) => {
|
||||||
cmd_name = cmd_str;
|
passed = false;
|
||||||
}
|
info = msg.to_owned();
|
||||||
};
|
}
|
||||||
let diag_type = diags::get_type(cmd_name);
|
TaskResult::Output(stdout, stderr, success) => {
|
||||||
match diag_type {
|
passed = *success;
|
||||||
diags::Type::Bitlocker
|
if title == "Filesystem" {
|
||||||
| diags::Type::BootConfigData
|
info = parse_chkdsk(stdout);
|
||||||
| diags::Type::Registry
|
} else {
|
||||||
| diags::Type::System => {
|
|
||||||
title = Some(format!("{diag_type}"));
|
|
||||||
}
|
|
||||||
diags::Type::FileSystem => {
|
|
||||||
title = None;
|
|
||||||
if let Some(result) = &task.result {
|
|
||||||
let passed: bool;
|
|
||||||
let info: String;
|
|
||||||
match result {
|
|
||||||
TaskResult::Error(msg) => {
|
|
||||||
passed = false;
|
|
||||||
info = msg.to_owned();
|
|
||||||
}
|
|
||||||
TaskResult::Output(stdout, _stderr, success) => {
|
|
||||||
passed = *success;
|
|
||||||
info = parse_chkdsk(stdout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.diag_groups.update(
|
|
||||||
String::from("Filesystem"),
|
|
||||||
Some(passed),
|
|
||||||
Some(info.to_owned()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
diags::Type::Unknown => {
|
|
||||||
title = None;
|
|
||||||
warn!("Unrecognized command: {:?}", &cmd_path);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
TaskType::TestPaths(_) => {
|
|
||||||
title = Some(format!("{}", diags::Type::FileSystem));
|
|
||||||
}
|
|
||||||
_ => title = None,
|
|
||||||
}
|
|
||||||
if let Some(title_str) = title {
|
|
||||||
if let Some(result) = &task.result {
|
|
||||||
let passed: bool;
|
|
||||||
let info: String;
|
|
||||||
match result {
|
|
||||||
TaskResult::Error(msg) => {
|
|
||||||
passed = false;
|
|
||||||
info = msg.to_owned();
|
|
||||||
}
|
|
||||||
TaskResult::Output(stdout, stderr, success) => {
|
|
||||||
passed = *success;
|
|
||||||
let div = if !(stdout.is_empty() || stderr.is_empty()) {
|
let div = if !(stdout.is_empty() || stderr.is_empty()) {
|
||||||
"\n\n-----------\n\n"
|
"\n\n-----------\n\n"
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -515,37 +456,19 @@ impl App {
|
||||||
info = format!("{stdout}{div}{stderr}");
|
info = format!("{stdout}{div}{stderr}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.diag_groups
|
|
||||||
.update(title_str, Some(passed), Some(info.to_owned()));
|
|
||||||
if let Some(group) = task_group {
|
|
||||||
if let Some(wat) = group {
|
|
||||||
info!("WAT? // {wat:?}");
|
|
||||||
if passed {
|
|
||||||
self.action_tx.send(Action::DiagEndLine {
|
|
||||||
result: DiagResult::Pass,
|
|
||||||
text: String::from("Pass?"),
|
|
||||||
})?;
|
|
||||||
} else {
|
|
||||||
self.action_tx.send(Action::DiagEndLine {
|
|
||||||
result: DiagResult::Fail,
|
|
||||||
text: String::from("Fail?"),
|
|
||||||
})?;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If title was set but there wasn't a result
|
|
||||||
self.action_tx.send(Action::DiagEndLine {
|
|
||||||
result: DiagResult::Warn,
|
|
||||||
text: String::from("Yellow no result?"),
|
|
||||||
})?;
|
|
||||||
}
|
}
|
||||||
} else {
|
self.diag_groups.update(title, passed, info);
|
||||||
// title was not set
|
if passed {
|
||||||
self.action_tx.send(Action::DiagEndLine {
|
self.action_tx.send(Action::DiagLineUpdate {
|
||||||
result: DiagResult::Warn,
|
result: DiagResult::Pass,
|
||||||
text: String::from("Yellow no title?"),
|
text: String::from("Pass?"),
|
||||||
})?;
|
})?;
|
||||||
|
} else {
|
||||||
|
self.action_tx.send(Action::DiagLineUpdate {
|
||||||
|
result: DiagResult::Fail,
|
||||||
|
text: String::from("Fail?"),
|
||||||
|
})?;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|
@ -577,6 +500,11 @@ impl App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
TaskType::GroupEnd { ref label } => {
|
||||||
|
self.action_tx.send(Action::DiagLineEnd {
|
||||||
|
text: label.clone(),
|
||||||
|
})?;
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -626,7 +554,6 @@ impl App {
|
||||||
],
|
],
|
||||||
)],
|
)],
|
||||||
);
|
);
|
||||||
self.task_groups.push_back(Some(String::from("Boot Files")));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bitlocker
|
// Bitlocker
|
||||||
|
|
@ -647,7 +574,6 @@ impl App {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
self.task_groups.push_back(Some(String::from("Bitlocker")));
|
|
||||||
|
|
||||||
// Filesystem Health
|
// Filesystem Health
|
||||||
let paths: Vec<PathBuf> = [
|
let paths: Vec<PathBuf> = [
|
||||||
|
|
@ -671,7 +597,6 @@ impl App {
|
||||||
TaskType::TestPaths(paths),
|
TaskType::TestPaths(paths),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
self.task_groups.push_back(Some(String::from("Filesystem")));
|
|
||||||
|
|
||||||
// DISM Health
|
// DISM Health
|
||||||
self.tasks.add_group(
|
self.tasks.add_group(
|
||||||
|
|
@ -681,8 +606,6 @@ impl App {
|
||||||
vec![format!("{letter_os}:")],
|
vec![format!("{letter_os}:")],
|
||||||
)],
|
)],
|
||||||
);
|
);
|
||||||
self.task_groups
|
|
||||||
.push_back(Some(String::from("System Files")));
|
|
||||||
|
|
||||||
// Registry
|
// Registry
|
||||||
self.tasks.add_group(
|
self.tasks.add_group(
|
||||||
|
|
@ -726,7 +649,6 @@ impl App {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
self.task_groups.push_back(Some(String::from("Registry")));
|
|
||||||
self.tasks.add(TaskType::Sleep); // NOTE: DELETEME
|
self.tasks.add(TaskType::Sleep); // NOTE: DELETEME
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ struct ProgressLine {
|
||||||
name: String,
|
name: String,
|
||||||
text: String,
|
text: String,
|
||||||
result: DiagResult,
|
result: DiagResult,
|
||||||
|
running: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProgressLine {
|
impl ProgressLine {
|
||||||
|
|
@ -70,17 +71,18 @@ impl Progress {
|
||||||
impl Component for Progress {
|
impl Component for Progress {
|
||||||
fn update(&mut self, action: Action) -> Result<Option<Action>> {
|
fn update(&mut self, action: Action) -> Result<Option<Action>> {
|
||||||
match action {
|
match action {
|
||||||
Action::DiagStartLine { text } => {
|
Action::DiagLineStart { text } => {
|
||||||
info!("Caught Action::DiagStartLine");
|
info!("Caught Action::DiagLineStart {{ \"{}\" }}", &text);
|
||||||
self.lines.push(ProgressLine {
|
self.lines.push(ProgressLine {
|
||||||
name: text,
|
name: text,
|
||||||
text: String::new(),
|
text: String::from("OK"),
|
||||||
result: DiagResult::Pass,
|
result: DiagResult::Pass,
|
||||||
|
running: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Action::DiagEndLine { result, text } => {
|
Action::DiagLineUpdate { result, text } => {
|
||||||
info!(
|
info!(
|
||||||
"Caught Action::DiagEndLine {{ {}, \"{}\" }}",
|
"Caught Action::DiagLineUpdate {{ {}, \"{}\" }}",
|
||||||
&result, &text
|
&result, &text
|
||||||
);
|
);
|
||||||
if let Some(line) = self.lines.last_mut() {
|
if let Some(line) = self.lines.last_mut() {
|
||||||
|
|
@ -88,6 +90,12 @@ impl Component for Progress {
|
||||||
line.text = text;
|
line.text = text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Action::DiagLineEnd { text } => {
|
||||||
|
info!("Caught Action::DiagLineEnd {{ \"{}\" }}", &text);
|
||||||
|
if let Some(line) = self.lines.last_mut() {
|
||||||
|
line.running = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
Action::SetMode(mode) => self.mode = mode,
|
Action::SetMode(mode) => self.mode = mode,
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
|
|
@ -111,7 +119,7 @@ impl Component for Progress {
|
||||||
DiagResult::Fail => Color::Red,
|
DiagResult::Fail => Color::Red,
|
||||||
DiagResult::Warn => Color::Yellow,
|
DiagResult::Warn => Color::Yellow,
|
||||||
};
|
};
|
||||||
let text = if line.text.is_empty() {
|
let text = if line.running || line.text.is_empty() {
|
||||||
String::from("...")
|
String::from("...")
|
||||||
} else {
|
} else {
|
||||||
line.text.clone()
|
line.text.clone()
|
||||||
|
|
|
||||||
|
|
@ -13,29 +13,9 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Deja-Vu. If not, see <https://www.gnu.org/licenses/>.
|
// along with Deja-Vu. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::{collections::HashMap, fmt};
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub enum Type {
|
use tracing::warn;
|
||||||
Bitlocker,
|
|
||||||
BootConfigData,
|
|
||||||
FileSystem,
|
|
||||||
Registry,
|
|
||||||
System,
|
|
||||||
Unknown,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Type {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
Type::Bitlocker => write!(f, "Bitlocker"),
|
|
||||||
Type::BootConfigData => write!(f, "Boot Files"),
|
|
||||||
Type::FileSystem => write!(f, "Filesystem"),
|
|
||||||
Type::Registry => write!(f, "Registry"),
|
|
||||||
Type::System => write!(f, "System Files"),
|
|
||||||
Type::Unknown => write!(f, "Unknown Type"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Groups {
|
pub struct Groups {
|
||||||
|
|
@ -51,8 +31,11 @@ impl Groups {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn contains(&self, name: &str) -> bool {
|
pub fn current_group(&self) -> String {
|
||||||
self.items.contains_key(name)
|
match self.order.last() {
|
||||||
|
Some(label) => label.clone(),
|
||||||
|
None => String::from("No current group"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self) -> Vec<&Line> {
|
pub fn get(&self) -> Vec<&Line> {
|
||||||
|
|
@ -65,24 +48,24 @@ impl Groups {
|
||||||
lines
|
lines
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, title: String, passed: Option<bool>, info: Option<String>) {
|
pub fn start(&mut self, title: String) {
|
||||||
|
self.order.push(title.clone());
|
||||||
|
self.items.insert(
|
||||||
|
title.clone(),
|
||||||
|
Line {
|
||||||
|
title,
|
||||||
|
passed: true,
|
||||||
|
info: Vec::new(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(&mut self, title: String, passed: bool, info: String) {
|
||||||
if let Some(line) = self.items.get_mut(&title) {
|
if let Some(line) = self.items.get_mut(&title) {
|
||||||
line.update(passed, info);
|
line.update(passed, info);
|
||||||
} else {
|
} else {
|
||||||
let info_list = if info.is_some() {
|
warn!("WARNING/DELETEME - This shouldn't happen?!");
|
||||||
vec![info.unwrap()]
|
self.start(title);
|
||||||
} else {
|
|
||||||
Vec::new()
|
|
||||||
};
|
|
||||||
self.order.push(title.clone());
|
|
||||||
self.items.insert(
|
|
||||||
title.clone(),
|
|
||||||
Line {
|
|
||||||
title,
|
|
||||||
passed: passed.unwrap_or(true),
|
|
||||||
info: info_list,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -95,34 +78,8 @@ pub struct Line {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Line {
|
impl Line {
|
||||||
pub fn update(&mut self, passed: Option<bool>, info: Option<String>) {
|
pub fn update(&mut self, passed: bool, info: String) {
|
||||||
if let Some(result) = passed {
|
self.passed &= passed; // We fail if any tests in this group fail
|
||||||
self.passed &= result; // We fail if any tests in this group fail
|
self.info.push(info);
|
||||||
}
|
|
||||||
if let Some(info_str) = info {
|
|
||||||
self.info.push(String::from(info_str));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_type(cmd_name: &str) -> Type {
|
|
||||||
if cmd_name.ends_with("exa") {
|
|
||||||
return Type::BootConfigData;
|
|
||||||
}
|
|
||||||
if cmd_name.ends_with("bcdedit.exe") {
|
|
||||||
return Type::BootConfigData;
|
|
||||||
}
|
|
||||||
if cmd_name.ends_with("dism.exe") {
|
|
||||||
return Type::System;
|
|
||||||
}
|
|
||||||
if cmd_name.ends_with("reg.exe") {
|
|
||||||
return Type::Registry;
|
|
||||||
}
|
|
||||||
if cmd_name.ends_with("chkdsk.exe") {
|
|
||||||
return Type::FileSystem;
|
|
||||||
}
|
|
||||||
if cmd_name.ends_with("manage-bde.exe") {
|
|
||||||
return Type::Bitlocker;
|
|
||||||
}
|
|
||||||
Type::Unknown
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,9 @@ pub enum DiagResult {
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
// App (Boot-Diags)
|
// App (Boot-Diags)
|
||||||
BootScan,
|
BootScan,
|
||||||
DiagStartLine { text: String },
|
DiagLineStart { text: String },
|
||||||
DiagEndLine { result: DiagResult, text: String },
|
DiagLineUpdate { result: DiagResult, text: String },
|
||||||
|
DiagLineEnd { text: String },
|
||||||
// App (Clone)
|
// App (Clone)
|
||||||
Highlight(usize),
|
Highlight(usize),
|
||||||
InstallDriver,
|
InstallDriver,
|
||||||
|
|
@ -44,7 +45,6 @@ pub enum Action {
|
||||||
Select(Option<usize>, Option<usize>), // indicies for (source, dest) etc
|
Select(Option<usize>, Option<usize>), // indicies for (source, dest) etc
|
||||||
SelectRight(Option<usize>, Option<usize>), // indicies for right info pane
|
SelectRight(Option<usize>, Option<usize>), // indicies for right info pane
|
||||||
TaskGroupStart(String),
|
TaskGroupStart(String),
|
||||||
TaskGroupEnd,
|
|
||||||
TasksComplete,
|
TasksComplete,
|
||||||
UpdateDiskList(Vec<Disk>),
|
UpdateDiskList(Vec<Disk>),
|
||||||
UpdateFooter(String),
|
UpdateFooter(String),
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ impl FpsCounter {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
mode: String::from(""),
|
mode: String::new(),
|
||||||
last_tick_update: Instant::now(),
|
last_tick_update: Instant::now(),
|
||||||
tick_count: 0,
|
tick_count: 0,
|
||||||
ticks_per_second: 0.0,
|
ticks_per_second: 0.0,
|
||||||
|
|
@ -92,7 +92,7 @@ impl Component for FpsCounter {
|
||||||
fn update(&mut self, action: Action) -> Result<Option<Action>> {
|
fn update(&mut self, action: Action) -> Result<Option<Action>> {
|
||||||
match action {
|
match action {
|
||||||
Action::SetMode(mode) => {
|
Action::SetMode(mode) => {
|
||||||
self.mode = format!("{:?}", mode);
|
self.mode = format!("{mode:?}");
|
||||||
}
|
}
|
||||||
Action::Render => self.render_tick()?,
|
Action::Render => self.render_tick()?,
|
||||||
Action::Tick => self.app_tick()?,
|
Action::Tick => self.app_tick()?,
|
||||||
|
|
|
||||||
|
|
@ -166,7 +166,6 @@ pub fn get_fake_disks() -> Vec<Disk> {
|
||||||
letter: String::from("C"),
|
letter: String::from("C"),
|
||||||
part_type: String::from("7"),
|
part_type: String::from("7"),
|
||||||
size: 104_857_600,
|
size: 104_857_600,
|
||||||
..Default::default()
|
|
||||||
},
|
},
|
||||||
Partition {
|
Partition {
|
||||||
id: 2,
|
id: 2,
|
||||||
|
|
@ -181,7 +180,6 @@ pub fn get_fake_disks() -> Vec<Disk> {
|
||||||
letter: String::from("D"),
|
letter: String::from("D"),
|
||||||
part_type: String::from("7"),
|
part_type: String::from("7"),
|
||||||
size: 267_701_452_800,
|
size: 267_701_452_800,
|
||||||
..Default::default()
|
|
||||||
},
|
},
|
||||||
Partition {
|
Partition {
|
||||||
id: 6,
|
id: 6,
|
||||||
|
|
@ -190,7 +188,6 @@ pub fn get_fake_disks() -> Vec<Disk> {
|
||||||
letter: String::from("E"),
|
letter: String::from("E"),
|
||||||
part_type: String::from("7"),
|
part_type: String::from("7"),
|
||||||
size: 524_288_000,
|
size: 524_288_000,
|
||||||
..Default::default()
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
serial: "MDZ1243".to_string(),
|
serial: "MDZ1243".to_string(),
|
||||||
|
|
@ -209,7 +206,6 @@ pub fn get_fake_disks() -> Vec<Disk> {
|
||||||
letter: String::from("G"),
|
letter: String::from("G"),
|
||||||
part_type: String::from("7"),
|
part_type: String::from("7"),
|
||||||
size: 249_998_951_424,
|
size: 249_998_951_424,
|
||||||
..Default::default()
|
|
||||||
}],
|
}],
|
||||||
serial: "000010000".to_string(),
|
serial: "000010000".to_string(),
|
||||||
size: 250_000_000_000,
|
size: 250_000_000_000,
|
||||||
|
|
@ -261,7 +257,6 @@ pub fn get_fake_disks() -> Vec<Disk> {
|
||||||
letter: String::from("I"),
|
letter: String::from("I"),
|
||||||
part_type: String::from("EFI"),
|
part_type: String::from("EFI"),
|
||||||
size: 209_715_200,
|
size: 209_715_200,
|
||||||
..Default::default()
|
|
||||||
},
|
},
|
||||||
Partition {
|
Partition {
|
||||||
id: 2,
|
id: 2,
|
||||||
|
|
|
||||||
|
|
@ -33,57 +33,57 @@ use crate::system::disk::{
|
||||||
static DEFAULT_MAX_DISKS: usize = 8;
|
static DEFAULT_MAX_DISKS: usize = 8;
|
||||||
|
|
||||||
struct RegexList {
|
struct RegexList {
|
||||||
re_detail_all_disks: OnceLock<Regex>,
|
detail_all_disks: OnceLock<Regex>,
|
||||||
re_detail_disk: OnceLock<Regex>,
|
detail_disk: OnceLock<Regex>,
|
||||||
re_detail_partition: OnceLock<Regex>,
|
detail_partition: OnceLock<Regex>,
|
||||||
re_disk_numbers: OnceLock<Regex>,
|
disk_numbers: OnceLock<Regex>,
|
||||||
re_list_disk: OnceLock<Regex>,
|
list_disk: OnceLock<Regex>,
|
||||||
re_list_partition: OnceLock<Regex>,
|
list_partition: OnceLock<Regex>,
|
||||||
re_list_volumes: OnceLock<Regex>,
|
list_volumes: OnceLock<Regex>,
|
||||||
re_split_all_disks: OnceLock<Regex>,
|
split_all_disks: OnceLock<Regex>,
|
||||||
re_uuid: OnceLock<Regex>,
|
re_uuid: OnceLock<Regex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RegexList {
|
impl RegexList {
|
||||||
pub fn detail_all_disks(&self) -> &Regex {
|
pub fn detail_all_disks(&self) -> &Regex {
|
||||||
self.re_detail_all_disks.get_or_init(|| {
|
self.detail_all_disks.get_or_init(|| {
|
||||||
Regex::new(r"(?s)Disk (\d+) is now the selected disk.*?\r?\n\s*\r?\n(.*)").unwrap()
|
Regex::new(r"(?s)Disk (\d+) is now the selected disk.*?\r?\n\s*\r?\n(.*)").unwrap()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn detail_disk(&self) -> &Regex {
|
pub fn detail_disk(&self) -> &Regex {
|
||||||
self.re_detail_disk.get_or_init(|| {
|
self.detail_disk.get_or_init(|| {
|
||||||
Regex::new(r"(.*?)\r?\nDisk ID\s*:\s+(.*?)\r?\nType\s*:\s+(.*?)\r?\n").unwrap()
|
Regex::new(r"(.*?)\r?\nDisk ID\s*:\s+(.*?)\r?\nType\s*:\s+(.*?)\r?\n").unwrap()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn detail_partition(&self) -> &Regex {
|
pub fn detail_partition(&self) -> &Regex {
|
||||||
self.re_detail_partition
|
self.detail_partition
|
||||||
.get_or_init(|| Regex::new(r"Partition (\d+)\r?\nType\s*: (\S+)(\r?\n.*){5}\s*(Volume.*\r?\n.*\r?\n|There is no volume)(.*)").unwrap())
|
.get_or_init(|| Regex::new(r"Partition (\d+)\r?\nType\s*: (\S+)(\r?\n.*){5}\s*(Volume.*\r?\n.*\r?\n|There is no volume)(.*)").unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn disk_numbers(&self) -> &Regex {
|
pub fn disk_numbers(&self) -> &Regex {
|
||||||
self.re_disk_numbers
|
self.disk_numbers
|
||||||
.get_or_init(|| Regex::new(r"\s+Disk\s+(\d+).*\n.*\n.*\nDisk ID:").unwrap())
|
.get_or_init(|| Regex::new(r"\s+Disk\s+(\d+).*\n.*\n.*\nDisk ID:").unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list_disk(&self) -> &Regex {
|
pub fn list_disk(&self) -> &Regex {
|
||||||
self.re_list_disk
|
self.list_disk
|
||||||
.get_or_init(|| Regex::new(r"Disk\s+(\d+)\s+(\w+)\s+(\d+\s+\w+B)").unwrap())
|
.get_or_init(|| Regex::new(r"Disk\s+(\d+)\s+(\w+)\s+(\d+\s+\w+B)").unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list_partition(&self) -> &Regex {
|
pub fn list_partition(&self) -> &Regex {
|
||||||
self.re_list_partition
|
self.list_partition
|
||||||
.get_or_init(|| Regex::new(r"Partition\s+(\d+)\s+\w+\s+(\d+\s+\w+B)").unwrap())
|
.get_or_init(|| Regex::new(r"Partition\s+(\d+)\s+\w+\s+(\d+\s+\w+B)").unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn split_all_disks(&self) -> &Regex {
|
pub fn split_all_disks(&self) -> &Regex {
|
||||||
self.re_split_all_disks
|
self.split_all_disks
|
||||||
.get_or_init(|| Regex::new(r"Disk \d+ is now the selected disk").unwrap())
|
.get_or_init(|| Regex::new(r"Disk \d+ is now the selected disk").unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list_volumes(&self) -> &Regex {
|
pub fn list_volumes(&self) -> &Regex {
|
||||||
self.re_list_volumes.get_or_init(|| {
|
self.list_volumes.get_or_init(|| {
|
||||||
// Volume ### Ltr Label Fs Type Size Status Info
|
// Volume ### Ltr Label Fs Type Size Status Info
|
||||||
// ---------- --- ----------- ----- ---------- ------- --------- --------
|
// ---------- --- ----------- ----- ---------- ------- --------- --------
|
||||||
// * Volume 1 S ESP FAT32 Partition 100 MB Healthy Hidden
|
// * Volume 1 S ESP FAT32 Partition 100 MB Healthy Hidden
|
||||||
|
|
@ -100,14 +100,14 @@ impl RegexList {
|
||||||
}
|
}
|
||||||
|
|
||||||
static REGEXES: RegexList = RegexList {
|
static REGEXES: RegexList = RegexList {
|
||||||
re_detail_all_disks: OnceLock::new(),
|
detail_all_disks: OnceLock::new(),
|
||||||
re_detail_disk: OnceLock::new(),
|
detail_disk: OnceLock::new(),
|
||||||
re_detail_partition: OnceLock::new(),
|
detail_partition: OnceLock::new(),
|
||||||
re_disk_numbers: OnceLock::new(),
|
disk_numbers: OnceLock::new(),
|
||||||
re_list_disk: OnceLock::new(),
|
list_disk: OnceLock::new(),
|
||||||
re_list_partition: OnceLock::new(),
|
list_partition: OnceLock::new(),
|
||||||
re_list_volumes: OnceLock::new(),
|
list_volumes: OnceLock::new(),
|
||||||
re_split_all_disks: OnceLock::new(),
|
split_all_disks: OnceLock::new(),
|
||||||
re_uuid: OnceLock::new(),
|
re_uuid: OnceLock::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -152,7 +152,7 @@ pub fn get_partition_details(
|
||||||
disk_details: Option<&str>,
|
disk_details: Option<&str>,
|
||||||
part_details: Option<&str>,
|
part_details: Option<&str>,
|
||||||
) -> Vec<Partition> {
|
) -> Vec<Partition> {
|
||||||
let re_list_partitions = REGEXES.list_partition();
|
let list_partitions = REGEXES.list_partition();
|
||||||
let mut parts = Vec::new();
|
let mut parts = Vec::new();
|
||||||
|
|
||||||
// List partition
|
// List partition
|
||||||
|
|
@ -163,7 +163,7 @@ pub fn get_partition_details(
|
||||||
let script = format!("select disk {disk_id}\r\nlist partition");
|
let script = format!("select disk {disk_id}\r\nlist partition");
|
||||||
contents = run_script(&script);
|
contents = run_script(&script);
|
||||||
};
|
};
|
||||||
for (_, [number, size]) in re_list_partitions
|
for (_, [number, size]) in list_partitions
|
||||||
.captures_iter(&contents)
|
.captures_iter(&contents)
|
||||||
.map(|c| c.extract())
|
.map(|c| c.extract())
|
||||||
{
|
{
|
||||||
|
|
@ -274,8 +274,8 @@ pub fn build_get_disk_script(disk_nums: Option<Vec<&str>>) -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_disks() -> Vec<Disk> {
|
pub fn get_disks() -> Vec<Disk> {
|
||||||
let re_detail_all_disks = REGEXES.detail_all_disks();
|
let detail_all_disks = REGEXES.detail_all_disks();
|
||||||
let re_list_disk = REGEXES.list_disk();
|
let list_disk = REGEXES.list_disk();
|
||||||
let mut contents: String;
|
let mut contents: String;
|
||||||
let mut output;
|
let mut output;
|
||||||
let mut script: String;
|
let mut script: String;
|
||||||
|
|
@ -317,7 +317,7 @@ pub fn get_disks() -> Vec<Disk> {
|
||||||
// i.e. 0, 1, 3, 4
|
// i.e. 0, 1, 3, 4
|
||||||
// For instance, this can happen if a drive is disconnected after startup
|
// For instance, this can happen if a drive is disconnected after startup
|
||||||
let mut disks_map: HashMap<&str, Disk> = HashMap::with_capacity(DEFAULT_MAX_DISKS);
|
let mut disks_map: HashMap<&str, Disk> = HashMap::with_capacity(DEFAULT_MAX_DISKS);
|
||||||
for (_, [number, _status, size]) in re_list_disk
|
for (_, [number, _status, size]) in list_disk
|
||||||
.captures_iter(dp_sections.remove(0)) // This is the "list disk" section
|
.captures_iter(dp_sections.remove(0)) // This is the "list disk" section
|
||||||
.map(|c| c.extract())
|
.map(|c| c.extract())
|
||||||
{
|
{
|
||||||
|
|
@ -334,10 +334,7 @@ pub fn get_disks() -> Vec<Disk> {
|
||||||
// Add Disk details
|
// Add Disk details
|
||||||
let mut disks_raw: Vec<Disk> = Vec::with_capacity(DEFAULT_MAX_DISKS);
|
let mut disks_raw: Vec<Disk> = Vec::with_capacity(DEFAULT_MAX_DISKS);
|
||||||
for section in dp_sections {
|
for section in dp_sections {
|
||||||
for (_, [id, details]) in re_detail_all_disks
|
for (_, [id, details]) in detail_all_disks.captures_iter(section).map(|c| c.extract()) {
|
||||||
.captures_iter(section)
|
|
||||||
.map(|c| c.extract())
|
|
||||||
{
|
|
||||||
if let Some(disk) = disks_map.remove(id) {
|
if let Some(disk) = disks_map.remove(id) {
|
||||||
// We remove the disk from the HashMap because we're moving it to the Vec
|
// We remove the disk from the HashMap because we're moving it to the Vec
|
||||||
let mut disk = get_disk_details(disk.id, disk.size, Some(details));
|
let mut disk = get_disk_details(disk.id, disk.size, Some(details));
|
||||||
|
|
@ -357,19 +354,19 @@ pub fn parse_disk_numbers(contents: &str) -> Vec<&str> {
|
||||||
//
|
//
|
||||||
//Red Hat VirtIO SCSI Disk Device
|
//Red Hat VirtIO SCSI Disk Device
|
||||||
//Disk ID: {E9CE8DFA-46B2-43C1-99BB-850C661CEE6B}
|
//Disk ID: {E9CE8DFA-46B2-43C1-99BB-850C661CEE6B}
|
||||||
let re_disk_numbers = REGEXES.disk_numbers();
|
let disk_numbers = REGEXES.disk_numbers();
|
||||||
let mut disk_nums = Vec::new();
|
let mut disk_nums = Vec::new();
|
||||||
for (_, [number]) in re_disk_numbers.captures_iter(contents).map(|c| c.extract()) {
|
for (_, [number]) in disk_numbers.captures_iter(contents).map(|c| c.extract()) {
|
||||||
disk_nums.push(number);
|
disk_nums.push(number);
|
||||||
}
|
}
|
||||||
disk_nums
|
disk_nums
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_partition_details(parts: &mut [Partition], contents: &str) {
|
pub fn parse_partition_details(parts: &mut [Partition], contents: &str) {
|
||||||
let re_detail_partition = REGEXES.detail_partition();
|
let detail_partition = REGEXES.detail_partition();
|
||||||
let re_list_volume = REGEXES.list_volumes();
|
let list_volume = REGEXES.list_volumes();
|
||||||
|
|
||||||
for (part_index, (_, [_part_id, part_type, _, _vol_header, vol_line])) in re_detail_partition
|
for (part_index, (_, [_part_id, part_type, _, _vol_header, vol_line])) in detail_partition
|
||||||
.captures_iter(contents)
|
.captures_iter(contents)
|
||||||
.map(|c| c.extract())
|
.map(|c| c.extract())
|
||||||
.enumerate()
|
.enumerate()
|
||||||
|
|
@ -380,7 +377,7 @@ pub fn parse_partition_details(parts: &mut [Partition], contents: &str) {
|
||||||
|
|
||||||
// Volume info
|
// Volume info
|
||||||
for (_, [_id, letter, label, fs_type]) in
|
for (_, [_id, letter, label, fs_type]) in
|
||||||
re_list_volume.captures_iter(vol_line).map(|c| c.extract())
|
list_volume.captures_iter(vol_line).map(|c| c.extract())
|
||||||
{
|
{
|
||||||
part.label = String::from(label.trim());
|
part.label = String::from(label.trim());
|
||||||
part.letter = String::from(letter.trim());
|
part.letter = String::from(letter.trim());
|
||||||
|
|
@ -425,11 +422,11 @@ pub fn run_script(script: &str) -> String {
|
||||||
|
|
||||||
pub fn split_diskpart_disk_output(contents: &str) -> Vec<&str> {
|
pub fn split_diskpart_disk_output(contents: &str) -> Vec<&str> {
|
||||||
// NOTE: A simple split isn't helpful since we want to include the matching lines
|
// NOTE: A simple split isn't helpful since we want to include the matching lines
|
||||||
let re_split_all_disks = REGEXES.split_all_disks();
|
let split_all_disks = REGEXES.split_all_disks();
|
||||||
let mut sections = Vec::new();
|
let mut sections = Vec::new();
|
||||||
let mut starts: Vec<usize> = vec![0];
|
let mut starts: Vec<usize> = vec![0];
|
||||||
let mut ends: Vec<usize> = Vec::new();
|
let mut ends: Vec<usize> = Vec::new();
|
||||||
let _: Vec<_> = re_split_all_disks
|
let _: Vec<_> = split_all_disks
|
||||||
.find_iter(contents)
|
.find_iter(contents)
|
||||||
.map(|m| {
|
.map(|m| {
|
||||||
ends.push(m.start() - 1);
|
ends.push(m.start() - 1);
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ pub enum TaskType {
|
||||||
UpdateDestDisk(usize), // (disk_index)
|
UpdateDestDisk(usize), // (disk_index)
|
||||||
UpdateDiskList,
|
UpdateDiskList,
|
||||||
GroupStart { label: String },
|
GroupStart { label: String },
|
||||||
GroupEnd,
|
GroupEnd { label: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for TaskType {
|
impl fmt::Display for TaskType {
|
||||||
|
|
@ -75,7 +75,7 @@ impl fmt::Display for TaskType {
|
||||||
TaskType::UpdateDestDisk(_) => write!(f, "UpdateDestDisk"),
|
TaskType::UpdateDestDisk(_) => write!(f, "UpdateDestDisk"),
|
||||||
TaskType::UpdateDiskList => write!(f, "UpdateDiskList"),
|
TaskType::UpdateDiskList => write!(f, "UpdateDiskList"),
|
||||||
TaskType::GroupStart { label } => write!(f, "GroupStart({})", &label),
|
TaskType::GroupStart { label } => write!(f, "GroupStart({})", &label),
|
||||||
TaskType::GroupEnd => write!(f, "GroupEnd"),
|
TaskType::GroupEnd { label } => write!(f, "GroupEnd({})", &label),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -136,10 +136,12 @@ impl Tasks {
|
||||||
self.task_list.push_back(Task::new(TaskType::GroupStart {
|
self.task_list.push_back(Task::new(TaskType::GroupStart {
|
||||||
label: group_label.to_string(),
|
label: group_label.to_string(),
|
||||||
}));
|
}));
|
||||||
group_tasks.into_iter().for_each(|task| {
|
for task in group_tasks {
|
||||||
self.task_list.push_back(Task::new(task));
|
self.task_list.push_back(Task::new(task));
|
||||||
});
|
}
|
||||||
self.task_list.push_back(Task::new(TaskType::GroupEnd));
|
self.task_list.push_back(Task::new(TaskType::GroupEnd {
|
||||||
|
label: group_label.to_string(),
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
|
@ -249,9 +251,13 @@ impl Tasks {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
TaskType::GroupStart { ref label } => {
|
TaskType::GroupStart { ref label } => {
|
||||||
self.action_tx.send(Action::TaskGroupStart(label.clone()))?
|
self.action_tx.send(Action::TaskGroupStart(label.clone()))?;
|
||||||
|
}
|
||||||
|
TaskType::GroupEnd { ref label } => {
|
||||||
|
self.action_tx.send(Action::DiagLineEnd {
|
||||||
|
text: label.clone(),
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
TaskType::GroupEnd => self.action_tx.send(Action::TaskGroupEnd)?,
|
|
||||||
}
|
}
|
||||||
// Done
|
// Done
|
||||||
self.cur_task.replace(task);
|
self.cur_task.replace(task);
|
||||||
|
|
@ -326,22 +332,21 @@ fn test_paths(
|
||||||
) -> JoinHandle<()> {
|
) -> JoinHandle<()> {
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let mut missing_paths = Vec::new();
|
let mut missing_paths = Vec::new();
|
||||||
let task_result: TaskResult;
|
for path in path_list {
|
||||||
path_list.iter().for_each(|path| {
|
|
||||||
if !path.exists() {
|
if !path.exists() {
|
||||||
missing_paths.push(String::from(path.to_string_lossy()));
|
missing_paths.push(String::from(path.to_string_lossy()));
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
if missing_paths.is_empty() {
|
let task_result = if missing_paths.is_empty() {
|
||||||
// No missing paths
|
// No missing paths
|
||||||
task_result = TaskResult::Output(String::from("OK"), String::new(), true);
|
TaskResult::Output(String::from("OK"), String::new(), true)
|
||||||
} else {
|
} else {
|
||||||
task_result = TaskResult::Output(
|
TaskResult::Output(
|
||||||
String::from("Missing item(s)"),
|
String::from("Missing item(s)"),
|
||||||
missing_paths.join(",\n"),
|
missing_paths.join(",\n"),
|
||||||
false,
|
false,
|
||||||
);
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let err_str = format!("Failed to send TaskResult: {:?}", &task_result);
|
let err_str = format!("Failed to send TaskResult: {:?}", &task_result);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue