diff --git a/src/action/common/configure_nix.rs b/src/action/common/configure_nix.rs index 5502270..b3f2111 100644 --- a/src/action/common/configure_nix.rs +++ b/src/action/common/configure_nix.rs @@ -65,7 +65,7 @@ impl ConfigureNix { } #[async_trait::async_trait] -#[typetag::serde(name = "configure-nix")] +#[typetag::serde(name = "configure_nix")] impl Action for ConfigureNix { fn describe_execute(&self) -> Vec { let Self { diff --git a/src/action/common/configure_nix_daemon_service.rs b/src/action/common/configure_nix_daemon_service.rs index 974d798..76ca88c 100644 --- a/src/action/common/configure_nix_daemon_service.rs +++ b/src/action/common/configure_nix_daemon_service.rs @@ -45,7 +45,7 @@ impl ConfigureNixDaemonService { } #[async_trait::async_trait] -#[typetag::serde(name = "configure-nix-daemon")] +#[typetag::serde(name = "configure_nix_daemon")] impl Action for ConfigureNixDaemonService { fn describe_execute(&self) -> Vec { if self.action_state == ActionState::Completed { diff --git a/src/action/common/configure_shell_profile.rs b/src/action/common/configure_shell_profile.rs index af9473b..f84c5dc 100644 --- a/src/action/common/configure_shell_profile.rs +++ b/src/action/common/configure_shell_profile.rs @@ -58,7 +58,7 @@ impl ConfigureShellProfile { } #[async_trait::async_trait] -#[typetag::serde(name = "configure-shell-profile")] +#[typetag::serde(name = "configure_shell_profile")] impl Action for ConfigureShellProfile { fn describe_execute(&self) -> Vec { if self.action_state == ActionState::Completed { diff --git a/src/action/common/create_directory.rs b/src/action/common/create_directory.rs index adb6871..b67fe76 100644 --- a/src/action/common/create_directory.rs +++ b/src/action/common/create_directory.rs @@ -67,7 +67,7 @@ impl CreateDirectory { } #[async_trait::async_trait] -#[typetag::serde(name = "create-directory")] +#[typetag::serde(name = "create_directory")] impl Action for CreateDirectory { fn describe_execute(&self) -> Vec { let Self { diff --git a/src/action/common/create_file.rs b/src/action/common/create_file.rs index 13baa1f..08b4c54 100644 --- a/src/action/common/create_file.rs +++ b/src/action/common/create_file.rs @@ -51,7 +51,7 @@ impl CreateFile { } #[async_trait::async_trait] -#[typetag::serde(name = "create-file")] +#[typetag::serde(name = "create_file")] impl Action for CreateFile { fn describe_execute(&self) -> Vec { let Self { diff --git a/src/action/common/create_group.rs b/src/action/common/create_group.rs index 21042cf..2ac3971 100644 --- a/src/action/common/create_group.rs +++ b/src/action/common/create_group.rs @@ -26,7 +26,7 @@ impl CreateGroup { } #[async_trait::async_trait] -#[typetag::serde(name = "create-group")] +#[typetag::serde(name = "create_group")] impl Action for CreateGroup { fn describe_execute(&self) -> Vec { let Self { diff --git a/src/action/common/create_nix_tree.rs b/src/action/common/create_nix_tree.rs index 7f81791..ab4d1e3 100644 --- a/src/action/common/create_nix_tree.rs +++ b/src/action/common/create_nix_tree.rs @@ -40,7 +40,7 @@ impl CreateNixTree { } #[async_trait::async_trait] -#[typetag::serde(name = "creat-nix-tree")] +#[typetag::serde(name = "create_nix_tree")] impl Action for CreateNixTree { fn describe_execute(&self) -> Vec { if self.action_state == ActionState::Completed { diff --git a/src/action/common/create_or_append_file.rs b/src/action/common/create_or_append_file.rs index d76a387..81ad802 100644 --- a/src/action/common/create_or_append_file.rs +++ b/src/action/common/create_or_append_file.rs @@ -48,7 +48,7 @@ impl CreateOrAppendFile { } #[async_trait::async_trait] -#[typetag::serde(name = "create-or-append-file")] +#[typetag::serde(name = "create_or_append_file")] impl Action for CreateOrAppendFile { fn describe_execute(&self) -> Vec { let Self { diff --git a/src/action/common/create_user.rs b/src/action/common/create_user.rs index 6083649..40a6086 100644 --- a/src/action/common/create_user.rs +++ b/src/action/common/create_user.rs @@ -30,7 +30,7 @@ impl CreateUser { } #[async_trait::async_trait] -#[typetag::serde(name = "create-user")] +#[typetag::serde(name = "create_user")] impl Action for CreateUser { fn describe_execute(&self) -> Vec { if self.action_state == ActionState::Completed { diff --git a/src/action/common/create_users_and_group.rs b/src/action/common/create_users_and_group.rs index 2ab9e5d..3b2cd62 100644 --- a/src/action/common/create_users_and_group.rs +++ b/src/action/common/create_users_and_group.rs @@ -55,7 +55,7 @@ impl CreateUsersAndGroup { } #[async_trait::async_trait] -#[typetag::serde(name = "create-users-and-group")] +#[typetag::serde(name = "create_users_and_group")] impl Action for CreateUsersAndGroup { fn describe_execute(&self) -> Vec { let Self { diff --git a/src/action/common/fetch_nix.rs b/src/action/common/fetch_nix.rs index a789996..47f7349 100644 --- a/src/action/common/fetch_nix.rs +++ b/src/action/common/fetch_nix.rs @@ -32,7 +32,7 @@ impl FetchNix { } #[async_trait::async_trait] -#[typetag::serde(name = "fetch-nix")] +#[typetag::serde(name = "fetch_nix")] impl Action for FetchNix { fn describe_execute(&self) -> Vec { let Self { diff --git a/src/action/common/move_unpacked_nix.rs b/src/action/common/move_unpacked_nix.rs index 6c92f40..6638cec 100644 --- a/src/action/common/move_unpacked_nix.rs +++ b/src/action/common/move_unpacked_nix.rs @@ -25,7 +25,7 @@ impl MoveUnpackedNix { } #[async_trait::async_trait] -#[typetag::serde(name = "mount-unpacked-nix")] +#[typetag::serde(name = "mount_unpacked_nix")] impl Action for MoveUnpackedNix { fn describe_execute(&self) -> Vec { if self.action_state == ActionState::Completed { diff --git a/src/action/common/place_channel_configuration.rs b/src/action/common/place_channel_configuration.rs index cae9581..ca424c1 100644 --- a/src/action/common/place_channel_configuration.rs +++ b/src/action/common/place_channel_configuration.rs @@ -45,7 +45,7 @@ impl PlaceChannelConfiguration { } #[async_trait::async_trait] -#[typetag::serde(name = "place-channel-configuration")] +#[typetag::serde(name = "place_channel_configuration")] impl Action for PlaceChannelConfiguration { fn describe_execute(&self) -> Vec { let Self { diff --git a/src/action/common/place_nix_configuration.rs b/src/action/common/place_nix_configuration.rs index 199a1d1..1e513ef 100644 --- a/src/action/common/place_nix_configuration.rs +++ b/src/action/common/place_nix_configuration.rs @@ -42,7 +42,7 @@ impl PlaceNixConfiguration { } #[async_trait::async_trait] -#[typetag::serde(name = "place-nix-configuration")] +#[typetag::serde(name = "place_nix_configuration")] impl Action for PlaceNixConfiguration { fn describe_execute(&self) -> Vec { if self.action_state == ActionState::Completed { diff --git a/src/action/common/provision_nix.rs b/src/action/common/provision_nix.rs index a09af72..60f9302 100644 --- a/src/action/common/provision_nix.rs +++ b/src/action/common/provision_nix.rs @@ -52,7 +52,7 @@ impl ProvisionNix { } #[async_trait::async_trait] -#[typetag::serde(name = "provision-nix")] +#[typetag::serde(name = "provision_nix")] impl Action for ProvisionNix { fn describe_execute(&self) -> Vec { let Self { diff --git a/src/action/common/setup_default_profile.rs b/src/action/common/setup_default_profile.rs index 819b9e6..38618f3 100644 --- a/src/action/common/setup_default_profile.rs +++ b/src/action/common/setup_default_profile.rs @@ -23,7 +23,7 @@ impl SetupDefaultProfile { } #[async_trait::async_trait] -#[typetag::serde(name = "setup-default-profile")] +#[typetag::serde(name = "setup_default_profile")] impl Action for SetupDefaultProfile { fn describe_execute(&self) -> Vec { if self.action_state == ActionState::Completed { diff --git a/src/action/darwin/bootstrap_volume.rs b/src/action/darwin/bootstrap_volume.rs index 13b46e6..ecdb447 100644 --- a/src/action/darwin/bootstrap_volume.rs +++ b/src/action/darwin/bootstrap_volume.rs @@ -28,7 +28,7 @@ impl BootstrapVolume { } #[async_trait::async_trait] -#[typetag::serde(name = "bootstrap-volume")] +#[typetag::serde(name = "bootstrap_volume")] impl Action for BootstrapVolume { fn describe_execute(&self) -> Vec { if self.action_state == ActionState::Completed { diff --git a/src/action/darwin/create_apfs_volume.rs b/src/action/darwin/create_apfs_volume.rs index 20c3f27..2d280fd 100644 --- a/src/action/darwin/create_apfs_volume.rs +++ b/src/action/darwin/create_apfs_volume.rs @@ -145,7 +145,7 @@ impl CreateApfsVolume { } #[async_trait::async_trait] -#[typetag::serde(name = "create-apfs-volume")] +#[typetag::serde(name = "create_apfs_volume")] impl Action for CreateApfsVolume { fn describe_execute(&self) -> Vec { let Self { diff --git a/src/action/darwin/create_synthetic_objects.rs b/src/action/darwin/create_synthetic_objects.rs index bf77e10..94a43e4 100644 --- a/src/action/darwin/create_synthetic_objects.rs +++ b/src/action/darwin/create_synthetic_objects.rs @@ -19,7 +19,7 @@ impl CreateSyntheticObjects { } #[async_trait::async_trait] -#[typetag::serde(name = "create-synthetic-objects")] +#[typetag::serde(name = "create_synthetic_objects")] impl Action for CreateSyntheticObjects { fn describe_execute(&self) -> Vec { if self.action_state == ActionState::Completed { diff --git a/src/action/darwin/create_volume.rs b/src/action/darwin/create_volume.rs index de42463..d29beab 100644 --- a/src/action/darwin/create_volume.rs +++ b/src/action/darwin/create_volume.rs @@ -34,7 +34,7 @@ impl CreateVolume { } #[async_trait::async_trait] -#[typetag::serde(name = "create-volume")] +#[typetag::serde(name = "create_volume")] impl Action for CreateVolume { fn describe_execute(&self) -> Vec { if self.action_state == ActionState::Completed { diff --git a/src/action/darwin/enable_ownership.rs b/src/action/darwin/enable_ownership.rs index f0c5c00..3e627ea 100644 --- a/src/action/darwin/enable_ownership.rs +++ b/src/action/darwin/enable_ownership.rs @@ -30,7 +30,7 @@ impl EnableOwnership { } #[async_trait::async_trait] -#[typetag::serde(name = "enable-ownership")] +#[typetag::serde(name = "enable_ownership")] impl Action for EnableOwnership { fn describe_execute(&self) -> Vec { if self.action_state == ActionState::Completed { diff --git a/src/action/darwin/encrypt_volume.rs b/src/action/darwin/encrypt_volume.rs index 251b2da..8e8f5c3 100644 --- a/src/action/darwin/encrypt_volume.rs +++ b/src/action/darwin/encrypt_volume.rs @@ -24,7 +24,7 @@ impl EncryptVolume { } #[async_trait::async_trait] -#[typetag::serde(name = "encrypt-volume")] +#[typetag::serde(name = "encrypt_volume")] impl Action for EncryptVolume { fn describe_execute(&self) -> Vec { if self.action_state == ActionState::Completed { diff --git a/src/action/darwin/kickstart_launchctl_service.rs b/src/action/darwin/kickstart_launchctl_service.rs index 6127584..337d9ee 100644 --- a/src/action/darwin/kickstart_launchctl_service.rs +++ b/src/action/darwin/kickstart_launchctl_service.rs @@ -24,7 +24,7 @@ impl KickstartLaunchctlService { } #[async_trait::async_trait] -#[typetag::serde(name = "kickstart-launchctl-service")] +#[typetag::serde(name = "kickstart_launchctl_service")] impl Action for KickstartLaunchctlService { fn describe_execute(&self) -> Vec { let Self { unit, action_state } = self; diff --git a/src/action/darwin/unmount_volume.rs b/src/action/darwin/unmount_volume.rs index 888f48a..83dfcf1 100644 --- a/src/action/darwin/unmount_volume.rs +++ b/src/action/darwin/unmount_volume.rs @@ -32,7 +32,7 @@ impl UnmountVolume { } #[async_trait::async_trait] -#[typetag::serde(name = "unmount-volume")] +#[typetag::serde(name = "unmount_volume")] impl Action for UnmountVolume { fn describe_execute(&self) -> Vec { if self.action_state == ActionState::Completed { diff --git a/src/action/linux/create_systemd_sysext.rs b/src/action/linux/create_systemd_sysext.rs index 18d838f..36c617a 100644 --- a/src/action/linux/create_systemd_sysext.rs +++ b/src/action/linux/create_systemd_sysext.rs @@ -92,7 +92,7 @@ impl CreateSystemdSysext { } #[async_trait::async_trait] -#[typetag::serde(name = "create-systemd-sysext")] +#[typetag::serde(name = "create_systemd_sysext")] impl Action for CreateSystemdSysext { fn describe_execute(&self) -> Vec { let Self { diff --git a/src/action/linux/start_systemd_unit.rs b/src/action/linux/start_systemd_unit.rs index 4601993..7f36f57 100644 --- a/src/action/linux/start_systemd_unit.rs +++ b/src/action/linux/start_systemd_unit.rs @@ -24,7 +24,7 @@ impl StartSystemdUnit { } #[async_trait::async_trait] -#[typetag::serde(name = "start-systemd-unit")] +#[typetag::serde(name = "start_systemd_unit")] impl Action for StartSystemdUnit { fn describe_execute(&self) -> Vec { if self.action_state == ActionState::Completed { diff --git a/src/action/linux/systemd_sysext_merge.rs b/src/action/linux/systemd_sysext_merge.rs index 563fbbd..332192f 100644 --- a/src/action/linux/systemd_sysext_merge.rs +++ b/src/action/linux/systemd_sysext_merge.rs @@ -26,7 +26,7 @@ impl SystemdSysextMerge { } #[async_trait::async_trait] -#[typetag::serde(name = "systemd-sysext-merge")] +#[typetag::serde(name = "systemd_sysext_merge")] impl Action for SystemdSysextMerge { fn describe_execute(&self) -> Vec { let Self { diff --git a/src/cli/subcommand/install.rs b/src/cli/subcommand/install.rs index d48f46e..38f1fc8 100644 --- a/src/cli/subcommand/install.rs +++ b/src/cli/subcommand/install.rs @@ -54,7 +54,7 @@ impl CommandExecute for Install { }; if !no_confirm { - if !interaction::confirm(plan.describe_execute(explain)).await? { + if !interaction::confirm(plan.describe_execute(explain).map_err(|e| eyre!(e))?).await? { interaction::clean_exit_with_message("Okay, didn't do anything! Bye!").await; } } diff --git a/src/interaction.rs b/src/interaction.rs index 2943781..0a6690f 100644 --- a/src/interaction.rs +++ b/src/interaction.rs @@ -13,7 +13,7 @@ pub(crate) async fn confirm(question: impl AsRef) -> eyre::Result { {are_you_sure} ({yes}/{no}): \ ", question = question.as_ref(), - are_you_sure = "Are you sure?".bright_white().bold(), + are_you_sure = "Proceed?".bright_white().bold(), no = "N".red().bold(), yes = "y".green(), ); diff --git a/src/plan.rs b/src/plan.rs index 7c6280c..c661787 100644 --- a/src/plan.rs +++ b/src/plan.rs @@ -1,5 +1,7 @@ use std::path::PathBuf; +use crossterm::style::Stylize; + use crate::{ action::{Action, ActionDescription}, planner::Planner, @@ -15,23 +17,37 @@ pub struct InstallPlan { impl InstallPlan { #[tracing::instrument(skip_all)] - pub fn describe_execute(&self, explain: bool) -> String { + pub fn describe_execute( + &self, + explain: bool, + ) -> Result> { let Self { planner, actions } = self; - format!( + let buf = format!( "\ - This Nix install is for:\n\ - Operating System: {os_type}\n\ - Init system: {init_type}\n\ - Nix channels: {nix_channels}\n\ + Nix install plan\n\ \n\ - Created by planner: {planner:?} + Planner: {planner}\n\ \n\ - The following actions will be taken:\n\ - {actions} + Planner settings:\n\ + \n\ + {plan_settings}\n\ + \n\ + The following actions will be taken{maybe_explain}:\n\ + \n\ + {actions}\n\ ", - os_type = "Linux", - init_type = "systemd", - nix_channels = "todo", + maybe_explain = if !explain { + " (`--explain` for more context)" + } else { + "" + }, + planner = planner.typetag_name(), + plan_settings = planner + .describe()? + .into_iter() + .map(|(k, v)| format!("* {k}: {v}", k = k.bold().white())) + .collect::>() + .join("\n"), actions = actions .iter() .map(|v| v.describe_execute()) @@ -43,17 +59,18 @@ impl InstallPlan { } = desc; let mut buf = String::default(); - buf.push_str(&format!("* {description}\n")); + buf.push_str(&format!("* {description}")); if explain { for line in explanation { - buf.push_str(&format!(" {line}\n")); + buf.push_str(&format!("\n {line}")); } } buf }) .collect::>() .join("\n"), - ) + ); + Ok(buf) } #[tracing::instrument(skip_all)] diff --git a/src/planner/darwin/multi.rs b/src/planner/darwin/multi.rs index 0f49ccd..b2bacae 100644 --- a/src/planner/darwin/multi.rs +++ b/src/planner/darwin/multi.rs @@ -1,4 +1,4 @@ -use std::io::Cursor; +use std::{collections::HashMap, io::Cursor}; use clap::ArgAction; use tokio::process::Command; @@ -97,6 +97,28 @@ impl Planner for DarwinMulti { ], }) } + + fn describe( + &self, + ) -> Result, Box> { + let Self { + settings, + volume_encrypt, + volume_label, + root_disk, + } = self; + let mut map = HashMap::default(); + + map.extend(settings.describe()?.into_iter()); + map.insert( + "volume_encrypt".into(), + serde_json::to_value(volume_encrypt)?, + ); + map.insert("volume_label".into(), serde_json::to_value(volume_label)?); + map.insert("root_disk".into(), serde_json::to_value(root_disk)?); + + Ok(map) + } } impl Into for DarwinMulti { diff --git a/src/planner/linux/multi.rs b/src/planner/linux/multi.rs index f7000a2..a1790ac 100644 --- a/src/planner/linux/multi.rs +++ b/src/planner/linux/multi.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use crate::{ action::{ common::{ConfigureNix, CreateDirectory, ProvisionNix}, @@ -33,6 +35,17 @@ impl Planner for LinuxMulti { ], }) } + + fn describe( + &self, + ) -> Result, Box> { + let Self { settings } = self; + let mut map = HashMap::default(); + + map.extend(settings.describe()?.into_iter()); + + Ok(map) + } } impl Into for LinuxMulti { diff --git a/src/planner/mod.rs b/src/planner/mod.rs index 4de4426..4dd3dfa 100644 --- a/src/planner/mod.rs +++ b/src/planner/mod.rs @@ -2,6 +2,8 @@ pub mod darwin; pub mod linux; pub mod specific; +use std::collections::HashMap; + use crate::{settings::InstallSettingsError, BoxableError, InstallPlan}; #[async_trait::async_trait] @@ -11,6 +13,9 @@ pub trait Planner: std::fmt::Debug + Send + Sync + dyn_clone::DynClone { where Self: Sized; async fn plan(self) -> Result>; + fn describe( + &self, + ) -> Result, Box>; } dyn_clone::clone_trait_object!(Planner); diff --git a/src/planner/specific/steam_deck.rs b/src/planner/specific/steam_deck.rs index 1907566..d9b170c 100644 --- a/src/planner/specific/steam_deck.rs +++ b/src/planner/specific/steam_deck.rs @@ -1,3 +1,7 @@ +use std::collections::HashMap; + +use serde_json::json; + use crate::{ action::{ common::{CreateDirectory, ProvisionNix}, @@ -33,6 +37,17 @@ impl Planner for SteamDeck { ], }) } + + fn describe( + &self, + ) -> Result, Box> { + let Self { settings } = self; + let mut map = HashMap::default(); + + map.extend(settings.describe()?.into_iter()); + + Ok(map) + } } impl Into for SteamDeck { diff --git a/src/settings.rs b/src/settings.rs index 5011b9d..63d7ffc 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -1,6 +1,10 @@ +use std::collections::HashMap; + use clap::ArgAction; use url::Url; +use crate::cli::arg::ChannelValue; + pub const NIX_X64_64_LINUX_URL: &str = "https://releases.nixos.org/nix/nix-2.11.0/nix-2.11.0-x86_64-linux.tar.xz"; pub const NIX_AARCH64_LINUX_URL: &str = @@ -145,6 +149,66 @@ impl CommonSettings { force: false, }) } + + pub fn describe( + &self, + ) -> Result, Box> { + let Self { + channels, + modify_profile, + daemon_user_count, + nix_build_group_name, + nix_build_group_id, + nix_build_user_prefix, + nix_build_user_id_base, + nix_package_url, + extra_conf, + force, + } = self; + let mut map = HashMap::default(); + + map.insert( + "channels".into(), + serde_json::to_value( + channels + .iter() + .map(|ChannelValue(k, v)| format!("{k}={v}")) + .collect::>(), + )?, + ); + map.insert( + "modify_profile".into(), + serde_json::to_value(modify_profile)?, + ); + map.insert( + "daemon_user_count".into(), + serde_json::to_value(daemon_user_count)?, + ); + map.insert( + "nix_build_group_name".into(), + serde_json::to_value(nix_build_group_name)?, + ); + map.insert( + "nix_build_group_id".into(), + serde_json::to_value(nix_build_group_id)?, + ); + map.insert( + "nix_build_user_prefix".into(), + serde_json::to_value(nix_build_user_prefix)?, + ); + map.insert( + "nix_build_user_id_base".into(), + serde_json::to_value(nix_build_user_id_base)?, + ); + map.insert( + "nix_package_url".into(), + serde_json::to_value(nix_package_url)?, + ); + map.insert("extra_conf".into(), serde_json::to_value(extra_conf)?); + map.insert("force".into(), serde_json::to_value(force)?); + + Ok(map) + } } // Builder Pattern