forked from lix-project/lix-installer
Logging and error tidying
This commit is contained in:
parent
47018ad00c
commit
b34a352753
|
@ -33,16 +33,21 @@ impl ConfigureNixDaemonService {
|
|||
#[async_trait::async_trait]
|
||||
impl Actionable for ConfigureNixDaemonService {
|
||||
type Error = ConfigureNixDaemonServiceError;
|
||||
fn description(&self) -> Vec<ActionDescription> {
|
||||
vec![ActionDescription::new(
|
||||
"Configure Nix daemon related settings with systemd".to_string(),
|
||||
vec![
|
||||
"Run `systemd-tempfiles --create --prefix=/nix/var/nix`".to_string(),
|
||||
"Run `systemctl link {SERVICE_SRC}`".to_string(),
|
||||
"Run `systemctl link {SOCKET_SRC}`".to_string(),
|
||||
"Run `systemctl daemon-reload`".to_string(),
|
||||
],
|
||||
)]
|
||||
|
||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||
if self.action_state == ActionState::Completed {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ActionDescription::new(
|
||||
"Configure Nix daemon related settings with systemd".to_string(),
|
||||
vec![
|
||||
"Run `systemd-tempfiles --create --prefix=/nix/var/nix`".to_string(),
|
||||
"Run `systemctl link {SERVICE_SRC}`".to_string(),
|
||||
"Run `systemctl link {SOCKET_SRC}`".to_string(),
|
||||
"Run `systemctl daemon-reload`".to_string(),
|
||||
],
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
|
@ -86,6 +91,22 @@ impl Actionable for ConfigureNixDaemonService {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn describe_revert(&self) -> Vec<ActionDescription> {
|
||||
if self.action_state == ActionState::Uncompleted {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ActionDescription::new(
|
||||
"Unconfigure Nix daemon related settings with systemd".to_string(),
|
||||
vec![
|
||||
"Run `systemctl disable {SOCKET_SRC}`".to_string(),
|
||||
"Run `systemctl disable {SERVICE_SRC}`".to_string(),
|
||||
"Run `systemd-tempfiles --remove --prefix=/nix/var/nix`".to_string(),
|
||||
"Run `systemctl daemon-reload`".to_string(),
|
||||
],
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
||||
let Self { action_state } = self;
|
||||
|
|
|
@ -50,7 +50,8 @@ impl CreateDirectory {
|
|||
#[async_trait::async_trait]
|
||||
impl Actionable for CreateDirectory {
|
||||
type Error = CreateDirectoryError;
|
||||
fn description(&self) -> Vec<ActionDescription> {
|
||||
|
||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||
let Self {
|
||||
path,
|
||||
user,
|
||||
|
@ -58,13 +59,17 @@ impl Actionable for CreateDirectory {
|
|||
mode,
|
||||
action_state: _,
|
||||
} = &self;
|
||||
vec![ActionDescription::new(
|
||||
format!("Create the directory `{}`", path.display()),
|
||||
vec![format!(
|
||||
"Creating directory `{}` owned by `{user}:{group}` with mode `{mode:#o}`",
|
||||
path.display()
|
||||
)],
|
||||
)]
|
||||
if self.action_state == ActionState::Completed {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ActionDescription::new(
|
||||
format!("Create the directory `{}`", path.display()),
|
||||
vec![format!(
|
||||
"Creating directory `{}` owned by `{user}:{group}` with mode `{mode:#o}`",
|
||||
path.display()
|
||||
)],
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(
|
||||
|
@ -110,6 +115,25 @@ impl Actionable for CreateDirectory {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
fn describe_revert(&self) -> Vec<ActionDescription> {
|
||||
let Self {
|
||||
path,
|
||||
user: _,
|
||||
group: _,
|
||||
mode: _,
|
||||
action_state: _,
|
||||
} = &self;
|
||||
if self.action_state == ActionState::Uncompleted {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ActionDescription::new(
|
||||
format!("Remove the directory `{}`", path.display()),
|
||||
vec![],
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(
|
||||
path = %self.path.display(),
|
||||
user = self.user,
|
||||
|
|
|
@ -52,7 +52,8 @@ impl CreateFile {
|
|||
#[async_trait::async_trait]
|
||||
impl Actionable for CreateFile {
|
||||
type Error = CreateFileError;
|
||||
fn description(&self) -> Vec<ActionDescription> {
|
||||
|
||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||
let Self {
|
||||
path,
|
||||
user,
|
||||
|
@ -62,12 +63,16 @@ impl Actionable for CreateFile {
|
|||
force: _,
|
||||
action_state: _,
|
||||
} = &self;
|
||||
vec![ActionDescription::new(
|
||||
format!("Create or overwrite file `{}`", path.display()),
|
||||
vec![format!(
|
||||
"Create or overwrite `{}` owned by `{user}:{group}` with mode `{mode:#o}` with `{buf}`", path.display()
|
||||
)],
|
||||
)]
|
||||
if self.action_state == ActionState::Completed {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ActionDescription::new(
|
||||
format!("Create or overwrite file `{}`", path.display()),
|
||||
vec![format!(
|
||||
"Create or overwrite `{}` owned by `{user}:{group}` with mode `{mode:#o}` with `{buf}`", path.display()
|
||||
)],
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(
|
||||
|
@ -121,6 +126,29 @@ impl Actionable for CreateFile {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
fn describe_revert(&self) -> Vec<ActionDescription> {
|
||||
let Self {
|
||||
path,
|
||||
user: _,
|
||||
group: _,
|
||||
mode: _,
|
||||
buf: _,
|
||||
force: _,
|
||||
action_state: _,
|
||||
} = &self;
|
||||
if self.action_state == ActionState::Uncompleted {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ActionDescription::new(
|
||||
format!("Delete file `{}`", path.display()),
|
||||
vec![format!(
|
||||
"Delete file `{}`", path.display()
|
||||
)],
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(
|
||||
path = %self.path.display(),
|
||||
user = self.user,
|
||||
|
|
|
@ -26,18 +26,23 @@ impl CreateGroup {
|
|||
#[async_trait::async_trait]
|
||||
impl Actionable for CreateGroup {
|
||||
type Error = CreateGroupError;
|
||||
fn description(&self) -> Vec<ActionDescription> {
|
||||
|
||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||
let Self {
|
||||
name,
|
||||
gid,
|
||||
action_state: _,
|
||||
} = &self;
|
||||
vec![ActionDescription::new(
|
||||
format!("Create group {name} with GID {gid}"),
|
||||
vec![format!(
|
||||
"The nix daemon requires a system user group its system users can be part of"
|
||||
)],
|
||||
)]
|
||||
if self.action_state == ActionState::Completed {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ActionDescription::new(
|
||||
format!("Create group {name} with GID {gid}"),
|
||||
vec![format!(
|
||||
"The nix daemon requires a system user group its system users can be part of"
|
||||
)],
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(
|
||||
|
@ -65,6 +70,25 @@ impl Actionable for CreateGroup {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
fn describe_revert(&self) -> Vec<ActionDescription> {
|
||||
let Self {
|
||||
name,
|
||||
gid: _,
|
||||
action_state: _,
|
||||
} = &self;
|
||||
if self.action_state == ActionState::Completed {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ActionDescription::new(
|
||||
format!("Delete group {name}"),
|
||||
vec![format!(
|
||||
"The nix daemon requires a system user group its system users can be part of"
|
||||
)],
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(
|
||||
user = self.name,
|
||||
gid = self.gid,
|
||||
|
|
|
@ -49,7 +49,8 @@ impl CreateOrAppendFile {
|
|||
#[async_trait::async_trait]
|
||||
impl Actionable for CreateOrAppendFile {
|
||||
type Error = CreateOrAppendFileError;
|
||||
fn description(&self) -> Vec<ActionDescription> {
|
||||
|
||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||
let Self {
|
||||
path,
|
||||
user,
|
||||
|
@ -58,12 +59,16 @@ impl Actionable for CreateOrAppendFile {
|
|||
buf,
|
||||
action_state: _,
|
||||
} = &self;
|
||||
vec![ActionDescription::new(
|
||||
format!("Create or append file `{}`", path.display()),
|
||||
vec![format!(
|
||||
"Create or append `{}` owned by `{user}:{group}` with mode `{mode:#o}` with `{buf}`", path.display()
|
||||
)],
|
||||
)]
|
||||
if self.action_state == ActionState::Completed {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ActionDescription::new(
|
||||
format!("Create or append file `{}`", path.display()),
|
||||
vec![format!(
|
||||
"Create or append `{}` owned by `{user}:{group}` with mode `{mode:#o}` with `{buf}`", path.display()
|
||||
)],
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(
|
||||
|
@ -123,6 +128,27 @@ impl Actionable for CreateOrAppendFile {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn describe_revert(&self) -> Vec<ActionDescription> {
|
||||
let Self {
|
||||
path,
|
||||
user: _,
|
||||
group: _,
|
||||
mode: _,
|
||||
buf,
|
||||
action_state: _,
|
||||
} = &self;
|
||||
if self.action_state == ActionState::Uncompleted {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ActionDescription::new(
|
||||
format!("Delete Nix related fragment from file `{}`", path.display()),
|
||||
vec![format!(
|
||||
"Delete Nix related fragment from file `{}`. Fragment: `{buf}`", path.display()
|
||||
)],
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(
|
||||
path = %self.path.display(),
|
||||
user = self.user,
|
||||
|
|
|
@ -28,15 +28,20 @@ impl CreateUser {
|
|||
#[async_trait::async_trait]
|
||||
impl Actionable for CreateUser {
|
||||
type Error = CreateUserError;
|
||||
fn description(&self) -> Vec<ActionDescription> {
|
||||
let name = &self.name;
|
||||
let uid = &self.uid;
|
||||
vec![ActionDescription::new(
|
||||
format!("Create user {name} with UID {uid}"),
|
||||
vec![format!(
|
||||
"The nix daemon requires system users it can act as in order to build"
|
||||
)],
|
||||
)]
|
||||
|
||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||
if self.action_state == ActionState::Completed {
|
||||
vec![]
|
||||
} else {
|
||||
let Self { name, uid, gid, action_state: _ } = self;
|
||||
|
||||
vec![ActionDescription::new(
|
||||
format!("Create user {name} with UID {uid} with group {gid}"),
|
||||
vec![format!(
|
||||
"The nix daemon requires system users it can act as in order to build"
|
||||
)],
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(
|
||||
|
@ -84,6 +89,22 @@ impl Actionable for CreateUser {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
fn describe_revert(&self) -> Vec<ActionDescription> {
|
||||
if self.action_state == ActionState::Uncompleted {
|
||||
vec![]
|
||||
} else {
|
||||
let Self { name, uid, gid, action_state: _ } = self;
|
||||
|
||||
vec![ActionDescription::new(
|
||||
format!("Delete user {name} with UID {uid} with group {gid}"),
|
||||
vec![format!(
|
||||
"The nix daemon requires system users it can act as in order to build"
|
||||
)],
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(
|
||||
user = self.name,
|
||||
uid = self.uid,
|
||||
|
|
|
@ -31,19 +31,24 @@ impl FetchNix {
|
|||
#[async_trait::async_trait]
|
||||
impl Actionable for FetchNix {
|
||||
type Error = FetchNixError;
|
||||
fn description(&self) -> Vec<ActionDescription> {
|
||||
|
||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||
let Self {
|
||||
url,
|
||||
dest,
|
||||
action_state: _,
|
||||
} = &self;
|
||||
vec![ActionDescription::new(
|
||||
format!("Fetch Nix from `{url}`"),
|
||||
vec![format!(
|
||||
"Unpack it to `{}` (moved later)",
|
||||
dest.display()
|
||||
)],
|
||||
)]
|
||||
if self.action_state == ActionState::Completed {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ActionDescription::new(
|
||||
format!("Fetch Nix from `{url}`"),
|
||||
vec![format!(
|
||||
"Unpack it to `{}` (moved later)",
|
||||
dest.display()
|
||||
)],
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(
|
||||
|
@ -85,6 +90,14 @@ impl Actionable for FetchNix {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn describe_revert(&self) -> Vec<ActionDescription> {
|
||||
if self.action_state == ActionState::Uncompleted {
|
||||
vec![]
|
||||
} else {
|
||||
vec![/* Deliberately empty -- this is a noop */]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(
|
||||
url = %self.url,
|
||||
dest = %self.dest.display(),
|
||||
|
@ -114,8 +127,9 @@ impl From<FetchNix> for Action {
|
|||
|
||||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum FetchNixError {
|
||||
#[error(transparent)]
|
||||
#[error("Joining spawned async task")]
|
||||
Join(
|
||||
#[source]
|
||||
#[from]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
JoinError,
|
||||
|
|
|
@ -26,18 +26,19 @@ impl MoveUnpackedNix {
|
|||
#[async_trait::async_trait]
|
||||
impl Actionable for MoveUnpackedNix {
|
||||
type Error = MoveUnpackedNixError;
|
||||
fn description(&self) -> Vec<ActionDescription> {
|
||||
let Self {
|
||||
src,
|
||||
action_state: _,
|
||||
} = &self;
|
||||
vec![ActionDescription::new(
|
||||
format!("Move the downloaded Nix into `/nix`"),
|
||||
vec![format!(
|
||||
"Nix is being downloaded to `{}` and should be in `nix`",
|
||||
src.display(),
|
||||
)],
|
||||
)]
|
||||
|
||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||
if self.action_state == ActionState::Completed {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ActionDescription::new(
|
||||
format!("Move the downloaded Nix into `/nix`"),
|
||||
vec![format!(
|
||||
"Nix is being downloaded to `{}` and should be in `nix`",
|
||||
self.src.display(),
|
||||
)],
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(
|
||||
|
@ -76,6 +77,15 @@ impl Actionable for MoveUnpackedNix {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn describe_revert(&self) -> Vec<ActionDescription> {
|
||||
if self.action_state == ActionState::Uncompleted {
|
||||
vec![]
|
||||
} else {
|
||||
vec![/* Deliberately empty -- this is a noop */]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[tracing::instrument(skip_all, fields(
|
||||
src = %self.src.display(),
|
||||
dest = DEST,
|
||||
|
|
|
@ -28,11 +28,19 @@ impl SetupDefaultProfile {
|
|||
#[async_trait::async_trait]
|
||||
impl Actionable for SetupDefaultProfile {
|
||||
type Error = SetupDefaultProfileError;
|
||||
fn description(&self) -> Vec<ActionDescription> {
|
||||
vec![ActionDescription::new(
|
||||
"Setup the default Nix profile".to_string(),
|
||||
vec!["TODO".to_string()],
|
||||
)]
|
||||
|
||||
|
||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||
if self.action_state == ActionState::Completed {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ActionDescription::new(
|
||||
"Setup the default Nix profile".to_string(),
|
||||
vec![
|
||||
"TODO".to_string()
|
||||
]
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(
|
||||
|
@ -131,6 +139,19 @@ impl Actionable for SetupDefaultProfile {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn describe_revert(&self) -> Vec<ActionDescription> {
|
||||
if self.action_state == ActionState::Uncompleted {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ActionDescription::new(
|
||||
"Unset the default Nix profile".to_string(),
|
||||
vec![
|
||||
"TODO".to_string()
|
||||
]
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(
|
||||
channels = %self.channels.join(","),
|
||||
))]
|
||||
|
|
|
@ -24,24 +24,17 @@ impl StartSystemdUnit {
|
|||
#[async_trait::async_trait]
|
||||
impl Actionable for StartSystemdUnit {
|
||||
type Error = StartSystemdUnitError;
|
||||
fn description(&self) -> Vec<ActionDescription> {
|
||||
match self.action_state {
|
||||
ActionState::Uncompleted => vec![
|
||||
ActionDescription::new(
|
||||
"Start the systemd Nix service and socket".to_string(),
|
||||
vec![
|
||||
"The `nix` command line tool communicates with a running Nix daemon managed by your init system".to_string()
|
||||
]
|
||||
),
|
||||
],
|
||||
ActionState::Completed => vec![
|
||||
ActionDescription::new(
|
||||
"Stop the systemd Nix service and socket".to_string(),
|
||||
vec![
|
||||
"The `nix` command line tool communicates with a running Nix daemon managed by your init system".to_string()
|
||||
]
|
||||
),
|
||||
],
|
||||
|
||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||
if self.action_state == ActionState::Completed {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ActionDescription::new(
|
||||
"Start the systemd Nix service and socket".to_string(),
|
||||
vec![
|
||||
"The `nix` command line tool communicates with a running Nix daemon managed by your init system".to_string()
|
||||
]
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,6 +64,19 @@ impl Actionable for StartSystemdUnit {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn describe_revert(&self) -> Vec<ActionDescription> {
|
||||
if self.action_state == ActionState::Uncompleted {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ActionDescription::new(
|
||||
"Stop the systemd Nix service and socket".to_string(),
|
||||
vec![
|
||||
"The `nix` command line tool communicates with a running Nix daemon managed by your init system".to_string()
|
||||
]
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(
|
||||
unit = %self.unit,
|
||||
))]
|
||||
|
|
|
@ -66,7 +66,7 @@ impl ConfigureNix {
|
|||
#[async_trait::async_trait]
|
||||
impl Actionable for ConfigureNix {
|
||||
type Error = ConfigureNixError;
|
||||
fn description(&self) -> Vec<ActionDescription> {
|
||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||
let Self {
|
||||
setup_default_profile,
|
||||
configure_nix_daemon_service,
|
||||
|
@ -76,15 +76,18 @@ impl Actionable for ConfigureNix {
|
|||
action_state: _,
|
||||
} = &self;
|
||||
|
||||
let mut buf = setup_default_profile.description();
|
||||
buf.append(&mut configure_nix_daemon_service.description());
|
||||
buf.append(&mut place_nix_configuration.description());
|
||||
buf.append(&mut place_channel_configuration.description());
|
||||
if let Some(configure_shell_profile) = configure_shell_profile {
|
||||
buf.append(&mut configure_shell_profile.description());
|
||||
if self.action_state == ActionState::Completed {
|
||||
vec![]
|
||||
} else {
|
||||
let mut buf = setup_default_profile.describe_execute();
|
||||
buf.append(&mut configure_nix_daemon_service.describe_execute());
|
||||
buf.append(&mut place_nix_configuration.describe_execute());
|
||||
buf.append(&mut place_channel_configuration.describe_execute());
|
||||
if let Some(configure_shell_profile) = configure_shell_profile {
|
||||
buf.append(&mut configure_shell_profile.describe_execute());
|
||||
}
|
||||
buf
|
||||
}
|
||||
|
||||
buf
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
|
@ -159,6 +162,33 @@ impl Actionable for ConfigureNix {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn describe_revert(&self) -> Vec<ActionDescription> {
|
||||
let Self {
|
||||
setup_default_profile,
|
||||
configure_nix_daemon_service,
|
||||
place_nix_configuration,
|
||||
place_channel_configuration,
|
||||
configure_shell_profile,
|
||||
action_state: _,
|
||||
} = &self;
|
||||
|
||||
if self.action_state == ActionState::Uncompleted {
|
||||
vec![]
|
||||
} else {
|
||||
let mut buf = Vec::default();
|
||||
if let Some(configure_shell_profile) = configure_shell_profile {
|
||||
buf.append(&mut configure_shell_profile.describe_revert());
|
||||
}
|
||||
buf.append(&mut place_channel_configuration.describe_revert());
|
||||
buf.append(&mut place_nix_configuration.describe_revert());
|
||||
buf.append(&mut configure_nix_daemon_service.describe_revert());
|
||||
buf.append(&mut setup_default_profile.describe_revert());
|
||||
|
||||
buf
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
||||
let Self {
|
||||
|
@ -197,14 +227,14 @@ impl From<ConfigureNix> for Action {
|
|||
|
||||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum ConfigureNixError {
|
||||
#[error(transparent)]
|
||||
SetupDefaultProfile(#[from] SetupDefaultProfileError),
|
||||
#[error(transparent)]
|
||||
PlaceNixConfiguration(#[from] PlaceNixConfigurationError),
|
||||
#[error(transparent)]
|
||||
PlaceChannelConfiguration(#[from] PlaceChannelConfigurationError),
|
||||
#[error(transparent)]
|
||||
ConfigureNixDaemonService(#[from] ConfigureNixDaemonServiceError),
|
||||
#[error(transparent)]
|
||||
ConfigureShellProfile(#[from] ConfigureShellProfileError),
|
||||
#[error("Setting up default profile")]
|
||||
SetupDefaultProfile(#[source] #[from] SetupDefaultProfileError),
|
||||
#[error("Placing Nix configuration")]
|
||||
PlaceNixConfiguration(#[source] #[from] PlaceNixConfigurationError),
|
||||
#[error("Placing channel configuration")]
|
||||
PlaceChannelConfiguration(#[source] #[from] PlaceChannelConfigurationError),
|
||||
#[error("Configuring Nix daemon")]
|
||||
ConfigureNixDaemonService(#[source] #[from] ConfigureNixDaemonServiceError),
|
||||
#[error("Configuring shell profile")]
|
||||
ConfigureShellProfile(#[source] #[from] ConfigureShellProfileError),
|
||||
}
|
||||
|
|
|
@ -57,11 +57,16 @@ impl ConfigureShellProfile {
|
|||
#[async_trait::async_trait]
|
||||
impl Actionable for ConfigureShellProfile {
|
||||
type Error = ConfigureShellProfileError;
|
||||
fn description(&self) -> Vec<ActionDescription> {
|
||||
vec![ActionDescription::new(
|
||||
"Configure the shell profiles".to_string(),
|
||||
vec!["Update shell profiles to import Nix".to_string()],
|
||||
)]
|
||||
|
||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||
if self.action_state == ActionState::Completed {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ActionDescription::new(
|
||||
"Configure the shell profiles".to_string(),
|
||||
vec!["Update shell profiles to import Nix".to_string()],
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
|
@ -112,6 +117,18 @@ impl Actionable for ConfigureShellProfile {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn describe_revert(&self) -> Vec<ActionDescription> {
|
||||
if self.action_state == ActionState::Uncompleted {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ActionDescription::new(
|
||||
"Unconfigure the shell profiles".to_string(),
|
||||
vec!["Update shell profiles to no longer import Nix".to_string()],
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
||||
let Self {
|
||||
|
@ -169,12 +186,17 @@ impl From<ConfigureShellProfile> for Action {
|
|||
|
||||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum ConfigureShellProfileError {
|
||||
#[error(transparent)]
|
||||
CreateOrAppendFile(#[from] CreateOrAppendFileError),
|
||||
#[error("Creating or appending to file")]
|
||||
CreateOrAppendFile(
|
||||
#[from]
|
||||
#[source]
|
||||
CreateOrAppendFileError
|
||||
),
|
||||
#[error("Multiple errors: {}", .0.iter().map(|v| format!("{v}")).collect::<Vec<_>>().join(" & "))]
|
||||
MultipleCreateOrAppendFile(Vec<CreateOrAppendFileError>),
|
||||
#[error(transparent)]
|
||||
#[error("Joining spawned async task")]
|
||||
Join(
|
||||
#[source]
|
||||
#[from]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
JoinError,
|
||||
|
|
|
@ -47,23 +47,28 @@ impl CreateNixTree {
|
|||
#[async_trait::async_trait]
|
||||
impl Actionable for CreateNixTree {
|
||||
type Error = CreateNixTreeError;
|
||||
fn description(&self) -> Vec<ActionDescription> {
|
||||
vec![ActionDescription::new(
|
||||
format!("Create a directory tree in `/nix`"),
|
||||
vec![
|
||||
format!(
|
||||
"Nix and the Nix daemon require a Nix Store, which will be stored at `/nix`"
|
||||
),
|
||||
format!(
|
||||
"Creates: {}",
|
||||
PATHS
|
||||
.iter()
|
||||
.map(|v| format!("`{v}`"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
),
|
||||
],
|
||||
)]
|
||||
|
||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||
if self.action_state == ActionState::Completed {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ActionDescription::new(
|
||||
format!("Create a directory tree in `/nix`"),
|
||||
vec![
|
||||
format!(
|
||||
"Nix and the Nix daemon require a Nix Store, which will be stored at `/nix`"
|
||||
),
|
||||
format!(
|
||||
"Creates: {}",
|
||||
PATHS
|
||||
.iter()
|
||||
.map(|v| format!("`{v}`"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
),
|
||||
],
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
|
@ -88,6 +93,30 @@ impl Actionable for CreateNixTree {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn describe_revert(&self) -> Vec<ActionDescription> {
|
||||
if self.action_state == ActionState::Uncompleted {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ActionDescription::new(
|
||||
format!("Remove the directory tree in `/nix`"),
|
||||
vec![
|
||||
format!(
|
||||
"Nix and the Nix daemon require a Nix Store, which will be stored at `/nix`"
|
||||
),
|
||||
format!(
|
||||
"Removes: {}",
|
||||
PATHS
|
||||
.iter()
|
||||
.rev()
|
||||
.map(|v| format!("`{v}`"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
),
|
||||
],
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
||||
let Self {
|
||||
|
@ -119,6 +148,6 @@ impl From<CreateNixTree> for Action {
|
|||
|
||||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum CreateNixTreeError {
|
||||
#[error(transparent)]
|
||||
CreateDirectory(#[from] CreateDirectoryError),
|
||||
#[error("Creating directory")]
|
||||
CreateDirectory(#[source] #[from] CreateDirectoryError),
|
||||
}
|
||||
|
|
|
@ -52,7 +52,8 @@ impl CreateUsersAndGroup {
|
|||
#[async_trait::async_trait]
|
||||
impl Actionable for CreateUsersAndGroup {
|
||||
type Error = CreateUsersAndGroupError;
|
||||
fn description(&self) -> Vec<ActionDescription> {
|
||||
|
||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||
let Self {
|
||||
daemon_user_count,
|
||||
nix_build_group_name,
|
||||
|
@ -63,17 +64,20 @@ impl Actionable for CreateUsersAndGroup {
|
|||
create_users: _,
|
||||
action_state: _,
|
||||
} = &self;
|
||||
|
||||
vec![
|
||||
ActionDescription::new(
|
||||
format!("Create build users and group"),
|
||||
vec![
|
||||
format!("The nix daemon requires system users (and a group they share) which it can act as in order to build"),
|
||||
format!("Create group `{nix_build_group_name}` with uid `{nix_build_group_id}`"),
|
||||
format!("Create {daemon_user_count} users with prefix `{nix_build_user_prefix}` starting at uid `{nix_build_user_id_base}`"),
|
||||
],
|
||||
)
|
||||
]
|
||||
if self.action_state == ActionState::Completed {
|
||||
vec![]
|
||||
} else {
|
||||
vec![
|
||||
ActionDescription::new(
|
||||
format!("Create build users and group"),
|
||||
vec![
|
||||
format!("The nix daemon requires system users (and a group they share) which it can act as in order to build"),
|
||||
format!("Create group `{nix_build_group_name}` with uid `{nix_build_group_id}`"),
|
||||
format!("Create {daemon_user_count} users with prefix `{nix_build_user_prefix}` starting at uid `{nix_build_user_id_base}`"),
|
||||
],
|
||||
)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(
|
||||
|
@ -138,6 +142,32 @@ impl Actionable for CreateUsersAndGroup {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn describe_revert(&self) -> Vec<ActionDescription> {
|
||||
let Self {
|
||||
daemon_user_count,
|
||||
nix_build_group_name,
|
||||
nix_build_group_id,
|
||||
nix_build_user_prefix,
|
||||
nix_build_user_id_base,
|
||||
create_group: _,
|
||||
create_users: _,
|
||||
action_state: _,
|
||||
} = &self;
|
||||
if self.action_state == ActionState::Uncompleted {
|
||||
vec![]
|
||||
} else {
|
||||
vec![
|
||||
ActionDescription::new(
|
||||
format!("Remove build users and group"),
|
||||
vec![
|
||||
format!("The nix daemon requires system users (and a group they share) which it can act as in order to build"),
|
||||
format!("Create group `{nix_build_group_name}` with uid `{nix_build_group_id}`"),
|
||||
format!("Create {daemon_user_count} users with prefix `{nix_build_user_prefix}` starting at uid `{nix_build_user_id_base}`"),
|
||||
],
|
||||
)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(
|
||||
daemon_user_count = self.daemon_user_count,
|
||||
|
@ -208,14 +238,15 @@ impl From<CreateUsersAndGroup> for Action {
|
|||
|
||||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum CreateUsersAndGroupError {
|
||||
#[error(transparent)]
|
||||
CreateUser(#[from] CreateUserError),
|
||||
#[error("Creating user")]
|
||||
CreateUser(#[source] #[from] CreateUserError),
|
||||
#[error("Multiple errors: {}", .0.iter().map(|v| format!("{v}")).collect::<Vec<_>>().join(" & "))]
|
||||
CreateUsers(Vec<CreateUserError>),
|
||||
#[error(transparent)]
|
||||
CreateGroup(#[from] CreateGroupError),
|
||||
#[error(transparent)]
|
||||
#[error("Creating group")]
|
||||
CreateGroup(#[source] #[from] CreateGroupError),
|
||||
#[error("Joining spawned async task")]
|
||||
Join(
|
||||
#[source]
|
||||
#[from]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
JoinError,
|
||||
|
|
|
@ -45,16 +45,21 @@ impl PlaceChannelConfiguration {
|
|||
#[async_trait::async_trait]
|
||||
impl Actionable for PlaceChannelConfiguration {
|
||||
type Error = PlaceChannelConfigurationError;
|
||||
fn description(&self) -> Vec<ActionDescription> {
|
||||
|
||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||
let Self {
|
||||
channels: _,
|
||||
create_file: _,
|
||||
action_state: _,
|
||||
} = self;
|
||||
vec![ActionDescription::new(
|
||||
"Place a channel configuration".to_string(),
|
||||
vec!["Place a configuration at `{NIX_CHANNELS_PATH}` setting the channels".to_string()],
|
||||
)]
|
||||
if self.action_state == ActionState::Completed {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ActionDescription::new(
|
||||
"Place channel configuration at `{NIX_CHANNELS_PATH}`".to_string(),
|
||||
vec!["Place channel configuration at `{NIX_CHANNELS_PATH}`".to_string()],
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(
|
||||
|
@ -79,6 +84,22 @@ impl Actionable for PlaceChannelConfiguration {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn describe_revert(&self) -> Vec<ActionDescription> {
|
||||
let Self {
|
||||
channels: _,
|
||||
create_file: _,
|
||||
action_state: _,
|
||||
} = self;
|
||||
if self.action_state == ActionState::Uncompleted {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ActionDescription::new(
|
||||
"Remove channel configuration at `{NIX_CHANNELS_PATH}`".to_string(),
|
||||
vec!["Remove channel configuration at `{NIX_CHANNELS_PATH}`".to_string()],
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(
|
||||
channels = self.channels.iter().map(|(c, u)| format!("{c}={u}")).collect::<Vec<_>>().join(", "),
|
||||
))]
|
||||
|
@ -110,6 +131,6 @@ impl From<PlaceChannelConfiguration> for Action {
|
|||
|
||||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum PlaceChannelConfigurationError {
|
||||
#[error(transparent)]
|
||||
CreateFile(#[from] CreateFileError),
|
||||
#[error("Creating file")]
|
||||
CreateFile(#[source] #[from] CreateFileError),
|
||||
}
|
||||
|
|
|
@ -49,14 +49,18 @@ impl PlaceNixConfiguration {
|
|||
impl Actionable for PlaceNixConfiguration {
|
||||
type Error = PlaceNixConfigurationError;
|
||||
|
||||
fn description(&self) -> Vec<ActionDescription> {
|
||||
vec![ActionDescription::new(
|
||||
format!("Place the nix configuration in `{NIX_CONF}`"),
|
||||
vec![
|
||||
"This file is read by the Nix daemon to set its configuration options at runtime."
|
||||
.to_string(),
|
||||
],
|
||||
)]
|
||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||
if self.action_state == ActionState::Completed {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ActionDescription::new(
|
||||
format!("Place the nix configuration in `{NIX_CONF}`"),
|
||||
vec![
|
||||
"This file is read by the Nix daemon to set its configuration options at runtime."
|
||||
.to_string(),
|
||||
],
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
|
@ -80,6 +84,20 @@ impl Actionable for PlaceNixConfiguration {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn describe_revert(&self) -> Vec<ActionDescription> {
|
||||
if self.action_state == ActionState::Uncompleted {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ActionDescription::new(
|
||||
format!("Remove the nix configuration in `{NIX_CONF}`"),
|
||||
vec![
|
||||
"This file is read by the Nix daemon to set its configuration options at runtime."
|
||||
.to_string(),
|
||||
],
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
||||
let Self {
|
||||
|
@ -110,8 +128,8 @@ impl From<PlaceNixConfiguration> for Action {
|
|||
|
||||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum PlaceNixConfigurationError {
|
||||
#[error(transparent)]
|
||||
CreateFile(#[from] CreateFileError),
|
||||
#[error(transparent)]
|
||||
CreateDirectory(#[from] CreateDirectoryError),
|
||||
#[error("Creating file")]
|
||||
CreateFile(#[source] #[from] CreateFileError),
|
||||
#[error("Creating directory")]
|
||||
CreateDirectory(#[source] #[from] CreateDirectoryError),
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ impl ProvisionNix {
|
|||
#[async_trait::async_trait]
|
||||
impl Actionable for ProvisionNix {
|
||||
type Error = ProvisionNixError;
|
||||
fn description(&self) -> Vec<ActionDescription> {
|
||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||
let Self {
|
||||
fetch_nix,
|
||||
create_users_and_group,
|
||||
|
@ -52,13 +52,16 @@ impl Actionable for ProvisionNix {
|
|||
move_unpacked_nix,
|
||||
action_state: _,
|
||||
} = &self;
|
||||
|
||||
let mut buf = fetch_nix.description();
|
||||
buf.append(&mut create_users_and_group.description());
|
||||
buf.append(&mut create_nix_tree.description());
|
||||
buf.append(&mut move_unpacked_nix.description());
|
||||
|
||||
buf
|
||||
if self.action_state == ActionState::Completed {
|
||||
vec![]
|
||||
} else {
|
||||
let mut buf = fetch_nix.describe_execute();
|
||||
buf.append(&mut create_users_and_group.describe_execute());
|
||||
buf.append(&mut create_nix_tree.describe_execute());
|
||||
buf.append(&mut move_unpacked_nix.describe_execute());
|
||||
|
||||
buf
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
|
@ -97,6 +100,27 @@ impl Actionable for ProvisionNix {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn describe_revert(&self) -> Vec<ActionDescription> {
|
||||
let Self {
|
||||
fetch_nix,
|
||||
create_users_and_group,
|
||||
create_nix_tree,
|
||||
move_unpacked_nix,
|
||||
action_state: _,
|
||||
} = &self;
|
||||
if self.action_state == ActionState::Uncompleted {
|
||||
vec![]
|
||||
} else {
|
||||
let mut buf = Vec::default();
|
||||
buf.append(&mut move_unpacked_nix.describe_revert());
|
||||
buf.append(&mut create_nix_tree.describe_revert());
|
||||
buf.append(&mut create_users_and_group.describe_revert());
|
||||
buf.append(&mut fetch_nix.describe_revert());
|
||||
buf
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
||||
let Self {
|
||||
|
@ -148,18 +172,19 @@ pub enum ProvisionNixError {
|
|||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
std::io::Error,
|
||||
),
|
||||
#[error(transparent)]
|
||||
FetchNix(#[from] FetchNixError),
|
||||
#[error(transparent)]
|
||||
#[error("Fetching Nix")]
|
||||
FetchNix(#[source] #[from] FetchNixError),
|
||||
#[error("Joining spawned async task")]
|
||||
Join(
|
||||
#[source]
|
||||
#[from]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
JoinError,
|
||||
),
|
||||
#[error(transparent)]
|
||||
CreateUsersAndGroup(#[from] CreateUsersAndGroupError),
|
||||
#[error(transparent)]
|
||||
CreateNixTree(#[from] CreateNixTreeError),
|
||||
#[error(transparent)]
|
||||
MoveUnpackedNix(#[from] MoveUnpackedNixError),
|
||||
#[error("Creating users and group")]
|
||||
CreateUsersAndGroup(#[source] #[from] CreateUsersAndGroupError),
|
||||
#[error("Creating nix tree")]
|
||||
CreateNixTree(#[source] #[from] CreateNixTreeError),
|
||||
#[error("Moving unpacked nix")]
|
||||
MoveUnpackedNix(#[source] #[from] MoveUnpackedNixError),
|
||||
}
|
||||
|
|
|
@ -26,8 +26,12 @@ impl StartNixDaemon {
|
|||
impl Actionable for StartNixDaemon {
|
||||
type Error = StartNixDaemonError;
|
||||
|
||||
fn description(&self) -> Vec<ActionDescription> {
|
||||
self.start_systemd_socket.description()
|
||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||
if self.action_state == ActionState::Completed {
|
||||
vec![]
|
||||
} else {
|
||||
self.start_systemd_socket.describe_execute()
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
|
@ -49,6 +53,14 @@ impl Actionable for StartNixDaemon {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn describe_revert(&self) -> Vec<ActionDescription> {
|
||||
if self.action_state == ActionState::Uncompleted {
|
||||
vec![]
|
||||
} else {
|
||||
self.start_systemd_socket.describe_revert()
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
||||
let Self {
|
||||
|
@ -78,6 +90,6 @@ impl From<StartNixDaemon> for Action {
|
|||
|
||||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum StartNixDaemonError {
|
||||
#[error(transparent)]
|
||||
StartSystemdUnit(#[from] StartSystemdUnitError),
|
||||
#[error("Starting systemd unit")]
|
||||
StartSystemdUnit(#[source] #[from] StartSystemdUnitError),
|
||||
}
|
||||
|
|
|
@ -23,7 +23,8 @@ use self::base::{StartSystemdUnit, StartSystemdUnitError};
|
|||
pub trait Actionable: DeserializeOwned + Serialize + Into<Action> {
|
||||
type Error: std::error::Error + std::fmt::Debug + Serialize + Into<ActionError>;
|
||||
|
||||
fn description(&self) -> Vec<ActionDescription>;
|
||||
fn describe_execute(&self) -> Vec<ActionDescription>;
|
||||
fn describe_revert(&self) -> Vec<ActionDescription>;
|
||||
|
||||
// They should also have an `async fn plan(args...) -> Result<ActionState<Self>, Self::Error>;`
|
||||
async fn execute(&mut self) -> Result<(), Self::Error>;
|
||||
|
@ -123,26 +124,26 @@ pub enum ActionError {
|
|||
#[async_trait::async_trait]
|
||||
impl Actionable for Action {
|
||||
type Error = ActionError;
|
||||
fn description(&self) -> Vec<ActionDescription> {
|
||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||
match self {
|
||||
Action::ConfigureNixDaemonService(i) => i.description(),
|
||||
Action::ConfigureNix(i) => i.description(),
|
||||
Action::ConfigureShellProfile(i) => i.description(),
|
||||
Action::CreateDirectory(i) => i.description(),
|
||||
Action::CreateFile(i) => i.description(),
|
||||
Action::CreateGroup(i) => i.description(),
|
||||
Action::CreateOrAppendFile(i) => i.description(),
|
||||
Action::CreateNixTree(i) => i.description(),
|
||||
Action::CreateUser(i) => i.description(),
|
||||
Action::CreateUsersAndGroup(i) => i.description(),
|
||||
Action::FetchNix(i) => i.description(),
|
||||
Action::MoveUnpackedNix(i) => i.description(),
|
||||
Action::PlaceChannelConfiguration(i) => i.description(),
|
||||
Action::PlaceNixConfiguration(i) => i.description(),
|
||||
Action::SetupDefaultProfile(i) => i.description(),
|
||||
Action::StartNixDaemon(i) => i.description(),
|
||||
Action::StartSystemdUnit(i) => i.description(),
|
||||
Action::ProvisionNix(i) => i.description(),
|
||||
Action::ConfigureNixDaemonService(i) => i.describe_execute(),
|
||||
Action::ConfigureNix(i) => i.describe_execute(),
|
||||
Action::ConfigureShellProfile(i) => i.describe_execute(),
|
||||
Action::CreateDirectory(i) => i.describe_execute(),
|
||||
Action::CreateFile(i) => i.describe_execute(),
|
||||
Action::CreateGroup(i) => i.describe_execute(),
|
||||
Action::CreateOrAppendFile(i) => i.describe_execute(),
|
||||
Action::CreateNixTree(i) => i.describe_execute(),
|
||||
Action::CreateUser(i) => i.describe_execute(),
|
||||
Action::CreateUsersAndGroup(i) => i.describe_execute(),
|
||||
Action::FetchNix(i) => i.describe_execute(),
|
||||
Action::MoveUnpackedNix(i) => i.describe_execute(),
|
||||
Action::PlaceChannelConfiguration(i) => i.describe_execute(),
|
||||
Action::PlaceNixConfiguration(i) => i.describe_execute(),
|
||||
Action::SetupDefaultProfile(i) => i.describe_execute(),
|
||||
Action::StartNixDaemon(i) => i.describe_execute(),
|
||||
Action::StartSystemdUnit(i) => i.describe_execute(),
|
||||
Action::ProvisionNix(i) => i.describe_execute(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,6 +171,29 @@ impl Actionable for Action {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn describe_revert(&self) -> Vec<ActionDescription> {
|
||||
match self {
|
||||
Action::ConfigureNixDaemonService(i) => i.describe_revert(),
|
||||
Action::ConfigureNix(i) => i.describe_revert(),
|
||||
Action::ConfigureShellProfile(i) => i.describe_revert(),
|
||||
Action::CreateDirectory(i) => i.describe_revert(),
|
||||
Action::CreateFile(i) => i.describe_revert(),
|
||||
Action::CreateGroup(i) => i.describe_revert(),
|
||||
Action::CreateOrAppendFile(i) => i.describe_revert(),
|
||||
Action::CreateNixTree(i) => i.describe_revert(),
|
||||
Action::CreateUser(i) => i.describe_revert(),
|
||||
Action::CreateUsersAndGroup(i) => i.describe_revert(),
|
||||
Action::FetchNix(i) => i.describe_revert(),
|
||||
Action::MoveUnpackedNix(i) => i.describe_revert(),
|
||||
Action::PlaceChannelConfiguration(i) => i.describe_revert(),
|
||||
Action::PlaceNixConfiguration(i) => i.describe_revert(),
|
||||
Action::SetupDefaultProfile(i) => i.describe_revert(),
|
||||
Action::StartNixDaemon(i) => i.describe_revert(),
|
||||
Action::StartSystemdUnit(i) => i.describe_revert(),
|
||||
Action::ProvisionNix(i) => i.describe_revert(),
|
||||
}
|
||||
}
|
||||
|
||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
||||
match self {
|
||||
Action::ConfigureNixDaemonService(i) => i.revert().await?,
|
||||
|
|
|
@ -96,11 +96,17 @@ impl CommandExecute for HarmonicCli {
|
|||
let mut plan = InstallPlan::new(settings).await?;
|
||||
|
||||
// TODO(@Hoverbear): Make this smarter
|
||||
if !interaction::confirm(plan.description()).await? {
|
||||
if !interaction::confirm(plan.describe_execute()).await? {
|
||||
interaction::clean_exit_with_message("Okay, didn't do anything! Bye!").await;
|
||||
}
|
||||
|
||||
let _receipt = plan.install().await?;
|
||||
|
||||
if let Err(err) = plan.install().await {
|
||||
tracing::error!("{err:#?}");
|
||||
if !interaction::confirm(plan.describe_revert()).await? {
|
||||
interaction::clean_exit_with_message("Okay, didn't do anything! Bye!").await;
|
||||
}
|
||||
plan.revert().await?
|
||||
}
|
||||
|
||||
Ok(ExitCode::SUCCESS)
|
||||
},
|
||||
|
|
|
@ -32,12 +32,18 @@ impl CommandExecute for Execute {
|
|||
let mut plan: InstallPlan = serde_json::from_str(&install_plan_string)?;
|
||||
|
||||
if !no_confirm {
|
||||
if !interaction::confirm(plan.description()).await? {
|
||||
if !interaction::confirm(plan.describe_execute()).await? {
|
||||
interaction::clean_exit_with_message("Okay, didn't do anything! Bye!").await;
|
||||
}
|
||||
}
|
||||
|
||||
plan.install().await?;
|
||||
if let Err(err) = plan.install().await {
|
||||
tracing::error!("{err:#?}");
|
||||
if !interaction::confirm(plan.describe_revert()).await? {
|
||||
interaction::clean_exit_with_message("Okay, didn't do anything! Bye!").await;
|
||||
}
|
||||
plan.revert().await?
|
||||
}
|
||||
|
||||
Ok(ExitCode::SUCCESS)
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ impl CommandExecute for Revert {
|
|||
let mut plan: InstallPlan = serde_json::from_str(&install_receipt_string)?;
|
||||
|
||||
if !no_confirm {
|
||||
if !interaction::confirm(plan.description()).await? {
|
||||
if !interaction::confirm(plan.describe_execute()).await? {
|
||||
interaction::clean_exit_with_message("Okay, didn't do anything! Bye!").await;
|
||||
}
|
||||
}
|
||||
|
|
89
src/plan.rs
89
src/plan.rs
|
@ -36,8 +36,24 @@ pub struct InstallPlan {
|
|||
}
|
||||
|
||||
impl InstallPlan {
|
||||
pub async fn new(settings: InstallSettings) -> Result<Self, HarmonicError> {
|
||||
Ok(Self {
|
||||
settings: settings.clone(),
|
||||
provision_nix: ProvisionNix::plan(settings.clone())
|
||||
.await
|
||||
.map_err(|e| ActionError::from(e))?,
|
||||
configure_nix: ConfigureNix::plan(settings)
|
||||
.await
|
||||
.map_err(|e| ActionError::from(e))?,
|
||||
start_nix_daemon: StartNixDaemon::plan()
|
||||
.await
|
||||
.map_err(|e| ActionError::from(e))?,
|
||||
})
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn description(&self) -> String {
|
||||
pub fn describe_execute(&self) -> String {
|
||||
let Self { settings, provision_nix, configure_nix, start_nix_daemon } = self;
|
||||
format!(
|
||||
"\
|
||||
This Nix install is for:\n\
|
||||
|
@ -50,17 +66,16 @@ impl InstallPlan {
|
|||
",
|
||||
os_type = "Linux",
|
||||
init_type = "systemd",
|
||||
nix_channels = self
|
||||
.settings
|
||||
nix_channels = settings
|
||||
.channels
|
||||
.iter()
|
||||
.map(|(name, url)| format!("{name}={url}"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(","),
|
||||
actions = {
|
||||
let mut buf = self.provision_nix.description();
|
||||
buf.append(&mut self.configure_nix.description());
|
||||
buf.append(&mut self.start_nix_daemon.description());
|
||||
let mut buf = provision_nix.describe_execute();
|
||||
buf.append(&mut configure_nix.describe_execute());
|
||||
buf.append(&mut start_nix_daemon.describe_execute());
|
||||
buf.iter()
|
||||
.map(|desc| {
|
||||
let ActionDescription {
|
||||
|
@ -82,20 +97,7 @@ impl InstallPlan {
|
|||
},
|
||||
)
|
||||
}
|
||||
pub async fn new(settings: InstallSettings) -> Result<Self, HarmonicError> {
|
||||
Ok(Self {
|
||||
settings: settings.clone(),
|
||||
provision_nix: ProvisionNix::plan(settings.clone())
|
||||
.await
|
||||
.map_err(|e| ActionError::from(e))?,
|
||||
configure_nix: ConfigureNix::plan(settings)
|
||||
.await
|
||||
.map_err(|e| ActionError::from(e))?,
|
||||
start_nix_daemon: StartNixDaemon::plan()
|
||||
.await
|
||||
.map_err(|e| ActionError::from(e))?,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub async fn install(&mut self) -> Result<(), HarmonicError> {
|
||||
|
@ -125,6 +127,53 @@ impl InstallPlan {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn describe_revert(&self) -> String {
|
||||
let Self { settings, provision_nix, configure_nix, start_nix_daemon } = self;
|
||||
format!(
|
||||
"\
|
||||
This Nix uninstall is for:\n\
|
||||
Operating System: {os_type}\n\
|
||||
Init system: {init_type}\n\
|
||||
Nix channels: {nix_channels}\n\
|
||||
\n\
|
||||
The following actions will be taken:\n\
|
||||
{actions}
|
||||
",
|
||||
os_type = "Linux",
|
||||
init_type = "systemd",
|
||||
nix_channels = settings
|
||||
.channels
|
||||
.iter()
|
||||
.map(|(name, url)| format!("{name}={url}"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(","),
|
||||
actions = {
|
||||
let mut buf = provision_nix.describe_revert();
|
||||
buf.append(&mut configure_nix.describe_revert());
|
||||
buf.append(&mut start_nix_daemon.describe_revert());
|
||||
buf.iter()
|
||||
.map(|desc| {
|
||||
let ActionDescription {
|
||||
description,
|
||||
explanation,
|
||||
} = desc;
|
||||
|
||||
let mut buf = String::default();
|
||||
buf.push_str(&format!("* {description}\n"));
|
||||
if self.settings.explain {
|
||||
for line in explanation {
|
||||
buf.push_str(&format!(" {line}\n"));
|
||||
}
|
||||
}
|
||||
buf
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub async fn revert(&mut self) -> Result<(), HarmonicError> {
|
||||
// This is **deliberately sequential**.
|
||||
|
|
Loading…
Reference in a new issue