forked from lix-project/lix-installer
Improve planner and plan output
This commit is contained in:
parent
615b8b502c
commit
eb1d8215f3
|
@ -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<ActionDescription> {
|
||||
let Self {
|
||||
|
|
|
@ -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<ActionDescription> {
|
||||
if self.action_state == ActionState::Completed {
|
||||
|
|
|
@ -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<ActionDescription> {
|
||||
if self.action_state == ActionState::Completed {
|
||||
|
|
|
@ -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<ActionDescription> {
|
||||
let Self {
|
||||
|
|
|
@ -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<ActionDescription> {
|
||||
let Self {
|
||||
|
|
|
@ -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<ActionDescription> {
|
||||
let Self {
|
||||
|
|
|
@ -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<ActionDescription> {
|
||||
if self.action_state == ActionState::Completed {
|
||||
|
|
|
@ -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<ActionDescription> {
|
||||
let Self {
|
||||
|
|
|
@ -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<ActionDescription> {
|
||||
if self.action_state == ActionState::Completed {
|
||||
|
|
|
@ -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<ActionDescription> {
|
||||
let Self {
|
||||
|
|
|
@ -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<ActionDescription> {
|
||||
let Self {
|
||||
|
|
|
@ -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<ActionDescription> {
|
||||
if self.action_state == ActionState::Completed {
|
||||
|
|
|
@ -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<ActionDescription> {
|
||||
let Self {
|
||||
|
|
|
@ -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<ActionDescription> {
|
||||
if self.action_state == ActionState::Completed {
|
||||
|
|
|
@ -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<ActionDescription> {
|
||||
let Self {
|
||||
|
|
|
@ -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<ActionDescription> {
|
||||
if self.action_state == ActionState::Completed {
|
||||
|
|
|
@ -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<ActionDescription> {
|
||||
if self.action_state == ActionState::Completed {
|
||||
|
|
|
@ -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<ActionDescription> {
|
||||
let Self {
|
||||
|
|
|
@ -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<ActionDescription> {
|
||||
if self.action_state == ActionState::Completed {
|
||||
|
|
|
@ -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<ActionDescription> {
|
||||
if self.action_state == ActionState::Completed {
|
||||
|
|
|
@ -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<ActionDescription> {
|
||||
if self.action_state == ActionState::Completed {
|
||||
|
|
|
@ -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<ActionDescription> {
|
||||
if self.action_state == ActionState::Completed {
|
||||
|
|
|
@ -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<ActionDescription> {
|
||||
let Self { unit, action_state } = self;
|
||||
|
|
|
@ -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<ActionDescription> {
|
||||
if self.action_state == ActionState::Completed {
|
||||
|
|
|
@ -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<ActionDescription> {
|
||||
let Self {
|
||||
|
|
|
@ -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<ActionDescription> {
|
||||
if self.action_state == ActionState::Completed {
|
||||
|
|
|
@ -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<ActionDescription> {
|
||||
let Self {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ pub(crate) async fn confirm(question: impl AsRef<str>) -> eyre::Result<bool> {
|
|||
{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(),
|
||||
);
|
||||
|
|
47
src/plan.rs
47
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<String, Box<dyn std::error::Error + Sync + Send>> {
|
||||
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::<Vec<_>>()
|
||||
.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::<Vec<_>>()
|
||||
.join("\n"),
|
||||
)
|
||||
);
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
|
|
|
@ -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<HashMap<String, serde_json::Value>, Box<dyn std::error::Error + Sync + Send>> {
|
||||
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<BuiltinPlanner> for DarwinMulti {
|
||||
|
|
|
@ -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<HashMap<String, serde_json::Value>, Box<dyn std::error::Error + Sync + Send>> {
|
||||
let Self { settings } = self;
|
||||
let mut map = HashMap::default();
|
||||
|
||||
map.extend(settings.describe()?.into_iter());
|
||||
|
||||
Ok(map)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<BuiltinPlanner> for LinuxMulti {
|
||||
|
|
|
@ -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<InstallPlan, Box<dyn std::error::Error + Sync + Send>>;
|
||||
fn describe(
|
||||
&self,
|
||||
) -> Result<HashMap<String, serde_json::Value>, Box<dyn std::error::Error + Sync + Send>>;
|
||||
}
|
||||
|
||||
dyn_clone::clone_trait_object!(Planner);
|
||||
|
|
|
@ -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<HashMap<String, serde_json::Value>, Box<dyn std::error::Error + Sync + Send>> {
|
||||
let Self { settings } = self;
|
||||
let mut map = HashMap::default();
|
||||
|
||||
map.extend(settings.describe()?.into_iter());
|
||||
|
||||
Ok(map)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<BuiltinPlanner> for SteamDeck {
|
||||
|
|
|
@ -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<HashMap<String, serde_json::Value>, Box<dyn std::error::Error + Sync + Send>> {
|
||||
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::<Vec<_>>(),
|
||||
)?,
|
||||
);
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue