Improve planner and plan output

This commit is contained in:
Ana Hobden 2022-10-28 12:44:07 -07:00
parent 615b8b502c
commit eb1d8215f3
35 changed files with 181 additions and 45 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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(),
);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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