Add clone and Pre/Post actions
This commit is contained in:
parent
a2cfe4baf8
commit
14df5b82ce
4 changed files with 142 additions and 24 deletions
|
|
@ -29,8 +29,8 @@ use crate::{
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Display, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Display, Serialize, Deserialize)]
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
// App
|
// App
|
||||||
Command(String, PathBuf, Vec<String>), // (label, command, args)
|
Command(PathBuf, Vec<String>), // (command, args)
|
||||||
Diskpart(String, String), // (label, script_as_string)
|
Diskpart(String), // (script_as_string)
|
||||||
InstallDriver,
|
InstallDriver,
|
||||||
Process,
|
Process,
|
||||||
ScanDisks,
|
ScanDisks,
|
||||||
|
|
|
||||||
158
src/app.rs
158
src/app.rs
|
|
@ -14,6 +14,7 @@
|
||||||
// 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::{
|
use std::{
|
||||||
|
env,
|
||||||
iter::zip,
|
iter::zip,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
|
|
@ -39,7 +40,7 @@ use crate::{
|
||||||
config::Config,
|
config::Config,
|
||||||
system::{
|
system::{
|
||||||
disk::{get_disks, Disk, PartitionTableType},
|
disk::{get_disks, Disk, PartitionTableType},
|
||||||
diskpart::refresh_disk_info,
|
diskpart::{build_dest_format_script, refresh_disk_info},
|
||||||
drivers::{self, Driver},
|
drivers::{self, Driver},
|
||||||
},
|
},
|
||||||
tui::{Event, Tui},
|
tui::{Event, Tui},
|
||||||
|
|
@ -275,19 +276,10 @@ impl App {
|
||||||
Action::Suspend => self.should_suspend = true,
|
Action::Suspend => self.should_suspend = true,
|
||||||
Action::Resume => self.should_suspend = false,
|
Action::Resume => self.should_suspend = false,
|
||||||
Action::ClearScreen => tui.terminal.clear()?,
|
Action::ClearScreen => tui.terminal.clear()?,
|
||||||
Action::Command(ref label, ref cmd_path, ref cmd_args) => {
|
Action::Command(ref cmd_path, ref cmd_args) => self
|
||||||
self.action_tx.send(Action::DisplayPopup(
|
.task_handles
|
||||||
popup::Type::Info,
|
.push(lazy_command(&cmd_path, cmd_args.clone())),
|
||||||
String::from(&label.to_owned()),
|
Action::Diskpart(ref script) => {
|
||||||
))?;
|
|
||||||
self.task_handles
|
|
||||||
.push(lazy_command(&cmd_path, cmd_args.clone()))
|
|
||||||
}
|
|
||||||
Action::Diskpart(ref label, ref script) => {
|
|
||||||
self.action_tx.send(Action::DisplayPopup(
|
|
||||||
popup::Type::Info,
|
|
||||||
String::from(&label.to_owned()),
|
|
||||||
))?;
|
|
||||||
self.task_handles.push(lazy_diskpart(&script.to_owned()))
|
self.task_handles.push(lazy_diskpart(&script.to_owned()))
|
||||||
}
|
}
|
||||||
Action::InstallDriver => {
|
Action::InstallDriver => {
|
||||||
|
|
@ -345,26 +337,146 @@ impl App {
|
||||||
.send(Action::UpdateDiskList(disk_list.clone()))?;
|
.send(Action::UpdateDiskList(disk_list.clone()))?;
|
||||||
}
|
}
|
||||||
Mode::PreClone => {
|
Mode::PreClone => {
|
||||||
// TODO: FIXME
|
self.action_tx.send(Action::DisplayPopup(
|
||||||
self.action_tx.send(Action::Diskpart(
|
popup::Type::Info,
|
||||||
String::from("Formatting destination disk"),
|
String::from("Formatting destination disk"),
|
||||||
String::from("TODO: FIXME"),
|
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
|
// Build Diskpart script to format destination disk
|
||||||
|
let disk_list = self.disk_list.lock().unwrap();
|
||||||
|
if let Some(disk_index) = self.disk_index_dest {
|
||||||
|
if let Some(disk) = disk_list.get(disk_index) {
|
||||||
|
let disk_id = disk.id.to_owned();
|
||||||
|
let table_type = self.table_type.clone().unwrap();
|
||||||
|
let diskpart_script =
|
||||||
|
build_dest_format_script(&disk_id, &table_type);
|
||||||
|
self.action_tx.send(Action::Diskpart(diskpart_script))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Mode::Clone => {
|
Mode::Clone => {
|
||||||
self.action_tx.send(Action::Command(
|
self.action_tx.send(Action::DisplayPopup(
|
||||||
|
popup::Type::Info,
|
||||||
String::from("Running Clone Tool"),
|
String::from("Running Clone Tool"),
|
||||||
|
))?;
|
||||||
|
self.action_tx.send(Action::Command(
|
||||||
self.config.clone_app_path.clone(),
|
self.config.clone_app_path.clone(),
|
||||||
Vec::new(),
|
Vec::new(),
|
||||||
))?;
|
))?;
|
||||||
}
|
}
|
||||||
Mode::PostClone => {
|
Mode::PostClone => {
|
||||||
// TODO: FIXME
|
// TODO: FIXME
|
||||||
self.action_tx.send(Action::UpdateDestDisk)?;
|
self.action_tx.send(Action::DisplayPopup(
|
||||||
self.action_tx.send(Action::Diskpart(
|
popup::Type::Info,
|
||||||
String::from("Creating boot files"),
|
String::from("Updating boot configuration"),
|
||||||
String::from("TODO: FIXME"),
|
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
|
// Get System32 path
|
||||||
|
let system32 = if cfg!(windows) {
|
||||||
|
match env::var("SYSTEMROOT") {
|
||||||
|
Ok(path) => path,
|
||||||
|
Err(_) => panic!("Failed to find SYSTEMROOT"),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String::from(".")
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add actions
|
||||||
|
let disk_list = self.disk_list.lock().unwrap();
|
||||||
|
if let Some(disk_index) = self.disk_index_dest {
|
||||||
|
if let Some(disk) = disk_list.get(disk_index) {
|
||||||
|
let table_type = self.table_type.clone().unwrap();
|
||||||
|
let letter_boot = if let Some(s) = disk
|
||||||
|
.parts
|
||||||
|
.get(self.part_index_boot.unwrap())
|
||||||
|
.clone()
|
||||||
|
.unwrap()
|
||||||
|
.letter
|
||||||
|
.clone()
|
||||||
|
{
|
||||||
|
s
|
||||||
|
} else {
|
||||||
|
String::from("??")
|
||||||
|
};
|
||||||
|
let letter_os = if let Some(s) = disk
|
||||||
|
.parts
|
||||||
|
.get(self.part_index_os.unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.letter
|
||||||
|
.clone()
|
||||||
|
{
|
||||||
|
s
|
||||||
|
} else {
|
||||||
|
String::from("??")
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create boot files
|
||||||
|
self.action_tx.send(Action::Command(
|
||||||
|
PathBuf::from(format!("{system32}/bcdboot.exe")),
|
||||||
|
vec![
|
||||||
|
format!("{letter_os}:\\Windows"),
|
||||||
|
String::from("/s"),
|
||||||
|
format!("{letter_boot}:"),
|
||||||
|
String::from("/f"),
|
||||||
|
String::from(match table_type {
|
||||||
|
PartitionTableType::Guid => "UEFI",
|
||||||
|
PartitionTableType::Legacy => "BIOS",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
))?;
|
||||||
|
|
||||||
|
// Update boot sector (for legacy setups)
|
||||||
|
if table_type == PartitionTableType::Legacy {
|
||||||
|
//
|
||||||
|
self.action_tx.send(Action::Command(
|
||||||
|
PathBuf::from(format!("{system32}/bootsect.exe")),
|
||||||
|
vec![
|
||||||
|
String::from("/nt60"),
|
||||||
|
format!("{letter_boot}:"),
|
||||||
|
String::from("/force"),
|
||||||
|
String::from("/mbr"),
|
||||||
|
],
|
||||||
|
))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lock in safe mode
|
||||||
|
let bcd_path = match table_type {
|
||||||
|
PartitionTableType::Guid => {
|
||||||
|
format!("{letter_boot}\\EFI\\Microsoft\\Boot\\BCD")
|
||||||
|
}
|
||||||
|
PartitionTableType::Legacy => {
|
||||||
|
format!("{letter_boot}\\Boot\\BCD")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.action_tx.send(Action::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"),
|
||||||
|
],
|
||||||
|
))?;
|
||||||
|
|
||||||
|
// Inject driver(s) (if selected)
|
||||||
|
if let Some(driver) = &self.driver {
|
||||||
|
if let Some(os_path) = driver.path.to_str() {
|
||||||
|
let driver_path_str = String::from(os_path);
|
||||||
|
self.action_tx.send(Action::Command(
|
||||||
|
PathBuf::from(format!("{system32}/dism.exe")),
|
||||||
|
vec![
|
||||||
|
format!("/image:{letter_os}:\\"),
|
||||||
|
String::from("/add-driver"),
|
||||||
|
format!("/driver:\"{}\"", driver_path_str,),
|
||||||
|
String::from("/recurse"),
|
||||||
|
],
|
||||||
|
))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Mode::Done => {
|
Mode::Done => {
|
||||||
self.action_tx.send(Action::DisplayPopup(
|
self.action_tx.send(Action::DisplayPopup(
|
||||||
|
|
@ -475,6 +587,7 @@ fn get_chunks(r: Rect) -> Vec<Rect> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lazy_command(cmd_path: &PathBuf, cmd_args: Vec<String>) -> JoinHandle<()> {
|
fn lazy_command(cmd_path: &PathBuf, cmd_args: Vec<String>) -> JoinHandle<()> {
|
||||||
|
info!("Running Command: {cmd_path:?} {cmd_args:?}");
|
||||||
if cfg!(windows) {
|
if cfg!(windows) {
|
||||||
// TODO: FIXME
|
// TODO: FIXME
|
||||||
thread::spawn(|| sleep(Duration::from_secs(1)))
|
thread::spawn(|| sleep(Duration::from_secs(1)))
|
||||||
|
|
@ -488,6 +601,7 @@ fn lazy_diskpart(script: &str) -> JoinHandle<()> {
|
||||||
// TODO: FIXME
|
// TODO: FIXME
|
||||||
thread::spawn(|| sleep(Duration::from_secs(1)))
|
thread::spawn(|| sleep(Duration::from_secs(1)))
|
||||||
} else {
|
} else {
|
||||||
|
info!("Running (lazy) Diskpart: {:?}", &script);
|
||||||
thread::spawn(|| sleep(Duration::from_secs(1)))
|
thread::spawn(|| sleep(Duration::from_secs(1)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ use std::{
|
||||||
thread::sleep,
|
thread::sleep,
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
use tracing::info;
|
||||||
|
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
@ -137,8 +138,10 @@ impl fmt::Display for PartitionTableType {
|
||||||
pub fn get_disks() -> Vec<Disk> {
|
pub fn get_disks() -> Vec<Disk> {
|
||||||
let disks: Vec<Disk>;
|
let disks: Vec<Disk>;
|
||||||
if cfg!(windows) {
|
if cfg!(windows) {
|
||||||
|
info!("Get disks via Diskpart");
|
||||||
disks = diskpart::get_disks();
|
disks = diskpart::get_disks();
|
||||||
} else {
|
} else {
|
||||||
|
info!("Get (fake) disks");
|
||||||
disks = get_fake_disks();
|
disks = get_fake_disks();
|
||||||
sleep(Duration::from_millis(500));
|
sleep(Duration::from_millis(500));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -325,6 +325,7 @@ pub fn parse_partition_details(disk: &mut Disk, contents: &str) {
|
||||||
|
|
||||||
pub fn refresh_disk_info(disk: &mut Disk) {
|
pub fn refresh_disk_info(disk: &mut Disk) {
|
||||||
// TODO: Needs refactor - assuming add_ functions are replaced with get_ variants
|
// TODO: Needs refactor - assuming add_ functions are replaced with get_ variants
|
||||||
|
info!("Refresh disk info");
|
||||||
disk.parts.clear();
|
disk.parts.clear();
|
||||||
disk.parts_description.clear();
|
disk.parts_description.clear();
|
||||||
add_disk_details(disk, None);
|
add_disk_details(disk, None);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue