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