Compare commits

..

No commits in common. "59b9ddbee64325c73ffccfe4dcbfc41e7eaa4af7" and "8be96d21b9509fd1e1ae338ca3d47dee1b7527f5" have entirely different histories.

50 changed files with 605 additions and 2405 deletions

593
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -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
# 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
# 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/>.
# along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
[workspace]
members = ["core", "boot_diags", "deja_vu", "pe_menu"]
default-members = ["boot_diags", "deja_vu", "pe_menu"]
members = ["core", "deja_vu", "pe_menu"]
default-members = ["deja_vu", "pe_menu"]
resolver = "2"

View file

@ -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"] }

View file

@ -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

View file

@ -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
}

View file

@ -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(())
}

View file

@ -1,5 +1,5 @@
{
"app_title": "Deja-Vu",
"app_title": "Deja-vu",
"clone_app_path": "C:/Program Files/Some Clone Tool/app.exe",
"conemu_path": "C:/Program Files/ConEmu/ConEmu64.exe",
"keybindings": {
@ -82,7 +82,7 @@
"<Ctrl-z>": "Suspend"
},
"Done": {
"<Enter>": "Process",
"<Enter>": "Quit",
"<q>": "Quit",
"<Ctrl-d>": "Quit",
"<Ctrl-c>": "Quit",
@ -95,66 +95,11 @@
"<Ctrl-c>": "Quit",
"<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": {
"<Enter>": "Process",
"<Up>": "KeyUp",
"<Down>": "KeyDown",
"<q>": "Quit",
"<r>": "Restart",
"<p>": "Shutdown",
"<t>": "OpenTerminal",
"<Ctrl-d>": "Quit",
"<Ctrl-c>": "Quit",

View file

@ -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
# 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
# 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/>.
# along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
[package]
name = "core"
authors = ["2Shirt <2xShirt@gmail.com>"]
edition = "2024"
edition = "2021"
license = "GPL"
version = "0.2.0"
@ -42,7 +42,6 @@ lazy_static = "1.5.0"
libc = "0.2.158"
once_cell = "1.20.2"
pretty_assertions = "1.4.0"
rand = "0.9.0"
ratatui = { version = "0.29.0", features = ["serde", "macros"] }
raw-cpuid = "11.2.0"
regex = "1.11.1"

View file

@ -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
// 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
// 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/>.
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
use anyhow::Result;
use vergen_gix::{BuildBuilder, CargoBuilder, Emitter, GixBuilder};

View file

@ -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
// 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
// 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/>.
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
use serde::{Deserialize, Serialize};
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)]
pub enum Action {
// App (Boot-Diags)
BootScan,
// App (Clone)
Highlight(usize),
InstallDriver,
@ -29,7 +27,6 @@ pub enum Action {
ScanDisks,
Select(Option<usize>, Option<usize>), // indicies for (source, dest) etc
SelectRight(Option<usize>, Option<usize>), // indicies for right info pane
TasksComplete,
UpdateDiskList(Vec<Disk>),
UpdateFooter(String),
UpdateLeft(String, Vec<String>, Vec<String>, usize), // (title, labels, items, select_num)
@ -38,10 +35,8 @@ pub enum Action {
// 1: For a single choice
// 2: For two selections (obviously)
UpdateRight(Vec<Vec<DVLine>>, usize, Vec<Vec<DVLine>>), // (labels, start_index, items) - items before start are always shown
// App (PE-Menu)
// App (PEMenu)
OpenTerminal,
Restart,
Shutdown,
// Screens
DismissPopup,
DisplayPopup(Type, String),

View file

@ -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
// 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
// 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/>.
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
use clap::Parser;
@ -38,7 +38,6 @@ const VERSION_MESSAGE: &str = concat!(
")"
);
#[must_use]
pub fn version() -> String {
let author = clap::crate_authors!();

View file

@ -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
// 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
// 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/>.
#![allow(clippy::missing_errors_doc)]
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
use color_eyre::Result;
use crossterm::event::{KeyEvent, MouseEvent};
use ratatui::{
Frame,
layout::{Rect, Size},
Frame,
};
use tokio::sync::mpsc::UnboundedSender;

View file

@ -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
// 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
// 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/>.
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
use color_eyre::Result;
use ratatui::{
@ -31,7 +31,6 @@ pub struct Footer {
}
impl Footer {
#[must_use]
pub fn new() -> Self {
Self {
text: String::from("(q) to quit"),
@ -52,7 +51,6 @@ impl Component for Footer {
}
fn update(&mut self, action: Action) -> Result<Option<Action>> {
#[allow(clippy::single_match)]
match action {
Action::UpdateFooter(text) => self.text = text,
_ => {}

View file

@ -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
// 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
// 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/>.
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
use std::time::Instant;
use color_eyre::Result;
use ratatui::{
Frame,
layout::{Constraint, Layout, Rect},
style::{Style, Stylize},
text::Span,
widgets::Paragraph,
Frame,
};
use super::Component;
@ -46,7 +46,6 @@ impl Default for FpsCounter {
}
impl FpsCounter {
#[must_use]
pub fn new() -> Self {
Self {
last_tick_update: Instant::now(),
@ -58,26 +57,24 @@ impl FpsCounter {
}
}
#[allow(clippy::unnecessary_wraps)]
fn app_tick(&mut self) -> Result<()> {
self.tick_count += 1;
let now = Instant::now();
let elapsed = (now - self.last_tick_update).as_secs_f64();
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.tick_count = 0;
}
Ok(())
}
#[allow(clippy::unnecessary_wraps)]
fn render_tick(&mut self) -> Result<()> {
self.frame_count += 1;
let now = Instant::now();
let elapsed = (now - self.last_frame_update).as_secs_f64();
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.frame_count = 0;
}

View file

@ -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
// 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
// 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/>.
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
use color_eyre::Result;
use crossterm::event::KeyEvent;
@ -21,7 +21,7 @@ use ratatui::{
};
use tokio::sync::mpsc::UnboundedSender;
use super::{Component, state::StatefulList};
use super::{state::StatefulList, Component};
use crate::{action::Action, config::Config};
#[derive(Default)]
@ -37,7 +37,6 @@ pub struct Left {
}
impl Left {
#[must_use]
pub fn new() -> Self {
Self {
select_num: 0,
@ -139,10 +138,14 @@ impl Component for Left {
.areas(area);
// Title
let title = Paragraph::new(
Line::from(Span::styled(self.title_text.as_str(), Style::default())).centered(),
)
.block(Block::default().borders(Borders::NONE));
let title_text = if self.selections[1].is_some() || self.select_num == 1 {
"Confirm Selections"
} else {
self.title_text.as_str()
};
let title =
Paragraph::new(Line::from(Span::styled(title_text, Style::default())).centered())
.block(Block::default().borders(Borders::NONE));
frame.render_widget(title, title_area);
// Body (Blank)
@ -168,7 +171,7 @@ impl Component for Left {
.map(|(index, item)| {
let mut style = Style::default();
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();
label.as_str()
} else {

View file

@ -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
// 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
// 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/>.
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
use color_eyre::Result;
use rand::random;
use ratatui::{
prelude::*,
widgets::{Block, Borders, Clear, Paragraph, Wrap},
@ -43,7 +42,6 @@ pub struct Popup {
}
impl Popup {
#[must_use]
pub fn new() -> Self {
Self::default()
}
@ -97,20 +95,3 @@ impl Component for Popup {
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 dont 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\nIts not DNS,\n\nTheres no way its 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!",
})
}

View file

@ -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
// 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
// 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/>.
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
use color_eyre::Result;
use crossterm::event::KeyEvent;
@ -21,7 +21,7 @@ use ratatui::{
};
use tokio::sync::mpsc::UnboundedSender;
use super::{Component, state::StatefulList};
use super::{state::StatefulList, Component};
use crate::{action::Action, config::Config, line::DVLine};
#[derive(Default)]
@ -37,7 +37,6 @@ pub struct Right {
}
impl Right {
#[must_use]
pub fn new() -> Self {
Self {
selections: vec![None, None],
@ -151,7 +150,7 @@ impl Component for Right {
// First selection
if let Some(first_index) = self.get_first() {
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
.iter()
.for_each(|dv| body_text.push(dv.as_line().bold()));

View file

@ -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
// 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
// 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/>.
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
use std::collections::HashMap;
@ -31,17 +31,14 @@ impl<T: Clone> StatefulList<T> {
self.items.clear();
}
#[must_use]
pub fn get(&self, index: usize) -> Option<&T> {
self.items.get(index)
}
#[must_use]
pub fn get_selected(&self) -> Option<T> {
self.state.selected().map(|i| self.items[i].clone())
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
@ -54,12 +51,11 @@ impl<T: Clone> StatefulList<T> {
}
}
#[must_use]
pub fn selected(&self) -> Option<usize> {
self.state.selected()
}
pub fn select_first_item(&mut self) {
fn select_first_item(&mut self) {
if self.items.is_empty() {
self.state.select(None);
} else {

View file

@ -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
// 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
// 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/>.
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
use color_eyre::Result;
use ratatui::{
@ -31,7 +31,6 @@ pub struct Title {
}
impl Title {
#[must_use]
pub fn new(text: &str) -> Self {
Self {
text: String::from(text),
@ -52,7 +51,6 @@ impl Component for Title {
}
fn update(&mut self, action: Action) -> Result<Option<Action>> {
#[allow(clippy::match_single_binding)]
match action {
_ => {}
}

View file

@ -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
// 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
// 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/>.
#![allow(clippy::missing_errors_doc)]
#![allow(clippy::missing_panics_doc)]
#![allow(clippy::ref_option)]
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
#![allow(dead_code)] // Remove this once you start using the code
use std::{collections::HashMap, env, path::PathBuf};
@ -25,7 +23,7 @@ use derive_deref::{Deref, DerefMut};
use directories::ProjectDirs;
use lazy_static::lazy_static;
use ratatui::style::{Color, Modifier, Style};
use serde::{Deserialize, de::Deserializer};
use serde::{de::Deserializer, Deserialize};
use tracing::error;
use crate::{action::Action, state::Mode};
@ -56,15 +54,15 @@ pub struct Config {
pub styles: Styles,
}
pub static PROJECT_NAME: &str = "DEJA-VU";
pub static PROJECT_NAME: &'static str = "DEJA-VU";
lazy_static! {
//pub static ref PROJECT_NAME: String = env!("CARGO_PKG_NAME").to_uppercase().to_string();
pub static ref DATA_FOLDER: Option<PathBuf> =
env::var(format!("{PROJECT_NAME}_DATA"))
env::var(format!("{}_DATA", PROJECT_NAME))
.ok()
.map(PathBuf::from);
pub static ref CONFIG_FOLDER: Option<PathBuf> =
env::var(format!("{PROJECT_NAME}_CONFIG"))
env::var(format!("{}_CONFIG", PROJECT_NAME))
.ok()
.map(PathBuf::from);
}
@ -128,7 +126,6 @@ impl Config {
}
}
#[must_use]
pub fn get_data_dir() -> PathBuf {
let directory = if let Some(s) = DATA_FOLDER.clone() {
s
@ -140,7 +137,6 @@ pub fn get_data_dir() -> PathBuf {
directory
}
#[must_use]
pub fn get_config_dir() -> PathBuf {
let directory = if let Some(s) = CONFIG_FOLDER.clone() {
s
@ -153,8 +149,8 @@ pub fn get_config_dir() -> PathBuf {
}
fn project_directory() -> Option<ProjectDirs> {
ProjectDirs::from("com", "Deja-Vu", "deja-vu")
//ProjectDirs::from("com", "Deja-Vu", env!("CARGO_PKG_NAME"))
ProjectDirs::from("com", "Deja-vu", "deja-vu")
//ProjectDirs::from("com", "Deja-vu", env!("CARGO_PKG_NAME"))
}
#[derive(Clone, Debug, Default, Deref, DerefMut)]
@ -262,7 +258,6 @@ fn parse_key_code_with_modifiers(
Ok(KeyEvent::new(c, modifiers))
}
#[must_use]
pub fn key_event_to_string(key_event: &KeyEvent) -> String {
let char;
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 {
let (foreground, background) =
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();
Some(Color::Indexed(c))
} 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;
#[allow(clippy::cast_possible_truncation)]
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 c = 16 + red * 36 + green * 6 + blue;
Some(Color::Indexed(c))

View file

@ -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
// 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
// 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/>.
#![allow(clippy::missing_errors_doc)]
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
use std::env;
use color_eyre::Result;

View file

@ -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
// 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
// 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/>.
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
pub mod action;
pub mod cli;

View file

@ -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
// 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
// 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/>.
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
use ratatui::{
style::{Color, Style},
@ -30,7 +30,6 @@ pub struct DVLine {
impl DVLine {
/// Convert to Line with colored span(s)
#[must_use]
pub fn as_line(&self) -> Line {
let mut spans = Vec::new();
zip(self.line_parts.clone(), self.line_colors.clone())
@ -38,7 +37,6 @@ impl DVLine {
Line::from(spans)
}
#[must_use]
pub fn blank() -> Self {
Self {
line_parts: vec![String::new()],
@ -47,11 +45,7 @@ impl DVLine {
}
}
#[must_use]
pub fn get_disk_description_right(
disk: &Disk,
boot_os_indicies: &Option<Vec<usize>>,
) -> Vec<DVLine> {
pub fn get_disk_description_right(disk: &Disk) -> Vec<DVLine> {
let mut description: Vec<DVLine> = vec![
DVLine {
line_parts: vec![format!(
@ -73,33 +67,15 @@ pub fn get_disk_description_right(
line_colors: vec![Color::Blue],
},
];
disk.parts_description
.iter()
.enumerate()
.for_each(|(index, line)| {
let mut line_parts = vec![line.clone()];
let mut line_colors = vec![Color::Reset];
if let Some(indicies) = boot_os_indicies {
let boot_index = indicies.first();
if boot_index.is_some_and(|i| i == &index) {
line_parts.push(String::from(" <-- Boot Partition"));
line_colors.push(Color::Cyan);
}
let boot_index = indicies.get(1);
if boot_index.is_some_and(|i| i == &index) {
line_parts.push(String::from(" <-- OS Partition"));
line_colors.push(Color::Cyan);
}
}
description.push(DVLine {
line_parts,
line_colors,
});
for line in &disk.parts_description {
description.push(DVLine {
line_parts: vec![line.clone()],
line_colors: vec![Color::Reset],
});
}
description
}
#[must_use]
pub fn get_part_description(part: &Partition) -> Vec<DVLine> {
let description: Vec<DVLine> = vec![
DVLine {

View file

@ -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
// 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
// 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/>.
#![allow(clippy::missing_errors_doc)]
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
use color_eyre::Result;
use tracing_error::ErrorLayer;
use tracing_subscriber::{EnvFilter, fmt, prelude::*};
use tracing_subscriber::{fmt, prelude::*, EnvFilter};
use crate::config;

View file

@ -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
// 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
// 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/>.
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
use std::sync::{Arc, Mutex};
@ -30,13 +30,6 @@ pub enum Mode {
Home,
Done,
Failed,
// Boot Diags
DiagMenu,
BootDiags,
BootScan,
BootSetup,
InjectDrivers,
SetBootMode,
// Clone
ScanDisks,
InstallDrivers,

View file

@ -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
// 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
// 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/>.
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
pub mod boot;
pub mod cpu;

View file

@ -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
// 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
// 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/>.
#![allow(clippy::missing_errors_doc)]
#![allow(clippy::missing_panics_doc)]
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
use super::{disk::PartitionTableType, drivers::Driver};
use crate::tasks::TaskType;
use crate::tasks::Task;
use color_eyre::Result;
use std::path::PathBuf;
#[derive(Clone, Debug, Default)]
pub enum SafeMode {
#[default]
Disable,
Enable,
}
#[must_use]
pub fn configure_disk(
letter_boot: &str,
letter_os: &str,
system32: &str,
table_type: &PartitionTableType,
) -> Vec<TaskType> {
table_type: PartitionTableType,
) -> Vec<Task> {
let mut tasks = Vec::new();
// Create
tasks.push(TaskType::CommandWait(
tasks.push(Task::Command(
PathBuf::from(format!("{system32}/bcdboot.exe")),
vec![
format!("{letter_os}:\\Windows"),
@ -52,8 +42,8 @@ pub fn configure_disk(
));
// Update boot sector (for legacy setups)
if *table_type == PartitionTableType::Legacy {
tasks.push(TaskType::CommandWait(
if table_type == PartitionTableType::Legacy {
tasks.push(Task::Command(
PathBuf::from(format!("{system32}/bootsect.exe")),
vec![
String::from("/nt60"),
@ -65,19 +55,34 @@ pub fn configure_disk(
}
// Lock in safe mode
tasks.push(
set_mode(letter_boot, &SafeMode::Enable, system32, table_type)
.expect("Failed to create set_mode task."),
);
let bcd_path = match table_type {
PartitionTableType::Guid => {
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
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() {
let driver_path = driver.path.to_str().unwrap();
Ok(TaskType::CommandWait(
Ok(Task::Command(
PathBuf::from(format!("{system32}/dism.exe")),
vec![
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,
))
}

View file

@ -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
// 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
// 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/>.
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
#[must_use]
pub fn get_cpu_name() -> String {

View file

@ -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
// 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
// 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/>.
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
use serde::{Deserialize, Serialize};
use std::{
@ -67,7 +67,6 @@ impl Disk {
}
}
#[must_use]
pub fn get_part_letter(&self, part_index: usize) -> String {
// Used to get Boot and OS letters
if let Some(part) = self.parts.get(part_index) {
@ -77,12 +76,10 @@ impl Disk {
}
}
#[must_use]
pub fn get_parts(&self) -> Vec<Partition> {
self.parts.clone()
}
#[must_use]
pub fn num_parts(&self) -> usize {
self.parts.len()
}

View file

@ -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
// 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
// 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/>.
#![allow(clippy::missing_panics_doc)]
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
use std::{
collections::HashMap,
fs::File,
@ -27,7 +26,7 @@ use tempfile::tempdir;
use tracing::{info, warn};
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;
@ -130,7 +129,7 @@ pub fn get_partition_details(
#[must_use]
pub fn build_dest_format_script(disk_id: usize, part_type: &PartitionTableType) -> String {
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 {
PartitionTableType::Guid => {
script.push("convert gpt");

View file

@ -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
// 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
// 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/>.
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
use std::{env, fmt, fs::read_dir, path::PathBuf, process::Command};

View file

@ -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
// 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
// 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/>.
#![allow(clippy::missing_errors_doc)]
#![allow(clippy::missing_panics_doc)]
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
use std::{
collections::VecDeque,
fmt,
path::PathBuf,
process::{Command, Stdio},
sync::{Arc, Mutex},
thread::{self, JoinHandle, sleep},
thread::{self, sleep, JoinHandle},
time::Duration,
};
@ -36,70 +34,23 @@ use crate::{
};
#[derive(Clone, Debug)]
pub enum TaskResult {
Error(String),
Output(String, String, bool), // stdout, stderr, success
}
#[derive(Clone, Debug)]
pub enum TaskType {
CommandNoWait(PathBuf, Vec<String>), // (command, args)
CommandWait(PathBuf, Vec<String>), // (command, args)
Diskpart(String), // (script_as_string)
pub enum Task {
Command(PathBuf, Vec<String>), // (command, args)
Diskpart(String), // (script_as_string)
ScanDisks,
Sleep,
UpdateDestDisk(usize), // (disk_index)
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)]
pub struct Tasks {
action_tx: mpsc::UnboundedSender<Action>,
disk_list: Arc<Mutex<Vec<disk::Disk>>>,
cur_handle: Option<JoinHandle<()>>,
cur_task: Option<Task>,
handle: Option<JoinHandle<()>>,
task_list: VecDeque<Task>,
task_rx: mpsc::UnboundedReceiver<TaskResult>,
task_tx: mpsc::UnboundedSender<TaskResult>,
task_rx: mpsc::UnboundedReceiver<Action>, // Used to forward Actions from Tasks to App
task_tx: mpsc::UnboundedSender<Action>, // Used to forward Actions from Tasks to App
}
impl Tasks {
@ -111,186 +62,159 @@ impl Tasks {
Tasks {
action_tx,
disk_list: disk_list_arc,
cur_handle: None,
cur_task: None,
handle: None,
task_list: VecDeque::new(),
task_rx,
task_tx,
}
}
pub fn add(&mut self, task_type: TaskType) {
info!("Adding task: {:?}", &task_type);
self.task_list.push_back(Task::new(task_type));
pub fn add(&mut self, task: Task) {
info!("Adding task: {:?}", &task);
self.task_list.push_back(task);
}
#[must_use]
pub fn idle(&self) -> bool {
self.cur_handle.is_none()
self.handle.is_none()
}
pub fn poll(&mut self) -> Result<Option<Task>> {
let mut return_task: Option<Task> = None;
// Handle task channel item(s)
if let Ok(result) = self.task_rx.try_recv() {
if let Some(mut task) = self.cur_task.take() {
task.result.replace(result);
self.cur_task.replace(task);
}
pub fn poll(&mut self) -> Result<()> {
// Forward any actions to main app
if let Ok(action) = self.task_rx.try_recv() {
let result = self.action_tx.send(action.clone());
assert!(result.is_ok(), "Failed to send Action: {action:?}");
}
// Check status of current task (if one is running).
// NOTE: Action::TasksComplete is sent once all tasks are complete
if let Some(task_handle) = self.cur_handle.take() {
if task_handle.is_finished() {
// Need to return task with handle
if let Some(mut cur_task) = self.cur_task.take() {
cur_task.handle = Some(task_handle);
return_task = Some(cur_task);
}
// NOTE: Action::NextScreen is sent once all tasks are complete
if let Some(handle) = self.handle.take() {
if handle.is_finished() {
if self.task_list.is_empty() {
// No tasks remain
self.action_tx.send(Action::TasksComplete)?;
self.task_tx.send(Action::NextScreen)?;
} else {
// Start next task
self.start()?;
}
} else {
// TaskType not complete, return handle
self.cur_handle.replace(task_handle);
// Task not complete, return handle
self.handle = Some(handle);
}
} else if !self.task_list.is_empty() {
// No current task but one is available
self.start()?;
}
Ok(return_task)
Ok(())
}
pub fn start(&mut self) -> Result<()> {
self.cur_task = self.task_list.pop_front();
if let Some(task) = self.cur_task.take() {
if let Some(task) = self.task_list.pop_front() {
let task_str = format!("{task:?}");
let task_tx = self.task_tx.clone();
match task.task_type {
TaskType::CommandNoWait(ref cmd_path, ref cmd_args) => {
self.cur_handle = None;
run_task_command(cmd_path.clone(), cmd_args.clone(), task_tx);
match task {
Task::Command(ref cmd_path, ref cmd_args) => {
let cmd_path = cmd_path.clone();
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) => {
self.cur_handle = Some(run_task_command(
cmd_path.clone(),
cmd_args.clone(),
task_tx,
));
Task::Diskpart(ref script) => {
if cfg!(windows) {
let script = String::from(script);
self.handle = Some(thread::spawn(move || {
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) => {
self.cur_handle = Some(run_task_diskpart(script, task_tx));
}
TaskType::ScanDisks => {
Task::ScanDisks => {
let disk_list_arc = self.disk_list.clone();
// 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();
*disks = disk::get_disks();
}));
}
TaskType::Sleep => {
self.cur_handle = Some(thread::spawn(|| sleep(Duration::from_millis(250))));
Task::Sleep => {
self.handle = Some(thread::spawn(|| sleep(Duration::from_millis(250))));
}
TaskType::UpdateDestDisk(index) => {
Task::UpdateDestDisk(index) => {
self.action_tx.send(Action::DisplayPopup(
popup::Type::Info,
String::from("Refreshing disk info"),
))?;
// Queue UpdateDiskList for various components
self.add(TaskType::Sleep);
self.add(TaskType::UpdateDiskList);
self.add(Task::Sleep);
self.add(Task::UpdateDiskList);
// Update destination disk ~in-place
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 old_disk = &mut disks[index];
disks[index] = disk::refresh_disk_info(old_disk);
}));
}
TaskType::UpdateDiskList => {
Task::UpdateDiskList => {
let disks = self.disk_list.lock().unwrap();
let disks_copy = disks.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)) {
panic!("Failed to send Action: {err:?}");
}
}));
}
}
// Done
self.cur_task.replace(task);
}
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)))
}
}

View file

@ -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
// 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
// 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/>.
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
pub mod sample_output;

View file

@ -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
// 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
// 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/>.
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
#[allow(dead_code)]
pub static DETAIL_DISK_GPT: &str = "Disk 2 is now the selected disk.

View file

@ -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
// 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
// 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/>.
#![allow(clippy::missing_errors_doc)]
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
#![allow(dead_code)] // Remove this once you start using the code
use std::{
io::{Stdout, stdout},
io::{stdout, Stdout},
ops::{Deref, DerefMut},
time::Duration,
};
@ -85,25 +85,21 @@ impl Tui {
})
}
#[must_use]
pub fn tick_rate(mut self, tick_rate: f64) -> Self {
self.tick_rate = tick_rate;
self
}
#[must_use]
pub fn frame_rate(mut self, frame_rate: f64) -> Self {
self.frame_rate = frame_rate;
self
}
#[must_use]
pub fn mouse(mut self, mouse: bool) -> Self {
self.mouse = mouse;
self
}
#[must_use]
pub fn paste(mut self, paste: bool) -> Self {
self.paste = paste;
self
@ -139,7 +135,7 @@ impl Tui {
.expect("failed to send init event");
loop {
let event = tokio::select! {
() = cancellation_token.cancelled() => {
_ = cancellation_token.cancelled() => {
break;
}
_ = tick_interval.tick() => Event::Tick,
@ -152,7 +148,7 @@ impl Tui {
CrosstermEvent::FocusLost => Event::FocusLost,
CrosstermEvent::FocusGained => Event::FocusGained,
CrosstermEvent::Paste(s) => Event::Paste(s),
CrosstermEvent::Key(_) => continue, // ignore other events
_ => continue, // ignore other events
}
Some(Err(_)) => Event::Error,
None => break, // the event stream has stopped and will not produce any more events

View file

@ -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
# 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
# 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/>.
# along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
[package]
name = "deja-vu"
authors = ["2Shirt <2xShirt@gmail.com>"]
edition = "2024"
edition = "2021"
license = "GPL"
version = "0.2.0"
@ -39,7 +39,7 @@ tokio-util = "0.7.11"
tracing = "0.1.41"
tracing-error = "0.2.0"
tracing-subscriber = { version = "0.3.18", features = ["env-filter", "serde"] }
check_elevation = "0.2.4"
rand = "0.8.5"
[build-dependencies]
anyhow = "1.0.86"

View file

@ -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
// 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
// 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/>.
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
use anyhow::Result;
use vergen_gix::{BuildBuilder, CargoBuilder, Emitter, GixBuilder};

View file

@ -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
// 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
// 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/>.
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
use core::{
action::Action,
components::{
Component, footer::Footer, fps::FpsCounter, left::Left, popup, right::Right,
state::StatefulList, title::Title,
footer::Footer, fps::FpsCounter, left::Left, popup, right::Right, state::StatefulList,
title::Title, Component,
},
config::Config,
line::{DVLine, get_disk_description_right, get_part_description},
line::{get_disk_description_right, get_part_description, DVLine},
state::{CloneSettings, Mode},
system::{
boot, cpu::get_cpu_name, disk::PartitionTableType, diskpart::build_dest_format_script,
drivers,
},
tasks::{Task, TaskResult, TaskType, Tasks},
tasks::{Task, Tasks},
tui::{Event, Tui},
};
use std::{
env,
iter::zip,
path::PathBuf,
sync::{Arc, Mutex},
};
use color_eyre::Result;
use rand::random;
use ratatui::{
crossterm::event::KeyEvent,
layout::{Constraint, Direction, Layout},
@ -100,7 +100,7 @@ impl App {
}
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::Failed => Some(Mode::Failed),
Mode::Done => Some(Mode::Done),
@ -115,19 +115,15 @@ impl App {
| Mode::Clone
| Mode::PostClone => None,
// Invalid states
Mode::BootDiags
| Mode::BootScan
| Mode::BootSetup
| Mode::DiagMenu
| Mode::InjectDrivers
| Mode::PEMenu
| Mode::SetBootMode => panic!("This shouldn't happen?"),
}
Mode::PEMenu => panic!("This shouldn't happen?"),
};
new_mode
}
pub fn next_mode(&mut self) -> Option<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::SelectDisks => Mode::SelectTableType,
Mode::SelectTableType => Mode::Confirm,
@ -138,13 +134,7 @@ impl App {
Mode::PostClone | Mode::Done => Mode::Done,
Mode::Failed => Mode::Failed,
// Invalid states
Mode::BootDiags
| Mode::BootScan
| Mode::BootSetup
| Mode::DiagMenu
| Mode::InjectDrivers
| Mode::PEMenu
| Mode::SetBootMode => panic!("This shouldn't happen?"),
Mode::PEMenu => panic!("This shouldn't happen?"),
};
if new_mode == self.cur_mode {
@ -163,7 +153,7 @@ impl App {
Mode::ScanDisks => {
self.prev_mode = self.cur_mode;
if self.tasks.idle() {
self.tasks.add(TaskType::ScanDisks);
self.tasks.add(Task::ScanDisks);
}
self.action_tx.send(Action::DisplayPopup(
popup::Type::Info,
@ -176,22 +166,13 @@ impl App {
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
let disk_list = self.clone.disk_list.lock().unwrap();
if let Some(disk_index) = self.clone.disk_index_dest {
if let Some(disk) = disk_list.get(disk_index) {
let table_type = self.clone.table_type.clone().unwrap();
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,
String::from("Running Clone Tool"),
))?;
self.tasks.add(TaskType::CommandWait(
self.tasks.add(Task::Command(
self.config.clone_app_path.clone(),
Vec::new(),
));
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 => {
@ -215,7 +196,18 @@ impl App {
))?;
// 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
let disk_list = self.clone.disk_list.lock().unwrap();
@ -235,7 +227,7 @@ impl App {
// Create boot files
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);
}
@ -256,7 +248,7 @@ impl App {
}
Mode::Done => {
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 {
Action::Tick => {
self.last_tick_key_events.drain(..);
// Check background task(s)
if let Some(task) = self.tasks.poll()? {
self.handle_task(&task)?;
match self.cur_mode {
Mode::ScanDisks | Mode::PreClone | Mode::Clone | Mode::PostClone => {
// Check background task
self.tasks.poll()?; // Once all are complete Action::NextScreen is sent
}
_ => {}
}
}
Action::Quit => self.should_quit = true,
@ -374,9 +369,6 @@ impl App {
Mode::Confirm => {
self.action_tx.send(Action::NextScreen)?;
}
Mode::Done => {
self.action_tx.send(Action::Quit)?;
}
_ => {}
},
Action::Resize(w, h) => self.handle_resize(tui, w, h)?,
@ -423,7 +415,7 @@ impl App {
0 => Some(PartitionTableType::Guid),
1 => Some(PartitionTableType::Legacy),
index => {
panic!("Failed to select PartitionTableType: {index}")
panic!("Failed to select PartitionTableType: {}", index)
}
}
} else {
@ -476,7 +468,6 @@ impl App {
_ => {}
};
}
Action::TasksComplete => self.action_tx.send(Action::NextScreen)?,
_ => {}
}
for component in &mut self.components {
@ -494,39 +485,6 @@ impl App {
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<()> {
tui.draw(|frame| {
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")
}
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(
"(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::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
Mode::BootDiags
| Mode::BootScan
| Mode::BootSetup
| Mode::DiagMenu
| Mode::InjectDrivers
| Mode::PEMenu
| Mode::SetBootMode => panic!("This shouldn't happen?"),
Mode::PEMenu => panic!("This shouldn't happen?"),
}
}
@ -687,13 +638,7 @@ fn build_left_items(app: &App, cur_mode: Mode) -> Action {
title = String::from("Done");
}
// Invalid states
Mode::BootDiags
| Mode::BootScan
| Mode::BootSetup
| Mode::DiagMenu
| Mode::InjectDrivers
| Mode::PEMenu
| Mode::SetBootMode => panic!("This shouldn't happen?"),
Mode::PEMenu => panic!("This shouldn't happen?"),
};
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();
disk_list
.iter()
.for_each(|disk| items.push(get_disk_description_right(disk, &None)));
.for_each(|disk| items.push(get_disk_description_right(&disk)));
}
Mode::SelectParts => {
for s in &["Boot", "OS"] {
vec!["Boot", "OS"].iter().for_each(|s| {
labels.push(vec![DVLine {
line_parts: vec![String::from(*s)],
line_colors: vec![Color::Cyan],
}]);
}
}])
});
if let Some(index) = app.clone.disk_index_dest {
start_index = 1;
let disk_list = app.clone.disk_list.lock().unwrap();
if let Some(disk) = disk_list.get(index) {
// Disk Details
items.push(get_disk_description_right(disk, &None));
items.push(get_disk_description_right(&disk));
// Partition Details
disk.parts
.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)
}
pub fn get_system32_path(action_tx: &mpsc::UnboundedSender<Action>) -> String {
let mut system32_path = String::from(".");
if cfg!(windows) {
if let Ok(path) = env::var("SYSTEMROOT") {
system32_path = format!("{path}/System32");
} else {
action_tx
.send(Action::Error(String::from(
"ERROR\n\n\nFailed to find SYSTEMROOT",
)))
.expect("Failed to find SYSTEMROOT and then failed to send action");
}
}
system32_path
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 dont 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\nIts not DNS,\n\nTheres no way its 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!",
})
}

View file

@ -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
// 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
// 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/>.
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
use clap::Parser;
use color_eyre::Result;
use core;
use crate::app::App;
@ -22,22 +23,11 @@ mod app;
#[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.");
}
};
if let Some(text) = msg {
println!("{text}");
} else {
core::errors::init()?;
core::logging::init()?;
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?;
}
let args = core::cli::Cli::parse();
let mut app = App::new(args.tick_rate, args.frame_rate)?;
app.run().await?;
Ok(())
}

View file

@ -1,5 +0,0 @@
name = 'Boot-Diagnostics'
command = 'X:\tools\boot-diags.exe'
description = "Boot issue assessment tool"
use_conemu = true
separator = false

View file

@ -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
# 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
# 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/>.
# along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
[package]
name = "pe-menu"
authors = ["2Shirt <2xShirt@gmail.com>"]
edition = "2024"
edition = "2021"
license = "GPL"
version = "0.2.0"

View file

@ -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
// 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
// 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/>.
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
use anyhow::Result;
use vergen_gix::{BuildBuilder, CargoBuilder, Emitter, GixBuilder};

View file

@ -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
// 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
// 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/>.
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
use core::{
action::Action,
components::{
Component, footer::Footer, fps::FpsCounter, left::Left, popup, right::Right,
state::StatefulList, title::Title,
footer::Footer, fps::FpsCounter, left::Left, popup, right::Right, state::StatefulList,
title::Title, Component,
},
config::Config,
line::DVLine,
state::Mode,
tasks::{TaskType, Tasks},
tasks::{Task, Tasks},
tui::{Event, Tui},
};
use std::{
@ -230,55 +230,25 @@ impl App {
// Run selected tool
if let Some(tool) = self.list.get_selected() {
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::Render => self.render(tui)?,
Action::SetMode(mode) => {
self.mode = mode;
self.action_tx.send(Action::UpdateFooter(String::from(
"(Enter) to select / (t) for terminal / (p) to power off / (r) to restart",
)))?;
self.action_tx
.send(Action::UpdateFooter(String::from("(Enter) to select")))?;
self.action_tx.send(build_left_items(self))?;
self.action_tx.send(build_right_items(self))?;
self.action_tx.send(Action::Select(None, None))?;
}
Action::OpenTerminal => {
self.tasks.add(TaskType::CommandNoWait(
self.tasks.add(Task::Command(
PathBuf::from("cmd.exe"),
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 {
@ -371,15 +341,14 @@ fn get_chunks(r: Rect) -> Vec<Rect> {
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 mut cmd_args: Vec<String> = Vec::new();
let start_index: usize;
if tool.use_conemu {
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(tool.command.clone());
start_index = 1;
} else {
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 {
@ -453,7 +422,7 @@ pub fn load_tools() -> Vec<Tool> {
entries
.iter()
.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");
tool
})

View file

@ -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
// 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
// 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/>.
// along with Deja-vu. If not, see <https://www.gnu.org/licenses/>.
//
use clap::Parser;
use color_eyre::Result;
use core;
use crate::app::App;