Compare commits
33 commits
8be96d21b9
...
59b9ddbee6
| Author | SHA1 | Date | |
|---|---|---|---|
| 59b9ddbee6 | |||
| 7e08ca5f72 | |||
| 31d1391925 | |||
| 3c4603dc7b | |||
| 5028e16c5b | |||
| 6970f2db3e | |||
| 367a290b6d | |||
| f22501ce7d | |||
| f1c3743584 | |||
| c5a9dc80cb | |||
| 2b2a5160fd | |||
| f272b0c482 | |||
| 121beeaa78 | |||
| 2829fbcac1 | |||
| 72130109cb | |||
| 1fab68500b | |||
| 1c9ed12d49 | |||
| cd38712ea9 | |||
| 167ec52d6f | |||
| 1336c20dc2 | |||
| 14b40410d4 | |||
| acccdccb38 | |||
| dd7c2fd7ab | |||
| 46311a3ede | |||
| de7520324b | |||
| b2b90bb946 | |||
| 1ce7f76229 | |||
| aa4ac8d5e8 | |||
| 9addea0676 | |||
| 76a27cd179 | |||
| 3674fbdee7 | |||
| 783e31a582 | |||
| 6938960f3e |
50 changed files with 2407 additions and 607 deletions
597
Cargo.lock
generated
597
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
12
Cargo.toml
12
Cargo.toml
|
|
@ -1,19 +1,19 @@
|
||||||
# This file is part of Deja-vu.
|
# This file is part of Deja-Vu.
|
||||||
#
|
#
|
||||||
# Deja-vu is free software: you can redistribute it and/or modify it
|
# 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
|
# under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# Deja-vu is distributed in the hope that it will be useful, but
|
# Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
# See the GNU General Public License for more details.
|
# See the GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# 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/>.
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["core", "deja_vu", "pe_menu"]
|
members = ["core", "boot_diags", "deja_vu", "pe_menu"]
|
||||||
default-members = ["deja_vu", "pe_menu"]
|
default-members = ["boot_diags", "deja_vu", "pe_menu"]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
|
||||||
47
boot_diags/Cargo.toml
Normal file
47
boot_diags/Cargo.toml
Normal file
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
[package]
|
||||||
|
name = "boot-diags"
|
||||||
|
authors = ["2Shirt <2xShirt@gmail.com>"]
|
||||||
|
edition = "2024"
|
||||||
|
license = "GPL"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
core = { path = "../core" }
|
||||||
|
clap = { version = "4.4.5", features = [
|
||||||
|
"derive",
|
||||||
|
"cargo",
|
||||||
|
"wrap_help",
|
||||||
|
"unicode",
|
||||||
|
"string",
|
||||||
|
"unstable-styles",
|
||||||
|
] }
|
||||||
|
color-eyre = "0.6.3"
|
||||||
|
crossterm = { version = "0.28.1", features = ["event-stream"] }
|
||||||
|
futures = "0.3.30"
|
||||||
|
ratatui = "0.29.0"
|
||||||
|
serde = { version = "1.0.217", features = ["derive"] }
|
||||||
|
tokio = { version = "1.43.0", features = ["full"] }
|
||||||
|
toml = "0.8.13"
|
||||||
|
tracing = "0.1.41"
|
||||||
|
tracing-error = "0.2.0"
|
||||||
|
tracing-subscriber = { version = "0.3.18", features = ["env-filter", "serde"] }
|
||||||
|
check_elevation = "0.2.4"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
anyhow = "1.0.86"
|
||||||
|
vergen-gix = { version = "1.0.0", features = ["build", "cargo"] }
|
||||||
28
boot_diags/build.rs
Normal file
28
boot_diags/build.rs
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
// 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 <https://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
use anyhow::Result;
|
||||||
|
use vergen_gix::{BuildBuilder, CargoBuilder, Emitter, GixBuilder};
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
let build = BuildBuilder::all_build()?;
|
||||||
|
let gix = GixBuilder::all_git()?;
|
||||||
|
let cargo = CargoBuilder::all_cargo()?;
|
||||||
|
Emitter::default()
|
||||||
|
.add_instructions(&build)?
|
||||||
|
.add_instructions(&gix)?
|
||||||
|
.add_instructions(&cargo)?
|
||||||
|
.emit()
|
||||||
|
}
|
||||||
1045
boot_diags/src/app.rs
Normal file
1045
boot_diags/src/app.rs
Normal file
File diff suppressed because it is too large
Load diff
102
boot_diags/src/diags.rs
Normal file
102
boot_diags/src/diags.rs
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
// 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 <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
pub enum Type {
|
||||||
|
Bitlocker,
|
||||||
|
BootConfigData,
|
||||||
|
FileSystem,
|
||||||
|
FilesAndFolders,
|
||||||
|
Registry,
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Groups {
|
||||||
|
items: HashMap<String, Line>,
|
||||||
|
order: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Groups {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Groups {
|
||||||
|
items: HashMap::new(),
|
||||||
|
order: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self) -> Vec<&Line> {
|
||||||
|
let mut lines = Vec::new();
|
||||||
|
self.order.iter().for_each(|key| {
|
||||||
|
if let Some(line) = self.items.get(key) {
|
||||||
|
lines.push(line);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
lines
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(&mut self, title: String, passed: bool, info: String) {
|
||||||
|
if let Some(line) = self.items.get_mut(&title) {
|
||||||
|
line.update(passed, info);
|
||||||
|
} else {
|
||||||
|
self.order.push(title.clone());
|
||||||
|
self.items.insert(
|
||||||
|
title.clone(),
|
||||||
|
Line {
|
||||||
|
title,
|
||||||
|
passed,
|
||||||
|
info: vec![info],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Line {
|
||||||
|
pub title: String,
|
||||||
|
pub passed: bool,
|
||||||
|
pub info: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Line {
|
||||||
|
pub fn update(&mut self, passed: bool, info: String) {
|
||||||
|
self.passed &= passed; // We fail if any tests in this group fail
|
||||||
|
self.info.push(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_type(cmd_name: &str) -> Type {
|
||||||
|
if cmd_name == "exa" {
|
||||||
|
return Type::BootConfigData;
|
||||||
|
}
|
||||||
|
if cmd_name == "bcdedit.exe" {
|
||||||
|
return Type::BootConfigData;
|
||||||
|
}
|
||||||
|
if cmd_name == "dir" {
|
||||||
|
return Type::FilesAndFolders;
|
||||||
|
}
|
||||||
|
if cmd_name == "reg.exe" {
|
||||||
|
return Type::Registry;
|
||||||
|
}
|
||||||
|
if cmd_name == "chkdsk.exe" {
|
||||||
|
return Type::FileSystem;
|
||||||
|
}
|
||||||
|
if cmd_name == "manage-bde.exe" {
|
||||||
|
return Type::Bitlocker;
|
||||||
|
}
|
||||||
|
Type::Unknown
|
||||||
|
}
|
||||||
47
boot_diags/src/main.rs
Normal file
47
boot_diags/src/main.rs
Normal file
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
use clap::Parser;
|
||||||
|
use color_eyre::Result;
|
||||||
|
|
||||||
|
use crate::app::App;
|
||||||
|
|
||||||
|
mod app;
|
||||||
|
mod diags;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<()> {
|
||||||
|
let mut msg = None;
|
||||||
|
if cfg!(windows) {
|
||||||
|
use check_elevation::is_elevated;
|
||||||
|
if !is_elevated().expect("Failed to get elevation status.") {
|
||||||
|
msg.replace("Administrator privedges required for Deja-Vu.");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match msg {
|
||||||
|
Some(text) => {
|
||||||
|
println!("{text}");
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
core::errors::init()?;
|
||||||
|
core::logging::init()?;
|
||||||
|
|
||||||
|
let args = core::cli::Cli::parse();
|
||||||
|
let mut app = App::new(args.tick_rate, args.frame_rate)?;
|
||||||
|
app.run().await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"app_title": "Deja-vu",
|
"app_title": "Deja-Vu",
|
||||||
"clone_app_path": "C:/Program Files/Some Clone Tool/app.exe",
|
"clone_app_path": "C:/Program Files/Some Clone Tool/app.exe",
|
||||||
"conemu_path": "C:/Program Files/ConEmu/ConEmu64.exe",
|
"conemu_path": "C:/Program Files/ConEmu/ConEmu64.exe",
|
||||||
"keybindings": {
|
"keybindings": {
|
||||||
|
|
@ -82,7 +82,7 @@
|
||||||
"<Ctrl-z>": "Suspend"
|
"<Ctrl-z>": "Suspend"
|
||||||
},
|
},
|
||||||
"Done": {
|
"Done": {
|
||||||
"<Enter>": "Quit",
|
"<Enter>": "Process",
|
||||||
"<q>": "Quit",
|
"<q>": "Quit",
|
||||||
"<Ctrl-d>": "Quit",
|
"<Ctrl-d>": "Quit",
|
||||||
"<Ctrl-c>": "Quit",
|
"<Ctrl-c>": "Quit",
|
||||||
|
|
@ -95,11 +95,66 @@
|
||||||
"<Ctrl-c>": "Quit",
|
"<Ctrl-c>": "Quit",
|
||||||
"<Ctrl-z>": "Suspend"
|
"<Ctrl-z>": "Suspend"
|
||||||
},
|
},
|
||||||
|
"DiagMenu": {
|
||||||
|
"<Enter>": "Process",
|
||||||
|
"<Up>": "KeyUp",
|
||||||
|
"<Down>": "KeyDown",
|
||||||
|
"<s>": "ScanDisks",
|
||||||
|
"<q>": "Quit",
|
||||||
|
"<Ctrl-d>": "Quit",
|
||||||
|
"<Ctrl-c>": "Quit",
|
||||||
|
"<Ctrl-z>": "Suspend"
|
||||||
|
},
|
||||||
|
"BootDiags": {
|
||||||
|
"<Enter>": "Process",
|
||||||
|
"<Up>": "KeyUp",
|
||||||
|
"<Down>": "KeyDown",
|
||||||
|
"<r>": "BootScan",
|
||||||
|
"<q>": "Quit",
|
||||||
|
"<Ctrl-d>": "Quit",
|
||||||
|
"<Ctrl-c>": "Quit",
|
||||||
|
"<Ctrl-z>": "Suspend"
|
||||||
|
},
|
||||||
|
"BootScan": {
|
||||||
|
"<q>": "Quit",
|
||||||
|
"<Ctrl-d>": "Quit",
|
||||||
|
"<Ctrl-c>": "Quit",
|
||||||
|
"<Ctrl-z>": "Suspend"
|
||||||
|
},
|
||||||
|
"BootSetup": {
|
||||||
|
"<Enter>": "Process",
|
||||||
|
"<Up>": "KeyUp",
|
||||||
|
"<Down>": "KeyDown",
|
||||||
|
"<q>": "Quit",
|
||||||
|
"<Ctrl-d>": "Quit",
|
||||||
|
"<Ctrl-c>": "Quit",
|
||||||
|
"<Ctrl-z>": "Suspend"
|
||||||
|
},
|
||||||
|
"InjectDrivers": {
|
||||||
|
"<Enter>": "Process",
|
||||||
|
"<Up>": "KeyUp",
|
||||||
|
"<Down>": "KeyDown",
|
||||||
|
"<q>": "Quit",
|
||||||
|
"<Ctrl-d>": "Quit",
|
||||||
|
"<Ctrl-c>": "Quit",
|
||||||
|
"<Ctrl-z>": "Suspend"
|
||||||
|
},
|
||||||
|
"SetBootMode": {
|
||||||
|
"<Enter>": "Process",
|
||||||
|
"<Up>": "KeyUp",
|
||||||
|
"<Down>": "KeyDown",
|
||||||
|
"<q>": "Quit",
|
||||||
|
"<Ctrl-d>": "Quit",
|
||||||
|
"<Ctrl-c>": "Quit",
|
||||||
|
"<Ctrl-z>": "Suspend"
|
||||||
|
},
|
||||||
"PEMenu": {
|
"PEMenu": {
|
||||||
"<Enter>": "Process",
|
"<Enter>": "Process",
|
||||||
"<Up>": "KeyUp",
|
"<Up>": "KeyUp",
|
||||||
"<Down>": "KeyDown",
|
"<Down>": "KeyDown",
|
||||||
"<q>": "Quit",
|
"<q>": "Quit",
|
||||||
|
"<r>": "Restart",
|
||||||
|
"<p>": "Shutdown",
|
||||||
"<t>": "OpenTerminal",
|
"<t>": "OpenTerminal",
|
||||||
"<Ctrl-d>": "Quit",
|
"<Ctrl-d>": "Quit",
|
||||||
"<Ctrl-c>": "Quit",
|
"<Ctrl-c>": "Quit",
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,22 @@
|
||||||
# This file is part of Deja-vu.
|
# This file is part of Deja-Vu.
|
||||||
#
|
#
|
||||||
# Deja-vu is free software: you can redistribute it and/or modify it
|
# 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
|
# under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# Deja-vu is distributed in the hope that it will be useful, but
|
# Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
# See the GNU General Public License for more details.
|
# See the GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# 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/>.
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "core"
|
name = "core"
|
||||||
authors = ["2Shirt <2xShirt@gmail.com>"]
|
authors = ["2Shirt <2xShirt@gmail.com>"]
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
license = "GPL"
|
license = "GPL"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
|
||||||
|
|
@ -42,6 +42,7 @@ lazy_static = "1.5.0"
|
||||||
libc = "0.2.158"
|
libc = "0.2.158"
|
||||||
once_cell = "1.20.2"
|
once_cell = "1.20.2"
|
||||||
pretty_assertions = "1.4.0"
|
pretty_assertions = "1.4.0"
|
||||||
|
rand = "0.9.0"
|
||||||
ratatui = { version = "0.29.0", features = ["serde", "macros"] }
|
ratatui = { version = "0.29.0", features = ["serde", "macros"] }
|
||||||
raw-cpuid = "11.2.0"
|
raw-cpuid = "11.2.0"
|
||||||
regex = "1.11.1"
|
regex = "1.11.1"
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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 anyhow::Result;
|
use anyhow::Result;
|
||||||
use vergen_gix::{BuildBuilder, CargoBuilder, Emitter, GixBuilder};
|
use vergen_gix::{BuildBuilder, CargoBuilder, Emitter, GixBuilder};
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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 serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use strum::Display;
|
use strum::Display;
|
||||||
|
|
@ -20,6 +20,8 @@ use crate::{components::popup::Type, line::DVLine, state::Mode, system::disk::Di
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Display, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Display, Serialize, Deserialize)]
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
|
// App (Boot-Diags)
|
||||||
|
BootScan,
|
||||||
// App (Clone)
|
// App (Clone)
|
||||||
Highlight(usize),
|
Highlight(usize),
|
||||||
InstallDriver,
|
InstallDriver,
|
||||||
|
|
@ -27,6 +29,7 @@ pub enum Action {
|
||||||
ScanDisks,
|
ScanDisks,
|
||||||
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
|
||||||
|
TasksComplete,
|
||||||
UpdateDiskList(Vec<Disk>),
|
UpdateDiskList(Vec<Disk>),
|
||||||
UpdateFooter(String),
|
UpdateFooter(String),
|
||||||
UpdateLeft(String, Vec<String>, Vec<String>, usize), // (title, labels, items, select_num)
|
UpdateLeft(String, Vec<String>, Vec<String>, usize), // (title, labels, items, select_num)
|
||||||
|
|
@ -35,8 +38,10 @@ pub enum Action {
|
||||||
// 1: For a single choice
|
// 1: For a single choice
|
||||||
// 2: For two selections (obviously)
|
// 2: For two selections (obviously)
|
||||||
UpdateRight(Vec<Vec<DVLine>>, usize, Vec<Vec<DVLine>>), // (labels, start_index, items) - items before start are always shown
|
UpdateRight(Vec<Vec<DVLine>>, usize, Vec<Vec<DVLine>>), // (labels, start_index, items) - items before start are always shown
|
||||||
// App (PEMenu)
|
// App (PE-Menu)
|
||||||
OpenTerminal,
|
OpenTerminal,
|
||||||
|
Restart,
|
||||||
|
Shutdown,
|
||||||
// Screens
|
// Screens
|
||||||
DismissPopup,
|
DismissPopup,
|
||||||
DisplayPopup(Type, String),
|
DisplayPopup(Type, String),
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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 clap::Parser;
|
use clap::Parser;
|
||||||
|
|
||||||
|
|
@ -38,6 +38,7 @@ const VERSION_MESSAGE: &str = concat!(
|
||||||
")"
|
")"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn version() -> String {
|
pub fn version() -> String {
|
||||||
let author = clap::crate_authors!();
|
let author = clap::crate_authors!();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,24 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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/>.
|
||||||
//
|
#![allow(clippy::missing_errors_doc)]
|
||||||
|
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use crossterm::event::{KeyEvent, MouseEvent};
|
use crossterm::event::{KeyEvent, MouseEvent};
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
layout::{Rect, Size},
|
|
||||||
Frame,
|
Frame,
|
||||||
|
layout::{Rect, Size},
|
||||||
};
|
};
|
||||||
use tokio::sync::mpsc::UnboundedSender;
|
use tokio::sync::mpsc::UnboundedSender;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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 color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
|
|
@ -31,6 +31,7 @@ pub struct Footer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Footer {
|
impl Footer {
|
||||||
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
text: String::from("(q) to quit"),
|
text: String::from("(q) to quit"),
|
||||||
|
|
@ -51,6 +52,7 @@ impl Component for Footer {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, action: Action) -> Result<Option<Action>> {
|
fn update(&mut self, action: Action) -> Result<Option<Action>> {
|
||||||
|
#[allow(clippy::single_match)]
|
||||||
match action {
|
match action {
|
||||||
Action::UpdateFooter(text) => self.text = text,
|
Action::UpdateFooter(text) => self.text = text,
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,27 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
|
Frame,
|
||||||
layout::{Constraint, Layout, Rect},
|
layout::{Constraint, Layout, Rect},
|
||||||
style::{Style, Stylize},
|
style::{Style, Stylize},
|
||||||
text::Span,
|
text::Span,
|
||||||
widgets::Paragraph,
|
widgets::Paragraph,
|
||||||
Frame,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::Component;
|
use super::Component;
|
||||||
|
|
@ -46,6 +46,7 @@ impl Default for FpsCounter {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FpsCounter {
|
impl FpsCounter {
|
||||||
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
last_tick_update: Instant::now(),
|
last_tick_update: Instant::now(),
|
||||||
|
|
@ -57,24 +58,26 @@ impl FpsCounter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::unnecessary_wraps)]
|
||||||
fn app_tick(&mut self) -> Result<()> {
|
fn app_tick(&mut self) -> Result<()> {
|
||||||
self.tick_count += 1;
|
self.tick_count += 1;
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
let elapsed = (now - self.last_tick_update).as_secs_f64();
|
let elapsed = (now - self.last_tick_update).as_secs_f64();
|
||||||
if elapsed >= 1.0 {
|
if elapsed >= 1.0 {
|
||||||
self.ticks_per_second = self.tick_count as f64 / elapsed;
|
self.ticks_per_second = f64::from(self.tick_count) / elapsed;
|
||||||
self.last_tick_update = now;
|
self.last_tick_update = now;
|
||||||
self.tick_count = 0;
|
self.tick_count = 0;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::unnecessary_wraps)]
|
||||||
fn render_tick(&mut self) -> Result<()> {
|
fn render_tick(&mut self) -> Result<()> {
|
||||||
self.frame_count += 1;
|
self.frame_count += 1;
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
let elapsed = (now - self.last_frame_update).as_secs_f64();
|
let elapsed = (now - self.last_frame_update).as_secs_f64();
|
||||||
if elapsed >= 1.0 {
|
if elapsed >= 1.0 {
|
||||||
self.frames_per_second = self.frame_count as f64 / elapsed;
|
self.frames_per_second = f64::from(self.frame_count) / elapsed;
|
||||||
self.last_frame_update = now;
|
self.last_frame_update = now;
|
||||||
self.frame_count = 0;
|
self.frame_count = 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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 color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use crossterm::event::KeyEvent;
|
use crossterm::event::KeyEvent;
|
||||||
|
|
@ -21,7 +21,7 @@ use ratatui::{
|
||||||
};
|
};
|
||||||
use tokio::sync::mpsc::UnboundedSender;
|
use tokio::sync::mpsc::UnboundedSender;
|
||||||
|
|
||||||
use super::{state::StatefulList, Component};
|
use super::{Component, state::StatefulList};
|
||||||
use crate::{action::Action, config::Config};
|
use crate::{action::Action, config::Config};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
@ -37,6 +37,7 @@ pub struct Left {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Left {
|
impl Left {
|
||||||
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
select_num: 0,
|
select_num: 0,
|
||||||
|
|
@ -138,14 +139,10 @@ 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()
|
.block(Block::default().borders(Borders::NONE));
|
||||||
};
|
|
||||||
let title =
|
|
||||||
Paragraph::new(Line::from(Span::styled(title_text, Style::default())).centered())
|
|
||||||
.block(Block::default().borders(Borders::NONE));
|
|
||||||
frame.render_widget(title, title_area);
|
frame.render_widget(title, title_area);
|
||||||
|
|
||||||
// Body (Blank)
|
// Body (Blank)
|
||||||
|
|
@ -171,7 +168,7 @@ impl Component for Left {
|
||||||
.map(|(index, item)| {
|
.map(|(index, item)| {
|
||||||
let mut style = Style::default();
|
let mut style = Style::default();
|
||||||
let text = if self.selections[0].is_some_and(|first_index| first_index == index) {
|
let text = if self.selections[0].is_some_and(|first_index| first_index == index) {
|
||||||
if let Some(label) = self.labels.get(0) {
|
if let Some(label) = self.labels.first() {
|
||||||
style = style.yellow();
|
style = style.yellow();
|
||||||
label.as_str()
|
label.as_str()
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,20 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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 color_eyre::Result;
|
use color_eyre::Result;
|
||||||
|
use rand::random;
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
widgets::{Block, Borders, Clear, Paragraph, Wrap},
|
widgets::{Block, Borders, Clear, Paragraph, Wrap},
|
||||||
|
|
@ -42,6 +43,7 @@ pub struct Popup {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Popup {
|
impl Popup {
|
||||||
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
@ -95,3 +97,20 @@ impl Component for Popup {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn fortune() -> String {
|
||||||
|
String::from(match random::<u8>() / 4 {
|
||||||
|
0 => "FUN FACT\n\n\nComputers barely work.",
|
||||||
|
1 => "CRASH OVERRIDE\n\n\n\"Hack the planet!\"",
|
||||||
|
2 => "CATS\n\n\n\"All your base are belong to us!\"",
|
||||||
|
3 => "HMM\n\n\nThis has all happened before...\n\nThis will all happen again.",
|
||||||
|
4 => "CYPHER\n\n\n\"I don’t even see the code. All I see is blonde, brunette, red-head.\"",
|
||||||
|
5 => "CONGRATULATIONS\n\n\nYour did it!",
|
||||||
|
6 => "DID YOU KNOW?\n\n\nmacOS includes a built-in screen reader!",
|
||||||
|
7 => "TIP OF THE DAY\n\n\nNever go full Snappy!",
|
||||||
|
8 => "WORDS OF WISDOM\n\n\n\nIt’s not DNS,\n\nThere’s no way it’s DNS,\n\nIt was DNS.",
|
||||||
|
9 => "HAL 9000\n\n\n\"I'm sorry Dave, I'm afraid I can't do that.\"",
|
||||||
|
_ => "COMPLETE\n\n\nThank you for using this tool!",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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 color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use crossterm::event::KeyEvent;
|
use crossterm::event::KeyEvent;
|
||||||
|
|
@ -21,7 +21,7 @@ use ratatui::{
|
||||||
};
|
};
|
||||||
use tokio::sync::mpsc::UnboundedSender;
|
use tokio::sync::mpsc::UnboundedSender;
|
||||||
|
|
||||||
use super::{state::StatefulList, Component};
|
use super::{Component, state::StatefulList};
|
||||||
use crate::{action::Action, config::Config, line::DVLine};
|
use crate::{action::Action, config::Config, line::DVLine};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
@ -37,6 +37,7 @@ pub struct Right {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Right {
|
impl Right {
|
||||||
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
selections: vec![None, None],
|
selections: vec![None, None],
|
||||||
|
|
@ -150,7 +151,7 @@ impl Component for Right {
|
||||||
// First selection
|
// First selection
|
||||||
if let Some(first_index) = self.get_first() {
|
if let Some(first_index) = self.get_first() {
|
||||||
if let Some(first_desc) = self.list.get(first_index) {
|
if let Some(first_desc) = self.list.get(first_index) {
|
||||||
if let Some(label) = self.list_labels.get(0) {
|
if let Some(label) = self.list_labels.first() {
|
||||||
label
|
label
|
||||||
.iter()
|
.iter()
|
||||||
.for_each(|dv| body_text.push(dv.as_line().bold()));
|
.for_each(|dv| body_text.push(dv.as_line().bold()));
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
|
@ -31,14 +31,17 @@ impl<T: Clone> StatefulList<T> {
|
||||||
self.items.clear();
|
self.items.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn get(&self, index: usize) -> Option<&T> {
|
pub fn get(&self, index: usize) -> Option<&T> {
|
||||||
self.items.get(index)
|
self.items.get(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn get_selected(&self) -> Option<T> {
|
pub fn get_selected(&self) -> Option<T> {
|
||||||
self.state.selected().map(|i| self.items[i].clone())
|
self.state.selected().map(|i| self.items[i].clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.items.is_empty()
|
self.items.is_empty()
|
||||||
}
|
}
|
||||||
|
|
@ -51,11 +54,12 @@ impl<T: Clone> StatefulList<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn selected(&self) -> Option<usize> {
|
pub fn selected(&self) -> Option<usize> {
|
||||||
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 {
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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 color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
|
|
@ -31,6 +31,7 @@ pub struct Title {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Title {
|
impl Title {
|
||||||
|
#[must_use]
|
||||||
pub fn new(text: &str) -> Self {
|
pub fn new(text: &str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
text: String::from(text),
|
text: String::from(text),
|
||||||
|
|
@ -51,6 +52,7 @@ impl Component for Title {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, action: Action) -> Result<Option<Action>> {
|
fn update(&mut self, action: Action) -> Result<Option<Action>> {
|
||||||
|
#[allow(clippy::match_single_binding)]
|
||||||
match action {
|
match action {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,20 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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/>.
|
||||||
//
|
#![allow(clippy::missing_errors_doc)]
|
||||||
|
#![allow(clippy::missing_panics_doc)]
|
||||||
|
#![allow(clippy::ref_option)]
|
||||||
#![allow(dead_code)] // Remove this once you start using the code
|
#![allow(dead_code)] // Remove this once you start using the code
|
||||||
|
|
||||||
use std::{collections::HashMap, env, path::PathBuf};
|
use std::{collections::HashMap, env, path::PathBuf};
|
||||||
|
|
@ -23,7 +25,7 @@ use derive_deref::{Deref, DerefMut};
|
||||||
use directories::ProjectDirs;
|
use directories::ProjectDirs;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use ratatui::style::{Color, Modifier, Style};
|
use ratatui::style::{Color, Modifier, Style};
|
||||||
use serde::{de::Deserializer, Deserialize};
|
use serde::{Deserialize, de::Deserializer};
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
|
||||||
use crate::{action::Action, state::Mode};
|
use crate::{action::Action, state::Mode};
|
||||||
|
|
@ -54,15 +56,15 @@ pub struct Config {
|
||||||
pub styles: Styles,
|
pub styles: Styles,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static PROJECT_NAME: &'static str = "DEJA-VU";
|
pub static PROJECT_NAME: &str = "DEJA-VU";
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
//pub static ref PROJECT_NAME: String = env!("CARGO_PKG_NAME").to_uppercase().to_string();
|
//pub static ref PROJECT_NAME: String = env!("CARGO_PKG_NAME").to_uppercase().to_string();
|
||||||
pub static ref DATA_FOLDER: Option<PathBuf> =
|
pub static ref DATA_FOLDER: Option<PathBuf> =
|
||||||
env::var(format!("{}_DATA", PROJECT_NAME))
|
env::var(format!("{PROJECT_NAME}_DATA"))
|
||||||
.ok()
|
.ok()
|
||||||
.map(PathBuf::from);
|
.map(PathBuf::from);
|
||||||
pub static ref CONFIG_FOLDER: Option<PathBuf> =
|
pub static ref CONFIG_FOLDER: Option<PathBuf> =
|
||||||
env::var(format!("{}_CONFIG", PROJECT_NAME))
|
env::var(format!("{PROJECT_NAME}_CONFIG"))
|
||||||
.ok()
|
.ok()
|
||||||
.map(PathBuf::from);
|
.map(PathBuf::from);
|
||||||
}
|
}
|
||||||
|
|
@ -126,6 +128,7 @@ impl Config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn get_data_dir() -> PathBuf {
|
pub fn get_data_dir() -> PathBuf {
|
||||||
let directory = if let Some(s) = DATA_FOLDER.clone() {
|
let directory = if let Some(s) = DATA_FOLDER.clone() {
|
||||||
s
|
s
|
||||||
|
|
@ -137,6 +140,7 @@ pub fn get_data_dir() -> PathBuf {
|
||||||
directory
|
directory
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn get_config_dir() -> PathBuf {
|
pub fn get_config_dir() -> PathBuf {
|
||||||
let directory = if let Some(s) = CONFIG_FOLDER.clone() {
|
let directory = if let Some(s) = CONFIG_FOLDER.clone() {
|
||||||
s
|
s
|
||||||
|
|
@ -149,8 +153,8 @@ pub fn get_config_dir() -> PathBuf {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn project_directory() -> Option<ProjectDirs> {
|
fn project_directory() -> Option<ProjectDirs> {
|
||||||
ProjectDirs::from("com", "Deja-vu", "deja-vu")
|
ProjectDirs::from("com", "Deja-Vu", "deja-vu")
|
||||||
//ProjectDirs::from("com", "Deja-vu", env!("CARGO_PKG_NAME"))
|
//ProjectDirs::from("com", "Deja-Vu", env!("CARGO_PKG_NAME"))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Deref, DerefMut)]
|
#[derive(Clone, Debug, Default, Deref, DerefMut)]
|
||||||
|
|
@ -258,6 +262,7 @@ fn parse_key_code_with_modifiers(
|
||||||
Ok(KeyEvent::new(c, modifiers))
|
Ok(KeyEvent::new(c, modifiers))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn key_event_to_string(key_event: &KeyEvent) -> String {
|
pub fn key_event_to_string(key_event: &KeyEvent) -> String {
|
||||||
let char;
|
let char;
|
||||||
let key_code = match key_event.code {
|
let key_code = match key_event.code {
|
||||||
|
|
@ -373,6 +378,7 @@ impl<'de> Deserialize<'de> for Styles {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn parse_style(line: &str) -> Style {
|
pub fn parse_style(line: &str) -> Style {
|
||||||
let (foreground, background) =
|
let (foreground, background) =
|
||||||
line.split_at(line.to_lowercase().find("on ").unwrap_or(line.len()));
|
line.split_at(line.to_lowercase().find("on ").unwrap_or(line.len()));
|
||||||
|
|
@ -435,8 +441,11 @@ fn parse_color(s: &str) -> Option<Color> {
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
Some(Color::Indexed(c))
|
Some(Color::Indexed(c))
|
||||||
} else if s.contains("rgb") {
|
} else if s.contains("rgb") {
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
let red = (s.as_bytes()[3] as char).to_digit(10).unwrap_or_default() as u8;
|
let red = (s.as_bytes()[3] as char).to_digit(10).unwrap_or_default() as u8;
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
let green = (s.as_bytes()[4] as char).to_digit(10).unwrap_or_default() as u8;
|
let green = (s.as_bytes()[4] as char).to_digit(10).unwrap_or_default() as u8;
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
let blue = (s.as_bytes()[5] as char).to_digit(10).unwrap_or_default() as u8;
|
let blue = (s.as_bytes()[5] as char).to_digit(10).unwrap_or_default() as u8;
|
||||||
let c = 16 + red * 36 + green * 6 + blue;
|
let c = 16 + red * 36 + green * 6 + blue;
|
||||||
Some(Color::Indexed(c))
|
Some(Color::Indexed(c))
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,19 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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/>.
|
||||||
//
|
#![allow(clippy::missing_errors_doc)]
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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/>.
|
||||||
//
|
//
|
||||||
pub mod action;
|
pub mod action;
|
||||||
pub mod cli;
|
pub mod cli;
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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 ratatui::{
|
use ratatui::{
|
||||||
style::{Color, Style},
|
style::{Color, Style},
|
||||||
|
|
@ -30,6 +30,7 @@ pub struct DVLine {
|
||||||
|
|
||||||
impl DVLine {
|
impl DVLine {
|
||||||
/// Convert to Line with colored span(s)
|
/// Convert to Line with colored span(s)
|
||||||
|
#[must_use]
|
||||||
pub fn as_line(&self) -> Line {
|
pub fn as_line(&self) -> Line {
|
||||||
let mut spans = Vec::new();
|
let mut spans = Vec::new();
|
||||||
zip(self.line_parts.clone(), self.line_colors.clone())
|
zip(self.line_parts.clone(), self.line_colors.clone())
|
||||||
|
|
@ -37,6 +38,7 @@ impl DVLine {
|
||||||
Line::from(spans)
|
Line::from(spans)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn blank() -> Self {
|
pub fn blank() -> Self {
|
||||||
Self {
|
Self {
|
||||||
line_parts: vec![String::new()],
|
line_parts: vec![String::new()],
|
||||||
|
|
@ -45,7 +47,11 @@ impl DVLine {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_disk_description_right(disk: &Disk) -> Vec<DVLine> {
|
#[must_use]
|
||||||
|
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,15 +73,33 @@ 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.first();
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn get_part_description(part: &Partition) -> Vec<DVLine> {
|
pub fn get_part_description(part: &Partition) -> Vec<DVLine> {
|
||||||
let description: Vec<DVLine> = vec![
|
let description: Vec<DVLine> = vec![
|
||||||
DVLine {
|
DVLine {
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,22 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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/>.
|
||||||
//
|
#![allow(clippy::missing_errors_doc)]
|
||||||
|
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use tracing_error::ErrorLayer;
|
use tracing_error::ErrorLayer;
|
||||||
use tracing_subscriber::{fmt, prelude::*, EnvFilter};
|
use tracing_subscriber::{EnvFilter, fmt, prelude::*};
|
||||||
|
|
||||||
use crate::config;
|
use crate::config;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
@ -30,6 +30,13 @@ pub enum Mode {
|
||||||
Home,
|
Home,
|
||||||
Done,
|
Done,
|
||||||
Failed,
|
Failed,
|
||||||
|
// Boot Diags
|
||||||
|
DiagMenu,
|
||||||
|
BootDiags,
|
||||||
|
BootScan,
|
||||||
|
BootSetup,
|
||||||
|
InjectDrivers,
|
||||||
|
SetBootMode,
|
||||||
// Clone
|
// Clone
|
||||||
ScanDisks,
|
ScanDisks,
|
||||||
InstallDrivers,
|
InstallDrivers,
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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/>.
|
||||||
//
|
//
|
||||||
pub mod boot;
|
pub mod boot;
|
||||||
pub mod cpu;
|
pub mod cpu;
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,43 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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/>.
|
||||||
//
|
#![allow(clippy::missing_errors_doc)]
|
||||||
|
#![allow(clippy::missing_panics_doc)]
|
||||||
|
|
||||||
use super::{disk::PartitionTableType, drivers::Driver};
|
use super::{disk::PartitionTableType, drivers::Driver};
|
||||||
use crate::tasks::Task;
|
use crate::tasks::TaskType;
|
||||||
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,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn configure_disk(
|
pub fn configure_disk(
|
||||||
letter_boot: &str,
|
letter_boot: &str,
|
||||||
letter_os: &str,
|
letter_os: &str,
|
||||||
system32: &str,
|
system32: &str,
|
||||||
table_type: PartitionTableType,
|
table_type: &PartitionTableType,
|
||||||
) -> Vec<Task> {
|
) -> Vec<TaskType> {
|
||||||
let mut tasks = Vec::new();
|
let mut tasks = Vec::new();
|
||||||
|
|
||||||
// Create
|
// Create
|
||||||
tasks.push(Task::Command(
|
tasks.push(TaskType::CommandWait(
|
||||||
PathBuf::from(format!("{system32}/bcdboot.exe")),
|
PathBuf::from(format!("{system32}/bcdboot.exe")),
|
||||||
vec![
|
vec![
|
||||||
format!("{letter_os}:\\Windows"),
|
format!("{letter_os}:\\Windows"),
|
||||||
|
|
@ -42,8 +52,8 @@ pub fn configure_disk(
|
||||||
));
|
));
|
||||||
|
|
||||||
// Update boot sector (for legacy setups)
|
// Update boot sector (for legacy setups)
|
||||||
if table_type == PartitionTableType::Legacy {
|
if *table_type == PartitionTableType::Legacy {
|
||||||
tasks.push(Task::Command(
|
tasks.push(TaskType::CommandWait(
|
||||||
PathBuf::from(format!("{system32}/bootsect.exe")),
|
PathBuf::from(format!("{system32}/bootsect.exe")),
|
||||||
vec![
|
vec![
|
||||||
String::from("/nt60"),
|
String::from("/nt60"),
|
||||||
|
|
@ -55,34 +65,19 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inject_driver(driver: &Driver, letter_os: &str, system32: &str) -> Result<Task> {
|
pub fn inject_driver(driver: &Driver, letter_os: &str, system32: &str) -> Result<TaskType> {
|
||||||
//if let Some(driver_path_str) = driver.path.to_str() {
|
//if let Some(driver_path_str) = driver.path.to_str() {
|
||||||
let driver_path = driver.path.to_str().unwrap();
|
let driver_path = driver.path.to_str().unwrap();
|
||||||
Ok(Task::Command(
|
Ok(TaskType::CommandWait(
|
||||||
PathBuf::from(format!("{system32}/dism.exe")),
|
PathBuf::from(format!("{system32}/dism.exe")),
|
||||||
vec![
|
vec![
|
||||||
format!("/image:{letter_os}:\\"),
|
format!("/image:{letter_os}:\\"),
|
||||||
|
|
@ -92,3 +87,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<TaskType> {
|
||||||
|
let bcd_path = match table_type {
|
||||||
|
PartitionTableType::Guid => {
|
||||||
|
format!("{letter_boot}:\\EFI\\Microsoft\\Boot\\BCD")
|
||||||
|
}
|
||||||
|
PartitionTableType::Legacy => {
|
||||||
|
format!("{letter_boot}:\\Boot\\BCD")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Build CommandWait
|
||||||
|
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(TaskType::CommandWait(
|
||||||
|
PathBuf::from(format!("{system32}/bcdedit.exe")),
|
||||||
|
cmd_args,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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/>.
|
||||||
//
|
//
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_cpu_name() -> String {
|
pub fn get_cpu_name() -> String {
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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 serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
|
|
@ -67,6 +67,7 @@ impl Disk {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn get_part_letter(&self, part_index: usize) -> String {
|
pub fn get_part_letter(&self, part_index: usize) -> String {
|
||||||
// Used to get Boot and OS letters
|
// Used to get Boot and OS letters
|
||||||
if let Some(part) = self.parts.get(part_index) {
|
if let Some(part) = self.parts.get(part_index) {
|
||||||
|
|
@ -76,10 +77,12 @@ impl Disk {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn get_parts(&self) -> Vec<Partition> {
|
pub fn get_parts(&self) -> Vec<Partition> {
|
||||||
self.parts.clone()
|
self.parts.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn num_parts(&self) -> usize {
|
pub fn num_parts(&self) -> usize {
|
||||||
self.parts.len()
|
self.parts.len()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,19 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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/>.
|
||||||
//
|
#![allow(clippy::missing_panics_doc)]
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fs::File,
|
fs::File,
|
||||||
|
|
@ -26,7 +27,7 @@ use tempfile::tempdir;
|
||||||
use tracing::{info, warn};
|
use tracing::{info, warn};
|
||||||
|
|
||||||
use crate::system::disk::{
|
use crate::system::disk::{
|
||||||
get_disk_serial_number, string_to_bytes, Disk, Partition, PartitionTableType,
|
Disk, Partition, PartitionTableType, get_disk_serial_number, string_to_bytes,
|
||||||
};
|
};
|
||||||
|
|
||||||
static DEFAULT_MAX_DISKS: usize = 8;
|
static DEFAULT_MAX_DISKS: usize = 8;
|
||||||
|
|
@ -129,7 +130,7 @@ pub fn get_partition_details(
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn build_dest_format_script(disk_id: usize, part_type: &PartitionTableType) -> String {
|
pub fn build_dest_format_script(disk_id: usize, part_type: &PartitionTableType) -> String {
|
||||||
let disk_id = format!("{disk_id}");
|
let disk_id = format!("{disk_id}");
|
||||||
let mut script = vec!["select disk {disk_id}", "clean"];
|
let mut script = vec!["automount enable noerr", "select disk {disk_id}", "clean"];
|
||||||
match part_type {
|
match part_type {
|
||||||
PartitionTableType::Guid => {
|
PartitionTableType::Guid => {
|
||||||
script.push("convert gpt");
|
script.push("convert gpt");
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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::{env, fmt, fs::read_dir, path::PathBuf, process::Command};
|
use std::{env, fmt, fs::read_dir, path::PathBuf, process::Command};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,27 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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/>.
|
||||||
//
|
#![allow(clippy::missing_errors_doc)]
|
||||||
|
#![allow(clippy::missing_panics_doc)]
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::VecDeque,
|
collections::VecDeque,
|
||||||
|
fmt,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
process::{Command, Stdio},
|
process::{Command, Stdio},
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
thread::{self, sleep, JoinHandle},
|
thread::{self, JoinHandle, sleep},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -34,23 +36,70 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Task {
|
pub enum TaskResult {
|
||||||
Command(PathBuf, Vec<String>), // (command, args)
|
Error(String),
|
||||||
Diskpart(String), // (script_as_string)
|
Output(String, String, bool), // stdout, stderr, success
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum TaskType {
|
||||||
|
CommandNoWait(PathBuf, Vec<String>), // (command, args)
|
||||||
|
CommandWait(PathBuf, Vec<String>), // (command, args)
|
||||||
|
Diskpart(String), // (script_as_string)
|
||||||
ScanDisks,
|
ScanDisks,
|
||||||
Sleep,
|
Sleep,
|
||||||
UpdateDestDisk(usize), // (disk_index)
|
UpdateDestDisk(usize), // (disk_index)
|
||||||
UpdateDiskList,
|
UpdateDiskList,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for TaskType {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
TaskType::CommandNoWait(cmd_path, _) | TaskType::CommandWait(cmd_path, _) => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Command(\"{}\")",
|
||||||
|
cmd_path.file_name().unwrap().to_string_lossy()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
TaskType::Diskpart(_) => {
|
||||||
|
write!(f, "Diskpart")
|
||||||
|
}
|
||||||
|
TaskType::ScanDisks => write!(f, "ScanDisks"),
|
||||||
|
TaskType::Sleep => write!(f, "Sleep"),
|
||||||
|
TaskType::UpdateDestDisk(_) => write!(f, "UpdateDestDisk"),
|
||||||
|
TaskType::UpdateDiskList => write!(f, "UpdateDiskList"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Task {
|
||||||
|
pub handle: Option<JoinHandle<()>>,
|
||||||
|
pub result: Option<TaskResult>,
|
||||||
|
pub task_type: TaskType,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Task {
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(task_type: TaskType) -> Task {
|
||||||
|
Task {
|
||||||
|
handle: None,
|
||||||
|
result: None,
|
||||||
|
task_type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Tasks {
|
pub struct Tasks {
|
||||||
action_tx: mpsc::UnboundedSender<Action>,
|
action_tx: mpsc::UnboundedSender<Action>,
|
||||||
disk_list: Arc<Mutex<Vec<disk::Disk>>>,
|
disk_list: Arc<Mutex<Vec<disk::Disk>>>,
|
||||||
handle: Option<JoinHandle<()>>,
|
cur_handle: Option<JoinHandle<()>>,
|
||||||
|
cur_task: Option<Task>,
|
||||||
task_list: VecDeque<Task>,
|
task_list: VecDeque<Task>,
|
||||||
task_rx: mpsc::UnboundedReceiver<Action>, // Used to forward Actions from Tasks to App
|
task_rx: mpsc::UnboundedReceiver<TaskResult>,
|
||||||
task_tx: mpsc::UnboundedSender<Action>, // Used to forward Actions from Tasks to App
|
task_tx: mpsc::UnboundedSender<TaskResult>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tasks {
|
impl Tasks {
|
||||||
|
|
@ -62,159 +111,186 @@ impl Tasks {
|
||||||
Tasks {
|
Tasks {
|
||||||
action_tx,
|
action_tx,
|
||||||
disk_list: disk_list_arc,
|
disk_list: disk_list_arc,
|
||||||
handle: None,
|
cur_handle: None,
|
||||||
|
cur_task: None,
|
||||||
task_list: VecDeque::new(),
|
task_list: VecDeque::new(),
|
||||||
task_rx,
|
task_rx,
|
||||||
task_tx,
|
task_tx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(&mut self, task: Task) {
|
pub fn add(&mut self, task_type: TaskType) {
|
||||||
info!("Adding task: {:?}", &task);
|
info!("Adding task: {:?}", &task_type);
|
||||||
self.task_list.push_back(task);
|
self.task_list.push_back(Task::new(task_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn idle(&self) -> bool {
|
pub fn idle(&self) -> bool {
|
||||||
self.handle.is_none()
|
self.cur_handle.is_none()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn poll(&mut self) -> Result<()> {
|
pub fn poll(&mut self) -> Result<Option<Task>> {
|
||||||
// Forward any actions to main app
|
let mut return_task: Option<Task> = None;
|
||||||
if let Ok(action) = self.task_rx.try_recv() {
|
// Handle task channel item(s)
|
||||||
let result = self.action_tx.send(action.clone());
|
if let Ok(result) = self.task_rx.try_recv() {
|
||||||
assert!(result.is_ok(), "Failed to send Action: {action:?}");
|
if let Some(mut task) = self.cur_task.take() {
|
||||||
|
task.result.replace(result);
|
||||||
|
self.cur_task.replace(task);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check status of current task (if one is running).
|
// Check status of current task (if one is running).
|
||||||
// NOTE: Action::NextScreen is sent once all tasks are complete
|
// NOTE: Action::TasksComplete is sent once all tasks are complete
|
||||||
if let Some(handle) = self.handle.take() {
|
if let Some(task_handle) = self.cur_handle.take() {
|
||||||
if handle.is_finished() {
|
if task_handle.is_finished() {
|
||||||
|
// Need to return task with handle
|
||||||
|
if let Some(mut cur_task) = self.cur_task.take() {
|
||||||
|
cur_task.handle = Some(task_handle);
|
||||||
|
return_task = Some(cur_task);
|
||||||
|
}
|
||||||
if self.task_list.is_empty() {
|
if self.task_list.is_empty() {
|
||||||
// No tasks remain
|
// No tasks remain
|
||||||
self.task_tx.send(Action::NextScreen)?;
|
self.action_tx.send(Action::TasksComplete)?;
|
||||||
} else {
|
} else {
|
||||||
// Start next task
|
// Start next task
|
||||||
self.start()?;
|
self.start()?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Task not complete, return handle
|
// TaskType not complete, return handle
|
||||||
self.handle = Some(handle);
|
self.cur_handle.replace(task_handle);
|
||||||
}
|
}
|
||||||
} else if !self.task_list.is_empty() {
|
} else if !self.task_list.is_empty() {
|
||||||
// No current task but one is available
|
// No current task but one is available
|
||||||
self.start()?;
|
self.start()?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(return_task)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(&mut self) -> Result<()> {
|
pub fn start(&mut self) -> Result<()> {
|
||||||
if let Some(task) = self.task_list.pop_front() {
|
self.cur_task = self.task_list.pop_front();
|
||||||
let task_str = format!("{task:?}");
|
if let Some(task) = self.cur_task.take() {
|
||||||
let task_tx = self.task_tx.clone();
|
let task_tx = self.task_tx.clone();
|
||||||
match task {
|
match task.task_type {
|
||||||
Task::Command(ref cmd_path, ref cmd_args) => {
|
TaskType::CommandNoWait(ref cmd_path, ref cmd_args) => {
|
||||||
let cmd_path = cmd_path.clone();
|
self.cur_handle = None;
|
||||||
let cmd_args = cmd_args.clone();
|
run_task_command(cmd_path.clone(), cmd_args.clone(), task_tx);
|
||||||
if cfg!(windows) {
|
|
||||||
self.handle = Some(thread::spawn(move || {
|
|
||||||
let result = Command::new(cmd_path)
|
|
||||||
.args(cmd_args)
|
|
||||||
.stdout(Stdio::piped())
|
|
||||||
.output();
|
|
||||||
if let Some(action) = match result {
|
|
||||||
Ok(output) => {
|
|
||||||
if output.status.success() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
// Command returned an error status
|
|
||||||
let mut msg = String::new();
|
|
||||||
if let Ok(stdout) = String::from_utf8(output.stdout) {
|
|
||||||
msg = String::from(stdout.trim());
|
|
||||||
}
|
|
||||||
if msg.is_empty() {
|
|
||||||
msg = String::from("Generic error");
|
|
||||||
}
|
|
||||||
Some(Action::Error(format!("Command failed: {msg}",)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
Some(Action::Error(format!("Failed to run command: {err:?}")))
|
|
||||||
}
|
|
||||||
} {
|
|
||||||
let msg = format!("{:?}", &action);
|
|
||||||
let result = task_tx.send(action);
|
|
||||||
assert!(result.is_ok(), "Failed to send Action: {msg}");
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
// Simulate task if not running under Windows
|
|
||||||
self.handle = Some(thread::spawn(|| sleep(Duration::from_millis(250))));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Task::Diskpart(ref script) => {
|
TaskType::CommandWait(ref cmd_path, ref cmd_args) => {
|
||||||
if cfg!(windows) {
|
self.cur_handle = Some(run_task_command(
|
||||||
let script = String::from(script);
|
cmd_path.clone(),
|
||||||
self.handle = Some(thread::spawn(move || {
|
cmd_args.clone(),
|
||||||
let output = diskpart::run_script_raw(script.as_str());
|
task_tx,
|
||||||
if !output.status.success()
|
));
|
||||||
&& task_tx
|
|
||||||
.send(Action::Error(String::from(
|
|
||||||
"Diskpart script returned an error",
|
|
||||||
)))
|
|
||||||
.is_err()
|
|
||||||
{
|
|
||||||
panic!("Failed to send Action: {task_str:?}");
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
// Simulate task if not running under Windows
|
|
||||||
self.handle = Some(thread::spawn(|| sleep(Duration::from_millis(250))));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Task::ScanDisks => {
|
TaskType::Diskpart(ref script) => {
|
||||||
|
self.cur_handle = Some(run_task_diskpart(script, task_tx));
|
||||||
|
}
|
||||||
|
TaskType::ScanDisks => {
|
||||||
let disk_list_arc = self.disk_list.clone();
|
let disk_list_arc = self.disk_list.clone();
|
||||||
|
|
||||||
// Queue UpdateDiskList for various components
|
// Queue UpdateDiskList for various components
|
||||||
self.add(Task::UpdateDiskList);
|
self.add(TaskType::UpdateDiskList);
|
||||||
|
|
||||||
self.handle = Some(thread::spawn(move || {
|
self.cur_handle = Some(thread::spawn(move || {
|
||||||
let mut disks = disk_list_arc.lock().unwrap();
|
let mut disks = disk_list_arc.lock().unwrap();
|
||||||
*disks = disk::get_disks();
|
*disks = disk::get_disks();
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
Task::Sleep => {
|
TaskType::Sleep => {
|
||||||
self.handle = Some(thread::spawn(|| sleep(Duration::from_millis(250))));
|
self.cur_handle = Some(thread::spawn(|| sleep(Duration::from_millis(250))));
|
||||||
}
|
}
|
||||||
Task::UpdateDestDisk(index) => {
|
TaskType::UpdateDestDisk(index) => {
|
||||||
self.action_tx.send(Action::DisplayPopup(
|
self.action_tx.send(Action::DisplayPopup(
|
||||||
popup::Type::Info,
|
popup::Type::Info,
|
||||||
String::from("Refreshing disk info"),
|
String::from("Refreshing disk info"),
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
// Queue UpdateDiskList for various components
|
// Queue UpdateDiskList for various components
|
||||||
self.add(Task::Sleep);
|
self.add(TaskType::Sleep);
|
||||||
self.add(Task::UpdateDiskList);
|
self.add(TaskType::UpdateDiskList);
|
||||||
|
|
||||||
// Update destination disk ~in-place
|
// Update destination disk ~in-place
|
||||||
let disk_list_arc = self.disk_list.clone();
|
let disk_list_arc = self.disk_list.clone();
|
||||||
self.handle = Some(thread::spawn(move || {
|
self.cur_handle = Some(thread::spawn(move || {
|
||||||
let mut disks = disk_list_arc.lock().unwrap();
|
let mut disks = disk_list_arc.lock().unwrap();
|
||||||
let old_disk = &mut disks[index];
|
let old_disk = &mut disks[index];
|
||||||
disks[index] = disk::refresh_disk_info(old_disk);
|
disks[index] = disk::refresh_disk_info(old_disk);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
Task::UpdateDiskList => {
|
TaskType::UpdateDiskList => {
|
||||||
let disks = self.disk_list.lock().unwrap();
|
let disks = self.disk_list.lock().unwrap();
|
||||||
let disks_copy = disks.clone();
|
let disks_copy = disks.clone();
|
||||||
let action_tx = self.action_tx.clone();
|
let action_tx = self.action_tx.clone();
|
||||||
self.handle = Some(thread::spawn(move || {
|
self.cur_handle = Some(thread::spawn(move || {
|
||||||
if let Err(err) = action_tx.send(Action::UpdateDiskList(disks_copy)) {
|
if let Err(err) = action_tx.send(Action::UpdateDiskList(disks_copy)) {
|
||||||
panic!("Failed to send Action: {err:?}");
|
panic!("Failed to send Action: {err:?}");
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Done
|
||||||
|
self.cur_task.replace(task);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_bytes_as_str(bytes: Vec<u8>) -> String {
|
||||||
|
match String::from_utf8(bytes) {
|
||||||
|
Ok(s) => s.trim().to_string(),
|
||||||
|
Err(_) => String::from("Failed to parse bytes as UTF-8 text"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_task_command(
|
||||||
|
cmd_path: PathBuf,
|
||||||
|
cmd_args: Vec<String>,
|
||||||
|
task_tx: mpsc::UnboundedSender<TaskResult>,
|
||||||
|
) -> JoinHandle<()> {
|
||||||
|
if cfg!(windows) {
|
||||||
|
thread::spawn(move || {
|
||||||
|
let result = Command::new(cmd_path)
|
||||||
|
.args(cmd_args)
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.output();
|
||||||
|
match result {
|
||||||
|
Err(e) => {
|
||||||
|
task_tx
|
||||||
|
.send(TaskResult::Error(format!("{:?}", &e)))
|
||||||
|
.expect("Failed to propegate error?");
|
||||||
|
}
|
||||||
|
Ok(output) => {
|
||||||
|
let stderr = parse_bytes_as_str(output.stderr.clone());
|
||||||
|
let stdout = parse_bytes_as_str(output.stdout.clone());
|
||||||
|
let task_result = TaskResult::Output(stdout, stderr, output.status.success());
|
||||||
|
let err_str = format!("Failed to send TaskResult: {:?}", &task_result);
|
||||||
|
task_tx
|
||||||
|
.send(task_result)
|
||||||
|
.unwrap_or_else(|_| panic!("{}", err_str));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// Simulate task if not running under Windows
|
||||||
|
thread::spawn(|| sleep(Duration::from_millis(250)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_task_diskpart(script: &str, task_tx: mpsc::UnboundedSender<TaskResult>) -> JoinHandle<()> {
|
||||||
|
if cfg!(windows) {
|
||||||
|
let script = script.to_owned();
|
||||||
|
thread::spawn(move || {
|
||||||
|
let output = diskpart::run_script_raw(&script);
|
||||||
|
let stderr = parse_bytes_as_str(output.stderr.clone());
|
||||||
|
let stdout = parse_bytes_as_str(output.stdout.clone());
|
||||||
|
let task_result = TaskResult::Output(stdout, stderr, output.status.success());
|
||||||
|
let err_str = format!("Failed to send TaskResult: {:?}", &task_result);
|
||||||
|
task_tx
|
||||||
|
.send(task_result)
|
||||||
|
.unwrap_or_else(|_| panic!("{}", err_str));
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// Simulate task if not running under Windows
|
||||||
|
thread::spawn(|| sleep(Duration::from_millis(250)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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/>.
|
||||||
//
|
//
|
||||||
pub mod sample_output;
|
pub mod sample_output;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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/>.
|
||||||
//
|
//
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub static DETAIL_DISK_GPT: &str = "Disk 2 is now the selected disk.
|
pub static DETAIL_DISK_GPT: &str = "Disk 2 is now the selected disk.
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,22 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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/>.
|
||||||
//
|
#![allow(clippy::missing_errors_doc)]
|
||||||
#![allow(dead_code)] // Remove this once you start using the code
|
#![allow(dead_code)] // Remove this once you start using the code
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
io::{stdout, Stdout},
|
io::{Stdout, stdout},
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
@ -85,21 +85,25 @@ impl Tui {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn tick_rate(mut self, tick_rate: f64) -> Self {
|
pub fn tick_rate(mut self, tick_rate: f64) -> Self {
|
||||||
self.tick_rate = tick_rate;
|
self.tick_rate = tick_rate;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn frame_rate(mut self, frame_rate: f64) -> Self {
|
pub fn frame_rate(mut self, frame_rate: f64) -> Self {
|
||||||
self.frame_rate = frame_rate;
|
self.frame_rate = frame_rate;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn mouse(mut self, mouse: bool) -> Self {
|
pub fn mouse(mut self, mouse: bool) -> Self {
|
||||||
self.mouse = mouse;
|
self.mouse = mouse;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn paste(mut self, paste: bool) -> Self {
|
pub fn paste(mut self, paste: bool) -> Self {
|
||||||
self.paste = paste;
|
self.paste = paste;
|
||||||
self
|
self
|
||||||
|
|
@ -135,7 +139,7 @@ impl Tui {
|
||||||
.expect("failed to send init event");
|
.expect("failed to send init event");
|
||||||
loop {
|
loop {
|
||||||
let event = tokio::select! {
|
let event = tokio::select! {
|
||||||
_ = cancellation_token.cancelled() => {
|
() = cancellation_token.cancelled() => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_ = tick_interval.tick() => Event::Tick,
|
_ = tick_interval.tick() => Event::Tick,
|
||||||
|
|
@ -148,7 +152,7 @@ impl Tui {
|
||||||
CrosstermEvent::FocusLost => Event::FocusLost,
|
CrosstermEvent::FocusLost => Event::FocusLost,
|
||||||
CrosstermEvent::FocusGained => Event::FocusGained,
|
CrosstermEvent::FocusGained => Event::FocusGained,
|
||||||
CrosstermEvent::Paste(s) => Event::Paste(s),
|
CrosstermEvent::Paste(s) => Event::Paste(s),
|
||||||
_ => continue, // ignore other events
|
CrosstermEvent::Key(_) => continue, // ignore other events
|
||||||
}
|
}
|
||||||
Some(Err(_)) => Event::Error,
|
Some(Err(_)) => Event::Error,
|
||||||
None => break, // the event stream has stopped and will not produce any more events
|
None => break, // the event stream has stopped and will not produce any more events
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,22 @@
|
||||||
# This file is part of Deja-vu.
|
# This file is part of Deja-Vu.
|
||||||
#
|
#
|
||||||
# Deja-vu is free software: you can redistribute it and/or modify it
|
# 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
|
# under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# Deja-vu is distributed in the hope that it will be useful, but
|
# Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
# See the GNU General Public License for more details.
|
# See the GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# 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/>.
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "deja-vu"
|
name = "deja-vu"
|
||||||
authors = ["2Shirt <2xShirt@gmail.com>"]
|
authors = ["2Shirt <2xShirt@gmail.com>"]
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
license = "GPL"
|
license = "GPL"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
|
||||||
|
|
@ -39,7 +39,7 @@ tokio-util = "0.7.11"
|
||||||
tracing = "0.1.41"
|
tracing = "0.1.41"
|
||||||
tracing-error = "0.2.0"
|
tracing-error = "0.2.0"
|
||||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter", "serde"] }
|
tracing-subscriber = { version = "0.3.18", features = ["env-filter", "serde"] }
|
||||||
rand = "0.8.5"
|
check_elevation = "0.2.4"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
anyhow = "1.0.86"
|
anyhow = "1.0.86"
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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 anyhow::Result;
|
use anyhow::Result;
|
||||||
use vergen_gix::{BuildBuilder, CargoBuilder, Emitter, GixBuilder};
|
use vergen_gix::{BuildBuilder, CargoBuilder, Emitter, GixBuilder};
|
||||||
|
|
|
||||||
|
|
@ -1,42 +1,42 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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 core::{
|
use core::{
|
||||||
action::Action,
|
action::Action,
|
||||||
components::{
|
components::{
|
||||||
footer::Footer, fps::FpsCounter, left::Left, popup, right::Right, state::StatefulList,
|
Component, footer::Footer, fps::FpsCounter, left::Left, popup, right::Right,
|
||||||
title::Title, Component,
|
state::StatefulList, title::Title,
|
||||||
},
|
},
|
||||||
config::Config,
|
config::Config,
|
||||||
line::{get_disk_description_right, get_part_description, DVLine},
|
line::{DVLine, get_disk_description_right, get_part_description},
|
||||||
state::{CloneSettings, Mode},
|
state::{CloneSettings, Mode},
|
||||||
system::{
|
system::{
|
||||||
boot, cpu::get_cpu_name, disk::PartitionTableType, diskpart::build_dest_format_script,
|
boot, cpu::get_cpu_name, disk::PartitionTableType, diskpart::build_dest_format_script,
|
||||||
drivers,
|
drivers,
|
||||||
},
|
},
|
||||||
tasks::{Task, Tasks},
|
tasks::{Task, TaskResult, TaskType, Tasks},
|
||||||
tui::{Event, Tui},
|
tui::{Event, Tui},
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
env,
|
env,
|
||||||
iter::zip,
|
iter::zip,
|
||||||
|
path::PathBuf,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use rand::random;
|
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
crossterm::event::KeyEvent,
|
crossterm::event::KeyEvent,
|
||||||
layout::{Constraint, Direction, Layout},
|
layout::{Constraint, Direction, Layout},
|
||||||
|
|
@ -100,7 +100,7 @@ impl App {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prev_mode(&mut self) -> Option<Mode> {
|
pub fn prev_mode(&mut self) -> Option<Mode> {
|
||||||
let new_mode = match self.cur_mode {
|
match self.cur_mode {
|
||||||
Mode::Home => Some(Mode::Home),
|
Mode::Home => Some(Mode::Home),
|
||||||
Mode::Failed => Some(Mode::Failed),
|
Mode::Failed => Some(Mode::Failed),
|
||||||
Mode::Done => Some(Mode::Done),
|
Mode::Done => Some(Mode::Done),
|
||||||
|
|
@ -115,15 +115,19 @@ impl App {
|
||||||
| Mode::Clone
|
| Mode::Clone
|
||||||
| Mode::PostClone => None,
|
| Mode::PostClone => None,
|
||||||
// Invalid states
|
// Invalid states
|
||||||
Mode::PEMenu => panic!("This shouldn't happen?"),
|
Mode::BootDiags
|
||||||
};
|
| Mode::BootScan
|
||||||
new_mode
|
| Mode::BootSetup
|
||||||
|
| Mode::DiagMenu
|
||||||
|
| Mode::InjectDrivers
|
||||||
|
| Mode::PEMenu
|
||||||
|
| Mode::SetBootMode => panic!("This shouldn't happen?"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next_mode(&mut self) -> Option<Mode> {
|
pub fn next_mode(&mut self) -> Option<Mode> {
|
||||||
let new_mode = match self.cur_mode {
|
let new_mode = match self.cur_mode {
|
||||||
Mode::Home => Mode::ScanDisks,
|
Mode::Home | Mode::InstallDrivers => Mode::ScanDisks,
|
||||||
Mode::InstallDrivers => Mode::ScanDisks,
|
|
||||||
Mode::ScanDisks => Mode::SelectDisks,
|
Mode::ScanDisks => Mode::SelectDisks,
|
||||||
Mode::SelectDisks => Mode::SelectTableType,
|
Mode::SelectDisks => Mode::SelectTableType,
|
||||||
Mode::SelectTableType => Mode::Confirm,
|
Mode::SelectTableType => Mode::Confirm,
|
||||||
|
|
@ -134,7 +138,13 @@ impl App {
|
||||||
Mode::PostClone | Mode::Done => Mode::Done,
|
Mode::PostClone | Mode::Done => Mode::Done,
|
||||||
Mode::Failed => Mode::Failed,
|
Mode::Failed => Mode::Failed,
|
||||||
// Invalid states
|
// Invalid states
|
||||||
Mode::PEMenu => panic!("This shouldn't happen?"),
|
Mode::BootDiags
|
||||||
|
| Mode::BootScan
|
||||||
|
| Mode::BootSetup
|
||||||
|
| Mode::DiagMenu
|
||||||
|
| Mode::InjectDrivers
|
||||||
|
| Mode::PEMenu
|
||||||
|
| Mode::SetBootMode => panic!("This shouldn't happen?"),
|
||||||
};
|
};
|
||||||
|
|
||||||
if new_mode == self.cur_mode {
|
if new_mode == self.cur_mode {
|
||||||
|
|
@ -153,7 +163,7 @@ impl App {
|
||||||
Mode::ScanDisks => {
|
Mode::ScanDisks => {
|
||||||
self.prev_mode = self.cur_mode;
|
self.prev_mode = self.cur_mode;
|
||||||
if self.tasks.idle() {
|
if self.tasks.idle() {
|
||||||
self.tasks.add(Task::ScanDisks);
|
self.tasks.add(TaskType::ScanDisks);
|
||||||
}
|
}
|
||||||
self.action_tx.send(Action::DisplayPopup(
|
self.action_tx.send(Action::DisplayPopup(
|
||||||
popup::Type::Info,
|
popup::Type::Info,
|
||||||
|
|
@ -166,13 +176,22 @@ impl App {
|
||||||
String::from("Formatting destination disk"),
|
String::from("Formatting destination disk"),
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
|
// Get System32 path
|
||||||
|
let system32 = get_system32_path(&self.action_tx);
|
||||||
|
|
||||||
|
// (Re)Enable volume mounting
|
||||||
|
self.tasks.add(TaskType::CommandWait(
|
||||||
|
PathBuf::from(format!("{system32}/mountvol.exe")),
|
||||||
|
vec![String::from("/e")],
|
||||||
|
));
|
||||||
|
|
||||||
// Build Diskpart script to format destination disk
|
// Build Diskpart script to format destination disk
|
||||||
let disk_list = self.clone.disk_list.lock().unwrap();
|
let disk_list = self.clone.disk_list.lock().unwrap();
|
||||||
if let Some(disk_index) = self.clone.disk_index_dest {
|
if let Some(disk_index) = self.clone.disk_index_dest {
|
||||||
if let Some(disk) = disk_list.get(disk_index) {
|
if let Some(disk) = disk_list.get(disk_index) {
|
||||||
let table_type = self.clone.table_type.clone().unwrap();
|
let table_type = self.clone.table_type.clone().unwrap();
|
||||||
let diskpart_script = build_dest_format_script(disk.id, &table_type);
|
let diskpart_script = build_dest_format_script(disk.id, &table_type);
|
||||||
self.tasks.add(Task::Diskpart(diskpart_script));
|
self.tasks.add(TaskType::Diskpart(diskpart_script));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -181,12 +200,12 @@ impl App {
|
||||||
popup::Type::Info,
|
popup::Type::Info,
|
||||||
String::from("Running Clone Tool"),
|
String::from("Running Clone Tool"),
|
||||||
))?;
|
))?;
|
||||||
self.tasks.add(Task::Command(
|
self.tasks.add(TaskType::CommandWait(
|
||||||
self.config.clone_app_path.clone(),
|
self.config.clone_app_path.clone(),
|
||||||
Vec::new(),
|
Vec::new(),
|
||||||
));
|
));
|
||||||
if let Some(dest_index) = self.clone.disk_index_dest {
|
if let Some(dest_index) = self.clone.disk_index_dest {
|
||||||
self.tasks.add(Task::UpdateDestDisk(dest_index));
|
self.tasks.add(TaskType::UpdateDestDisk(dest_index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Mode::PostClone => {
|
Mode::PostClone => {
|
||||||
|
|
@ -196,18 +215,7 @@ impl App {
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
// Get System32 path
|
// Get System32 path
|
||||||
let system32 = if cfg!(windows) {
|
let system32 = get_system32_path(&self.action_tx);
|
||||||
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(".")
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add actions
|
// Add actions
|
||||||
let disk_list = self.clone.disk_list.lock().unwrap();
|
let disk_list = self.clone.disk_list.lock().unwrap();
|
||||||
|
|
@ -227,7 +235,7 @@ impl App {
|
||||||
|
|
||||||
// Create boot files
|
// Create boot files
|
||||||
for task in
|
for task in
|
||||||
boot::configure_disk(&letter_boot, &letter_os, &system32, table_type)
|
boot::configure_disk(&letter_boot, &letter_os, &system32, &table_type)
|
||||||
{
|
{
|
||||||
self.tasks.add(task);
|
self.tasks.add(task);
|
||||||
}
|
}
|
||||||
|
|
@ -248,7 +256,7 @@ impl App {
|
||||||
}
|
}
|
||||||
Mode::Done => {
|
Mode::Done => {
|
||||||
self.action_tx
|
self.action_tx
|
||||||
.send(Action::DisplayPopup(popup::Type::Success, fortune()))?;
|
.send(Action::DisplayPopup(popup::Type::Success, popup::fortune()))?;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
@ -343,12 +351,9 @@ impl App {
|
||||||
match action {
|
match action {
|
||||||
Action::Tick => {
|
Action::Tick => {
|
||||||
self.last_tick_key_events.drain(..);
|
self.last_tick_key_events.drain(..);
|
||||||
match self.cur_mode {
|
// Check background task(s)
|
||||||
Mode::ScanDisks | Mode::PreClone | Mode::Clone | Mode::PostClone => {
|
if let Some(task) = self.tasks.poll()? {
|
||||||
// Check background task
|
self.handle_task(&task)?;
|
||||||
self.tasks.poll()?; // Once all are complete Action::NextScreen is sent
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Action::Quit => self.should_quit = true,
|
Action::Quit => self.should_quit = true,
|
||||||
|
|
@ -369,6 +374,9 @@ impl App {
|
||||||
Mode::Confirm => {
|
Mode::Confirm => {
|
||||||
self.action_tx.send(Action::NextScreen)?;
|
self.action_tx.send(Action::NextScreen)?;
|
||||||
}
|
}
|
||||||
|
Mode::Done => {
|
||||||
|
self.action_tx.send(Action::Quit)?;
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
Action::Resize(w, h) => self.handle_resize(tui, w, h)?,
|
Action::Resize(w, h) => self.handle_resize(tui, w, h)?,
|
||||||
|
|
@ -415,7 +423,7 @@ impl App {
|
||||||
0 => Some(PartitionTableType::Guid),
|
0 => Some(PartitionTableType::Guid),
|
||||||
1 => Some(PartitionTableType::Legacy),
|
1 => Some(PartitionTableType::Legacy),
|
||||||
index => {
|
index => {
|
||||||
panic!("Failed to select PartitionTableType: {}", index)
|
panic!("Failed to select PartitionTableType: {index}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -468,6 +476,7 @@ impl App {
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Action::TasksComplete => self.action_tx.send(Action::NextScreen)?,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
for component in &mut self.components {
|
for component in &mut self.components {
|
||||||
|
|
@ -485,6 +494,39 @@ impl App {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_task(&mut self, task: &Task) -> Result<()> {
|
||||||
|
match task.task_type {
|
||||||
|
TaskType::CommandWait(_, _) | TaskType::Diskpart(_) => {
|
||||||
|
// Check result
|
||||||
|
if let Some(result) = &task.result {
|
||||||
|
match result {
|
||||||
|
TaskResult::Error(msg) => {
|
||||||
|
self.action_tx
|
||||||
|
.send(Action::Error(format!("{} Failed: {msg}", task.task_type)))?;
|
||||||
|
}
|
||||||
|
TaskResult::Output(stdout, stderr, success) => {
|
||||||
|
if !success {
|
||||||
|
let msg = if !stdout.is_empty() {
|
||||||
|
stdout.clone()
|
||||||
|
} else if !stderr.is_empty() {
|
||||||
|
stderr.clone()
|
||||||
|
} else {
|
||||||
|
String::from("Unknown Error")
|
||||||
|
};
|
||||||
|
self.action_tx.send(Action::Error(format!(
|
||||||
|
"{} Failed: {msg}",
|
||||||
|
task.task_type
|
||||||
|
)))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn render(&mut self, tui: &mut Tui) -> Result<()> {
|
fn render(&mut self, tui: &mut Tui) -> Result<()> {
|
||||||
tui.draw(|frame| {
|
tui.draw(|frame| {
|
||||||
if let [header, _body, footer, left, right, popup] = get_chunks(frame.area())[..] {
|
if let [header, _body, footer, left, right, popup] = get_chunks(frame.area())[..] {
|
||||||
|
|
@ -566,14 +608,21 @@ 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::PEMenu => panic!("This shouldn't happen?"),
|
Mode::BootDiags
|
||||||
|
| Mode::BootScan
|
||||||
|
| Mode::BootSetup
|
||||||
|
| Mode::DiagMenu
|
||||||
|
| Mode::InjectDrivers
|
||||||
|
| Mode::PEMenu
|
||||||
|
| Mode::SetBootMode => panic!("This shouldn't happen?"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -638,7 +687,13 @@ fn build_left_items(app: &App, cur_mode: Mode) -> Action {
|
||||||
title = String::from("Done");
|
title = String::from("Done");
|
||||||
}
|
}
|
||||||
// Invalid states
|
// Invalid states
|
||||||
Mode::PEMenu => panic!("This shouldn't happen?"),
|
Mode::BootDiags
|
||||||
|
| Mode::BootScan
|
||||||
|
| Mode::BootSetup
|
||||||
|
| Mode::DiagMenu
|
||||||
|
| Mode::InjectDrivers
|
||||||
|
| Mode::PEMenu
|
||||||
|
| Mode::SetBootMode => panic!("This shouldn't happen?"),
|
||||||
};
|
};
|
||||||
Action::UpdateLeft(title, labels, items, select_num)
|
Action::UpdateLeft(title, labels, items, select_num)
|
||||||
}
|
}
|
||||||
|
|
@ -691,26 +746,26 @@ 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| {
|
for s in &["Boot", "OS"] {
|
||||||
labels.push(vec![DVLine {
|
labels.push(vec![DVLine {
|
||||||
line_parts: vec![String::from(*s)],
|
line_parts: vec![String::from(*s)],
|
||||||
line_colors: vec![Color::Cyan],
|
line_colors: vec![Color::Cyan],
|
||||||
}])
|
}]);
|
||||||
});
|
}
|
||||||
if let Some(index) = app.clone.disk_index_dest {
|
if let Some(index) = app.clone.disk_index_dest {
|
||||||
start_index = 1;
|
start_index = 1;
|
||||||
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
|
||||||
.iter()
|
.iter()
|
||||||
.for_each(|part| items.push(get_part_description(&part)));
|
.for_each(|part| items.push(get_part_description(part)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -719,18 +774,18 @@ fn build_right_items(app: &App, cur_mode: Mode) -> Action {
|
||||||
Action::UpdateRight(labels, start_index, items)
|
Action::UpdateRight(labels, start_index, items)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fortune() -> String {
|
pub fn get_system32_path(action_tx: &mpsc::UnboundedSender<Action>) -> String {
|
||||||
String::from(match random::<u8>() / 4 {
|
let mut system32_path = String::from(".");
|
||||||
0 => "FUN FACT\n\n\nComputers barely work.",
|
if cfg!(windows) {
|
||||||
1 => "CRASH OVERRIDE\n\n\n\"Hack the planet!\"",
|
if let Ok(path) = env::var("SYSTEMROOT") {
|
||||||
2 => "CATS\n\n\n\"All your base are belong to us!\"",
|
system32_path = format!("{path}/System32");
|
||||||
3 => "HMM\n\n\nThis has all happened before...\n\nThis will all happen again.",
|
} else {
|
||||||
4 => "CYPHER\n\n\n\"I don’t even see the code. All I see is blonde, brunette, red-head.\"",
|
action_tx
|
||||||
5 => "CONGRATULATIONS\n\n\nYour did it!",
|
.send(Action::Error(String::from(
|
||||||
6 => "DID YOU KNOW?\n\n\nmacOS includes a built-in screen reader!",
|
"ERROR\n\n\nFailed to find SYSTEMROOT",
|
||||||
7 => "TIP OF THE DAY\n\n\nNever go full Snappy!",
|
)))
|
||||||
8 => "WORDS OF WISDOM\n\n\n\nIt’s not DNS,\n\nThere’s no way it’s DNS,\n\nIt was DNS.",
|
.expect("Failed to find SYSTEMROOT and then failed to send action");
|
||||||
9 => "HAL 9000\n\n\n\"I'm sorry Dave, I'm afraid I can't do that.\"",
|
}
|
||||||
_ => "COMPLETE\n\n\nThank you for using this tool!",
|
}
|
||||||
})
|
system32_path
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,20 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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 clap::Parser;
|
use clap::Parser;
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use core;
|
|
||||||
|
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
|
|
||||||
|
|
@ -23,11 +22,22 @@ mod app;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
core::errors::init()?;
|
let mut msg = None;
|
||||||
core::logging::init()?;
|
if cfg!(windows) {
|
||||||
|
use check_elevation::is_elevated;
|
||||||
|
if !is_elevated().expect("Failed to get elevation status.") {
|
||||||
|
msg.replace("Administrator privedges required for Deja-Vu.");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Some(text) = msg {
|
||||||
|
println!("{text}");
|
||||||
|
} else {
|
||||||
|
core::errors::init()?;
|
||||||
|
core::logging::init()?;
|
||||||
|
|
||||||
let args = core::cli::Cli::parse();
|
let args = core::cli::Cli::parse();
|
||||||
let mut app = App::new(args.tick_rate, args.frame_rate)?;
|
let mut app = App::new(args.tick_rate, args.frame_rate)?;
|
||||||
app.run().await?;
|
app.run().await?;
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
5
include/menu_entries/11_boot-diags.toml
Normal file
5
include/menu_entries/11_boot-diags.toml
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
name = 'Boot-Diagnostics'
|
||||||
|
command = 'X:\tools\boot-diags.exe'
|
||||||
|
description = "Boot issue assessment tool"
|
||||||
|
use_conemu = true
|
||||||
|
separator = false
|
||||||
|
|
@ -1,22 +1,22 @@
|
||||||
# This file is part of Deja-vu.
|
# This file is part of Deja-Vu.
|
||||||
#
|
#
|
||||||
# Deja-vu is free software: you can redistribute it and/or modify it
|
# 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
|
# under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# Deja-vu is distributed in the hope that it will be useful, but
|
# Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
# See the GNU General Public License for more details.
|
# See the GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# 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/>.
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "pe-menu"
|
name = "pe-menu"
|
||||||
authors = ["2Shirt <2xShirt@gmail.com>"]
|
authors = ["2Shirt <2xShirt@gmail.com>"]
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
license = "GPL"
|
license = "GPL"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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 anyhow::Result;
|
use anyhow::Result;
|
||||||
use vergen_gix::{BuildBuilder, CargoBuilder, Emitter, GixBuilder};
|
use vergen_gix::{BuildBuilder, CargoBuilder, Emitter, GixBuilder};
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,28 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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 core::{
|
use core::{
|
||||||
action::Action,
|
action::Action,
|
||||||
components::{
|
components::{
|
||||||
footer::Footer, fps::FpsCounter, left::Left, popup, right::Right, state::StatefulList,
|
Component, footer::Footer, fps::FpsCounter, left::Left, popup, right::Right,
|
||||||
title::Title, Component,
|
state::StatefulList, title::Title,
|
||||||
},
|
},
|
||||||
config::Config,
|
config::Config,
|
||||||
line::DVLine,
|
line::DVLine,
|
||||||
state::Mode,
|
state::Mode,
|
||||||
tasks::{Task, Tasks},
|
tasks::{TaskType, Tasks},
|
||||||
tui::{Event, Tui},
|
tui::{Event, Tui},
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
|
|
@ -230,25 +230,55 @@ impl App {
|
||||||
// Run selected tool
|
// Run selected tool
|
||||||
if let Some(tool) = self.list.get_selected() {
|
if let Some(tool) = self.list.get_selected() {
|
||||||
info!("Run tool: {:?}", &tool);
|
info!("Run tool: {:?}", &tool);
|
||||||
self.tasks.add(build_command(&self, &tool));
|
self.tasks.add(build_tool_command(self, &tool));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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::SetMode(mode) => {
|
Action::SetMode(mode) => {
|
||||||
self.mode = mode;
|
self.mode = mode;
|
||||||
self.action_tx
|
self.action_tx.send(Action::UpdateFooter(String::from(
|
||||||
.send(Action::UpdateFooter(String::from("(Enter) to select")))?;
|
"(Enter) to select / (t) for terminal / (p) to power off / (r) to restart",
|
||||||
|
)))?;
|
||||||
self.action_tx.send(build_left_items(self))?;
|
self.action_tx.send(build_left_items(self))?;
|
||||||
self.action_tx.send(build_right_items(self))?;
|
self.action_tx.send(build_right_items(self))?;
|
||||||
self.action_tx.send(Action::Select(None, None))?;
|
self.action_tx.send(Action::Select(None, None))?;
|
||||||
}
|
}
|
||||||
Action::OpenTerminal => {
|
Action::OpenTerminal => {
|
||||||
self.tasks.add(Task::Command(
|
self.tasks.add(TaskType::CommandNoWait(
|
||||||
PathBuf::from("cmd.exe"),
|
PathBuf::from("cmd.exe"),
|
||||||
vec![String::from("-new_console:n")],
|
vec![String::from("-new_console:n")],
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
Action::Restart => {
|
||||||
|
self.action_tx.send(Action::DisplayPopup(
|
||||||
|
popup::Type::Info,
|
||||||
|
String::from("Restarting..."),
|
||||||
|
))?;
|
||||||
|
self.tasks.add(TaskType::CommandWait(
|
||||||
|
PathBuf::from("X:/Windows/System32/sync64.exe"),
|
||||||
|
vec![String::from("-r")],
|
||||||
|
));
|
||||||
|
self.tasks.add(TaskType::CommandWait(
|
||||||
|
PathBuf::from("X:/Windows/System32/wpeutil.exe"),
|
||||||
|
vec![String::from("reboot")],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Action::Shutdown => {
|
||||||
|
// NOTE: Using 'Powering off' to match the key pressed
|
||||||
|
self.action_tx.send(Action::DisplayPopup(
|
||||||
|
popup::Type::Info,
|
||||||
|
String::from("Powering off..."),
|
||||||
|
))?;
|
||||||
|
self.tasks.add(TaskType::CommandWait(
|
||||||
|
PathBuf::from("X:/Windows/System32/sync64.exe"),
|
||||||
|
vec![String::from("-r")],
|
||||||
|
));
|
||||||
|
self.tasks.add(TaskType::CommandWait(
|
||||||
|
PathBuf::from("X:/Windows/System32/wpeutil.exe"),
|
||||||
|
vec![String::from("shutdown")],
|
||||||
|
));
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
for component in &mut self.components {
|
for component in &mut self.components {
|
||||||
|
|
@ -341,14 +371,15 @@ fn get_chunks(r: Rect) -> Vec<Rect> {
|
||||||
chunks
|
chunks
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_command(app: &App, tool: &Tool) -> Task {
|
pub fn build_tool_command(app: &App, tool: &Tool) -> TaskType {
|
||||||
let cmd_path: PathBuf;
|
let cmd_path: PathBuf;
|
||||||
let mut cmd_args: Vec<String> = Vec::new();
|
let mut cmd_args: Vec<String> = Vec::new();
|
||||||
let start_index: usize;
|
let start_index: usize;
|
||||||
if tool.use_conemu {
|
if tool.use_conemu {
|
||||||
cmd_path = app.config.conemu_path.clone();
|
cmd_path = app.config.conemu_path.clone();
|
||||||
cmd_args.push(String::from("-new_console:n"));
|
cmd_args.push(String::from("-run"));
|
||||||
cmd_args.push(tool.command.clone());
|
cmd_args.push(tool.command.clone());
|
||||||
|
cmd_args.push(String::from("-new_console:n"));
|
||||||
start_index = 1;
|
start_index = 1;
|
||||||
} else {
|
} else {
|
||||||
cmd_path = PathBuf::from(tool.command.clone());
|
cmd_path = PathBuf::from(tool.command.clone());
|
||||||
|
|
@ -361,7 +392,7 @@ pub fn build_command(app: &App, tool: &Tool) -> Task {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Task::Command(cmd_path, cmd_args)
|
TaskType::CommandNoWait(cmd_path, cmd_args)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_left_items(app: &App) -> Action {
|
fn build_left_items(app: &App) -> Action {
|
||||||
|
|
@ -422,7 +453,7 @@ pub fn load_tools() -> Vec<Tool> {
|
||||||
entries
|
entries
|
||||||
.iter()
|
.iter()
|
||||||
.map(|entry| {
|
.map(|entry| {
|
||||||
let contents = fs::read_to_string(&entry).expect("Failed to read tool config file");
|
let contents = fs::read_to_string(entry).expect("Failed to read tool config file");
|
||||||
let tool: Tool = toml::from_str(&contents).expect("Failed to parse tool config file");
|
let tool: Tool = toml::from_str(&contents).expect("Failed to parse tool config file");
|
||||||
tool
|
tool
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,20 @@
|
||||||
// This file is part of Deja-vu.
|
// This file is part of Deja-Vu.
|
||||||
//
|
//
|
||||||
// Deja-vu is free software: you can redistribute it and/or modify it
|
// 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
|
// under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Deja-vu is distributed in the hope that it will be useful, but
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// 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 clap::Parser;
|
use clap::Parser;
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use core;
|
|
||||||
|
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue