fix & fmt
This commit is contained in:
parent
48646c7cad
commit
f6d90695f6
|
@ -4,9 +4,9 @@ use serde::Serialize;
|
|||
use tokio::fs::remove_file;
|
||||
use tokio::process::Command;
|
||||
|
||||
use crate::{execute_command};
|
||||
use crate::execute_command;
|
||||
|
||||
use crate::actions::{ActionDescription, Actionable, ActionState, Action};
|
||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
||||
|
||||
const SERVICE_SRC: &str = "/nix/var/nix/profiles/default/lib/systemd/system/nix-daemon.service";
|
||||
const SOCKET_SRC: &str = "/nix/var/nix/profiles/default/lib/systemd/system/nix-daemon.socket";
|
||||
|
@ -62,49 +62,53 @@ impl Actionable for ConfigureNixDaemonService {
|
|||
.arg("--create")
|
||||
.arg("--prefix=/nix/var/nix"),
|
||||
)
|
||||
.await.map_err(Self::Error::CommandFailed)?;
|
||||
.await
|
||||
.map_err(Self::Error::CommandFailed)?;
|
||||
|
||||
execute_command(
|
||||
Command::new("systemctl").arg("link").arg(SERVICE_SRC),
|
||||
)
|
||||
.await.map_err(Self::Error::CommandFailed)?;
|
||||
|
||||
execute_command(Command::new("systemctl").arg("link").arg(SOCKET_SRC)).await
|
||||
execute_command(Command::new("systemctl").arg("link").arg(SERVICE_SRC))
|
||||
.await
|
||||
.map_err(Self::Error::CommandFailed)?;
|
||||
|
||||
execute_command(Command::new("systemctl").arg("daemon-reload")).await
|
||||
execute_command(Command::new("systemctl").arg("link").arg(SOCKET_SRC))
|
||||
.await
|
||||
.map_err(Self::Error::CommandFailed)?;
|
||||
|
||||
execute_command(Command::new("systemctl").arg("daemon-reload"))
|
||||
.await
|
||||
.map_err(Self::Error::CommandFailed)?;
|
||||
|
||||
*action_state = ActionState::Completed;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
||||
let Self { action_state } = self;
|
||||
tracing::info!("Unconfiguring nix daemon service");
|
||||
|
||||
// We don't need to do this! Systemd does it for us! (In fact, it's an error if we try to do this...)
|
||||
execute_command(Command::new("systemctl").args(["disable", SOCKET_SRC])).await
|
||||
execute_command(Command::new("systemctl").args(["disable", SOCKET_SRC]))
|
||||
.await
|
||||
.map_err(Self::Error::CommandFailed)?;
|
||||
|
||||
execute_command(
|
||||
Command::new("systemctl").args(["disable", SERVICE_SRC]),
|
||||
)
|
||||
.await.map_err(Self::Error::CommandFailed)?;
|
||||
execute_command(Command::new("systemctl").args(["disable", SERVICE_SRC]))
|
||||
.await
|
||||
.map_err(Self::Error::CommandFailed)?;
|
||||
|
||||
execute_command(
|
||||
Command::new("systemd-tmpfiles")
|
||||
.arg("--remove")
|
||||
.arg("--prefix=/nix/var/nix"),
|
||||
)
|
||||
.await.map_err(Self::Error::CommandFailed)?;
|
||||
.await
|
||||
.map_err(Self::Error::CommandFailed)?;
|
||||
|
||||
remove_file(TMPFILES_DEST).await
|
||||
remove_file(TMPFILES_DEST)
|
||||
.await
|
||||
.map_err(|e| Self::Error::RemoveFile(PathBuf::from(TMPFILES_DEST), e))?;
|
||||
|
||||
execute_command(Command::new("systemctl").arg("daemon-reload")).await
|
||||
execute_command(Command::new("systemctl").arg("daemon-reload"))
|
||||
.await
|
||||
.map_err(Self::Error::CommandFailed)?;
|
||||
|
||||
*action_state = ActionState::Reverted;
|
||||
|
@ -112,8 +116,6 @@ impl Actionable for ConfigureNixDaemonService {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
impl From<ConfigureNixDaemonService> for Action {
|
||||
fn from(v: ConfigureNixDaemonService) -> Self {
|
||||
Action::ConfigureNixDaemonService(v)
|
||||
|
@ -128,16 +130,21 @@ pub enum ConfigureNixDaemonServiceError {
|
|||
std::path::PathBuf,
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
std::io::Error
|
||||
std::io::Error,
|
||||
),
|
||||
#[error("Command failed to execute")]
|
||||
CommandFailed(
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
std::io::Error
|
||||
std::io::Error,
|
||||
),
|
||||
#[error("Remove file `{0}`")]
|
||||
RemoveFile(std::path::PathBuf, #[source] #[serde(serialize_with = "crate::serialize_error_to_display")] std::io::Error),
|
||||
RemoveFile(
|
||||
std::path::PathBuf,
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
std::io::Error,
|
||||
),
|
||||
#[error("No supported init system found")]
|
||||
InitNotSupported,
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
use std::os::unix::prelude::PermissionsExt;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
|
@ -6,9 +5,7 @@ use nix::unistd::{chown, Group, User};
|
|||
use serde::Serialize;
|
||||
use tokio::fs::{create_dir, remove_dir_all};
|
||||
|
||||
|
||||
|
||||
use crate::actions::{ActionDescription, Actionable, ActionState, Action};
|
||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
||||
|
||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||
pub struct CreateDirectory {
|
||||
|
@ -100,12 +97,10 @@ impl Actionable for CreateDirectory {
|
|||
.await
|
||||
.map_err(|e| Self::Error::SetPermissions(*mode, path.to_owned(), e))?;
|
||||
|
||||
|
||||
*action_state = ActionState::Completed;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
||||
let Self {
|
||||
|
@ -126,32 +121,66 @@ impl Actionable for CreateDirectory {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl From<CreateDirectory> for Action {
|
||||
fn from(v: CreateDirectory) -> Self {
|
||||
Action::CreateDirectory(v)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum CreateDirectoryError {
|
||||
#[error("Directory exists `{0}`")]
|
||||
Exists(std::path::PathBuf, #[source] #[serde(serialize_with = "crate::serialize_error_to_display")] std::io::Error),
|
||||
Exists(
|
||||
std::path::PathBuf,
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
std::io::Error,
|
||||
),
|
||||
#[error("Creating directory `{0}`")]
|
||||
Creating(std::path::PathBuf, #[source] #[serde(serialize_with = "crate::serialize_error_to_display")] std::io::Error),
|
||||
Creating(
|
||||
std::path::PathBuf,
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
std::io::Error,
|
||||
),
|
||||
#[error("Removing directory `{0}`")]
|
||||
Removing(std::path::PathBuf, #[source] #[serde(serialize_with = "crate::serialize_error_to_display")] std::io::Error),
|
||||
Removing(
|
||||
std::path::PathBuf,
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
std::io::Error,
|
||||
),
|
||||
#[error("Set mode `{0}` on `{1}`")]
|
||||
SetPermissions(u32, std::path::PathBuf, #[source] #[serde(serialize_with = "crate::serialize_error_to_display")] std::io::Error),
|
||||
SetPermissions(
|
||||
u32,
|
||||
std::path::PathBuf,
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
std::io::Error,
|
||||
),
|
||||
#[error("Chowning directory `{0}`")]
|
||||
Chown(std::path::PathBuf, #[source] #[serde(serialize_with = "crate::serialize_error_to_display")] nix::errno::Errno),
|
||||
Chown(
|
||||
std::path::PathBuf,
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
nix::errno::Errno,
|
||||
),
|
||||
#[error("Getting uid for user `{0}`")]
|
||||
UserId(String, #[source] #[serde(serialize_with = "crate::serialize_error_to_display")] nix::errno::Errno),
|
||||
UserId(
|
||||
String,
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
nix::errno::Errno,
|
||||
),
|
||||
#[error("Getting user `{0}`")]
|
||||
NoUser(String),
|
||||
#[error("Getting gid for group `{0}`")]
|
||||
GroupId(String, #[source] #[serde(serialize_with = "crate::serialize_error_to_display")] nix::errno::Errno),
|
||||
GroupId(
|
||||
String,
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
nix::errno::Errno,
|
||||
),
|
||||
#[error("Getting group `{0}`")]
|
||||
NoGroup(String),
|
||||
}
|
||||
|
|
|
@ -2,11 +2,11 @@ use nix::unistd::{chown, Group, User};
|
|||
use serde::Serialize;
|
||||
use std::path::{Path, PathBuf};
|
||||
use tokio::{
|
||||
fs::{OpenOptions, remove_file},
|
||||
fs::{remove_file, OpenOptions},
|
||||
io::AsyncWriteExt,
|
||||
};
|
||||
|
||||
use crate::{actions::{ActionState, Action, ActionError}};
|
||||
use crate::actions::{Action, ActionState};
|
||||
|
||||
use crate::actions::{ActionDescription, Actionable};
|
||||
|
||||
|
@ -111,7 +111,6 @@ impl Actionable for CreateFile {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
||||
let Self {
|
||||
|
@ -126,7 +125,8 @@ impl Actionable for CreateFile {
|
|||
|
||||
tracing::trace!(path = %path.display(), "Deleting file");
|
||||
|
||||
remove_file(&path).await
|
||||
remove_file(&path)
|
||||
.await
|
||||
.map_err(|e| Self::Error::RemoveFile(path.to_owned(), e))?;
|
||||
|
||||
*action_state = ActionState::Reverted;
|
||||
|
@ -145,19 +145,49 @@ pub enum CreateFileError {
|
|||
#[error("File exists `{0}`")]
|
||||
Exists(std::path::PathBuf),
|
||||
#[error("Remove file `{0}`")]
|
||||
RemoveFile(std::path::PathBuf, #[source] #[serde(serialize_with = "crate::serialize_error_to_display")] std::io::Error),
|
||||
RemoveFile(
|
||||
std::path::PathBuf,
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
std::io::Error,
|
||||
),
|
||||
#[error("Open file `{0}`")]
|
||||
OpenFile(std::path::PathBuf, #[source] #[serde(serialize_with = "crate::serialize_error_to_display")] std::io::Error),
|
||||
OpenFile(
|
||||
std::path::PathBuf,
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
std::io::Error,
|
||||
),
|
||||
#[error("Write file `{0}`")]
|
||||
WriteFile(std::path::PathBuf, #[source] #[serde(serialize_with = "crate::serialize_error_to_display")] std::io::Error),
|
||||
WriteFile(
|
||||
std::path::PathBuf,
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
std::io::Error,
|
||||
),
|
||||
#[error("Getting uid for user `{0}`")]
|
||||
UserId(String, #[source] #[serde(serialize_with = "crate::serialize_error_to_display")] nix::errno::Errno),
|
||||
UserId(
|
||||
String,
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
nix::errno::Errno,
|
||||
),
|
||||
#[error("Getting user `{0}`")]
|
||||
NoUser(String),
|
||||
#[error("Getting gid for group `{0}`")]
|
||||
GroupId(String, #[source] #[serde(serialize_with = "crate::serialize_error_to_display")] nix::errno::Errno),
|
||||
GroupId(
|
||||
String,
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
nix::errno::Errno,
|
||||
),
|
||||
#[error("Getting group `{0}`")]
|
||||
NoGroup(String),
|
||||
#[error("Chowning directory `{0}`")]
|
||||
Chown(std::path::PathBuf, #[source] #[serde(serialize_with = "crate::serialize_error_to_display")] nix::errno::Errno),
|
||||
Chown(
|
||||
std::path::PathBuf,
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
nix::errno::Errno,
|
||||
),
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use serde::Serialize;
|
||||
use tokio::process::Command;
|
||||
|
||||
use crate::{HarmonicError, execute_command};
|
||||
use crate::execute_command;
|
||||
|
||||
use crate::actions::{ActionDescription, Actionable, ActionState, Action, ActionError};
|
||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
||||
|
||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||
pub struct CreateGroup {
|
||||
|
@ -15,7 +15,11 @@ pub struct CreateGroup {
|
|||
impl CreateGroup {
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn plan(name: String, gid: usize) -> Self {
|
||||
Self { name, gid, action_state: ActionState::Planned }
|
||||
Self {
|
||||
name,
|
||||
gid,
|
||||
action_state: ActionState::Planned,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,7 +27,11 @@ impl CreateGroup {
|
|||
impl Actionable for CreateGroup {
|
||||
type Error = CreateGroupError;
|
||||
fn description(&self) -> Vec<ActionDescription> {
|
||||
let Self { name, gid, action_state: _ } = &self;
|
||||
let Self {
|
||||
name,
|
||||
gid,
|
||||
action_state: _,
|
||||
} = &self;
|
||||
vec![ActionDescription::new(
|
||||
format!("Create group {name} with GID {gid}"),
|
||||
vec![format!(
|
||||
|
@ -34,12 +42,15 @@ impl Actionable for CreateGroup {
|
|||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
||||
let Self { name, gid, action_state } = self;
|
||||
|
||||
execute_command(
|
||||
Command::new("groupadd").args(["-g", &gid.to_string(), "--system", &name]),
|
||||
).await.map_err(CreateGroupError::Command)?;
|
||||
let Self {
|
||||
name,
|
||||
gid,
|
||||
action_state,
|
||||
} = self;
|
||||
|
||||
execute_command(Command::new("groupadd").args(["-g", &gid.to_string(), "--system", &name]))
|
||||
.await
|
||||
.map_err(CreateGroupError::Command)?;
|
||||
|
||||
*action_state = ActionState::Completed;
|
||||
Ok(())
|
||||
|
@ -47,11 +58,15 @@ impl Actionable for CreateGroup {
|
|||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
||||
let Self { name, gid: _, action_state } = self;
|
||||
let Self {
|
||||
name,
|
||||
gid: _,
|
||||
action_state,
|
||||
} = self;
|
||||
|
||||
execute_command(
|
||||
Command::new("groupdel").arg(&name),
|
||||
).await.map_err(CreateGroupError::Command)?;
|
||||
execute_command(Command::new("groupdel").arg(&name))
|
||||
.await
|
||||
.map_err(CreateGroupError::Command)?;
|
||||
|
||||
*action_state = ActionState::Reverted;
|
||||
Ok(())
|
||||
|
@ -67,5 +82,9 @@ impl From<CreateGroup> for Action {
|
|||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum CreateGroupError {
|
||||
#[error("Failed to execute command")]
|
||||
Command(#[source] #[serde(serialize_with = "crate::serialize_error_to_display")] std::io::Error)
|
||||
Command(
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
std::io::Error,
|
||||
),
|
||||
}
|
|
@ -2,14 +2,15 @@ use nix::unistd::{chown, Group, User};
|
|||
use serde::Serialize;
|
||||
use std::{
|
||||
io::SeekFrom,
|
||||
path::{Path, PathBuf}, os::unix::prelude::PermissionsExt, f32::consts::E,
|
||||
os::unix::prelude::PermissionsExt,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use tokio::{
|
||||
fs::{create_dir_all, OpenOptions, remove_file},
|
||||
io::{AsyncSeekExt, AsyncWriteExt, AsyncReadExt},
|
||||
fs::{remove_file, OpenOptions},
|
||||
io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt},
|
||||
};
|
||||
|
||||
use crate::{HarmonicError, actions::{ActionState, Action, ActionError}};
|
||||
use crate::actions::{Action, ActionState};
|
||||
|
||||
use crate::actions::{ActionDescription, Actionable};
|
||||
|
||||
|
@ -110,12 +111,10 @@ impl Actionable for CreateOrAppendFile {
|
|||
tracing::trace!(path = %path.display(), "Chowning");
|
||||
chown(path, Some(uid), Some(gid)).map_err(|e| Self::Error::Chown(path.clone(), e))?;
|
||||
|
||||
|
||||
*action_state = ActionState::Completed;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
||||
let Self {
|
||||
|
@ -137,7 +136,8 @@ impl Actionable for CreateOrAppendFile {
|
|||
.map_err(|e| Self::Error::ReadFile(path.to_owned(), e))?;
|
||||
|
||||
let mut file_contents = String::default();
|
||||
file.read_to_string(&mut file_contents).await
|
||||
file.read_to_string(&mut file_contents)
|
||||
.await
|
||||
.map_err(|e| Self::Error::SeekFile(path.to_owned(), e))?;
|
||||
|
||||
if let Some(start) = file_contents.rfind(buf.as_str()) {
|
||||
|
@ -146,7 +146,9 @@ impl Actionable for CreateOrAppendFile {
|
|||
}
|
||||
|
||||
if buf.is_empty() {
|
||||
remove_file(&path).await.map_err(|e| Self::Error::RemoveFile(path.to_owned(), e))?;
|
||||
remove_file(&path)
|
||||
.await
|
||||
.map_err(|e| Self::Error::RemoveFile(path.to_owned(), e))?;
|
||||
} else {
|
||||
file.seek(SeekFrom::Start(0))
|
||||
.await
|
||||
|
@ -161,7 +163,6 @@ impl Actionable for CreateOrAppendFile {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl From<CreateOrAppendFile> for Action {
|
||||
fn from(v: CreateOrAppendFile) -> Self {
|
||||
Action::CreateOrAppendFile(v)
|
||||
|
@ -171,25 +172,71 @@ impl From<CreateOrAppendFile> for Action {
|
|||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum CreateOrAppendFileError {
|
||||
#[error("Remove file `{0}`")]
|
||||
RemoveFile(std::path::PathBuf, #[source] #[serde(serialize_with = "crate::serialize_error_to_display")] std::io::Error),
|
||||
RemoveFile(
|
||||
std::path::PathBuf,
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
std::io::Error,
|
||||
),
|
||||
#[error("Remove file `{0}`")]
|
||||
ReadFile(std::path::PathBuf, #[source] #[serde(serialize_with = "crate::serialize_error_to_display")] std::io::Error),
|
||||
ReadFile(
|
||||
std::path::PathBuf,
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
std::io::Error,
|
||||
),
|
||||
#[error("Open file `{0}`")]
|
||||
OpenFile(std::path::PathBuf, #[source] #[serde(serialize_with = "crate::serialize_error_to_display")] std::io::Error),
|
||||
OpenFile(
|
||||
std::path::PathBuf,
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
std::io::Error,
|
||||
),
|
||||
#[error("Write file `{0}`")]
|
||||
WriteFile(std::path::PathBuf, #[source] #[serde(serialize_with = "crate::serialize_error_to_display")] std::io::Error),
|
||||
WriteFile(
|
||||
std::path::PathBuf,
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
std::io::Error,
|
||||
),
|
||||
#[error("Seek file `{0}`")]
|
||||
SeekFile(std::path::PathBuf, #[source] #[serde(serialize_with = "crate::serialize_error_to_display")] std::io::Error),
|
||||
SeekFile(
|
||||
std::path::PathBuf,
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
std::io::Error,
|
||||
),
|
||||
#[error("Getting uid for user `{0}`")]
|
||||
UserId(String, #[source] #[serde(serialize_with = "crate::serialize_error_to_display")] nix::errno::Errno),
|
||||
UserId(
|
||||
String,
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
nix::errno::Errno,
|
||||
),
|
||||
#[error("Getting user `{0}`")]
|
||||
NoUser(String),
|
||||
#[error("Getting gid for group `{0}`")]
|
||||
GroupId(String, #[source] #[serde(serialize_with = "crate::serialize_error_to_display")] nix::errno::Errno),
|
||||
GroupId(
|
||||
String,
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
nix::errno::Errno,
|
||||
),
|
||||
#[error("Getting group `{0}`")]
|
||||
NoGroup(String),
|
||||
#[error("Set mode `{0}` on `{1}`")]
|
||||
SetPermissions(u32, std::path::PathBuf, #[source] #[serde(serialize_with = "crate::serialize_error_to_display")] std::io::Error),
|
||||
SetPermissions(
|
||||
u32,
|
||||
std::path::PathBuf,
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
std::io::Error,
|
||||
),
|
||||
#[error("Chowning directory `{0}`")]
|
||||
Chown(std::path::PathBuf, #[source] #[serde(serialize_with = "crate::serialize_error_to_display")] nix::errno::Errno),
|
||||
Chown(
|
||||
std::path::PathBuf,
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
nix::errno::Errno,
|
||||
),
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use serde::Serialize;
|
||||
use tokio::process::Command;
|
||||
|
||||
use crate::{HarmonicError, execute_command};
|
||||
use crate::execute_command;
|
||||
|
||||
use crate::actions::{ActionDescription, Actionable, ActionState, Action, ActionError};
|
||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
||||
|
||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||
pub struct CreateUser {
|
||||
|
@ -16,7 +16,12 @@ pub struct CreateUser {
|
|||
impl CreateUser {
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn plan(name: String, uid: usize, gid: usize) -> Self {
|
||||
Self { name, uid, gid, action_state: ActionState::Planned }
|
||||
Self {
|
||||
name,
|
||||
uid,
|
||||
gid,
|
||||
action_state: ActionState::Planned,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,7 +41,12 @@ impl Actionable for CreateUser {
|
|||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
||||
let Self { name, uid, gid, action_state } = self;
|
||||
let Self {
|
||||
name,
|
||||
uid,
|
||||
gid,
|
||||
action_state,
|
||||
} = self;
|
||||
|
||||
execute_command(Command::new("useradd").args([
|
||||
"--home-dir",
|
||||
|
@ -56,20 +66,26 @@ impl Actionable for CreateUser {
|
|||
"--password",
|
||||
"\"!\"",
|
||||
&name.to_string(),
|
||||
])).await.map_err(Self::Error::Command)?;
|
||||
]))
|
||||
.await
|
||||
.map_err(Self::Error::Command)?;
|
||||
|
||||
*action_state = ActionState::Completed;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
||||
let Self { name, uid: _, gid: _, action_state } = self;
|
||||
let Self {
|
||||
name,
|
||||
uid: _,
|
||||
gid: _,
|
||||
action_state,
|
||||
} = self;
|
||||
|
||||
execute_command(Command::new("userdel").args([
|
||||
&name.to_string(),
|
||||
])).await.map_err(Self::Error::Command)?;
|
||||
execute_command(Command::new("userdel").args([&name.to_string()]))
|
||||
.await
|
||||
.map_err(Self::Error::Command)?;
|
||||
|
||||
*action_state = ActionState::Completed;
|
||||
Ok(())
|
||||
|
@ -85,5 +101,9 @@ impl From<CreateUser> for Action {
|
|||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum CreateUserError {
|
||||
#[error("Failed to execute command")]
|
||||
Command(#[source] #[serde(serialize_with = "crate::serialize_error_to_display")] std::io::Error)
|
||||
Command(
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
std::io::Error,
|
||||
),
|
||||
}
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
use std::path::{PathBuf};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use bytes::Buf;
|
||||
use reqwest::Url;
|
||||
use serde::Serialize;
|
||||
use tokio::task::{spawn_blocking, JoinError};
|
||||
|
||||
use crate::HarmonicError;
|
||||
|
||||
use crate::actions::{ActionDescription, Actionable, ActionState, Action, ActionError};
|
||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
||||
|
||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||
pub struct FetchNix {
|
||||
|
@ -22,7 +20,11 @@ impl FetchNix {
|
|||
// TODO(@hoverbear): Check URL exists?
|
||||
// TODO(@hoverbear): Check tempdir exists
|
||||
|
||||
Ok(Self { url, destination, action_state: ActionState::Planned })
|
||||
Ok(Self {
|
||||
url,
|
||||
destination,
|
||||
action_state: ActionState::Planned,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,7 +32,11 @@ impl FetchNix {
|
|||
impl Actionable for FetchNix {
|
||||
type Error = FetchNixError;
|
||||
fn description(&self) -> Vec<ActionDescription> {
|
||||
let Self { url, destination, action_state: _ } = &self;
|
||||
let Self {
|
||||
url,
|
||||
destination,
|
||||
action_state: _,
|
||||
} = &self;
|
||||
vec![ActionDescription::new(
|
||||
format!("Fetch Nix from `{url}`"),
|
||||
vec![format!(
|
||||
|
@ -42,7 +48,11 @@ impl Actionable for FetchNix {
|
|||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
||||
let Self { url, destination, action_state } = self;
|
||||
let Self {
|
||||
url,
|
||||
destination,
|
||||
action_state,
|
||||
} = self;
|
||||
|
||||
tracing::trace!(%url, "Fetching url");
|
||||
let res = reqwest::get(url.clone())
|
||||
|
@ -67,10 +77,13 @@ impl Actionable for FetchNix {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
||||
let Self { url: _, destination: _, action_state } = self;
|
||||
let Self {
|
||||
url: _,
|
||||
destination: _,
|
||||
action_state,
|
||||
} = self;
|
||||
|
||||
tracing::trace!("Nothing to do for `FetchNix` revert");
|
||||
|
||||
|
@ -91,10 +104,19 @@ pub enum FetchNixError {
|
|||
Join(
|
||||
#[from]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
JoinError
|
||||
JoinError,
|
||||
),
|
||||
#[error("Request error")]
|
||||
Reqwest(#[from] #[source] #[serde(serialize_with = "crate::serialize_error_to_display")] reqwest::Error),
|
||||
Reqwest(
|
||||
#[from]
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
reqwest::Error,
|
||||
),
|
||||
#[error("Unarchiving error")]
|
||||
Unarchive(#[source] #[serde(serialize_with = "crate::serialize_error_to_display")] std::io::Error),
|
||||
Unarchive(
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
std::io::Error,
|
||||
),
|
||||
}
|
||||
|
|
|
@ -13,9 +13,7 @@ mod place_nix_configuration;
|
|||
mod setup_default_profile;
|
||||
mod start_systemd_unit;
|
||||
|
||||
pub use configure_nix_daemon_service::{
|
||||
ConfigureNixDaemonService, ConfigureNixDaemonServiceError,
|
||||
};
|
||||
pub use configure_nix_daemon_service::{ConfigureNixDaemonService, ConfigureNixDaemonServiceError};
|
||||
pub use create_directory::{CreateDirectory, CreateDirectoryError};
|
||||
pub use create_file::{CreateFile, CreateFileError};
|
||||
pub use create_group::{CreateGroup, CreateGroupError};
|
||||
|
@ -23,9 +21,7 @@ pub use create_or_append_file::{CreateOrAppendFile, CreateOrAppendFileError};
|
|||
pub use create_user::{CreateUser, CreateUserError};
|
||||
pub use fetch_nix::{FetchNix, FetchNixError};
|
||||
pub use move_unpacked_nix::{MoveUnpackedNix, MoveUnpackedNixError};
|
||||
pub use place_channel_configuration::{
|
||||
PlaceChannelConfiguration, PlaceChannelConfigurationError,
|
||||
};
|
||||
pub use place_channel_configuration::{PlaceChannelConfiguration, PlaceChannelConfigurationError};
|
||||
pub use place_nix_configuration::{PlaceNixConfiguration, PlaceNixConfigurationError};
|
||||
pub use setup_default_profile::{SetupDefaultProfile, SetupDefaultProfileError};
|
||||
pub use start_systemd_unit::{StartSystemdUnit, StartSystemdUnitError};
|
||||
|
|
|
@ -2,9 +2,7 @@ use std::path::{Path, PathBuf};
|
|||
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::HarmonicError;
|
||||
|
||||
use crate::actions::{ActionDescription, Actionable, ActionState, Action, ActionError};
|
||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
||||
|
||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||
pub struct MoveUnpackedNix {
|
||||
|
@ -16,7 +14,10 @@ impl MoveUnpackedNix {
|
|||
#[tracing::instrument(skip_all)]
|
||||
pub async fn plan(source: PathBuf) -> Result<Self, MoveUnpackedNixError> {
|
||||
// Note: Do NOT try to check for the source/dest since the installer creates those
|
||||
Ok(Self { source, action_state: ActionState::Planned })
|
||||
Ok(Self {
|
||||
source,
|
||||
action_state: ActionState::Planned,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,7 +25,10 @@ impl MoveUnpackedNix {
|
|||
impl Actionable for MoveUnpackedNix {
|
||||
type Error = MoveUnpackedNixError;
|
||||
fn description(&self) -> Vec<ActionDescription> {
|
||||
let Self { source, action_state: _ } = &self;
|
||||
let Self {
|
||||
source,
|
||||
action_state: _,
|
||||
} = &self;
|
||||
vec![ActionDescription::new(
|
||||
format!("Move the downloaded Nix into `/nix`"),
|
||||
vec![format!(
|
||||
|
@ -36,7 +40,10 @@ impl Actionable for MoveUnpackedNix {
|
|||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
||||
let Self { source, action_state } = self;
|
||||
let Self {
|
||||
source,
|
||||
action_state,
|
||||
} = self;
|
||||
|
||||
// TODO(@Hoverbear): I would like to make this less awful
|
||||
let found_nix_paths =
|
||||
|
@ -58,10 +65,12 @@ impl Actionable for MoveUnpackedNix {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
||||
let Self { source: _, action_state } = self;
|
||||
let Self {
|
||||
source: _,
|
||||
action_state,
|
||||
} = self;
|
||||
|
||||
tracing::trace!("Nothing to do for `MoveUnpackedNix` revert");
|
||||
|
||||
|
@ -79,9 +88,25 @@ impl From<MoveUnpackedNix> for Action {
|
|||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum MoveUnpackedNixError {
|
||||
#[error("Glob pattern error")]
|
||||
GlobPatternError(#[from] #[source] #[serde(serialize_with = "crate::serialize_error_to_display")] glob::PatternError),
|
||||
GlobPatternError(
|
||||
#[from]
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
glob::PatternError,
|
||||
),
|
||||
#[error("Glob globbing error")]
|
||||
GlobGlobError(#[from] #[source] #[serde(serialize_with = "crate::serialize_error_to_display")] glob::GlobError),
|
||||
GlobGlobError(
|
||||
#[from]
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
glob::GlobError,
|
||||
),
|
||||
#[error("Rename `{0}` to `{1}`")]
|
||||
Rename(std::path::PathBuf, std::path::PathBuf, #[source] #[serde(serialize_with = "crate::serialize_error_to_display")] std::io::Error),
|
||||
Rename(
|
||||
std::path::PathBuf,
|
||||
std::path::PathBuf,
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
std::io::Error,
|
||||
),
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
use reqwest::Url;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::HarmonicError;
|
||||
|
||||
use crate::actions::{ActionDescription, Actionable, ActionState, Action, ActionError};
|
||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
||||
|
||||
use super::{CreateFile, CreateFileError};
|
||||
|
||||
|
@ -18,14 +16,24 @@ pub struct PlaceChannelConfiguration {
|
|||
|
||||
impl PlaceChannelConfiguration {
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub async fn plan(channels: Vec<(String, Url)>, force: bool) -> Result<Self, PlaceChannelConfigurationError> {
|
||||
pub async fn plan(
|
||||
channels: Vec<(String, Url)>,
|
||||
force: bool,
|
||||
) -> Result<Self, PlaceChannelConfigurationError> {
|
||||
let buf = channels
|
||||
.iter()
|
||||
.map(|(name, url)| format!("{} {}", url, name))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
let create_file =
|
||||
CreateFile::plan(NIX_CHANNELS_PATH, "root".into(), "root".into(), 0o0664, buf, force).await?;
|
||||
let create_file = CreateFile::plan(
|
||||
NIX_CHANNELS_PATH,
|
||||
"root".into(),
|
||||
"root".into(),
|
||||
0o0664,
|
||||
buf,
|
||||
force,
|
||||
)
|
||||
.await?;
|
||||
Ok(Self {
|
||||
create_file,
|
||||
channels,
|
||||
|
@ -63,7 +71,6 @@ impl Actionable for PlaceChannelConfiguration {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
||||
let Self {
|
||||
|
@ -85,7 +92,6 @@ impl From<PlaceChannelConfiguration> for Action {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum PlaceChannelConfigurationError {
|
||||
#[error(transparent)]
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
use serde::Serialize;
|
||||
|
||||
use crate::HarmonicError;
|
||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
||||
|
||||
use crate::actions::{ActionDescription, Actionable, ActionState, Action, ActionError};
|
||||
|
||||
use super::{CreateFile, CreateFileError, CreateDirectory, CreateDirectoryError};
|
||||
use super::{CreateDirectory, CreateDirectoryError, CreateFile, CreateFileError};
|
||||
|
||||
const NIX_CONF_FOLDER: &str = "/etc/nix";
|
||||
const NIX_CONF: &str = "/etc/nix/nix.conf";
|
||||
|
@ -34,10 +32,16 @@ impl PlaceNixConfiguration {
|
|||
",
|
||||
extra_conf = extra_conf.unwrap_or_else(|| "".into()),
|
||||
);
|
||||
let create_directory = CreateDirectory::plan(NIX_CONF_FOLDER, "root".into(), "root".into(), 0o0755, force).await?;
|
||||
let create_directory =
|
||||
CreateDirectory::plan(NIX_CONF_FOLDER, "root".into(), "root".into(), 0o0755, force)
|
||||
.await?;
|
||||
let create_file =
|
||||
CreateFile::plan(NIX_CONF, "root".into(), "root".into(), 0o0664, buf, force).await?;
|
||||
Ok(Self { create_directory, create_file, action_state: ActionState::Planned })
|
||||
Ok(Self {
|
||||
create_directory,
|
||||
create_file,
|
||||
action_state: ActionState::Planned,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,13 +52,20 @@ impl Actionable for PlaceNixConfiguration {
|
|||
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()],
|
||||
vec![
|
||||
"This file is read by the Nix daemon to set its configuration options at runtime."
|
||||
.to_string(),
|
||||
],
|
||||
)]
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
||||
let Self { create_file, create_directory, action_state } = self;
|
||||
let Self {
|
||||
create_file,
|
||||
create_directory,
|
||||
action_state,
|
||||
} = self;
|
||||
|
||||
create_directory.execute().await?;
|
||||
create_file.execute().await?;
|
||||
|
@ -63,10 +74,13 @@ impl Actionable for PlaceNixConfiguration {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
||||
let Self { create_file, create_directory, action_state } = self;
|
||||
let Self {
|
||||
create_file,
|
||||
create_directory,
|
||||
action_state,
|
||||
} = self;
|
||||
|
||||
create_file.revert().await?;
|
||||
create_directory.revert().await?;
|
||||
|
@ -82,7 +96,6 @@ impl From<PlaceNixConfiguration> for Action {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum PlaceNixConfigurationError {
|
||||
#[error(transparent)]
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
use crate::{execute_command, actions::{ActionState, Action, ActionError}, set_env};
|
||||
use crate::{
|
||||
actions::{Action, ActionState},
|
||||
execute_command, set_env,
|
||||
};
|
||||
|
||||
use glob::glob;
|
||||
use serde::Serialize;
|
||||
|
@ -15,7 +18,10 @@ pub struct SetupDefaultProfile {
|
|||
impl SetupDefaultProfile {
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub async fn plan(channels: Vec<String>) -> Result<Self, SetupDefaultProfileError> {
|
||||
Ok(Self { channels, action_state: ActionState::Planned })
|
||||
Ok(Self {
|
||||
channels,
|
||||
action_state: ActionState::Planned,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,7 +37,10 @@ impl Actionable for SetupDefaultProfile {
|
|||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
||||
let Self { channels, action_state } = self;
|
||||
let Self {
|
||||
channels,
|
||||
action_state,
|
||||
} = self;
|
||||
tracing::info!("Setting up default profile");
|
||||
|
||||
// Find an `nix` package
|
||||
|
@ -59,7 +68,8 @@ impl Actionable for SetupDefaultProfile {
|
|||
.arg("-i")
|
||||
.arg(&nix_pkg),
|
||||
)
|
||||
.await.map_err(SetupDefaultProfileError::Command)?;
|
||||
.await
|
||||
.map_err(SetupDefaultProfileError::Command)?;
|
||||
|
||||
// Find an `nss-cacert` package, add it too.
|
||||
let nss_ca_cert_pkg_glob = "/nix/store/*-nss-cacert-*";
|
||||
|
@ -86,7 +96,8 @@ impl Actionable for SetupDefaultProfile {
|
|||
.arg("-i")
|
||||
.arg(&nss_ca_cert_pkg),
|
||||
)
|
||||
.await.map_err(SetupDefaultProfileError::Command)?;
|
||||
.await
|
||||
.map_err(SetupDefaultProfileError::Command)?;
|
||||
|
||||
set_env(
|
||||
"NIX_SSL_CERT_FILE",
|
||||
|
@ -104,16 +115,20 @@ impl Actionable for SetupDefaultProfile {
|
|||
"/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt",
|
||||
);
|
||||
|
||||
execute_command(&mut command).await.map_err(SetupDefaultProfileError::Command)?;
|
||||
execute_command(&mut command)
|
||||
.await
|
||||
.map_err(SetupDefaultProfileError::Command)?;
|
||||
}
|
||||
*action_state = ActionState::Completed;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
||||
let Self { channels: _, action_state } = self;
|
||||
let Self {
|
||||
channels: _,
|
||||
action_state,
|
||||
} = self;
|
||||
|
||||
std::env::remove_var("NIX_SSL_CERT_FILE");
|
||||
|
||||
|
@ -128,15 +143,28 @@ impl From<SetupDefaultProfile> for Action {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum SetupDefaultProfileError {
|
||||
#[error("Glob pattern error")]
|
||||
GlobPatternError(#[from] #[source] #[serde(serialize_with = "crate::serialize_error_to_display")] glob::PatternError),
|
||||
GlobPatternError(
|
||||
#[from]
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
glob::PatternError,
|
||||
),
|
||||
#[error("Glob globbing error")]
|
||||
GlobGlobError(#[from] #[source] #[serde(serialize_with = "crate::serialize_error_to_display")] glob::GlobError),
|
||||
GlobGlobError(
|
||||
#[from]
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
glob::GlobError,
|
||||
),
|
||||
#[error("Unarchived Nix store did not appear to include a `nss-cacert` location")]
|
||||
NoNssCacert,
|
||||
#[error("Failed to execute command")]
|
||||
Command(#[source] #[serde(serialize_with = "crate::serialize_error_to_display")] std::io::Error)
|
||||
Command(
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
std::io::Error,
|
||||
),
|
||||
}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
use serde::Serialize;
|
||||
use tokio::process::Command;
|
||||
|
||||
use crate::actions::meta::StartNixDaemon;
|
||||
use crate::{execute_command, HarmonicError};
|
||||
use crate::execute_command;
|
||||
|
||||
use crate::actions::{ActionDescription, Actionable, ActionState, Action, ActionError};
|
||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
||||
|
||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||
pub struct StartSystemdUnit {
|
||||
|
@ -15,7 +14,10 @@ pub struct StartSystemdUnit {
|
|||
impl StartSystemdUnit {
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub async fn plan(unit: String) -> Result<Self, StartSystemdUnitError> {
|
||||
Ok(Self { unit, action_state: ActionState::Planned })
|
||||
Ok(Self {
|
||||
unit,
|
||||
action_state: ActionState::Planned,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,7 +64,8 @@ impl Actionable for StartSystemdUnit {
|
|||
.arg("--now")
|
||||
.arg(format!("{unit}")),
|
||||
)
|
||||
.await.map_err(StartSystemdUnitError::Command)?;
|
||||
.await
|
||||
.map_err(StartSystemdUnitError::Command)?;
|
||||
|
||||
*action_state = ActionState::Completed;
|
||||
Ok(())
|
||||
|
@ -73,12 +76,9 @@ impl Actionable for StartSystemdUnit {
|
|||
let Self { unit, action_state } = self;
|
||||
|
||||
// TODO(@Hoverbear): Handle proxy vars
|
||||
execute_command(
|
||||
Command::new("systemctl")
|
||||
.arg("stop")
|
||||
.arg(format!("{unit}")),
|
||||
)
|
||||
.await.map_err(StartSystemdUnitError::Command)?;
|
||||
execute_command(Command::new("systemctl").arg("stop").arg(format!("{unit}")))
|
||||
.await
|
||||
.map_err(StartSystemdUnitError::Command)?;
|
||||
|
||||
*action_state = ActionState::Reverted;
|
||||
Ok(())
|
||||
|
@ -94,5 +94,9 @@ impl From<StartSystemdUnit> for Action {
|
|||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum StartSystemdUnitError {
|
||||
#[error("Failed to execute command")]
|
||||
Command(#[source] #[serde(serialize_with = "crate::serialize_error_to_display")] std::io::Error)
|
||||
Command(
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
std::io::Error,
|
||||
),
|
||||
}
|
||||
|
|
|
@ -2,12 +2,14 @@ use serde::Serialize;
|
|||
|
||||
use crate::actions::{
|
||||
base::{
|
||||
ConfigureNixDaemonService, ConfigureNixDaemonServiceError, PlaceNixConfiguration,
|
||||
PlaceNixConfigurationError, SetupDefaultProfile, SetupDefaultProfileError, PlaceChannelConfiguration, PlaceChannelConfigurationError,
|
||||
ConfigureNixDaemonService, ConfigureNixDaemonServiceError, PlaceChannelConfiguration,
|
||||
PlaceChannelConfigurationError, PlaceNixConfiguration, PlaceNixConfigurationError,
|
||||
SetupDefaultProfile, SetupDefaultProfileError,
|
||||
},
|
||||
meta::{ConfigureShellProfile, ConfigureShellProfileError}, ActionState, Action, ActionError,
|
||||
meta::{ConfigureShellProfile, ConfigureShellProfileError},
|
||||
Action, ActionState,
|
||||
};
|
||||
use crate::{HarmonicError, InstallSettings};
|
||||
use crate::InstallSettings;
|
||||
|
||||
use crate::actions::{ActionDescription, Actionable};
|
||||
|
||||
|
@ -39,8 +41,12 @@ impl ConfigureNix {
|
|||
};
|
||||
let place_channel_configuration =
|
||||
PlaceChannelConfiguration::plan(settings.channels, settings.force).await?;
|
||||
let place_nix_configuration =
|
||||
PlaceNixConfiguration::plan(settings.nix_build_group_name, settings.extra_conf, settings.force).await?;
|
||||
let place_nix_configuration = PlaceNixConfiguration::plan(
|
||||
settings.nix_build_group_name,
|
||||
settings.extra_conf,
|
||||
settings.force,
|
||||
)
|
||||
.await?;
|
||||
let configure_nix_daemon_service = ConfigureNixDaemonService::plan().await?;
|
||||
|
||||
Ok(Self {
|
||||
|
@ -91,16 +97,51 @@ impl Actionable for ConfigureNix {
|
|||
|
||||
if let Some(configure_shell_profile) = configure_shell_profile {
|
||||
tokio::try_join!(
|
||||
async move { setup_default_profile.execute().await.map_err(|e| ConfigureNixError::from(e)) },
|
||||
async move { place_nix_configuration.execute().await.map_err(|e| ConfigureNixError::from(e)) },
|
||||
async move { place_channel_configuration.execute().await.map_err(|e| ConfigureNixError::from(e)) },
|
||||
async move { configure_shell_profile.execute().await.map_err(|e| ConfigureNixError::from(e)) },
|
||||
async move {
|
||||
setup_default_profile
|
||||
.execute()
|
||||
.await
|
||||
.map_err(|e| ConfigureNixError::from(e))
|
||||
},
|
||||
async move {
|
||||
place_nix_configuration
|
||||
.execute()
|
||||
.await
|
||||
.map_err(|e| ConfigureNixError::from(e))
|
||||
},
|
||||
async move {
|
||||
place_channel_configuration
|
||||
.execute()
|
||||
.await
|
||||
.map_err(|e| ConfigureNixError::from(e))
|
||||
},
|
||||
async move {
|
||||
configure_shell_profile
|
||||
.execute()
|
||||
.await
|
||||
.map_err(|e| ConfigureNixError::from(e))
|
||||
},
|
||||
)?;
|
||||
} else {
|
||||
tokio::try_join!(
|
||||
async move { setup_default_profile.execute().await.map_err(|e| ConfigureNixError::from(e)) },
|
||||
async move { place_nix_configuration.execute().await.map_err(|e| ConfigureNixError::from(e)) },
|
||||
async move { place_channel_configuration.execute().await.map_err(|e| ConfigureNixError::from(e)) },
|
||||
async move {
|
||||
setup_default_profile
|
||||
.execute()
|
||||
.await
|
||||
.map_err(|e| ConfigureNixError::from(e))
|
||||
},
|
||||
async move {
|
||||
place_nix_configuration
|
||||
.execute()
|
||||
.await
|
||||
.map_err(|e| ConfigureNixError::from(e))
|
||||
},
|
||||
async move {
|
||||
place_channel_configuration
|
||||
.execute()
|
||||
.await
|
||||
.map_err(|e| ConfigureNixError::from(e))
|
||||
},
|
||||
)?;
|
||||
};
|
||||
configure_nix_daemon_service.execute().await?;
|
||||
|
@ -109,7 +150,6 @@ impl Actionable for ConfigureNix {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
||||
let Self {
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
use std::path::Path;
|
||||
|
||||
use serde::Serialize;
|
||||
use tokio::task::{JoinSet, JoinError};
|
||||
|
||||
use crate::HarmonicError;
|
||||
use tokio::task::{JoinError, JoinSet};
|
||||
|
||||
use crate::actions::base::{CreateOrAppendFile, CreateOrAppendFileError};
|
||||
use crate::actions::{ActionDescription, Actionable, ActionState, Action, ActionError};
|
||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
||||
|
||||
const PROFILE_TARGETS: &[&str] = &[
|
||||
"/etc/bashrc",
|
||||
|
@ -79,12 +77,17 @@ impl Actionable for ConfigureShellProfile {
|
|||
|
||||
for (idx, create_or_append_file) in create_or_append_files.iter().enumerate() {
|
||||
let mut create_or_append_file_clone = create_or_append_file.clone();
|
||||
let _abort_handle = set.spawn(async move { create_or_append_file_clone.execute().await?; Result::<_, CreateOrAppendFileError>::Ok((idx, create_or_append_file_clone)) });
|
||||
let _abort_handle = set.spawn(async move {
|
||||
create_or_append_file_clone.execute().await?;
|
||||
Result::<_, CreateOrAppendFileError>::Ok((idx, create_or_append_file_clone))
|
||||
});
|
||||
}
|
||||
|
||||
while let Some(result) = set.join_next().await {
|
||||
match result {
|
||||
Ok(Ok((idx, create_or_append_file))) => create_or_append_files[idx] = create_or_append_file,
|
||||
Ok(Ok((idx, create_or_append_file))) => {
|
||||
create_or_append_files[idx] = create_or_append_file
|
||||
},
|
||||
Ok(Err(e)) => errors.push(e),
|
||||
Err(e) => return Err(e.into()),
|
||||
};
|
||||
|
@ -94,7 +97,9 @@ impl Actionable for ConfigureShellProfile {
|
|||
if errors.len() == 1 {
|
||||
return Err(errors.into_iter().next().unwrap().into());
|
||||
} else {
|
||||
return Err(ConfigureShellProfileError::MultipleCreateOrAppendFile(errors));
|
||||
return Err(ConfigureShellProfileError::MultipleCreateOrAppendFile(
|
||||
errors,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,7 +107,6 @@ impl Actionable for ConfigureShellProfile {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
||||
let Self {
|
||||
|
@ -116,12 +120,17 @@ impl Actionable for ConfigureShellProfile {
|
|||
|
||||
for (idx, create_or_append_file) in create_or_append_files.iter().enumerate() {
|
||||
let mut create_or_append_file_clone = create_or_append_file.clone();
|
||||
let _abort_handle = set.spawn(async move { create_or_append_file_clone.revert().await?; Result::<_, CreateOrAppendFileError>::Ok((idx, create_or_append_file_clone)) });
|
||||
let _abort_handle = set.spawn(async move {
|
||||
create_or_append_file_clone.revert().await?;
|
||||
Result::<_, CreateOrAppendFileError>::Ok((idx, create_or_append_file_clone))
|
||||
});
|
||||
}
|
||||
|
||||
while let Some(result) = set.join_next().await {
|
||||
match result {
|
||||
Ok(Ok((idx, create_or_append_file))) => create_or_append_files[idx] = create_or_append_file,
|
||||
Ok(Ok((idx, create_or_append_file))) => {
|
||||
create_or_append_files[idx] = create_or_append_file
|
||||
},
|
||||
Ok(Err(e)) => errors.push(e),
|
||||
Err(e) => return Err(e.into()),
|
||||
};
|
||||
|
@ -131,7 +140,9 @@ impl Actionable for ConfigureShellProfile {
|
|||
if errors.len() == 1 {
|
||||
return Err(errors.into_iter().next().unwrap().into());
|
||||
} else {
|
||||
return Err(ConfigureShellProfileError::MultipleCreateOrAppendFile(errors));
|
||||
return Err(ConfigureShellProfileError::MultipleCreateOrAppendFile(
|
||||
errors,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,5 +164,9 @@ pub enum ConfigureShellProfileError {
|
|||
#[error("Multiple errors: {}", .0.iter().map(|v| format!("{v}")).collect::<Vec<_>>().join(" & "))]
|
||||
MultipleCreateOrAppendFile(Vec<CreateOrAppendFileError>),
|
||||
#[error(transparent)]
|
||||
Join(#[from] #[serde(serialize_with = "crate::serialize_error_to_display")] JoinError),
|
||||
Join(
|
||||
#[from]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
JoinError,
|
||||
),
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
use serde::Serialize;
|
||||
|
||||
use crate::HarmonicError;
|
||||
|
||||
use crate::actions::base::{CreateDirectory, CreateDirectoryError};
|
||||
use crate::actions::{ActionDescription, Actionable, ActionState, Action, ActionError};
|
||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
||||
|
||||
const PATHS: &[&str] = &[
|
||||
"/nix",
|
||||
|
@ -39,7 +37,10 @@ impl CreateNixTree {
|
|||
)
|
||||
}
|
||||
|
||||
Ok(Self { create_directories, action_state: ActionState::Planned })
|
||||
Ok(Self {
|
||||
create_directories,
|
||||
action_state: ActionState::Planned,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,15 +51,27 @@ impl Actionable for CreateNixTree {
|
|||
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(", ")),
|
||||
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)]
|
||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
||||
let Self { create_directories, action_state } = self;
|
||||
let Self {
|
||||
create_directories,
|
||||
action_state,
|
||||
} = self;
|
||||
|
||||
// Just do sequential since parallizing this will have little benefit
|
||||
for create_directory in create_directories {
|
||||
|
@ -69,10 +82,12 @@ impl Actionable for CreateNixTree {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
||||
let Self { create_directories, action_state } = self;
|
||||
let Self {
|
||||
create_directories,
|
||||
action_state,
|
||||
} = self;
|
||||
|
||||
// Just do sequential since parallizing this will have little benefit
|
||||
for create_directory in create_directories.iter_mut().rev() {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use serde::Serialize;
|
||||
use tokio::task::{JoinSet, JoinError};
|
||||
use tokio::task::{JoinError, JoinSet};
|
||||
|
||||
use crate::{HarmonicError, InstallSettings};
|
||||
use crate::InstallSettings;
|
||||
|
||||
use crate::actions::base::{CreateGroup, CreateGroupError, CreateUserError};
|
||||
use crate::actions::{ActionDescription, Actionable, CreateUser, ActionState, Action};
|
||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable, CreateUser};
|
||||
|
||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||
pub struct CreateUsersAndGroup {
|
||||
|
@ -89,7 +89,6 @@ impl Actionable for CreateUsersAndGroup {
|
|||
action_state,
|
||||
} = self;
|
||||
|
||||
|
||||
// Create group
|
||||
create_group.execute().await?;
|
||||
|
||||
|
@ -101,7 +100,10 @@ impl Actionable for CreateUsersAndGroup {
|
|||
|
||||
for (idx, create_user) in create_users.iter().enumerate() {
|
||||
let mut create_user_clone = create_user.clone();
|
||||
let _abort_handle = set.spawn(async move { create_user_clone.execute().await?; Result::<_, CreateUserError>::Ok((idx, create_user_clone)) });
|
||||
let _abort_handle = set.spawn(async move {
|
||||
create_user_clone.execute().await?;
|
||||
Result::<_, CreateUserError>::Ok((idx, create_user_clone))
|
||||
});
|
||||
}
|
||||
|
||||
while let Some(result) = set.join_next().await {
|
||||
|
@ -120,7 +122,6 @@ impl Actionable for CreateUsersAndGroup {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
*action_state = ActionState::Completed;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -146,7 +147,10 @@ impl Actionable for CreateUsersAndGroup {
|
|||
|
||||
for (idx, create_user) in create_users.iter().enumerate() {
|
||||
let mut create_user_clone = create_user.clone();
|
||||
let _abort_handle = set.spawn(async move { create_user_clone.revert().await?; Result::<_, CreateUserError>::Ok((idx, create_user_clone)) });
|
||||
let _abort_handle = set.spawn(async move {
|
||||
create_user_clone.revert().await?;
|
||||
Result::<_, CreateUserError>::Ok((idx, create_user_clone))
|
||||
});
|
||||
}
|
||||
|
||||
while let Some(result) = set.join_next().await {
|
||||
|
@ -173,14 +177,12 @@ impl Actionable for CreateUsersAndGroup {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl From<CreateUsersAndGroup> for Action {
|
||||
fn from(v: CreateUsersAndGroup) -> Self {
|
||||
Action::CreateUsersAndGroup(v)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum CreateUsersAndGroupError {
|
||||
#[error(transparent)]
|
||||
|
@ -193,7 +195,6 @@ pub enum CreateUsersAndGroupError {
|
|||
Join(
|
||||
#[from]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
JoinError
|
||||
JoinError,
|
||||
),
|
||||
}
|
||||
|
||||
|
|
|
@ -3,14 +3,11 @@ use tempdir::TempDir;
|
|||
use tokio::task::JoinError;
|
||||
|
||||
use crate::actions::base::{FetchNix, FetchNixError, MoveUnpackedNix, MoveUnpackedNixError};
|
||||
use crate::{HarmonicError, InstallSettings};
|
||||
use crate::InstallSettings;
|
||||
|
||||
use crate::actions::{ActionDescription, Actionable, ActionState, Action, ActionError};
|
||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
||||
|
||||
use super::{
|
||||
CreateNixTree, CreateNixTreeError,
|
||||
CreateUsersAndGroup, CreateUsersAndGroupError,
|
||||
};
|
||||
use super::{CreateNixTree, CreateNixTreeError, CreateUsersAndGroup, CreateUsersAndGroupError};
|
||||
|
||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||
pub struct ProvisionNix {
|
||||
|
@ -76,10 +73,16 @@ impl Actionable for ProvisionNix {
|
|||
|
||||
// We fetch nix while doing the rest, then move it over.
|
||||
let mut fetch_nix_clone = fetch_nix.clone();
|
||||
let fetch_nix_handle = tokio::task::spawn(async { fetch_nix_clone.execute().await?; Result::<_, Self::Error>::Ok(fetch_nix_clone) });
|
||||
let fetch_nix_handle = tokio::task::spawn(async {
|
||||
fetch_nix_clone.execute().await?;
|
||||
Result::<_, Self::Error>::Ok(fetch_nix_clone)
|
||||
});
|
||||
|
||||
create_users_and_group.execute().await?;
|
||||
create_nix_tree.execute().await.map_err(ProvisionNixError::from)?;
|
||||
create_nix_tree
|
||||
.execute()
|
||||
.await
|
||||
.map_err(ProvisionNixError::from)?;
|
||||
|
||||
*fetch_nix = fetch_nix_handle.await.map_err(ProvisionNixError::from)??;
|
||||
move_unpacked_nix.execute().await?;
|
||||
|
@ -100,10 +103,16 @@ impl Actionable for ProvisionNix {
|
|||
|
||||
// We fetch nix while doing the rest, then move it over.
|
||||
let mut fetch_nix_clone = fetch_nix.clone();
|
||||
let fetch_nix_handle = tokio::task::spawn(async { fetch_nix_clone.revert().await?; Result::<_, Self::Error>::Ok(fetch_nix_clone) });
|
||||
let fetch_nix_handle = tokio::task::spawn(async {
|
||||
fetch_nix_clone.revert().await?;
|
||||
Result::<_, Self::Error>::Ok(fetch_nix_clone)
|
||||
});
|
||||
|
||||
create_users_and_group.revert().await?;
|
||||
create_nix_tree.revert().await.map_err(ProvisionNixError::from)?;
|
||||
create_nix_tree
|
||||
.revert()
|
||||
.await
|
||||
.map_err(ProvisionNixError::from)?;
|
||||
|
||||
*fetch_nix = fetch_nix_handle.await.map_err(ProvisionNixError::from)??;
|
||||
move_unpacked_nix.revert().await?;
|
||||
|
@ -119,14 +128,13 @@ impl From<ProvisionNix> for Action {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum ProvisionNixError {
|
||||
#[error("Failed create tempdir")]
|
||||
TempDir(
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
std::io::Error
|
||||
std::io::Error,
|
||||
),
|
||||
#[error(transparent)]
|
||||
FetchNix(#[from] FetchNixError),
|
||||
|
@ -134,7 +142,7 @@ pub enum ProvisionNixError {
|
|||
Join(
|
||||
#[from]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
JoinError
|
||||
JoinError,
|
||||
),
|
||||
#[error(transparent)]
|
||||
CreateUsersAndGroup(#[from] CreateUsersAndGroupError),
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
use serde::Serialize;
|
||||
|
||||
use crate::actions::base::{StartSystemdUnit, StartSystemdUnitError};
|
||||
use crate::HarmonicError;
|
||||
|
||||
use crate::actions::{ActionDescription, Actionable, ActionState, Action, ActionError};
|
||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
||||
|
||||
/// This is mostly indirection for supporting non-systemd
|
||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||
|
@ -33,7 +32,10 @@ impl Actionable for StartNixDaemon {
|
|||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
||||
let Self { start_systemd_socket, action_state } = self;
|
||||
let Self {
|
||||
start_systemd_socket,
|
||||
action_state,
|
||||
} = self;
|
||||
|
||||
start_systemd_socket.execute().await?;
|
||||
|
||||
|
@ -43,7 +45,11 @@ impl Actionable for StartNixDaemon {
|
|||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
||||
let Self { start_systemd_socket, action_state, .. } = self;
|
||||
let Self {
|
||||
start_systemd_socket,
|
||||
action_state,
|
||||
..
|
||||
} = self;
|
||||
|
||||
start_systemd_socket.revert().await?;
|
||||
|
||||
|
@ -61,5 +67,5 @@ impl From<StartNixDaemon> for Action {
|
|||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum StartNixDaemonError {
|
||||
#[error(transparent)]
|
||||
StartSystemdUnit(#[from] StartSystemdUnitError)
|
||||
StartSystemdUnit(#[from] StartSystemdUnitError),
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
pub mod base;
|
||||
pub mod meta;
|
||||
|
||||
use std::{error::Error, fmt::Display};
|
||||
use std::error::Error;
|
||||
|
||||
use base::{
|
||||
ConfigureNixDaemonService, ConfigureNixDaemonServiceError, CreateDirectory,
|
||||
|
@ -13,11 +13,10 @@ use base::{
|
|||
};
|
||||
use meta::{
|
||||
ConfigureNix, ConfigureNixError, ConfigureShellProfile, ConfigureShellProfileError,
|
||||
CreateNixTree, CreateNixTreeError, CreateUsersAndGroup, CreateUsersAndGroupError,
|
||||
ProvisionNix, ProvisionNixError, StartNixDaemon, StartNixDaemonError,
|
||||
CreateNixTree, CreateNixTreeError, CreateUsersAndGroup, CreateUsersAndGroupError, ProvisionNix,
|
||||
ProvisionNixError, StartNixDaemon, StartNixDaemonError,
|
||||
};
|
||||
use serde::{Deserialize, de::DeserializeOwned, Serialize};
|
||||
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
|
||||
use self::base::{StartSystemdUnit, StartSystemdUnitError};
|
||||
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
use std::{process::ExitCode, path::PathBuf};
|
||||
use std::{path::PathBuf, process::ExitCode};
|
||||
|
||||
use clap::{ArgAction, Parser};
|
||||
use harmonic::InstallPlan;
|
||||
use eyre::WrapErr;
|
||||
use harmonic::InstallPlan;
|
||||
|
||||
use crate::{
|
||||
cli::CommandExecute,
|
||||
interaction,
|
||||
};
|
||||
use crate::{cli::CommandExecute, interaction};
|
||||
|
||||
/// An opinionated, experimental Nix installer
|
||||
#[derive(Debug, Parser)]
|
||||
|
@ -29,7 +26,9 @@ impl CommandExecute for Execute {
|
|||
async fn execute(self) -> eyre::Result<ExitCode> {
|
||||
let Self { no_confirm, plan } = self;
|
||||
|
||||
let install_plan_string = tokio::fs::read_to_string(plan).await.wrap_err("Reading plan")?;
|
||||
let install_plan_string = tokio::fs::read_to_string(plan)
|
||||
.await
|
||||
.wrap_err("Reading plan")?;
|
||||
let mut plan: InstallPlan = serde_json::from_str(&install_plan_string)?;
|
||||
|
||||
if !no_confirm {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use std::{process::ExitCode, path::PathBuf};
|
||||
use std::{path::PathBuf, process::ExitCode};
|
||||
|
||||
use clap::{ArgAction, Parser};
|
||||
use harmonic::{InstallPlan, InstallSettings};
|
||||
use tokio::io::AsyncWriteExt;
|
||||
|
||||
use eyre::WrapErr;
|
||||
|
||||
use crate::cli::{arg::ChannelValue, CommandExecute};
|
||||
|
@ -80,7 +80,9 @@ impl CommandExecute for Plan {
|
|||
let install_plan = InstallPlan::new(settings).await?;
|
||||
|
||||
let json = serde_json::to_string_pretty(&install_plan)?;
|
||||
tokio::fs::write(plan, json).await.wrap_err("Writing plan")?;
|
||||
tokio::fs::write(plan, json)
|
||||
.await
|
||||
.wrap_err("Writing plan")?;
|
||||
|
||||
Ok(ExitCode::SUCCESS)
|
||||
}
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
use std::{process::ExitCode, path::PathBuf};
|
||||
use std::{path::PathBuf, process::ExitCode};
|
||||
|
||||
use clap::{ArgAction, Parser};
|
||||
use harmonic::InstallPlan;
|
||||
use eyre::WrapErr;
|
||||
use harmonic::InstallPlan;
|
||||
|
||||
use crate::{
|
||||
cli::CommandExecute,
|
||||
interaction,
|
||||
};
|
||||
use crate::{cli::CommandExecute, interaction};
|
||||
|
||||
/// An opinionated, experimental Nix installer
|
||||
#[derive(Debug, Parser)]
|
||||
|
@ -27,9 +24,14 @@ pub(crate) struct Revert {
|
|||
impl CommandExecute for Revert {
|
||||
#[tracing::instrument(skip_all, fields())]
|
||||
async fn execute(self) -> eyre::Result<ExitCode> {
|
||||
let Self { no_confirm, receipt } = self;
|
||||
let Self {
|
||||
no_confirm,
|
||||
receipt,
|
||||
} = self;
|
||||
|
||||
let install_receipt_string = tokio::fs::read_to_string(receipt).await.wrap_err("Reading receipt")?;
|
||||
let install_receipt_string = tokio::fs::read_to_string(receipt)
|
||||
.await
|
||||
.wrap_err("Reading receipt")?;
|
||||
let mut plan: InstallPlan = serde_json::from_str(&install_receipt_string)?;
|
||||
|
||||
if !no_confirm {
|
||||
|
|
|
@ -5,7 +5,11 @@ use crate::actions::ActionError;
|
|||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum HarmonicError {
|
||||
#[error("Error executing action")]
|
||||
ActionError(#[source] #[from] ActionError),
|
||||
ActionError(
|
||||
#[source]
|
||||
#[from]
|
||||
ActionError,
|
||||
),
|
||||
#[error("Recording install receipt")]
|
||||
RecordingReceipt(PathBuf, #[source] std::io::Error),
|
||||
#[error(transparent)]
|
||||
|
|
39
src/lib.rs
39
src/lib.rs
|
@ -3,43 +3,26 @@ mod error;
|
|||
mod plan;
|
||||
mod settings;
|
||||
|
||||
use std::{
|
||||
ffi::OsStr,
|
||||
fs::Permissions,
|
||||
io::SeekFrom,
|
||||
os::unix::fs::PermissionsExt,
|
||||
path::{Path, PathBuf},
|
||||
process::ExitStatus, fmt::Display,
|
||||
};
|
||||
use std::{ffi::OsStr, fmt::Display, process::ExitStatus};
|
||||
|
||||
pub use error::HarmonicError;
|
||||
pub use plan::InstallPlan;
|
||||
use serde::Serializer;
|
||||
pub use settings::InstallSettings;
|
||||
|
||||
use bytes::Buf;
|
||||
use glob::glob;
|
||||
use reqwest::Url;
|
||||
use tempdir::TempDir;
|
||||
use tokio::{
|
||||
io::{AsyncSeekExt, AsyncWriteExt},
|
||||
process::Command,
|
||||
task::spawn_blocking,
|
||||
};
|
||||
|
||||
use tokio::process::Command;
|
||||
|
||||
#[tracing::instrument(skip_all, fields(command = %format!("{:?}", command.as_std())))]
|
||||
async fn execute_command(
|
||||
command: &mut Command,
|
||||
) -> Result<ExitStatus, std::io::Error> {
|
||||
async fn execute_command(command: &mut Command) -> Result<ExitStatus, std::io::Error> {
|
||||
tracing::trace!("Executing");
|
||||
let command_str = format!("{:?}", command.as_std());
|
||||
let status = command
|
||||
.status()
|
||||
.await?;
|
||||
let status = command.status().await?;
|
||||
match status.success() {
|
||||
true => Ok(status),
|
||||
false => Err(std::io::Error::new(std::io::ErrorKind::Other, format!("Command `{command_str}` failed status"))),
|
||||
false => Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!("Command `{command_str}` failed status"),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,6 +35,10 @@ fn set_env(k: impl AsRef<OsStr>, v: impl AsRef<OsStr>) {
|
|||
std::env::set_var(k.as_ref(), v.as_ref());
|
||||
}
|
||||
|
||||
fn serialize_error_to_display<E, S>(err: &E, ser: S) -> Result<S::Ok, S::Error> where E: Display, S: Serializer {
|
||||
fn serialize_error_to_display<E, S>(err: &E, ser: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
E: Display,
|
||||
S: Serializer,
|
||||
{
|
||||
ser.serialize_str(&format!("{err:#}"))
|
||||
}
|
45
src/plan.rs
45
src/plan.rs
|
@ -1,12 +1,9 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::fs::File;
|
||||
|
||||
use crate::{
|
||||
actions::{
|
||||
meta::{ConfigureNix, ProvisionNix, StartNixDaemon},
|
||||
Action, ActionDescription, Actionable, ActionState, ActionError,
|
||||
ActionDescription, ActionError, Actionable,
|
||||
},
|
||||
settings::InstallSettings,
|
||||
HarmonicError,
|
||||
|
@ -88,11 +85,14 @@ impl InstallPlan {
|
|||
pub async fn new(settings: InstallSettings) -> Result<Self, HarmonicError> {
|
||||
Ok(Self {
|
||||
settings: settings.clone(),
|
||||
provision_nix: ProvisionNix::plan(settings.clone()).await
|
||||
provision_nix: ProvisionNix::plan(settings.clone())
|
||||
.await
|
||||
.map_err(|e| ActionError::from(e))?,
|
||||
configure_nix: ConfigureNix::plan(settings).await
|
||||
configure_nix: ConfigureNix::plan(settings)
|
||||
.await
|
||||
.map_err(|e| ActionError::from(e))?,
|
||||
start_nix_daemon: StartNixDaemon::plan().await
|
||||
start_nix_daemon: StartNixDaemon::plan()
|
||||
.await
|
||||
.map_err(|e| ActionError::from(e))?,
|
||||
})
|
||||
}
|
||||
|
@ -102,17 +102,24 @@ impl InstallPlan {
|
|||
// This is **deliberately sequential**.
|
||||
// Actions which are parallelizable are represented by "group actions" like CreateUsers
|
||||
// The plan itself represents the concept of the sequence of stages.
|
||||
self.provision_nix.execute().await
|
||||
self.provision_nix
|
||||
.execute()
|
||||
.await
|
||||
.map_err(|e| ActionError::from(e))?;
|
||||
self.configure_nix.execute().await
|
||||
self.configure_nix
|
||||
.execute()
|
||||
.await
|
||||
.map_err(|e| ActionError::from(e))?;
|
||||
self.start_nix_daemon.execute().await
|
||||
self.start_nix_daemon
|
||||
.execute()
|
||||
.await
|
||||
.map_err(|e| ActionError::from(e))?;
|
||||
|
||||
let install_receipt_path = PathBuf::from("/nix/receipt.json");
|
||||
let self_json = serde_json::to_string_pretty(&self)
|
||||
.map_err(HarmonicError::SerializingReceipt)?;
|
||||
tokio::fs::write(&install_receipt_path, self_json).await
|
||||
let self_json =
|
||||
serde_json::to_string_pretty(&self).map_err(HarmonicError::SerializingReceipt)?;
|
||||
tokio::fs::write(&install_receipt_path, self_json)
|
||||
.await
|
||||
.map_err(|e| HarmonicError::RecordingReceipt(install_receipt_path, e))?;
|
||||
|
||||
Ok(())
|
||||
|
@ -123,11 +130,17 @@ impl InstallPlan {
|
|||
// This is **deliberately sequential**.
|
||||
// Actions which are parallelizable are represented by "group actions" like CreateUsers
|
||||
// The plan itself represents the concept of the sequence of stages.
|
||||
self.start_nix_daemon.revert().await
|
||||
self.start_nix_daemon
|
||||
.revert()
|
||||
.await
|
||||
.map_err(|e| ActionError::from(e))?;
|
||||
self.configure_nix.revert().await
|
||||
self.configure_nix
|
||||
.revert()
|
||||
.await
|
||||
.map_err(|e| ActionError::from(e))?;
|
||||
self.provision_nix.revert().await
|
||||
self.provision_nix
|
||||
.revert()
|
||||
.await
|
||||
.map_err(|e| ActionError::from(e))?;
|
||||
|
||||
Ok(())
|
||||
|
|
Loading…
Reference in a new issue