Compare commits
No commits in common. "59b9ddbee64325c73ffccfe4dcbfc41e7eaa4af7" and "8be96d21b9509fd1e1ae338ca3d47dee1b7527f5" have entirely different histories.
59b9ddbee6
...
8be96d21b9
50 changed files with 605 additions and 2405 deletions
593
Cargo.lock
generated
593
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", "boot_diags", "deja_vu", "pe_menu"]
|
members = ["core", "deja_vu", "pe_menu"]
|
||||||
default-members = ["boot_diags", "deja_vu", "pe_menu"]
|
default-members = ["deja_vu", "pe_menu"]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
# 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"] }
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
// 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()
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,102 +0,0 @@
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
// 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>": "Process",
|
"<Enter>": "Quit",
|
||||||
"<q>": "Quit",
|
"<q>": "Quit",
|
||||||
"<Ctrl-d>": "Quit",
|
"<Ctrl-d>": "Quit",
|
||||||
"<Ctrl-c>": "Quit",
|
"<Ctrl-c>": "Quit",
|
||||||
|
|
@ -95,66 +95,11 @@
|
||||||
"<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 = "2024"
|
edition = "2021"
|
||||||
license = "GPL"
|
license = "GPL"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
|
||||||
|
|
@ -42,7 +42,6 @@ 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,8 +20,6 @@ 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,
|
||||||
|
|
@ -29,7 +27,6 @@ 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)
|
||||||
|
|
@ -38,10 +35,8 @@ 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 (PE-Menu)
|
// App (PEMenu)
|
||||||
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,7 +38,6 @@ 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,24 +1,23 @@
|
||||||
// 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::{
|
||||||
Frame,
|
|
||||||
layout::{Rect, Size},
|
layout::{Rect, Size},
|
||||||
|
Frame,
|
||||||
};
|
};
|
||||||
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,7 +31,6 @@ 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"),
|
||||||
|
|
@ -52,7 +51,6 @@ 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,7 +46,6 @@ 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(),
|
||||||
|
|
@ -58,26 +57,24 @@ 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 = f64::from(self.tick_count) / elapsed;
|
self.ticks_per_second = self.tick_count as f64 / 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 = f64::from(self.frame_count) / elapsed;
|
self.frames_per_second = self.frame_count as f64 / 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::{Component, state::StatefulList};
|
use super::{state::StatefulList, Component};
|
||||||
use crate::{action::Action, config::Config};
|
use crate::{action::Action, config::Config};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
@ -37,7 +37,6 @@ 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,
|
||||||
|
|
@ -139,10 +138,14 @@ impl Component for Left {
|
||||||
.areas(area);
|
.areas(area);
|
||||||
|
|
||||||
// Title
|
// Title
|
||||||
let title = Paragraph::new(
|
let title_text = if self.selections[1].is_some() || self.select_num == 1 {
|
||||||
Line::from(Span::styled(self.title_text.as_str(), Style::default())).centered(),
|
"Confirm Selections"
|
||||||
)
|
} else {
|
||||||
.block(Block::default().borders(Borders::NONE));
|
self.title_text.as_str()
|
||||||
|
};
|
||||||
|
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)
|
||||||
|
|
@ -168,7 +171,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.first() {
|
if let Some(label) = self.labels.get(0) {
|
||||||
style = style.yellow();
|
style = style.yellow();
|
||||||
label.as_str()
|
label.as_str()
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -1,20 +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/>.
|
||||||
//
|
//
|
||||||
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},
|
||||||
|
|
@ -43,7 +42,6 @@ pub struct Popup {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Popup {
|
impl Popup {
|
||||||
#[must_use]
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
@ -97,20 +95,3 @@ 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::{Component, state::StatefulList};
|
use super::{state::StatefulList, Component};
|
||||||
use crate::{action::Action, config::Config, line::DVLine};
|
use crate::{action::Action, config::Config, line::DVLine};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
@ -37,7 +37,6 @@ 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],
|
||||||
|
|
@ -151,7 +150,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.first() {
|
if let Some(label) = self.list_labels.get(0) {
|
||||||
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,17 +31,14 @@ 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()
|
||||||
}
|
}
|
||||||
|
|
@ -54,12 +51,11 @@ 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()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn select_first_item(&mut self) {
|
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,7 +31,6 @@ 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),
|
||||||
|
|
@ -52,7 +51,6 @@ 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,20 +1,18 @@
|
||||||
// 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};
|
||||||
|
|
@ -25,7 +23,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::{Deserialize, de::Deserializer};
|
use serde::{de::Deserializer, Deserialize};
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
|
||||||
use crate::{action::Action, state::Mode};
|
use crate::{action::Action, state::Mode};
|
||||||
|
|
@ -56,15 +54,15 @@ pub struct Config {
|
||||||
pub styles: Styles,
|
pub styles: Styles,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static PROJECT_NAME: &str = "DEJA-VU";
|
pub static PROJECT_NAME: &'static 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!("{PROJECT_NAME}_DATA"))
|
env::var(format!("{}_DATA", PROJECT_NAME))
|
||||||
.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!("{PROJECT_NAME}_CONFIG"))
|
env::var(format!("{}_CONFIG", PROJECT_NAME))
|
||||||
.ok()
|
.ok()
|
||||||
.map(PathBuf::from);
|
.map(PathBuf::from);
|
||||||
}
|
}
|
||||||
|
|
@ -128,7 +126,6 @@ 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
|
||||||
|
|
@ -140,7 +137,6 @@ 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
|
||||||
|
|
@ -153,8 +149,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)]
|
||||||
|
|
@ -262,7 +258,6 @@ 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 {
|
||||||
|
|
@ -378,7 +373,6 @@ 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()));
|
||||||
|
|
@ -441,11 +435,8 @@ 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,19 +1,18 @@
|
||||||
// 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,7 +30,6 @@ 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())
|
||||||
|
|
@ -38,7 +37,6 @@ 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()],
|
||||||
|
|
@ -47,11 +45,7 @@ impl DVLine {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
pub fn get_disk_description_right(disk: &Disk) -> Vec<DVLine> {
|
||||||
pub fn get_disk_description_right(
|
|
||||||
disk: &Disk,
|
|
||||||
boot_os_indicies: &Option<Vec<usize>>,
|
|
||||||
) -> Vec<DVLine> {
|
|
||||||
let mut description: Vec<DVLine> = vec![
|
let mut description: Vec<DVLine> = vec![
|
||||||
DVLine {
|
DVLine {
|
||||||
line_parts: vec![format!(
|
line_parts: vec![format!(
|
||||||
|
|
@ -73,33 +67,15 @@ pub fn get_disk_description_right(
|
||||||
line_colors: vec![Color::Blue],
|
line_colors: vec![Color::Blue],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
disk.parts_description
|
for line in &disk.parts_description {
|
||||||
.iter()
|
description.push(DVLine {
|
||||||
.enumerate()
|
line_parts: vec![line.clone()],
|
||||||
.for_each(|(index, line)| {
|
line_colors: vec![Color::Reset],
|
||||||
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,22 +1,21 @@
|
||||||
// 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::{EnvFilter, fmt, prelude::*};
|
use tracing_subscriber::{fmt, prelude::*, EnvFilter};
|
||||||
|
|
||||||
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,13 +30,6 @@ 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,43 +1,33 @@
|
||||||
// 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::TaskType;
|
use crate::tasks::Task;
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
|
||||||
pub enum SafeMode {
|
|
||||||
#[default]
|
|
||||||
Disable,
|
|
||||||
Enable,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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<TaskType> {
|
) -> Vec<Task> {
|
||||||
let mut tasks = Vec::new();
|
let mut tasks = Vec::new();
|
||||||
|
|
||||||
// Create
|
// Create
|
||||||
tasks.push(TaskType::CommandWait(
|
tasks.push(Task::Command(
|
||||||
PathBuf::from(format!("{system32}/bcdboot.exe")),
|
PathBuf::from(format!("{system32}/bcdboot.exe")),
|
||||||
vec![
|
vec![
|
||||||
format!("{letter_os}:\\Windows"),
|
format!("{letter_os}:\\Windows"),
|
||||||
|
|
@ -52,8 +42,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(TaskType::CommandWait(
|
tasks.push(Task::Command(
|
||||||
PathBuf::from(format!("{system32}/bootsect.exe")),
|
PathBuf::from(format!("{system32}/bootsect.exe")),
|
||||||
vec![
|
vec![
|
||||||
String::from("/nt60"),
|
String::from("/nt60"),
|
||||||
|
|
@ -65,19 +55,34 @@ pub fn configure_disk(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock in safe mode
|
// Lock in safe mode
|
||||||
tasks.push(
|
let bcd_path = match table_type {
|
||||||
set_mode(letter_boot, &SafeMode::Enable, system32, table_type)
|
PartitionTableType::Guid => {
|
||||||
.expect("Failed to create set_mode task."),
|
format!("{letter_boot}:\\EFI\\Microsoft\\Boot\\BCD")
|
||||||
);
|
}
|
||||||
|
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<TaskType> {
|
pub fn inject_driver(driver: &Driver, letter_os: &str, system32: &str) -> Result<Task> {
|
||||||
//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(TaskType::CommandWait(
|
Ok(Task::Command(
|
||||||
PathBuf::from(format!("{system32}/dism.exe")),
|
PathBuf::from(format!("{system32}/dism.exe")),
|
||||||
vec![
|
vec![
|
||||||
format!("/image:{letter_os}:\\"),
|
format!("/image:{letter_os}:\\"),
|
||||||
|
|
@ -87,39 +92,3 @@ 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,7 +67,6 @@ 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) {
|
||||||
|
|
@ -77,12 +76,10 @@ 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,19 +1,18 @@
|
||||||
// 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,
|
||||||
|
|
@ -27,7 +26,7 @@ use tempfile::tempdir;
|
||||||
use tracing::{info, warn};
|
use tracing::{info, warn};
|
||||||
|
|
||||||
use crate::system::disk::{
|
use crate::system::disk::{
|
||||||
Disk, Partition, PartitionTableType, get_disk_serial_number, string_to_bytes,
|
get_disk_serial_number, string_to_bytes, Disk, Partition, PartitionTableType,
|
||||||
};
|
};
|
||||||
|
|
||||||
static DEFAULT_MAX_DISKS: usize = 8;
|
static DEFAULT_MAX_DISKS: usize = 8;
|
||||||
|
|
@ -130,7 +129,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!["automount enable noerr", "select disk {disk_id}", "clean"];
|
let mut script = vec!["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,27 +1,25 @@
|
||||||
// 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, JoinHandle, sleep},
|
thread::{self, sleep, JoinHandle},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -36,70 +34,23 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum TaskResult {
|
pub enum Task {
|
||||||
Error(String),
|
Command(PathBuf, Vec<String>), // (command, args)
|
||||||
Output(String, String, bool), // stdout, stderr, success
|
Diskpart(String), // (script_as_string)
|
||||||
}
|
|
||||||
|
|
||||||
#[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>>>,
|
||||||
cur_handle: Option<JoinHandle<()>>,
|
handle: Option<JoinHandle<()>>,
|
||||||
cur_task: Option<Task>,
|
|
||||||
task_list: VecDeque<Task>,
|
task_list: VecDeque<Task>,
|
||||||
task_rx: mpsc::UnboundedReceiver<TaskResult>,
|
task_rx: mpsc::UnboundedReceiver<Action>, // Used to forward Actions from Tasks to App
|
||||||
task_tx: mpsc::UnboundedSender<TaskResult>,
|
task_tx: mpsc::UnboundedSender<Action>, // Used to forward Actions from Tasks to App
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tasks {
|
impl Tasks {
|
||||||
|
|
@ -111,186 +62,159 @@ impl Tasks {
|
||||||
Tasks {
|
Tasks {
|
||||||
action_tx,
|
action_tx,
|
||||||
disk_list: disk_list_arc,
|
disk_list: disk_list_arc,
|
||||||
cur_handle: None,
|
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_type: TaskType) {
|
pub fn add(&mut self, task: Task) {
|
||||||
info!("Adding task: {:?}", &task_type);
|
info!("Adding task: {:?}", &task);
|
||||||
self.task_list.push_back(Task::new(task_type));
|
self.task_list.push_back(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn idle(&self) -> bool {
|
pub fn idle(&self) -> bool {
|
||||||
self.cur_handle.is_none()
|
self.handle.is_none()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn poll(&mut self) -> Result<Option<Task>> {
|
pub fn poll(&mut self) -> Result<()> {
|
||||||
let mut return_task: Option<Task> = None;
|
// Forward any actions to main app
|
||||||
// Handle task channel item(s)
|
if let Ok(action) = self.task_rx.try_recv() {
|
||||||
if let Ok(result) = self.task_rx.try_recv() {
|
let result = self.action_tx.send(action.clone());
|
||||||
if let Some(mut task) = self.cur_task.take() {
|
assert!(result.is_ok(), "Failed to send Action: {action:?}");
|
||||||
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::TasksComplete is sent once all tasks are complete
|
// NOTE: Action::NextScreen is sent once all tasks are complete
|
||||||
if let Some(task_handle) = self.cur_handle.take() {
|
if let Some(handle) = self.handle.take() {
|
||||||
if task_handle.is_finished() {
|
if 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.action_tx.send(Action::TasksComplete)?;
|
self.task_tx.send(Action::NextScreen)?;
|
||||||
} else {
|
} else {
|
||||||
// Start next task
|
// Start next task
|
||||||
self.start()?;
|
self.start()?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// TaskType not complete, return handle
|
// Task not complete, return handle
|
||||||
self.cur_handle.replace(task_handle);
|
self.handle = Some(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(return_task)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(&mut self) -> Result<()> {
|
pub fn start(&mut self) -> Result<()> {
|
||||||
self.cur_task = self.task_list.pop_front();
|
if let Some(task) = self.task_list.pop_front() {
|
||||||
if let Some(task) = self.cur_task.take() {
|
let task_str = format!("{task:?}");
|
||||||
let task_tx = self.task_tx.clone();
|
let task_tx = self.task_tx.clone();
|
||||||
match task.task_type {
|
match task {
|
||||||
TaskType::CommandNoWait(ref cmd_path, ref cmd_args) => {
|
Task::Command(ref cmd_path, ref cmd_args) => {
|
||||||
self.cur_handle = None;
|
let cmd_path = cmd_path.clone();
|
||||||
run_task_command(cmd_path.clone(), cmd_args.clone(), task_tx);
|
let cmd_args = cmd_args.clone();
|
||||||
|
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))));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
TaskType::CommandWait(ref cmd_path, ref cmd_args) => {
|
Task::Diskpart(ref script) => {
|
||||||
self.cur_handle = Some(run_task_command(
|
if cfg!(windows) {
|
||||||
cmd_path.clone(),
|
let script = String::from(script);
|
||||||
cmd_args.clone(),
|
self.handle = Some(thread::spawn(move || {
|
||||||
task_tx,
|
let output = diskpart::run_script_raw(script.as_str());
|
||||||
));
|
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))));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
TaskType::Diskpart(ref script) => {
|
Task::ScanDisks => {
|
||||||
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(TaskType::UpdateDiskList);
|
self.add(Task::UpdateDiskList);
|
||||||
|
|
||||||
self.cur_handle = Some(thread::spawn(move || {
|
self.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();
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
TaskType::Sleep => {
|
Task::Sleep => {
|
||||||
self.cur_handle = Some(thread::spawn(|| sleep(Duration::from_millis(250))));
|
self.handle = Some(thread::spawn(|| sleep(Duration::from_millis(250))));
|
||||||
}
|
}
|
||||||
TaskType::UpdateDestDisk(index) => {
|
Task::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(TaskType::Sleep);
|
self.add(Task::Sleep);
|
||||||
self.add(TaskType::UpdateDiskList);
|
self.add(Task::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.cur_handle = Some(thread::spawn(move || {
|
self.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);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
TaskType::UpdateDiskList => {
|
Task::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.cur_handle = Some(thread::spawn(move || {
|
self.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,25 +85,21 @@ 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
|
||||||
|
|
@ -139,7 +135,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,
|
||||||
|
|
@ -152,7 +148,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),
|
||||||
CrosstermEvent::Key(_) => continue, // ignore other events
|
_ => 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 = "2024"
|
edition = "2021"
|
||||||
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"] }
|
||||||
check_elevation = "0.2.4"
|
rand = "0.8.5"
|
||||||
|
|
||||||
[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::{
|
||||||
Component, footer::Footer, fps::FpsCounter, left::Left, popup, right::Right,
|
footer::Footer, fps::FpsCounter, left::Left, popup, right::Right, state::StatefulList,
|
||||||
state::StatefulList, title::Title,
|
title::Title, Component,
|
||||||
},
|
},
|
||||||
config::Config,
|
config::Config,
|
||||||
line::{DVLine, get_disk_description_right, get_part_description},
|
line::{get_disk_description_right, get_part_description, DVLine},
|
||||||
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, TaskResult, TaskType, Tasks},
|
tasks::{Task, 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> {
|
||||||
match self.cur_mode {
|
let new_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,19 +115,15 @@ impl App {
|
||||||
| Mode::Clone
|
| Mode::Clone
|
||||||
| Mode::PostClone => None,
|
| Mode::PostClone => None,
|
||||||
// Invalid states
|
// Invalid states
|
||||||
Mode::BootDiags
|
Mode::PEMenu => panic!("This shouldn't happen?"),
|
||||||
| Mode::BootScan
|
};
|
||||||
| Mode::BootSetup
|
new_mode
|
||||||
| 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::InstallDrivers => Mode::ScanDisks,
|
Mode::Home => 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,
|
||||||
|
|
@ -138,13 +134,7 @@ 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::BootDiags
|
Mode::PEMenu => panic!("This shouldn't happen?"),
|
||||||
| 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 {
|
||||||
|
|
@ -163,7 +153,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(TaskType::ScanDisks);
|
self.tasks.add(Task::ScanDisks);
|
||||||
}
|
}
|
||||||
self.action_tx.send(Action::DisplayPopup(
|
self.action_tx.send(Action::DisplayPopup(
|
||||||
popup::Type::Info,
|
popup::Type::Info,
|
||||||
|
|
@ -176,22 +166,13 @@ 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(TaskType::Diskpart(diskpart_script));
|
self.tasks.add(Task::Diskpart(diskpart_script));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -200,12 +181,12 @@ impl App {
|
||||||
popup::Type::Info,
|
popup::Type::Info,
|
||||||
String::from("Running Clone Tool"),
|
String::from("Running Clone Tool"),
|
||||||
))?;
|
))?;
|
||||||
self.tasks.add(TaskType::CommandWait(
|
self.tasks.add(Task::Command(
|
||||||
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(TaskType::UpdateDestDisk(dest_index));
|
self.tasks.add(Task::UpdateDestDisk(dest_index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Mode::PostClone => {
|
Mode::PostClone => {
|
||||||
|
|
@ -215,7 +196,18 @@ impl App {
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
// Get System32 path
|
// Get System32 path
|
||||||
let system32 = get_system32_path(&self.action_tx);
|
let system32 = if cfg!(windows) {
|
||||||
|
if let Ok(path) = env::var("SYSTEMROOT") {
|
||||||
|
format!("{path}/System32")
|
||||||
|
} else {
|
||||||
|
self.action_tx.send(Action::Error(String::from(
|
||||||
|
"ERROR\n\n\nFailed to find SYSTEMROOT",
|
||||||
|
)))?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String::from(".")
|
||||||
|
};
|
||||||
|
|
||||||
// Add actions
|
// Add actions
|
||||||
let disk_list = self.clone.disk_list.lock().unwrap();
|
let disk_list = self.clone.disk_list.lock().unwrap();
|
||||||
|
|
@ -235,7 +227,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);
|
||||||
}
|
}
|
||||||
|
|
@ -256,7 +248,7 @@ impl App {
|
||||||
}
|
}
|
||||||
Mode::Done => {
|
Mode::Done => {
|
||||||
self.action_tx
|
self.action_tx
|
||||||
.send(Action::DisplayPopup(popup::Type::Success, popup::fortune()))?;
|
.send(Action::DisplayPopup(popup::Type::Success, fortune()))?;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
@ -351,9 +343,12 @@ impl App {
|
||||||
match action {
|
match action {
|
||||||
Action::Tick => {
|
Action::Tick => {
|
||||||
self.last_tick_key_events.drain(..);
|
self.last_tick_key_events.drain(..);
|
||||||
// Check background task(s)
|
match self.cur_mode {
|
||||||
if let Some(task) = self.tasks.poll()? {
|
Mode::ScanDisks | Mode::PreClone | Mode::Clone | Mode::PostClone => {
|
||||||
self.handle_task(&task)?;
|
// Check background task
|
||||||
|
self.tasks.poll()?; // Once all are complete Action::NextScreen is sent
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Action::Quit => self.should_quit = true,
|
Action::Quit => self.should_quit = true,
|
||||||
|
|
@ -374,9 +369,6 @@ 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)?,
|
||||||
|
|
@ -423,7 +415,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 {
|
||||||
|
|
@ -476,7 +468,6 @@ impl App {
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Action::TasksComplete => self.action_tx.send(Action::NextScreen)?,
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
for component in &mut self.components {
|
for component in &mut self.components {
|
||||||
|
|
@ -494,39 +485,6 @@ 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())[..] {
|
||||||
|
|
@ -608,21 +566,14 @@ 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 => String::from("(Enter) or (q) to quit"),
|
Mode::Done | Mode::Failed | Mode::InstallDrivers => String::from("(Enter) or (q) to quit"),
|
||||||
// Invalid states
|
// Invalid states
|
||||||
Mode::BootDiags
|
Mode::PEMenu => panic!("This shouldn't happen?"),
|
||||||
| Mode::BootScan
|
|
||||||
| Mode::BootSetup
|
|
||||||
| Mode::DiagMenu
|
|
||||||
| Mode::InjectDrivers
|
|
||||||
| Mode::PEMenu
|
|
||||||
| Mode::SetBootMode => panic!("This shouldn't happen?"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -687,13 +638,7 @@ fn build_left_items(app: &App, cur_mode: Mode) -> Action {
|
||||||
title = String::from("Done");
|
title = String::from("Done");
|
||||||
}
|
}
|
||||||
// Invalid states
|
// Invalid states
|
||||||
Mode::BootDiags
|
Mode::PEMenu => panic!("This shouldn't happen?"),
|
||||||
| 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)
|
||||||
}
|
}
|
||||||
|
|
@ -746,26 +691,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, &None)));
|
.for_each(|disk| items.push(get_disk_description_right(&disk)));
|
||||||
}
|
}
|
||||||
Mode::SelectParts => {
|
Mode::SelectParts => {
|
||||||
for s in &["Boot", "OS"] {
|
vec!["Boot", "OS"].iter().for_each(|s| {
|
||||||
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, &None));
|
items.push(get_disk_description_right(&disk));
|
||||||
|
|
||||||
// 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)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -774,18 +719,18 @@ fn build_right_items(app: &App, cur_mode: Mode) -> Action {
|
||||||
Action::UpdateRight(labels, start_index, items)
|
Action::UpdateRight(labels, start_index, items)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_system32_path(action_tx: &mpsc::UnboundedSender<Action>) -> String {
|
fn fortune() -> String {
|
||||||
let mut system32_path = String::from(".");
|
String::from(match random::<u8>() / 4 {
|
||||||
if cfg!(windows) {
|
0 => "FUN FACT\n\n\nComputers barely work.",
|
||||||
if let Ok(path) = env::var("SYSTEMROOT") {
|
1 => "CRASH OVERRIDE\n\n\n\"Hack the planet!\"",
|
||||||
system32_path = format!("{path}/System32");
|
2 => "CATS\n\n\n\"All your base are belong to us!\"",
|
||||||
} else {
|
3 => "HMM\n\n\nThis has all happened before...\n\nThis will all happen again.",
|
||||||
action_tx
|
4 => "CYPHER\n\n\n\"I don’t even see the code. All I see is blonde, brunette, red-head.\"",
|
||||||
.send(Action::Error(String::from(
|
5 => "CONGRATULATIONS\n\n\nYour did it!",
|
||||||
"ERROR\n\n\nFailed to find SYSTEMROOT",
|
6 => "DID YOU KNOW?\n\n\nmacOS includes a built-in screen reader!",
|
||||||
)))
|
7 => "TIP OF THE DAY\n\n\nNever go full Snappy!",
|
||||||
.expect("Failed to find SYSTEMROOT and then failed to send action");
|
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!",
|
||||||
system32_path
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,21 @@
|
||||||
// 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;
|
||||||
|
|
||||||
|
|
@ -22,22 +23,11 @@ mod app;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
let mut msg = None;
|
core::errors::init()?;
|
||||||
if cfg!(windows) {
|
core::logging::init()?;
|
||||||
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(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
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 = "2024"
|
edition = "2021"
|
||||||
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::{
|
||||||
Component, footer::Footer, fps::FpsCounter, left::Left, popup, right::Right,
|
footer::Footer, fps::FpsCounter, left::Left, popup, right::Right, state::StatefulList,
|
||||||
state::StatefulList, title::Title,
|
title::Title, Component,
|
||||||
},
|
},
|
||||||
config::Config,
|
config::Config,
|
||||||
line::DVLine,
|
line::DVLine,
|
||||||
state::Mode,
|
state::Mode,
|
||||||
tasks::{TaskType, Tasks},
|
tasks::{Task, Tasks},
|
||||||
tui::{Event, Tui},
|
tui::{Event, Tui},
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
|
|
@ -230,55 +230,25 @@ 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_tool_command(self, &tool));
|
self.tasks.add(build_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.send(Action::UpdateFooter(String::from(
|
self.action_tx
|
||||||
"(Enter) to select / (t) for terminal / (p) to power off / (r) to restart",
|
.send(Action::UpdateFooter(String::from("(Enter) to select")))?;
|
||||||
)))?;
|
|
||||||
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(TaskType::CommandNoWait(
|
self.tasks.add(Task::Command(
|
||||||
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 {
|
||||||
|
|
@ -371,15 +341,14 @@ fn get_chunks(r: Rect) -> Vec<Rect> {
|
||||||
chunks
|
chunks
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_tool_command(app: &App, tool: &Tool) -> TaskType {
|
pub fn build_command(app: &App, tool: &Tool) -> Task {
|
||||||
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("-run"));
|
|
||||||
cmd_args.push(tool.command.clone());
|
|
||||||
cmd_args.push(String::from("-new_console:n"));
|
cmd_args.push(String::from("-new_console:n"));
|
||||||
|
cmd_args.push(tool.command.clone());
|
||||||
start_index = 1;
|
start_index = 1;
|
||||||
} else {
|
} else {
|
||||||
cmd_path = PathBuf::from(tool.command.clone());
|
cmd_path = PathBuf::from(tool.command.clone());
|
||||||
|
|
@ -392,7 +361,7 @@ pub fn build_tool_command(app: &App, tool: &Tool) -> TaskType {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TaskType::CommandNoWait(cmd_path, cmd_args)
|
Task::Command(cmd_path, cmd_args)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_left_items(app: &App) -> Action {
|
fn build_left_items(app: &App) -> Action {
|
||||||
|
|
@ -453,7 +422,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,20 +1,21 @@
|
||||||
// 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