forked from lix-project/lix-installer
Box up errors, dyn Actionables
Signed-off-by: Ana Hobden <operator@hoverbear.org>
This commit is contained in:
parent
706af47714
commit
cc1cbe109a
|
@ -7,7 +7,7 @@ use tokio::process::Command;
|
||||||
|
|
||||||
use crate::execute_command;
|
use crate::execute_command;
|
||||||
|
|
||||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
use crate::actions::{ActionDescription, ActionError, ActionState, Actionable};
|
||||||
|
|
||||||
const SERVICE_SRC: &str = "/nix/var/nix/profiles/default/lib/systemd/system/nix-daemon.service";
|
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";
|
const SOCKET_SRC: &str = "/nix/var/nix/profiles/default/lib/systemd/system/nix-daemon.socket";
|
||||||
|
@ -21,7 +21,7 @@ pub struct ConfigureNixDaemonService {
|
||||||
|
|
||||||
impl ConfigureNixDaemonService {
|
impl ConfigureNixDaemonService {
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub async fn plan() -> Result<Self, ConfigureNixDaemonServiceError> {
|
pub async fn plan() -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
match OperatingSystem::host() {
|
match OperatingSystem::host() {
|
||||||
OperatingSystem::MacOSX {
|
OperatingSystem::MacOSX {
|
||||||
major: _,
|
major: _,
|
||||||
|
@ -31,7 +31,7 @@ impl ConfigureNixDaemonService {
|
||||||
| OperatingSystem::Darwin => (),
|
| OperatingSystem::Darwin => (),
|
||||||
_ => {
|
_ => {
|
||||||
if !Path::new("/run/systemd/system").exists() {
|
if !Path::new("/run/systemd/system").exists() {
|
||||||
return Err(ConfigureNixDaemonServiceError::InitNotSupported);
|
return Err(ConfigureNixDaemonServiceError::InitNotSupported.boxed());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -43,9 +43,8 @@ impl ConfigureNixDaemonService {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
#[typetag::serde(name = "configure-nix-daemon")]
|
||||||
impl Actionable for ConfigureNixDaemonService {
|
impl Actionable for ConfigureNixDaemonService {
|
||||||
type Error = ConfigureNixDaemonServiceError;
|
|
||||||
|
|
||||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||||
if self.action_state == ActionState::Completed {
|
if self.action_state == ActionState::Completed {
|
||||||
vec![]
|
vec![]
|
||||||
|
@ -63,7 +62,7 @@ impl Actionable for ConfigureNixDaemonService {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
async fn execute(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self { action_state } = self;
|
let Self { action_state } = self;
|
||||||
if *action_state == ActionState::Completed {
|
if *action_state == ActionState::Completed {
|
||||||
tracing::trace!("Already completed: Configuring nix daemon service");
|
tracing::trace!("Already completed: Configuring nix daemon service");
|
||||||
|
@ -85,11 +84,12 @@ impl Actionable for ConfigureNixDaemonService {
|
||||||
tokio::fs::copy(src.clone(), DARWIN_NIX_DAEMON_DEST)
|
tokio::fs::copy(src.clone(), DARWIN_NIX_DAEMON_DEST)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
Self::Error::Copy(
|
ConfigureNixDaemonServiceError::Copy(
|
||||||
src.to_path_buf(),
|
src.to_path_buf(),
|
||||||
PathBuf::from(DARWIN_NIX_DAEMON_DEST),
|
PathBuf::from(DARWIN_NIX_DAEMON_DEST),
|
||||||
e,
|
e,
|
||||||
)
|
)
|
||||||
|
.boxed()
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
execute_command(
|
execute_command(
|
||||||
|
@ -98,18 +98,19 @@ impl Actionable for ConfigureNixDaemonService {
|
||||||
.arg(DARWIN_NIX_DAEMON_DEST),
|
.arg(DARWIN_NIX_DAEMON_DEST),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::CommandFailed)?;
|
.map_err(|e| ConfigureNixDaemonServiceError::CommandFailed(e).boxed())?;
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
tracing::trace!(src = TMPFILES_SRC, dest = TMPFILES_DEST, "Symlinking");
|
tracing::trace!(src = TMPFILES_SRC, dest = TMPFILES_DEST, "Symlinking");
|
||||||
tokio::fs::symlink(TMPFILES_SRC, TMPFILES_DEST)
|
tokio::fs::symlink(TMPFILES_SRC, TMPFILES_DEST)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
Self::Error::Symlink(
|
ConfigureNixDaemonServiceError::Symlink(
|
||||||
PathBuf::from(TMPFILES_SRC),
|
PathBuf::from(TMPFILES_SRC),
|
||||||
PathBuf::from(TMPFILES_DEST),
|
PathBuf::from(TMPFILES_DEST),
|
||||||
e,
|
e,
|
||||||
)
|
)
|
||||||
|
.boxed()
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
execute_command(
|
execute_command(
|
||||||
|
@ -118,19 +119,19 @@ impl Actionable for ConfigureNixDaemonService {
|
||||||
.arg("--prefix=/nix/var/nix"),
|
.arg("--prefix=/nix/var/nix"),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::CommandFailed)?;
|
.map_err(|e| ConfigureNixDaemonServiceError::CommandFailed(e).boxed())?;
|
||||||
|
|
||||||
execute_command(Command::new("systemctl").arg("link").arg(SERVICE_SRC))
|
execute_command(Command::new("systemctl").arg("link").arg(SERVICE_SRC))
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::CommandFailed)?;
|
.map_err(|e| ConfigureNixDaemonServiceError::CommandFailed(e).boxed())?;
|
||||||
|
|
||||||
execute_command(Command::new("systemctl").arg("link").arg(SOCKET_SRC))
|
execute_command(Command::new("systemctl").arg("link").arg(SOCKET_SRC))
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::CommandFailed)?;
|
.map_err(|e| ConfigureNixDaemonServiceError::CommandFailed(e).boxed())?;
|
||||||
|
|
||||||
execute_command(Command::new("systemctl").arg("daemon-reload"))
|
execute_command(Command::new("systemctl").arg("daemon-reload"))
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::CommandFailed)?;
|
.map_err(|e| ConfigureNixDaemonServiceError::CommandFailed(e).boxed())?;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -156,7 +157,7 @@ impl Actionable for ConfigureNixDaemonService {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
async fn revert(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self { action_state } = self;
|
let Self { action_state } = self;
|
||||||
if *action_state == ActionState::Uncompleted {
|
if *action_state == ActionState::Uncompleted {
|
||||||
tracing::trace!("Already reverted: Unconfiguring nix daemon service");
|
tracing::trace!("Already reverted: Unconfiguring nix daemon service");
|
||||||
|
@ -167,11 +168,11 @@ impl Actionable for ConfigureNixDaemonService {
|
||||||
// We don't need to do this! Systemd does it for us! (In fact, it's an error if we try to do this...)
|
// 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]))
|
execute_command(Command::new("systemctl").args(["disable", SOCKET_SRC]))
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::CommandFailed)?;
|
.map_err(|e| ConfigureNixDaemonServiceError::CommandFailed(e).boxed())?;
|
||||||
|
|
||||||
execute_command(Command::new("systemctl").args(["disable", SERVICE_SRC]))
|
execute_command(Command::new("systemctl").args(["disable", SERVICE_SRC]))
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::CommandFailed)?;
|
.map_err(|e| ConfigureNixDaemonServiceError::CommandFailed(e).boxed())?;
|
||||||
|
|
||||||
execute_command(
|
execute_command(
|
||||||
Command::new("systemd-tmpfiles")
|
Command::new("systemd-tmpfiles")
|
||||||
|
@ -179,15 +180,15 @@ impl Actionable for ConfigureNixDaemonService {
|
||||||
.arg("--prefix=/nix/var/nix"),
|
.arg("--prefix=/nix/var/nix"),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::CommandFailed)?;
|
.map_err(|e| ConfigureNixDaemonServiceError::CommandFailed(e).boxed())?;
|
||||||
|
|
||||||
remove_file(TMPFILES_DEST)
|
remove_file(TMPFILES_DEST).await.map_err(|e| {
|
||||||
.await
|
ConfigureNixDaemonServiceError::RemoveFile(PathBuf::from(TMPFILES_DEST), e).boxed()
|
||||||
.map_err(|e| Self::Error::RemoveFile(PathBuf::from(TMPFILES_DEST), e))?;
|
})?;
|
||||||
|
|
||||||
execute_command(Command::new("systemctl").arg("daemon-reload"))
|
execute_command(Command::new("systemctl").arg("daemon-reload"))
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::CommandFailed)?;
|
.map_err(|e| ConfigureNixDaemonServiceError::CommandFailed(e).boxed())?;
|
||||||
|
|
||||||
tracing::trace!("Unconfigured nix daemon service");
|
tracing::trace!("Unconfigured nix daemon service");
|
||||||
*action_state = ActionState::Uncompleted;
|
*action_state = ActionState::Uncompleted;
|
||||||
|
@ -195,12 +196,6 @@ impl Actionable for ConfigureNixDaemonService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ConfigureNixDaemonService> for Action {
|
|
||||||
fn from(v: ConfigureNixDaemonService) -> Self {
|
|
||||||
Action::ConfigureNixDaemonService(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, Serialize)]
|
#[derive(Debug, thiserror::Error, Serialize)]
|
||||||
pub enum ConfigureNixDaemonServiceError {
|
pub enum ConfigureNixDaemonServiceError {
|
||||||
#[error("Symlinking from `{0}` to `{1}`")]
|
#[error("Symlinking from `{0}` to `{1}`")]
|
||||||
|
|
|
@ -5,7 +5,7 @@ use nix::unistd::{chown, Group, User};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use tokio::fs::{create_dir, remove_dir_all};
|
use tokio::fs::{create_dir, remove_dir_all};
|
||||||
|
|
||||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
use crate::actions::{ActionDescription, ActionError, ActionState, Actionable};
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||||
pub struct CreateDirectory {
|
pub struct CreateDirectory {
|
||||||
|
@ -25,16 +25,16 @@ impl CreateDirectory {
|
||||||
group: impl Into<Option<String>>,
|
group: impl Into<Option<String>>,
|
||||||
mode: impl Into<Option<u32>>,
|
mode: impl Into<Option<u32>>,
|
||||||
force_prune_on_revert: bool,
|
force_prune_on_revert: bool,
|
||||||
) -> Result<Self, CreateDirectoryError> {
|
) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
let user = user.into();
|
let user = user.into();
|
||||||
let group = group.into();
|
let group = group.into();
|
||||||
let mode = mode.into();
|
let mode = mode.into();
|
||||||
|
|
||||||
let action_state = if path.exists() {
|
let action_state = if path.exists() {
|
||||||
let metadata = tokio::fs::metadata(path)
|
let metadata = tokio::fs::metadata(path).await.map_err(|e| {
|
||||||
.await
|
CreateDirectoryError::GettingMetadata(path.to_path_buf(), e).boxed()
|
||||||
.map_err(|e| CreateDirectoryError::GettingMetadata(path.to_path_buf(), e))?;
|
})?;
|
||||||
if metadata.is_dir() {
|
if metadata.is_dir() {
|
||||||
// TODO: Validate owner/group...
|
// TODO: Validate owner/group...
|
||||||
ActionState::Completed
|
ActionState::Completed
|
||||||
|
@ -45,7 +45,8 @@ impl CreateDirectory {
|
||||||
"Path `{}` already exists and is not directory",
|
"Path `{}` already exists and is not directory",
|
||||||
path.display()
|
path.display()
|
||||||
),
|
),
|
||||||
)));
|
))
|
||||||
|
.boxed());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ActionState::Uncompleted
|
ActionState::Uncompleted
|
||||||
|
@ -63,9 +64,8 @@ impl CreateDirectory {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
#[typetag::serde(name = "create-directory")]
|
||||||
impl Actionable for CreateDirectory {
|
impl Actionable for CreateDirectory {
|
||||||
type Error = CreateDirectoryError;
|
|
||||||
|
|
||||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||||
let Self {
|
let Self {
|
||||||
path,
|
path,
|
||||||
|
@ -91,7 +91,7 @@ impl Actionable for CreateDirectory {
|
||||||
group = self.group,
|
group = self.group,
|
||||||
mode = self.mode.map(|v| tracing::field::display(format!("{:#o}", v))),
|
mode = self.mode.map(|v| tracing::field::display(format!("{:#o}", v))),
|
||||||
))]
|
))]
|
||||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
async fn execute(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
path,
|
path,
|
||||||
user,
|
user,
|
||||||
|
@ -109,8 +109,8 @@ impl Actionable for CreateDirectory {
|
||||||
let gid = if let Some(group) = group {
|
let gid = if let Some(group) = group {
|
||||||
Some(
|
Some(
|
||||||
Group::from_name(group.as_str())
|
Group::from_name(group.as_str())
|
||||||
.map_err(|e| Self::Error::GroupId(group.clone(), e))?
|
.map_err(|e| CreateDirectoryError::GroupId(group.clone(), e).boxed())?
|
||||||
.ok_or(Self::Error::NoGroup(group.clone()))?
|
.ok_or(CreateDirectoryError::NoGroup(group.clone()).boxed())?
|
||||||
.gid,
|
.gid,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
@ -119,8 +119,8 @@ impl Actionable for CreateDirectory {
|
||||||
let uid = if let Some(user) = user {
|
let uid = if let Some(user) = user {
|
||||||
Some(
|
Some(
|
||||||
User::from_name(user.as_str())
|
User::from_name(user.as_str())
|
||||||
.map_err(|e| Self::Error::UserId(user.clone(), e))?
|
.map_err(|e| CreateDirectoryError::UserId(user.clone(), e).boxed())?
|
||||||
.ok_or(Self::Error::NoUser(user.clone()))?
|
.ok_or(CreateDirectoryError::NoUser(user.clone()).boxed())?
|
||||||
.uid,
|
.uid,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
@ -129,13 +129,15 @@ impl Actionable for CreateDirectory {
|
||||||
|
|
||||||
create_dir(path.clone())
|
create_dir(path.clone())
|
||||||
.await
|
.await
|
||||||
.map_err(|e| Self::Error::Creating(path.clone(), e))?;
|
.map_err(|e| CreateDirectoryError::Creating(path.clone(), e).boxed())?;
|
||||||
chown(path, uid, gid).map_err(|e| Self::Error::Chown(path.clone(), e))?;
|
chown(path, uid, gid).map_err(|e| CreateDirectoryError::Chown(path.clone(), e).boxed())?;
|
||||||
|
|
||||||
if let Some(mode) = mode {
|
if let Some(mode) = mode {
|
||||||
tokio::fs::set_permissions(&path, PermissionsExt::from_mode(*mode))
|
tokio::fs::set_permissions(&path, PermissionsExt::from_mode(*mode))
|
||||||
.await
|
.await
|
||||||
.map_err(|e| Self::Error::SetPermissions(*mode, path.to_owned(), e))?;
|
.map_err(|e| {
|
||||||
|
CreateDirectoryError::SetPermissions(*mode, path.to_owned(), e).boxed()
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing::trace!("Created directory");
|
tracing::trace!("Created directory");
|
||||||
|
@ -176,7 +178,7 @@ impl Actionable for CreateDirectory {
|
||||||
group = self.group,
|
group = self.group,
|
||||||
mode = self.mode.map(|v| tracing::field::display(format!("{:#o}", v))),
|
mode = self.mode.map(|v| tracing::field::display(format!("{:#o}", v))),
|
||||||
))]
|
))]
|
||||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
async fn revert(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
path,
|
path,
|
||||||
user: _,
|
user: _,
|
||||||
|
@ -195,13 +197,13 @@ impl Actionable for CreateDirectory {
|
||||||
|
|
||||||
let is_empty = path
|
let is_empty = path
|
||||||
.read_dir()
|
.read_dir()
|
||||||
.map_err(|e| CreateDirectoryError::ReadDir(path.clone(), e))?
|
.map_err(|e| CreateDirectoryError::ReadDir(path.clone(), e).boxed())?
|
||||||
.next()
|
.next()
|
||||||
.is_some();
|
.is_some();
|
||||||
match (is_empty, force_prune_on_revert) {
|
match (is_empty, force_prune_on_revert) {
|
||||||
(true, _) | (false, true) => remove_dir_all(path.clone())
|
(true, _) | (false, true) => remove_dir_all(path.clone())
|
||||||
.await
|
.await
|
||||||
.map_err(|e| Self::Error::Removing(path.clone(), e))?,
|
.map_err(|e| CreateDirectoryError::Removing(path.clone(), e).boxed())?,
|
||||||
(false, false) => {},
|
(false, false) => {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -211,12 +213,6 @@ impl Actionable for CreateDirectory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<CreateDirectory> for Action {
|
|
||||||
fn from(v: CreateDirectory) -> Self {
|
|
||||||
Action::CreateDirectory(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, Serialize)]
|
#[derive(Debug, thiserror::Error, Serialize)]
|
||||||
pub enum CreateDirectoryError {
|
pub enum CreateDirectoryError {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
|
|
|
@ -6,7 +6,7 @@ use tokio::{
|
||||||
io::AsyncWriteExt,
|
io::AsyncWriteExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::actions::{Action, ActionState};
|
use crate::actions::{ActionError, ActionState};
|
||||||
|
|
||||||
use crate::actions::{ActionDescription, Actionable};
|
use crate::actions::{ActionDescription, Actionable};
|
||||||
|
|
||||||
|
@ -30,11 +30,11 @@ impl CreateFile {
|
||||||
mode: impl Into<Option<u32>>,
|
mode: impl Into<Option<u32>>,
|
||||||
buf: String,
|
buf: String,
|
||||||
force: bool,
|
force: bool,
|
||||||
) -> Result<Self, CreateFileError> {
|
) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let path = path.as_ref().to_path_buf();
|
let path = path.as_ref().to_path_buf();
|
||||||
|
|
||||||
if path.exists() && !force {
|
if path.exists() && !force {
|
||||||
return Err(CreateFileError::Exists(path.to_path_buf()));
|
return Err(CreateFileError::Exists(path.to_path_buf()).boxed());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
@ -50,9 +50,8 @@ impl CreateFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
#[typetag::serde(name = "create-file")]
|
||||||
impl Actionable for CreateFile {
|
impl Actionable for CreateFile {
|
||||||
type Error = CreateFileError;
|
|
||||||
|
|
||||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||||
let Self {
|
let Self {
|
||||||
path,
|
path,
|
||||||
|
@ -79,7 +78,7 @@ impl Actionable for CreateFile {
|
||||||
group = self.group,
|
group = self.group,
|
||||||
mode = self.mode.map(|v| tracing::field::display(format!("{:#o}", v))),
|
mode = self.mode.map(|v| tracing::field::display(format!("{:#o}", v))),
|
||||||
))]
|
))]
|
||||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
async fn execute(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
path,
|
path,
|
||||||
user,
|
user,
|
||||||
|
@ -105,17 +104,17 @@ impl Actionable for CreateFile {
|
||||||
let mut file = options
|
let mut file = options
|
||||||
.open(&path)
|
.open(&path)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| Self::Error::OpenFile(path.to_owned(), e))?;
|
.map_err(|e| CreateFileError::OpenFile(path.to_owned(), e).boxed())?;
|
||||||
|
|
||||||
file.write_all(buf.as_bytes())
|
file.write_all(buf.as_bytes())
|
||||||
.await
|
.await
|
||||||
.map_err(|e| Self::Error::WriteFile(path.to_owned(), e))?;
|
.map_err(|e| CreateFileError::WriteFile(path.to_owned(), e).boxed())?;
|
||||||
|
|
||||||
let gid = if let Some(group) = group {
|
let gid = if let Some(group) = group {
|
||||||
Some(
|
Some(
|
||||||
Group::from_name(group.as_str())
|
Group::from_name(group.as_str())
|
||||||
.map_err(|e| Self::Error::GroupId(group.clone(), e))?
|
.map_err(|e| CreateFileError::GroupId(group.clone(), e).boxed())?
|
||||||
.ok_or(Self::Error::NoGroup(group.clone()))?
|
.ok_or(CreateFileError::NoGroup(group.clone()).boxed())?
|
||||||
.gid,
|
.gid,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
@ -124,14 +123,14 @@ impl Actionable for CreateFile {
|
||||||
let uid = if let Some(user) = user {
|
let uid = if let Some(user) = user {
|
||||||
Some(
|
Some(
|
||||||
User::from_name(user.as_str())
|
User::from_name(user.as_str())
|
||||||
.map_err(|e| Self::Error::UserId(user.clone(), e))?
|
.map_err(|e| CreateFileError::UserId(user.clone(), e).boxed())?
|
||||||
.ok_or(Self::Error::NoUser(user.clone()))?
|
.ok_or(CreateFileError::NoUser(user.clone()).boxed())?
|
||||||
.uid,
|
.uid,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
chown(path, uid, gid).map_err(|e| Self::Error::Chown(path.clone(), e))?;
|
chown(path, uid, gid).map_err(|e| CreateFileError::Chown(path.clone(), e).boxed())?;
|
||||||
|
|
||||||
tracing::trace!("Created file");
|
tracing::trace!("Created file");
|
||||||
*action_state = ActionState::Completed;
|
*action_state = ActionState::Completed;
|
||||||
|
@ -164,7 +163,7 @@ impl Actionable for CreateFile {
|
||||||
group = self.group,
|
group = self.group,
|
||||||
mode = self.mode.map(|v| tracing::field::display(format!("{:#o}", v))),
|
mode = self.mode.map(|v| tracing::field::display(format!("{:#o}", v))),
|
||||||
))]
|
))]
|
||||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
async fn revert(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
path,
|
path,
|
||||||
user: _,
|
user: _,
|
||||||
|
@ -182,7 +181,7 @@ impl Actionable for CreateFile {
|
||||||
|
|
||||||
remove_file(&path)
|
remove_file(&path)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| Self::Error::RemoveFile(path.to_owned(), e))?;
|
.map_err(|e| CreateFileError::RemoveFile(path.to_owned(), e).boxed())?;
|
||||||
|
|
||||||
tracing::trace!("Deleted file");
|
tracing::trace!("Deleted file");
|
||||||
*action_state = ActionState::Uncompleted;
|
*action_state = ActionState::Uncompleted;
|
||||||
|
@ -190,12 +189,6 @@ impl Actionable for CreateFile {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<CreateFile> for Action {
|
|
||||||
fn from(v: CreateFile) -> Self {
|
|
||||||
Action::CreateFile(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, Serialize)]
|
#[derive(Debug, thiserror::Error, Serialize)]
|
||||||
pub enum CreateFileError {
|
pub enum CreateFileError {
|
||||||
#[error("File exists `{0}`")]
|
#[error("File exists `{0}`")]
|
||||||
|
|
|
@ -3,7 +3,7 @@ use tokio::process::Command;
|
||||||
|
|
||||||
use crate::execute_command;
|
use crate::execute_command;
|
||||||
|
|
||||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
use crate::actions::{ActionDescription, ActionError, ActionState, Actionable};
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||||
pub struct CreateGroup {
|
pub struct CreateGroup {
|
||||||
|
@ -24,9 +24,8 @@ impl CreateGroup {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
#[typetag::serde(name = "create-group")]
|
||||||
impl Actionable for CreateGroup {
|
impl Actionable for CreateGroup {
|
||||||
type Error = CreateGroupError;
|
|
||||||
|
|
||||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||||
let Self {
|
let Self {
|
||||||
name,
|
name,
|
||||||
|
@ -49,7 +48,7 @@ impl Actionable for CreateGroup {
|
||||||
user = self.name,
|
user = self.name,
|
||||||
gid = self.gid,
|
gid = self.gid,
|
||||||
))]
|
))]
|
||||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
async fn execute(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
name,
|
name,
|
||||||
gid,
|
gid,
|
||||||
|
@ -79,7 +78,7 @@ impl Actionable for CreateGroup {
|
||||||
name.as_str(),
|
name.as_str(),
|
||||||
]))
|
]))
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::Command)?;
|
.map_err(|e| CreateGroupError::Command(e).boxed())?;
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
execute_command(Command::new("groupadd").args([
|
execute_command(Command::new("groupadd").args([
|
||||||
|
@ -89,7 +88,7 @@ impl Actionable for CreateGroup {
|
||||||
&name,
|
&name,
|
||||||
]))
|
]))
|
||||||
.await
|
.await
|
||||||
.map_err(CreateGroupError::Command)?;
|
.map_err(|e| CreateGroupError::Command(e).boxed())?;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -120,7 +119,7 @@ impl Actionable for CreateGroup {
|
||||||
user = self.name,
|
user = self.name,
|
||||||
gid = self.gid,
|
gid = self.gid,
|
||||||
))]
|
))]
|
||||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
async fn revert(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
name,
|
name,
|
||||||
gid: _,
|
gid: _,
|
||||||
|
@ -142,12 +141,12 @@ impl Actionable for CreateGroup {
|
||||||
| OperatingSystem::Darwin => {
|
| OperatingSystem::Darwin => {
|
||||||
execute_command(Command::new("groupdel").arg(&name))
|
execute_command(Command::new("groupdel").arg(&name))
|
||||||
.await
|
.await
|
||||||
.map_err(CreateGroupError::Command)?;
|
.map_err(|e| CreateGroupError::Command(e).boxed())?;
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
execute_command(Command::new("userdel").args([&name.to_string()]))
|
execute_command(Command::new("groupdel").arg(&name))
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::Command)?;
|
.map_err(|e| CreateGroupError::Command(e).boxed())?;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -157,12 +156,6 @@ impl Actionable for CreateGroup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<CreateGroup> for Action {
|
|
||||||
fn from(v: CreateGroup) -> Self {
|
|
||||||
Action::CreateGroup(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, Serialize)]
|
#[derive(Debug, thiserror::Error, Serialize)]
|
||||||
pub enum CreateGroupError {
|
pub enum CreateGroupError {
|
||||||
#[error("Failed to execute command")]
|
#[error("Failed to execute command")]
|
||||||
|
|
|
@ -10,7 +10,7 @@ use tokio::{
|
||||||
io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt},
|
io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::actions::{Action, ActionState};
|
use crate::actions::{ActionError, ActionState};
|
||||||
|
|
||||||
use crate::actions::{ActionDescription, Actionable};
|
use crate::actions::{ActionDescription, Actionable};
|
||||||
|
|
||||||
|
@ -47,9 +47,8 @@ impl CreateOrAppendFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
#[typetag::serde(name = "create-or-append-file")]
|
||||||
impl Actionable for CreateOrAppendFile {
|
impl Actionable for CreateOrAppendFile {
|
||||||
type Error = CreateOrAppendFileError;
|
|
||||||
|
|
||||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||||
let Self {
|
let Self {
|
||||||
path,
|
path,
|
||||||
|
@ -75,7 +74,7 @@ impl Actionable for CreateOrAppendFile {
|
||||||
group = self.group,
|
group = self.group,
|
||||||
mode = self.mode.map(|v| tracing::field::display(format!("{:#o}", v))),
|
mode = self.mode.map(|v| tracing::field::display(format!("{:#o}", v))),
|
||||||
))]
|
))]
|
||||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
async fn execute(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
path,
|
path,
|
||||||
user,
|
user,
|
||||||
|
@ -96,21 +95,21 @@ impl Actionable for CreateOrAppendFile {
|
||||||
.read(true)
|
.read(true)
|
||||||
.open(&path)
|
.open(&path)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| Self::Error::OpenFile(path.to_owned(), e))?;
|
.map_err(|e| CreateOrAppendFileError::OpenFile(path.to_owned(), e).boxed())?;
|
||||||
|
|
||||||
file.seek(SeekFrom::End(0))
|
file.seek(SeekFrom::End(0))
|
||||||
.await
|
.await
|
||||||
.map_err(|e| Self::Error::SeekFile(path.to_owned(), e))?;
|
.map_err(|e| CreateOrAppendFileError::SeekFile(path.to_owned(), e).boxed())?;
|
||||||
|
|
||||||
file.write_all(buf.as_bytes())
|
file.write_all(buf.as_bytes())
|
||||||
.await
|
.await
|
||||||
.map_err(|e| Self::Error::WriteFile(path.to_owned(), e))?;
|
.map_err(|e| CreateOrAppendFileError::WriteFile(path.to_owned(), e).boxed())?;
|
||||||
|
|
||||||
let gid = if let Some(group) = group {
|
let gid = if let Some(group) = group {
|
||||||
Some(
|
Some(
|
||||||
Group::from_name(group.as_str())
|
Group::from_name(group.as_str())
|
||||||
.map_err(|e| Self::Error::GroupId(group.clone(), e))?
|
.map_err(|e| CreateOrAppendFileError::GroupId(group.clone(), e).boxed())?
|
||||||
.ok_or(Self::Error::NoGroup(group.clone()))?
|
.ok_or(CreateOrAppendFileError::NoGroup(group.clone()).boxed())?
|
||||||
.gid,
|
.gid,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
@ -119,8 +118,8 @@ impl Actionable for CreateOrAppendFile {
|
||||||
let uid = if let Some(user) = user {
|
let uid = if let Some(user) = user {
|
||||||
Some(
|
Some(
|
||||||
User::from_name(user.as_str())
|
User::from_name(user.as_str())
|
||||||
.map_err(|e| Self::Error::UserId(user.clone(), e))?
|
.map_err(|e| CreateOrAppendFileError::UserId(user.clone(), e).boxed())?
|
||||||
.ok_or(Self::Error::NoUser(user.clone()))?
|
.ok_or(CreateOrAppendFileError::NoUser(user.clone()).boxed())?
|
||||||
.uid,
|
.uid,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
@ -130,10 +129,13 @@ impl Actionable for CreateOrAppendFile {
|
||||||
if let Some(mode) = mode {
|
if let Some(mode) = mode {
|
||||||
tokio::fs::set_permissions(&path, PermissionsExt::from_mode(*mode))
|
tokio::fs::set_permissions(&path, PermissionsExt::from_mode(*mode))
|
||||||
.await
|
.await
|
||||||
.map_err(|e| Self::Error::SetPermissions(*mode, path.to_owned(), e))?;
|
.map_err(|e| {
|
||||||
|
CreateOrAppendFileError::SetPermissions(*mode, path.to_owned(), e).boxed()
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
chown(path, uid, gid).map_err(|e| Self::Error::Chown(path.clone(), e))?;
|
chown(path, uid, gid)
|
||||||
|
.map_err(|e| CreateOrAppendFileError::Chown(path.clone(), e).boxed())?;
|
||||||
|
|
||||||
tracing::trace!("Created or appended fragment to file");
|
tracing::trace!("Created or appended fragment to file");
|
||||||
*action_state = ActionState::Completed;
|
*action_state = ActionState::Completed;
|
||||||
|
@ -168,7 +170,7 @@ impl Actionable for CreateOrAppendFile {
|
||||||
group = self.group,
|
group = self.group,
|
||||||
mode = self.mode.map(|v| tracing::field::display(format!("{:#o}", v))),
|
mode = self.mode.map(|v| tracing::field::display(format!("{:#o}", v))),
|
||||||
))]
|
))]
|
||||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
async fn revert(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
path,
|
path,
|
||||||
user: _,
|
user: _,
|
||||||
|
@ -189,12 +191,12 @@ impl Actionable for CreateOrAppendFile {
|
||||||
.read(true)
|
.read(true)
|
||||||
.open(&path)
|
.open(&path)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| Self::Error::ReadFile(path.to_owned(), e))?;
|
.map_err(|e| CreateOrAppendFileError::ReadFile(path.to_owned(), e).boxed())?;
|
||||||
|
|
||||||
let mut file_contents = String::default();
|
let mut file_contents = String::default();
|
||||||
file.read_to_string(&mut file_contents)
|
file.read_to_string(&mut file_contents)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| Self::Error::SeekFile(path.to_owned(), e))?;
|
.map_err(|e| CreateOrAppendFileError::SeekFile(path.to_owned(), e).boxed())?;
|
||||||
|
|
||||||
if let Some(start) = file_contents.rfind(buf.as_str()) {
|
if let Some(start) = file_contents.rfind(buf.as_str()) {
|
||||||
let end = start + buf.len();
|
let end = start + buf.len();
|
||||||
|
@ -204,16 +206,16 @@ impl Actionable for CreateOrAppendFile {
|
||||||
if buf.is_empty() {
|
if buf.is_empty() {
|
||||||
remove_file(&path)
|
remove_file(&path)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| Self::Error::RemoveFile(path.to_owned(), e))?;
|
.map_err(|e| CreateOrAppendFileError::RemoveFile(path.to_owned(), e).boxed())?;
|
||||||
|
|
||||||
tracing::trace!("Removed file (since all content was removed)");
|
tracing::trace!("Removed file (since all content was removed)");
|
||||||
} else {
|
} else {
|
||||||
file.seek(SeekFrom::Start(0))
|
file.seek(SeekFrom::Start(0))
|
||||||
.await
|
.await
|
||||||
.map_err(|e| Self::Error::SeekFile(path.to_owned(), e))?;
|
.map_err(|e| CreateOrAppendFileError::SeekFile(path.to_owned(), e).boxed())?;
|
||||||
file.write_all(file_contents.as_bytes())
|
file.write_all(file_contents.as_bytes())
|
||||||
.await
|
.await
|
||||||
.map_err(|e| Self::Error::WriteFile(path.to_owned(), e))?;
|
.map_err(|e| CreateOrAppendFileError::WriteFile(path.to_owned(), e).boxed())?;
|
||||||
|
|
||||||
tracing::trace!("Removed fragment from from file");
|
tracing::trace!("Removed fragment from from file");
|
||||||
}
|
}
|
||||||
|
@ -222,12 +224,6 @@ impl Actionable for CreateOrAppendFile {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<CreateOrAppendFile> for Action {
|
|
||||||
fn from(v: CreateOrAppendFile) -> Self {
|
|
||||||
Action::CreateOrAppendFile(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, Serialize)]
|
#[derive(Debug, thiserror::Error, Serialize)]
|
||||||
pub enum CreateOrAppendFileError {
|
pub enum CreateOrAppendFileError {
|
||||||
#[error("Remove file `{0}`")]
|
#[error("Remove file `{0}`")]
|
||||||
|
|
|
@ -3,7 +3,7 @@ use tokio::process::Command;
|
||||||
|
|
||||||
use crate::execute_command;
|
use crate::execute_command;
|
||||||
|
|
||||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
use crate::actions::{ActionDescription, ActionError, ActionState, Actionable};
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||||
pub struct CreateUser {
|
pub struct CreateUser {
|
||||||
|
@ -28,9 +28,8 @@ impl CreateUser {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
#[typetag::serde(name = "create-user")]
|
||||||
impl Actionable for CreateUser {
|
impl Actionable for CreateUser {
|
||||||
type Error = CreateUserError;
|
|
||||||
|
|
||||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||||
if self.action_state == ActionState::Completed {
|
if self.action_state == ActionState::Completed {
|
||||||
vec![]
|
vec![]
|
||||||
|
@ -58,7 +57,7 @@ impl Actionable for CreateUser {
|
||||||
groupname = self.groupname,
|
groupname = self.groupname,
|
||||||
gid = self.gid,
|
gid = self.gid,
|
||||||
))]
|
))]
|
||||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
async fn execute(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
name,
|
name,
|
||||||
uid,
|
uid,
|
||||||
|
@ -86,7 +85,7 @@ impl Actionable for CreateUser {
|
||||||
&format!("/Users/{name}"),
|
&format!("/Users/{name}"),
|
||||||
]))
|
]))
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::Command)?;
|
.map_err(|e| CreateUserError::Command(e).boxed())?;
|
||||||
execute_command(Command::new("/usr/bin/dscl").args([
|
execute_command(Command::new("/usr/bin/dscl").args([
|
||||||
".",
|
".",
|
||||||
"-create",
|
"-create",
|
||||||
|
@ -95,7 +94,7 @@ impl Actionable for CreateUser {
|
||||||
&format!("{uid}"),
|
&format!("{uid}"),
|
||||||
]))
|
]))
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::Command)?;
|
.map_err(|e| CreateUserError::Command(e).boxed())?;
|
||||||
execute_command(Command::new("/usr/bin/dscl").args([
|
execute_command(Command::new("/usr/bin/dscl").args([
|
||||||
".",
|
".",
|
||||||
"-create",
|
"-create",
|
||||||
|
@ -104,7 +103,7 @@ impl Actionable for CreateUser {
|
||||||
&format!("{gid}"),
|
&format!("{gid}"),
|
||||||
]))
|
]))
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::Command)?;
|
.map_err(|e| CreateUserError::Command(e).boxed())?;
|
||||||
execute_command(Command::new("/usr/bin/dscl").args([
|
execute_command(Command::new("/usr/bin/dscl").args([
|
||||||
".",
|
".",
|
||||||
"-create",
|
"-create",
|
||||||
|
@ -113,7 +112,7 @@ impl Actionable for CreateUser {
|
||||||
"/var/empty",
|
"/var/empty",
|
||||||
]))
|
]))
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::Command)?;
|
.map_err(|e| CreateUserError::Command(e).boxed())?;
|
||||||
execute_command(Command::new("/usr/bin/dscl").args([
|
execute_command(Command::new("/usr/bin/dscl").args([
|
||||||
".",
|
".",
|
||||||
"-create",
|
"-create",
|
||||||
|
@ -122,7 +121,7 @@ impl Actionable for CreateUser {
|
||||||
"/sbin/nologin",
|
"/sbin/nologin",
|
||||||
]))
|
]))
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::Command)?;
|
.map_err(|e| CreateUserError::Command(e).boxed())?;
|
||||||
execute_command(
|
execute_command(
|
||||||
Command::new("/usr/bin/dscl")
|
Command::new("/usr/bin/dscl")
|
||||||
.args([
|
.args([
|
||||||
|
@ -134,7 +133,7 @@ impl Actionable for CreateUser {
|
||||||
.arg(&name),
|
.arg(&name),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::Command)?;
|
.map_err(|e| CreateUserError::Command(e).boxed())?;
|
||||||
execute_command(Command::new("/usr/bin/dscl").args([
|
execute_command(Command::new("/usr/bin/dscl").args([
|
||||||
".",
|
".",
|
||||||
"-create",
|
"-create",
|
||||||
|
@ -143,7 +142,7 @@ impl Actionable for CreateUser {
|
||||||
"1",
|
"1",
|
||||||
]))
|
]))
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::Command)?;
|
.map_err(|e| CreateUserError::Command(e).boxed())?;
|
||||||
execute_command(
|
execute_command(
|
||||||
Command::new("/usr/sbin/dseditgroup")
|
Command::new("/usr/sbin/dseditgroup")
|
||||||
.args(["-o", "edit"])
|
.args(["-o", "edit"])
|
||||||
|
@ -154,7 +153,7 @@ impl Actionable for CreateUser {
|
||||||
.arg(groupname),
|
.arg(groupname),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::Command)?;
|
.map_err(|e| CreateUserError::Command(e).boxed())?;
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
execute_command(Command::new("useradd").args([
|
execute_command(Command::new("useradd").args([
|
||||||
|
@ -177,7 +176,7 @@ impl Actionable for CreateUser {
|
||||||
&name.to_string(),
|
&name.to_string(),
|
||||||
]))
|
]))
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::Command)?;
|
.map_err(|e| CreateUserError::Command(e).boxed())?;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +211,7 @@ impl Actionable for CreateUser {
|
||||||
uid = self.uid,
|
uid = self.uid,
|
||||||
gid = self.gid,
|
gid = self.gid,
|
||||||
))]
|
))]
|
||||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
async fn revert(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
name,
|
name,
|
||||||
uid: _,
|
uid: _,
|
||||||
|
@ -240,12 +239,12 @@ impl Actionable for CreateUser {
|
||||||
&format!("/Users/{name}"),
|
&format!("/Users/{name}"),
|
||||||
]))
|
]))
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::Command)?;
|
.map_err(|e| CreateUserError::Command(e).boxed())?;
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
execute_command(Command::new("userdel").args([&name.to_string()]))
|
execute_command(Command::new("userdel").args([&name.to_string()]))
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::Command)?;
|
.map_err(|e| CreateUserError::Command(e).boxed())?;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -255,12 +254,6 @@ impl Actionable for CreateUser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<CreateUser> for Action {
|
|
||||||
fn from(v: CreateUser) -> Self {
|
|
||||||
Action::CreateUser(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, Serialize)]
|
#[derive(Debug, thiserror::Error, Serialize)]
|
||||||
pub enum CreateUserError {
|
pub enum CreateUserError {
|
||||||
#[error("Failed to execute command")]
|
#[error("Failed to execute command")]
|
||||||
|
|
|
@ -5,7 +5,7 @@ use tokio::process::Command;
|
||||||
|
|
||||||
use crate::execute_command;
|
use crate::execute_command;
|
||||||
|
|
||||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
use crate::actions::{ActionDescription, ActionError, ActionState, Actionable};
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||||
pub struct BootstrapVolume {
|
pub struct BootstrapVolume {
|
||||||
|
@ -15,7 +15,9 @@ pub struct BootstrapVolume {
|
||||||
|
|
||||||
impl BootstrapVolume {
|
impl BootstrapVolume {
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub async fn plan(path: impl AsRef<Path>) -> Result<Self, BootstrapVolumeError> {
|
pub async fn plan(
|
||||||
|
path: impl AsRef<Path>,
|
||||||
|
) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
path: path.as_ref().to_path_buf(),
|
path: path.as_ref().to_path_buf(),
|
||||||
action_state: ActionState::Uncompleted,
|
action_state: ActionState::Uncompleted,
|
||||||
|
@ -24,9 +26,8 @@ impl BootstrapVolume {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
#[typetag::serde(name = "bootstrap-volume")]
|
||||||
impl Actionable for BootstrapVolume {
|
impl Actionable for BootstrapVolume {
|
||||||
type Error = BootstrapVolumeError;
|
|
||||||
|
|
||||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||||
if self.action_state == ActionState::Completed {
|
if self.action_state == ActionState::Completed {
|
||||||
vec![]
|
vec![]
|
||||||
|
@ -41,7 +42,7 @@ impl Actionable for BootstrapVolume {
|
||||||
#[tracing::instrument(skip_all, fields(
|
#[tracing::instrument(skip_all, fields(
|
||||||
path = %self.path.display(),
|
path = %self.path.display(),
|
||||||
))]
|
))]
|
||||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
async fn execute(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self { path, action_state } = self;
|
let Self { path, action_state } = self;
|
||||||
if *action_state == ActionState::Completed {
|
if *action_state == ActionState::Completed {
|
||||||
tracing::trace!("Already completed: Bootstrapping volume");
|
tracing::trace!("Already completed: Bootstrapping volume");
|
||||||
|
@ -55,14 +56,14 @@ impl Actionable for BootstrapVolume {
|
||||||
.arg(path),
|
.arg(path),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::Command)?;
|
.map_err(|e| BootstrapVolumeError::Command(e).boxed())?;
|
||||||
execute_command(Command::new("launchctl").args([
|
execute_command(Command::new("launchctl").args([
|
||||||
"kickstart",
|
"kickstart",
|
||||||
"-k",
|
"-k",
|
||||||
"system/org.nixos.darwin-store",
|
"system/org.nixos.darwin-store",
|
||||||
]))
|
]))
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::Command)?;
|
.map_err(|e| BootstrapVolumeError::Command(e).boxed())?;
|
||||||
|
|
||||||
tracing::trace!("Bootstrapped volume");
|
tracing::trace!("Bootstrapped volume");
|
||||||
*action_state = ActionState::Completed;
|
*action_state = ActionState::Completed;
|
||||||
|
@ -83,7 +84,7 @@ impl Actionable for BootstrapVolume {
|
||||||
#[tracing::instrument(skip_all, fields(
|
#[tracing::instrument(skip_all, fields(
|
||||||
path = %self.path.display(),
|
path = %self.path.display(),
|
||||||
))]
|
))]
|
||||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
async fn revert(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self { path, action_state } = self;
|
let Self { path, action_state } = self;
|
||||||
if *action_state == ActionState::Uncompleted {
|
if *action_state == ActionState::Uncompleted {
|
||||||
tracing::trace!("Already reverted: Stop volume");
|
tracing::trace!("Already reverted: Stop volume");
|
||||||
|
@ -97,7 +98,7 @@ impl Actionable for BootstrapVolume {
|
||||||
.arg(path),
|
.arg(path),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::Command)?;
|
.map_err(|e| BootstrapVolumeError::Command(e).boxed())?;
|
||||||
|
|
||||||
tracing::trace!("Stopped volume");
|
tracing::trace!("Stopped volume");
|
||||||
*action_state = ActionState::Completed;
|
*action_state = ActionState::Completed;
|
||||||
|
@ -105,12 +106,6 @@ impl Actionable for BootstrapVolume {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<BootstrapVolume> for Action {
|
|
||||||
fn from(v: BootstrapVolume) -> Self {
|
|
||||||
Action::DarwinBootstrapVolume(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, Serialize)]
|
#[derive(Debug, thiserror::Error, Serialize)]
|
||||||
pub enum BootstrapVolumeError {
|
pub enum BootstrapVolumeError {
|
||||||
#[error("Failed to execute command")]
|
#[error("Failed to execute command")]
|
||||||
|
|
|
@ -3,7 +3,7 @@ use tokio::process::Command;
|
||||||
|
|
||||||
use crate::execute_command;
|
use crate::execute_command;
|
||||||
|
|
||||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
use crate::actions::{ActionDescription, ActionError, ActionState, Actionable};
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||||
pub struct CreateSyntheticObjects {
|
pub struct CreateSyntheticObjects {
|
||||||
|
@ -12,7 +12,7 @@ pub struct CreateSyntheticObjects {
|
||||||
|
|
||||||
impl CreateSyntheticObjects {
|
impl CreateSyntheticObjects {
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub async fn plan() -> Result<Self, CreateSyntheticObjectsError> {
|
pub async fn plan() -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
action_state: ActionState::Uncompleted,
|
action_state: ActionState::Uncompleted,
|
||||||
})
|
})
|
||||||
|
@ -20,9 +20,8 @@ impl CreateSyntheticObjects {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
#[typetag::serde(name = "create-synthetic-objects")]
|
||||||
impl Actionable for CreateSyntheticObjects {
|
impl Actionable for CreateSyntheticObjects {
|
||||||
type Error = CreateSyntheticObjectsError;
|
|
||||||
|
|
||||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||||
if self.action_state == ActionState::Completed {
|
if self.action_state == ActionState::Completed {
|
||||||
vec![]
|
vec![]
|
||||||
|
@ -35,7 +34,7 @@ impl Actionable for CreateSyntheticObjects {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all, fields())]
|
#[tracing::instrument(skip_all, fields())]
|
||||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
async fn execute(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self { action_state } = self;
|
let Self { action_state } = self;
|
||||||
if *action_state == ActionState::Completed {
|
if *action_state == ActionState::Completed {
|
||||||
tracing::trace!("Already completed: Creating synthetic objects");
|
tracing::trace!("Already completed: Creating synthetic objects");
|
||||||
|
@ -74,7 +73,7 @@ impl Actionable for CreateSyntheticObjects {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all, fields())]
|
#[tracing::instrument(skip_all, fields())]
|
||||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
async fn revert(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self { action_state } = self;
|
let Self { action_state } = self;
|
||||||
if *action_state == ActionState::Uncompleted {
|
if *action_state == ActionState::Uncompleted {
|
||||||
tracing::trace!("Already reverted: Refreshing synthetic objects");
|
tracing::trace!("Already reverted: Refreshing synthetic objects");
|
||||||
|
@ -102,12 +101,6 @@ impl Actionable for CreateSyntheticObjects {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<CreateSyntheticObjects> for Action {
|
|
||||||
fn from(v: CreateSyntheticObjects) -> Self {
|
|
||||||
Action::DarwinCreateSyntheticObjects(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, Serialize)]
|
#[derive(Debug, thiserror::Error, Serialize)]
|
||||||
pub enum CreateSyntheticObjectsError {
|
pub enum CreateSyntheticObjectsError {
|
||||||
#[error("Failed to execute command")]
|
#[error("Failed to execute command")]
|
||||||
|
|
|
@ -5,7 +5,7 @@ use tokio::process::Command;
|
||||||
|
|
||||||
use crate::execute_command;
|
use crate::execute_command;
|
||||||
|
|
||||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
use crate::actions::{ActionDescription, ActionError, ActionState, Actionable};
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||||
pub struct CreateVolume {
|
pub struct CreateVolume {
|
||||||
|
@ -21,7 +21,7 @@ impl CreateVolume {
|
||||||
disk: impl AsRef<Path>,
|
disk: impl AsRef<Path>,
|
||||||
name: String,
|
name: String,
|
||||||
case_sensitive: bool,
|
case_sensitive: bool,
|
||||||
) -> Result<Self, CreateVolumeError> {
|
) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
disk: disk.as_ref().to_path_buf(),
|
disk: disk.as_ref().to_path_buf(),
|
||||||
name,
|
name,
|
||||||
|
@ -32,9 +32,8 @@ impl CreateVolume {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
#[typetag::serde(name = "create-volume")]
|
||||||
impl Actionable for CreateVolume {
|
impl Actionable for CreateVolume {
|
||||||
type Error = CreateVolumeError;
|
|
||||||
|
|
||||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||||
if self.action_state == ActionState::Completed {
|
if self.action_state == ActionState::Completed {
|
||||||
vec![]
|
vec![]
|
||||||
|
@ -55,7 +54,7 @@ impl Actionable for CreateVolume {
|
||||||
name = %self.name,
|
name = %self.name,
|
||||||
case_sensitive = %self.case_sensitive,
|
case_sensitive = %self.case_sensitive,
|
||||||
))]
|
))]
|
||||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
async fn execute(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
disk,
|
disk,
|
||||||
name,
|
name,
|
||||||
|
@ -81,7 +80,7 @@ impl Actionable for CreateVolume {
|
||||||
"-nomount",
|
"-nomount",
|
||||||
]))
|
]))
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::Command)?;
|
.map_err(|e| CreateVolumeError::Command(e).boxed())?;
|
||||||
|
|
||||||
tracing::trace!("Created volume");
|
tracing::trace!("Created volume");
|
||||||
*action_state = ActionState::Completed;
|
*action_state = ActionState::Completed;
|
||||||
|
@ -108,7 +107,7 @@ impl Actionable for CreateVolume {
|
||||||
name = %self.name,
|
name = %self.name,
|
||||||
case_sensitive = %self.case_sensitive,
|
case_sensitive = %self.case_sensitive,
|
||||||
))]
|
))]
|
||||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
async fn revert(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
disk: _,
|
disk: _,
|
||||||
name,
|
name,
|
||||||
|
@ -123,7 +122,7 @@ impl Actionable for CreateVolume {
|
||||||
|
|
||||||
execute_command(Command::new("/usr/sbin/diskutil").args(["apfs", "deleteVolume", name]))
|
execute_command(Command::new("/usr/sbin/diskutil").args(["apfs", "deleteVolume", name]))
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::Command)?;
|
.map_err(|e| CreateVolumeError::Command(e).boxed())?;
|
||||||
|
|
||||||
tracing::trace!("Deleted volume");
|
tracing::trace!("Deleted volume");
|
||||||
*action_state = ActionState::Completed;
|
*action_state = ActionState::Completed;
|
||||||
|
@ -131,12 +130,6 @@ impl Actionable for CreateVolume {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<CreateVolume> for Action {
|
|
||||||
fn from(v: CreateVolume) -> Self {
|
|
||||||
Action::DarwinCreateVolume(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, Serialize)]
|
#[derive(Debug, thiserror::Error, Serialize)]
|
||||||
pub enum CreateVolumeError {
|
pub enum CreateVolumeError {
|
||||||
#[error("Failed to execute command")]
|
#[error("Failed to execute command")]
|
||||||
|
|
|
@ -6,7 +6,7 @@ use tokio::process::Command;
|
||||||
|
|
||||||
use crate::execute_command;
|
use crate::execute_command;
|
||||||
|
|
||||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
use crate::actions::{ActionDescription, ActionError, ActionState, Actionable};
|
||||||
use crate::os::darwin::DiskUtilOutput;
|
use crate::os::darwin::DiskUtilOutput;
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||||
|
@ -17,7 +17,9 @@ pub struct EnableOwnership {
|
||||||
|
|
||||||
impl EnableOwnership {
|
impl EnableOwnership {
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub async fn plan(path: impl AsRef<Path>) -> Result<Self, EnableOwnershipError> {
|
pub async fn plan(
|
||||||
|
path: impl AsRef<Path>,
|
||||||
|
) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
path: path.as_ref().to_path_buf(),
|
path: path.as_ref().to_path_buf(),
|
||||||
action_state: ActionState::Uncompleted,
|
action_state: ActionState::Uncompleted,
|
||||||
|
@ -26,9 +28,8 @@ impl EnableOwnership {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
#[typetag::serde(name = "enable-ownership")]
|
||||||
impl Actionable for EnableOwnership {
|
impl Actionable for EnableOwnership {
|
||||||
type Error = EnableOwnershipError;
|
|
||||||
|
|
||||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||||
if self.action_state == ActionState::Completed {
|
if self.action_state == ActionState::Completed {
|
||||||
vec![]
|
vec![]
|
||||||
|
@ -43,7 +44,7 @@ impl Actionable for EnableOwnership {
|
||||||
#[tracing::instrument(skip_all, fields(
|
#[tracing::instrument(skip_all, fields(
|
||||||
path = %self.path.display(),
|
path = %self.path.display(),
|
||||||
))]
|
))]
|
||||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
async fn execute(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self { path, action_state } = self;
|
let Self { path, action_state } = self;
|
||||||
if *action_state == ActionState::Completed {
|
if *action_state == ActionState::Completed {
|
||||||
tracing::trace!("Already completed: Enabling ownership");
|
tracing::trace!("Already completed: Enabling ownership");
|
||||||
|
@ -72,7 +73,7 @@ impl Actionable for EnableOwnership {
|
||||||
.arg(path),
|
.arg(path),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::Command)?;
|
.map_err(|e| EnableOwnershipError::Command(e).boxed())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing::trace!("Enabled ownership");
|
tracing::trace!("Enabled ownership");
|
||||||
|
@ -91,7 +92,7 @@ impl Actionable for EnableOwnership {
|
||||||
#[tracing::instrument(skip_all, fields(
|
#[tracing::instrument(skip_all, fields(
|
||||||
path = %self.path.display(),
|
path = %self.path.display(),
|
||||||
))]
|
))]
|
||||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
async fn revert(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
path: _,
|
path: _,
|
||||||
action_state,
|
action_state,
|
||||||
|
@ -108,12 +109,6 @@ impl Actionable for EnableOwnership {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<EnableOwnership> for Action {
|
|
||||||
fn from(v: EnableOwnership) -> Self {
|
|
||||||
Action::DarwinEnableOwnership(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, Serialize)]
|
#[derive(Debug, thiserror::Error, Serialize)]
|
||||||
pub enum EnableOwnershipError {
|
pub enum EnableOwnershipError {
|
||||||
#[error("Failed to execute command")]
|
#[error("Failed to execute command")]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
use crate::actions::{ActionDescription, ActionError, ActionState, Actionable};
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||||
pub struct EncryptVolume {
|
pub struct EncryptVolume {
|
||||||
|
@ -15,7 +15,7 @@ impl EncryptVolume {
|
||||||
pub async fn plan(
|
pub async fn plan(
|
||||||
disk: impl AsRef<Path>,
|
disk: impl AsRef<Path>,
|
||||||
password: String,
|
password: String,
|
||||||
) -> Result<Self, EncryptVolumeError> {
|
) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
disk: disk.as_ref().to_path_buf(),
|
disk: disk.as_ref().to_path_buf(),
|
||||||
password,
|
password,
|
||||||
|
@ -25,9 +25,8 @@ impl EncryptVolume {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
#[typetag::serde(name = "encrypt-volume")]
|
||||||
impl Actionable for EncryptVolume {
|
impl Actionable for EncryptVolume {
|
||||||
type Error = EncryptVolumeError;
|
|
||||||
|
|
||||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||||
if self.action_state == ActionState::Completed {
|
if self.action_state == ActionState::Completed {
|
||||||
vec![]
|
vec![]
|
||||||
|
@ -42,7 +41,7 @@ impl Actionable for EncryptVolume {
|
||||||
#[tracing::instrument(skip_all, fields(
|
#[tracing::instrument(skip_all, fields(
|
||||||
disk = %self.disk.display(),
|
disk = %self.disk.display(),
|
||||||
))]
|
))]
|
||||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
async fn execute(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
disk: _,
|
disk: _,
|
||||||
password: _,
|
password: _,
|
||||||
|
@ -72,7 +71,7 @@ impl Actionable for EncryptVolume {
|
||||||
#[tracing::instrument(skip_all, fields(
|
#[tracing::instrument(skip_all, fields(
|
||||||
disk = %self.disk.display(),
|
disk = %self.disk.display(),
|
||||||
))]
|
))]
|
||||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
async fn revert(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
disk: _,
|
disk: _,
|
||||||
password: _,
|
password: _,
|
||||||
|
@ -90,12 +89,6 @@ impl Actionable for EncryptVolume {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<EncryptVolume> for Action {
|
|
||||||
fn from(v: EncryptVolume) -> Self {
|
|
||||||
Action::DarwinEncryptVolume(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, Serialize)]
|
#[derive(Debug, thiserror::Error, Serialize)]
|
||||||
pub enum EncryptVolumeError {
|
pub enum EncryptVolumeError {
|
||||||
#[error("Failed to execute command")]
|
#[error("Failed to execute command")]
|
||||||
|
|
|
@ -3,7 +3,7 @@ use tokio::process::Command;
|
||||||
|
|
||||||
use crate::execute_command;
|
use crate::execute_command;
|
||||||
|
|
||||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
use crate::actions::{ActionDescription, ActionError, ActionState, Actionable};
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||||
pub struct KickstartLaunchctlService {
|
pub struct KickstartLaunchctlService {
|
||||||
|
@ -13,7 +13,7 @@ pub struct KickstartLaunchctlService {
|
||||||
|
|
||||||
impl KickstartLaunchctlService {
|
impl KickstartLaunchctlService {
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub async fn plan(unit: String) -> Result<Self, KickstartLaunchctlServiceError> {
|
pub async fn plan(unit: String) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
unit,
|
unit,
|
||||||
action_state: ActionState::Uncompleted,
|
action_state: ActionState::Uncompleted,
|
||||||
|
@ -22,9 +22,8 @@ impl KickstartLaunchctlService {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
#[typetag::serde(name = "kickstart-launchctl-service")]
|
||||||
impl Actionable for KickstartLaunchctlService {
|
impl Actionable for KickstartLaunchctlService {
|
||||||
type Error = KickstartLaunchctlServiceError;
|
|
||||||
|
|
||||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||||
let Self { unit, action_state } = self;
|
let Self { unit, action_state } = self;
|
||||||
if *action_state == ActionState::Completed {
|
if *action_state == ActionState::Completed {
|
||||||
|
@ -42,7 +41,7 @@ impl Actionable for KickstartLaunchctlService {
|
||||||
#[tracing::instrument(skip_all, fields(
|
#[tracing::instrument(skip_all, fields(
|
||||||
unit = %self.unit,
|
unit = %self.unit,
|
||||||
))]
|
))]
|
||||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
async fn execute(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self { unit, action_state } = self;
|
let Self { unit, action_state } = self;
|
||||||
if *action_state == ActionState::Completed {
|
if *action_state == ActionState::Completed {
|
||||||
tracing::trace!("Already completed: Kickstarting launchctl unit");
|
tracing::trace!("Already completed: Kickstarting launchctl unit");
|
||||||
|
@ -57,7 +56,7 @@ impl Actionable for KickstartLaunchctlService {
|
||||||
.arg(unit),
|
.arg(unit),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(KickstartLaunchctlServiceError::Command)?;
|
.map_err(|e| KickstartLaunchctlServiceError::Command(e).boxed())?;
|
||||||
|
|
||||||
tracing::trace!("Kickstarted launchctl unit");
|
tracing::trace!("Kickstarted launchctl unit");
|
||||||
*action_state = ActionState::Completed;
|
*action_state = ActionState::Completed;
|
||||||
|
@ -80,7 +79,7 @@ impl Actionable for KickstartLaunchctlService {
|
||||||
#[tracing::instrument(skip_all, fields(
|
#[tracing::instrument(skip_all, fields(
|
||||||
unit = %self.unit,
|
unit = %self.unit,
|
||||||
))]
|
))]
|
||||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
async fn revert(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self { unit, action_state } = self;
|
let Self { unit, action_state } = self;
|
||||||
if *action_state == ActionState::Uncompleted {
|
if *action_state == ActionState::Uncompleted {
|
||||||
tracing::trace!("Already reverted: Stopping launchctl unit");
|
tracing::trace!("Already reverted: Stopping launchctl unit");
|
||||||
|
@ -90,7 +89,7 @@ impl Actionable for KickstartLaunchctlService {
|
||||||
|
|
||||||
execute_command(Command::new("launchctl").arg("stop").arg(unit))
|
execute_command(Command::new("launchctl").arg("stop").arg(unit))
|
||||||
.await
|
.await
|
||||||
.map_err(KickstartLaunchctlServiceError::Command)?;
|
.map_err(|e| KickstartLaunchctlServiceError::Command(e).boxed())?;
|
||||||
|
|
||||||
tracing::trace!("Stopped launchctl unit");
|
tracing::trace!("Stopped launchctl unit");
|
||||||
*action_state = ActionState::Completed;
|
*action_state = ActionState::Completed;
|
||||||
|
@ -98,12 +97,6 @@ impl Actionable for KickstartLaunchctlService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<KickstartLaunchctlService> for Action {
|
|
||||||
fn from(v: KickstartLaunchctlService) -> Self {
|
|
||||||
Action::DarwinKickStartLaunchctlService(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, Serialize)]
|
#[derive(Debug, thiserror::Error, Serialize)]
|
||||||
pub enum KickstartLaunchctlServiceError {
|
pub enum KickstartLaunchctlServiceError {
|
||||||
#[error("Failed to execute command")]
|
#[error("Failed to execute command")]
|
||||||
|
|
|
@ -5,7 +5,7 @@ use tokio::process::Command;
|
||||||
|
|
||||||
use crate::execute_command;
|
use crate::execute_command;
|
||||||
|
|
||||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
use crate::actions::{ActionDescription, ActionError, ActionState, Actionable};
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||||
pub struct UnmountVolume {
|
pub struct UnmountVolume {
|
||||||
|
@ -16,7 +16,10 @@ pub struct UnmountVolume {
|
||||||
|
|
||||||
impl UnmountVolume {
|
impl UnmountVolume {
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub async fn plan(disk: impl AsRef<Path>, name: String) -> Result<Self, UnmountVolumeError> {
|
pub async fn plan(
|
||||||
|
disk: impl AsRef<Path>,
|
||||||
|
name: String,
|
||||||
|
) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let disk = disk.as_ref().to_owned();
|
let disk = disk.as_ref().to_owned();
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
disk,
|
disk,
|
||||||
|
@ -27,9 +30,8 @@ impl UnmountVolume {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
#[typetag::serde(name = "unmount-volume")]
|
||||||
impl Actionable for UnmountVolume {
|
impl Actionable for UnmountVolume {
|
||||||
type Error = UnmountVolumeError;
|
|
||||||
|
|
||||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||||
if self.action_state == ActionState::Completed {
|
if self.action_state == ActionState::Completed {
|
||||||
vec![]
|
vec![]
|
||||||
|
@ -47,7 +49,7 @@ impl Actionable for UnmountVolume {
|
||||||
disk = %self.disk.display(),
|
disk = %self.disk.display(),
|
||||||
name = %self.name,
|
name = %self.name,
|
||||||
))]
|
))]
|
||||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
async fn execute(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
disk: _,
|
disk: _,
|
||||||
name,
|
name,
|
||||||
|
@ -65,7 +67,7 @@ impl Actionable for UnmountVolume {
|
||||||
.arg(name),
|
.arg(name),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::Command)?;
|
.map_err(|e| UnmountVolumeError::Command(e).boxed())?;
|
||||||
|
|
||||||
tracing::trace!("Unmounted volume");
|
tracing::trace!("Unmounted volume");
|
||||||
*action_state = ActionState::Completed;
|
*action_state = ActionState::Completed;
|
||||||
|
@ -89,7 +91,7 @@ impl Actionable for UnmountVolume {
|
||||||
disk = %self.disk.display(),
|
disk = %self.disk.display(),
|
||||||
name = %self.name,
|
name = %self.name,
|
||||||
))]
|
))]
|
||||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
async fn revert(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
disk: _,
|
disk: _,
|
||||||
name,
|
name,
|
||||||
|
@ -107,7 +109,7 @@ impl Actionable for UnmountVolume {
|
||||||
.arg(name),
|
.arg(name),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::Command)?;
|
.map_err(|e| UnmountVolumeError::Command(e).boxed())?;
|
||||||
|
|
||||||
tracing::trace!("Stopped systemd unit");
|
tracing::trace!("Stopped systemd unit");
|
||||||
*action_state = ActionState::Completed;
|
*action_state = ActionState::Completed;
|
||||||
|
@ -115,12 +117,6 @@ impl Actionable for UnmountVolume {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<UnmountVolume> for Action {
|
|
||||||
fn from(v: UnmountVolume) -> Self {
|
|
||||||
Action::DarwinUnmountVolume(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, Serialize)]
|
#[derive(Debug, thiserror::Error, Serialize)]
|
||||||
pub enum UnmountVolumeError {
|
pub enum UnmountVolumeError {
|
||||||
#[error("Failed to execute command")]
|
#[error("Failed to execute command")]
|
||||||
|
|
|
@ -5,7 +5,7 @@ use reqwest::Url;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use tokio::task::JoinError;
|
use tokio::task::JoinError;
|
||||||
|
|
||||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
use crate::actions::{ActionDescription, ActionError, ActionState, Actionable};
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||||
pub struct FetchNix {
|
pub struct FetchNix {
|
||||||
|
@ -29,9 +29,8 @@ impl FetchNix {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
#[typetag::serde(name = "fetch-nix")]
|
||||||
impl Actionable for FetchNix {
|
impl Actionable for FetchNix {
|
||||||
type Error = FetchNixError;
|
|
||||||
|
|
||||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||||
let Self {
|
let Self {
|
||||||
url,
|
url,
|
||||||
|
@ -52,7 +51,7 @@ impl Actionable for FetchNix {
|
||||||
url = %self.url,
|
url = %self.url,
|
||||||
dest = %self.dest.display(),
|
dest = %self.dest.display(),
|
||||||
))]
|
))]
|
||||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
async fn execute(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
url,
|
url,
|
||||||
dest,
|
dest,
|
||||||
|
@ -66,8 +65,11 @@ impl Actionable for FetchNix {
|
||||||
|
|
||||||
let res = reqwest::get(url.clone())
|
let res = reqwest::get(url.clone())
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::Reqwest)?;
|
.map_err(|e| FetchNixError::Reqwest(e).boxed())?;
|
||||||
let bytes = res.bytes().await.map_err(Self::Error::Reqwest)?;
|
let bytes = res
|
||||||
|
.bytes()
|
||||||
|
.await
|
||||||
|
.map_err(|e| FetchNixError::Reqwest(e).boxed())?;
|
||||||
// TODO(@Hoverbear): Pick directory
|
// TODO(@Hoverbear): Pick directory
|
||||||
tracing::trace!("Unpacking tar.xz");
|
tracing::trace!("Unpacking tar.xz");
|
||||||
let dest_clone = dest.clone();
|
let dest_clone = dest.clone();
|
||||||
|
@ -76,7 +78,7 @@ impl Actionable for FetchNix {
|
||||||
let mut archive = tar::Archive::new(decoder);
|
let mut archive = tar::Archive::new(decoder);
|
||||||
archive
|
archive
|
||||||
.unpack(&dest_clone)
|
.unpack(&dest_clone)
|
||||||
.map_err(Self::Error::Unarchive)?;
|
.map_err(|e| FetchNixError::Unarchive(e).boxed())?;
|
||||||
|
|
||||||
tracing::trace!("Fetched Nix");
|
tracing::trace!("Fetched Nix");
|
||||||
*action_state = ActionState::Completed;
|
*action_state = ActionState::Completed;
|
||||||
|
@ -95,7 +97,7 @@ impl Actionable for FetchNix {
|
||||||
url = %self.url,
|
url = %self.url,
|
||||||
dest = %self.dest.display(),
|
dest = %self.dest.display(),
|
||||||
))]
|
))]
|
||||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
async fn revert(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
url: _,
|
url: _,
|
||||||
dest: _,
|
dest: _,
|
||||||
|
@ -112,12 +114,6 @@ impl Actionable for FetchNix {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<FetchNix> for Action {
|
|
||||||
fn from(v: FetchNix) -> Self {
|
|
||||||
Action::FetchNix(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, Serialize)]
|
#[derive(Debug, thiserror::Error, Serialize)]
|
||||||
pub enum FetchNixError {
|
pub enum FetchNixError {
|
||||||
#[error("Joining spawned async task")]
|
#[error("Joining spawned async task")]
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
use crate::actions::{ActionDescription, ActionError, ActionState, Actionable};
|
||||||
|
|
||||||
const DEST: &str = "/nix/store";
|
const DEST: &str = "/nix/store";
|
||||||
|
|
||||||
|
@ -24,9 +24,8 @@ impl MoveUnpackedNix {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
#[typetag::serde(name = "mount-unpacked-nix")]
|
||||||
impl Actionable for MoveUnpackedNix {
|
impl Actionable for MoveUnpackedNix {
|
||||||
type Error = MoveUnpackedNixError;
|
|
||||||
|
|
||||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||||
if self.action_state == ActionState::Completed {
|
if self.action_state == ActionState::Completed {
|
||||||
vec![]
|
vec![]
|
||||||
|
@ -45,7 +44,7 @@ impl Actionable for MoveUnpackedNix {
|
||||||
src = %self.src.display(),
|
src = %self.src.display(),
|
||||||
dest = DEST,
|
dest = DEST,
|
||||||
))]
|
))]
|
||||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
async fn execute(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self { src, action_state } = self;
|
let Self { src, action_state } = self;
|
||||||
if *action_state == ActionState::Completed {
|
if *action_state == ActionState::Completed {
|
||||||
tracing::trace!("Already completed: Moving Nix");
|
tracing::trace!("Already completed: Moving Nix");
|
||||||
|
@ -54,8 +53,10 @@ impl Actionable for MoveUnpackedNix {
|
||||||
tracing::debug!("Moving Nix");
|
tracing::debug!("Moving Nix");
|
||||||
|
|
||||||
// TODO(@Hoverbear): I would like to make this less awful
|
// TODO(@Hoverbear): I would like to make this less awful
|
||||||
let found_nix_paths =
|
let found_nix_paths = glob::glob(&format!("{}/nix-*", src.display()))
|
||||||
glob::glob(&format!("{}/nix-*", src.display()))?.collect::<Result<Vec<_>, _>>()?;
|
.map_err(|e| e.boxed())?
|
||||||
|
.collect::<Result<Vec<_>, _>>()
|
||||||
|
.map_err(|e| e.boxed())?;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
found_nix_paths.len(),
|
found_nix_paths.len(),
|
||||||
1,
|
1,
|
||||||
|
@ -67,11 +68,13 @@ impl Actionable for MoveUnpackedNix {
|
||||||
let dest = Path::new(DEST);
|
let dest = Path::new(DEST);
|
||||||
tokio::fs::rename(src_store.clone(), dest)
|
tokio::fs::rename(src_store.clone(), dest)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| MoveUnpackedNixError::Rename(src_store.clone(), dest.to_owned(), e))?;
|
.map_err(|e| {
|
||||||
|
MoveUnpackedNixError::Rename(src_store.clone(), dest.to_owned(), e).boxed()
|
||||||
|
})?;
|
||||||
|
|
||||||
tokio::fs::remove_dir_all(src)
|
tokio::fs::remove_dir_all(src)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| MoveUnpackedNixError::Rename(src_store, dest.to_owned(), e))?;
|
.map_err(|e| MoveUnpackedNixError::Rename(src_store, dest.to_owned(), e).boxed())?;
|
||||||
tracing::trace!("Moved Nix");
|
tracing::trace!("Moved Nix");
|
||||||
*action_state = ActionState::Completed;
|
*action_state = ActionState::Completed;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -89,7 +92,7 @@ impl Actionable for MoveUnpackedNix {
|
||||||
src = %self.src.display(),
|
src = %self.src.display(),
|
||||||
dest = DEST,
|
dest = DEST,
|
||||||
))]
|
))]
|
||||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
async fn revert(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
src: _,
|
src: _,
|
||||||
action_state,
|
action_state,
|
||||||
|
@ -104,12 +107,6 @@ impl Actionable for MoveUnpackedNix {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<MoveUnpackedNix> for Action {
|
|
||||||
fn from(v: MoveUnpackedNix) -> Self {
|
|
||||||
Action::MoveUnpackedNix(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, Serialize)]
|
#[derive(Debug, thiserror::Error, Serialize)]
|
||||||
pub enum MoveUnpackedNixError {
|
pub enum MoveUnpackedNixError {
|
||||||
#[error("Glob pattern error")]
|
#[error("Glob pattern error")]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
actions::{Action, ActionState},
|
actions::{ActionError, ActionState},
|
||||||
execute_command, set_env,
|
execute_command, set_env,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -26,9 +26,8 @@ impl SetupDefaultProfile {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
#[typetag::serde(name = "setup-default-profile")]
|
||||||
impl Actionable for SetupDefaultProfile {
|
impl Actionable for SetupDefaultProfile {
|
||||||
type Error = SetupDefaultProfileError;
|
|
||||||
|
|
||||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||||
if self.action_state == ActionState::Completed {
|
if self.action_state == ActionState::Completed {
|
||||||
vec![]
|
vec![]
|
||||||
|
@ -43,7 +42,7 @@ impl Actionable for SetupDefaultProfile {
|
||||||
#[tracing::instrument(skip_all, fields(
|
#[tracing::instrument(skip_all, fields(
|
||||||
channels = %self.channels.join(","),
|
channels = %self.channels.join(","),
|
||||||
))]
|
))]
|
||||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
async fn execute(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
channels,
|
channels,
|
||||||
action_state,
|
action_state,
|
||||||
|
@ -57,7 +56,9 @@ impl Actionable for SetupDefaultProfile {
|
||||||
// Find an `nix` package
|
// Find an `nix` package
|
||||||
let nix_pkg_glob = "/nix/store/*-nix-*";
|
let nix_pkg_glob = "/nix/store/*-nix-*";
|
||||||
let mut found_nix_pkg = None;
|
let mut found_nix_pkg = None;
|
||||||
for entry in glob(nix_pkg_glob).map_err(Self::Error::GlobPatternError)? {
|
for entry in
|
||||||
|
glob(nix_pkg_glob).map_err(|e| SetupDefaultProfileError::GlobPatternError(e).boxed())?
|
||||||
|
{
|
||||||
match entry {
|
match entry {
|
||||||
Ok(path) => {
|
Ok(path) => {
|
||||||
// TODO(@Hoverbear): Should probably ensure is unique
|
// TODO(@Hoverbear): Should probably ensure is unique
|
||||||
|
@ -70,13 +71,15 @@ impl Actionable for SetupDefaultProfile {
|
||||||
let nix_pkg = if let Some(nix_pkg) = found_nix_pkg {
|
let nix_pkg = if let Some(nix_pkg) = found_nix_pkg {
|
||||||
nix_pkg
|
nix_pkg
|
||||||
} else {
|
} else {
|
||||||
return Err(Self::Error::NoNssCacert); // TODO(@hoverbear): Fix this error
|
return Err(Box::new(SetupDefaultProfileError::NoNssCacert)); // TODO(@hoverbear): Fix this error
|
||||||
};
|
};
|
||||||
|
|
||||||
// Find an `nss-cacert` package, add it too.
|
// Find an `nss-cacert` package, add it too.
|
||||||
let nss_ca_cert_pkg_glob = "/nix/store/*-nss-cacert-*";
|
let nss_ca_cert_pkg_glob = "/nix/store/*-nss-cacert-*";
|
||||||
let mut found_nss_ca_cert_pkg = None;
|
let mut found_nss_ca_cert_pkg = None;
|
||||||
for entry in glob(nss_ca_cert_pkg_glob).map_err(Self::Error::GlobPatternError)? {
|
for entry in glob(nss_ca_cert_pkg_glob)
|
||||||
|
.map_err(|e| SetupDefaultProfileError::GlobPatternError(e).boxed())?
|
||||||
|
{
|
||||||
match entry {
|
match entry {
|
||||||
Ok(path) => {
|
Ok(path) => {
|
||||||
// TODO(@Hoverbear): Should probably ensure is unique
|
// TODO(@Hoverbear): Should probably ensure is unique
|
||||||
|
@ -89,7 +92,7 @@ impl Actionable for SetupDefaultProfile {
|
||||||
let nss_ca_cert_pkg = if let Some(nss_ca_cert_pkg) = found_nss_ca_cert_pkg {
|
let nss_ca_cert_pkg = if let Some(nss_ca_cert_pkg) = found_nss_ca_cert_pkg {
|
||||||
nss_ca_cert_pkg
|
nss_ca_cert_pkg
|
||||||
} else {
|
} else {
|
||||||
return Err(Self::Error::NoNssCacert);
|
return Err(Box::new(SetupDefaultProfileError::NoNssCacert));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Install `nix` itself into the store
|
// Install `nix` itself into the store
|
||||||
|
@ -97,14 +100,17 @@ impl Actionable for SetupDefaultProfile {
|
||||||
Command::new(nix_pkg.join("bin/nix-env"))
|
Command::new(nix_pkg.join("bin/nix-env"))
|
||||||
.arg("-i")
|
.arg("-i")
|
||||||
.arg(&nix_pkg)
|
.arg(&nix_pkg)
|
||||||
.env("HOME", dirs::home_dir().ok_or(Self::Error::NoRootHome)?)
|
.env(
|
||||||
|
"HOME",
|
||||||
|
dirs::home_dir().ok_or_else(|| SetupDefaultProfileError::NoRootHome.boxed())?,
|
||||||
|
)
|
||||||
.env(
|
.env(
|
||||||
"NIX_SSL_CERT_FILE",
|
"NIX_SSL_CERT_FILE",
|
||||||
nss_ca_cert_pkg.join("etc/ssl/certs/ca-bundle.crt"),
|
nss_ca_cert_pkg.join("etc/ssl/certs/ca-bundle.crt"),
|
||||||
), /* This is apparently load bearing... */
|
), /* This is apparently load bearing... */
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(SetupDefaultProfileError::Command)?;
|
.map_err(|e| SetupDefaultProfileError::Command(e).boxed())?;
|
||||||
|
|
||||||
// Install `nss-cacert` into the store
|
// Install `nss-cacert` into the store
|
||||||
execute_command(
|
execute_command(
|
||||||
|
@ -117,7 +123,7 @@ impl Actionable for SetupDefaultProfile {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(SetupDefaultProfileError::Command)?;
|
.map_err(|e| SetupDefaultProfileError::Command(e).boxed())?;
|
||||||
|
|
||||||
set_env(
|
set_env(
|
||||||
"NIX_SSL_CERT_FILE",
|
"NIX_SSL_CERT_FILE",
|
||||||
|
@ -137,7 +143,7 @@ impl Actionable for SetupDefaultProfile {
|
||||||
|
|
||||||
execute_command(&mut command)
|
execute_command(&mut command)
|
||||||
.await
|
.await
|
||||||
.map_err(SetupDefaultProfileError::Command)?;
|
.map_err(|e| SetupDefaultProfileError::Command(e).boxed())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing::trace!("Set up default profile");
|
tracing::trace!("Set up default profile");
|
||||||
|
@ -159,7 +165,7 @@ impl Actionable for SetupDefaultProfile {
|
||||||
#[tracing::instrument(skip_all, fields(
|
#[tracing::instrument(skip_all, fields(
|
||||||
channels = %self.channels.join(","),
|
channels = %self.channels.join(","),
|
||||||
))]
|
))]
|
||||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
async fn revert(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
channels: _,
|
channels: _,
|
||||||
action_state,
|
action_state,
|
||||||
|
@ -178,12 +184,6 @@ impl Actionable for SetupDefaultProfile {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SetupDefaultProfile> for Action {
|
|
||||||
fn from(v: SetupDefaultProfile) -> Self {
|
|
||||||
Action::SetupDefaultProfile(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, Serialize)]
|
#[derive(Debug, thiserror::Error, Serialize)]
|
||||||
pub enum SetupDefaultProfileError {
|
pub enum SetupDefaultProfileError {
|
||||||
#[error("Glob pattern error")]
|
#[error("Glob pattern error")]
|
||||||
|
|
|
@ -3,7 +3,7 @@ use tokio::process::Command;
|
||||||
|
|
||||||
use crate::execute_command;
|
use crate::execute_command;
|
||||||
|
|
||||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
use crate::actions::{ActionDescription, ActionError, ActionState, Actionable};
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||||
pub struct StartSystemdUnit {
|
pub struct StartSystemdUnit {
|
||||||
|
@ -13,7 +13,7 @@ pub struct StartSystemdUnit {
|
||||||
|
|
||||||
impl StartSystemdUnit {
|
impl StartSystemdUnit {
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub async fn plan(unit: String) -> Result<Self, StartSystemdUnitError> {
|
pub async fn plan(unit: String) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
unit,
|
unit,
|
||||||
action_state: ActionState::Uncompleted,
|
action_state: ActionState::Uncompleted,
|
||||||
|
@ -22,9 +22,8 @@ impl StartSystemdUnit {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
#[typetag::serde(name = "start-systemd-unit")]
|
||||||
impl Actionable for StartSystemdUnit {
|
impl Actionable for StartSystemdUnit {
|
||||||
type Error = StartSystemdUnitError;
|
|
||||||
|
|
||||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||||
if self.action_state == ActionState::Completed {
|
if self.action_state == ActionState::Completed {
|
||||||
vec![]
|
vec![]
|
||||||
|
@ -41,7 +40,7 @@ impl Actionable for StartSystemdUnit {
|
||||||
#[tracing::instrument(skip_all, fields(
|
#[tracing::instrument(skip_all, fields(
|
||||||
unit = %self.unit,
|
unit = %self.unit,
|
||||||
))]
|
))]
|
||||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
async fn execute(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self { unit, action_state } = self;
|
let Self { unit, action_state } = self;
|
||||||
if *action_state == ActionState::Completed {
|
if *action_state == ActionState::Completed {
|
||||||
tracing::trace!("Already completed: Starting systemd unit");
|
tracing::trace!("Already completed: Starting systemd unit");
|
||||||
|
@ -57,7 +56,7 @@ impl Actionable for StartSystemdUnit {
|
||||||
.arg(format!("{unit}")),
|
.arg(format!("{unit}")),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(StartSystemdUnitError::Command)?;
|
.map_err(|e| StartSystemdUnitError::Command(e).boxed())?;
|
||||||
|
|
||||||
tracing::trace!("Started systemd unit");
|
tracing::trace!("Started systemd unit");
|
||||||
*action_state = ActionState::Completed;
|
*action_state = ActionState::Completed;
|
||||||
|
@ -80,7 +79,7 @@ impl Actionable for StartSystemdUnit {
|
||||||
#[tracing::instrument(skip_all, fields(
|
#[tracing::instrument(skip_all, fields(
|
||||||
unit = %self.unit,
|
unit = %self.unit,
|
||||||
))]
|
))]
|
||||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
async fn revert(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self { unit, action_state } = self;
|
let Self { unit, action_state } = self;
|
||||||
if *action_state == ActionState::Uncompleted {
|
if *action_state == ActionState::Uncompleted {
|
||||||
tracing::trace!("Already reverted: Stopping systemd unit");
|
tracing::trace!("Already reverted: Stopping systemd unit");
|
||||||
|
@ -91,7 +90,7 @@ impl Actionable for StartSystemdUnit {
|
||||||
// TODO(@Hoverbear): Handle proxy vars
|
// TODO(@Hoverbear): Handle proxy vars
|
||||||
execute_command(Command::new("systemctl").arg("stop").arg(format!("{unit}")))
|
execute_command(Command::new("systemctl").arg("stop").arg(format!("{unit}")))
|
||||||
.await
|
.await
|
||||||
.map_err(StartSystemdUnitError::Command)?;
|
.map_err(|e| StartSystemdUnitError::Command(e).boxed())?;
|
||||||
|
|
||||||
tracing::trace!("Stopped systemd unit");
|
tracing::trace!("Stopped systemd unit");
|
||||||
*action_state = ActionState::Completed;
|
*action_state = ActionState::Completed;
|
||||||
|
@ -99,12 +98,6 @@ impl Actionable for StartSystemdUnit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<StartSystemdUnit> for Action {
|
|
||||||
fn from(v: StartSystemdUnit) -> Self {
|
|
||||||
Action::StartSystemdUnit(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, Serialize)]
|
#[derive(Debug, thiserror::Error, Serialize)]
|
||||||
pub enum StartSystemdUnitError {
|
pub enum StartSystemdUnitError {
|
||||||
#[error("Failed to execute command")]
|
#[error("Failed to execute command")]
|
||||||
|
|
|
@ -5,7 +5,7 @@ use tokio::process::Command;
|
||||||
|
|
||||||
use crate::execute_command;
|
use crate::execute_command;
|
||||||
|
|
||||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
use crate::actions::{ActionDescription, ActionError, ActionState, Actionable};
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||||
pub struct SystemdSysextMerge {
|
pub struct SystemdSysextMerge {
|
||||||
|
@ -24,9 +24,8 @@ impl SystemdSysextMerge {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
#[typetag::serde(name = "systemd-sysext-merge")]
|
||||||
impl Actionable for SystemdSysextMerge {
|
impl Actionable for SystemdSysextMerge {
|
||||||
type Error = SystemdSysextMergeError;
|
|
||||||
|
|
||||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||||
let Self {
|
let Self {
|
||||||
action_state,
|
action_state,
|
||||||
|
@ -45,7 +44,7 @@ impl Actionable for SystemdSysextMerge {
|
||||||
#[tracing::instrument(skip_all, fields(
|
#[tracing::instrument(skip_all, fields(
|
||||||
device = %self.device.display(),
|
device = %self.device.display(),
|
||||||
))]
|
))]
|
||||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
async fn execute(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
device,
|
device,
|
||||||
action_state,
|
action_state,
|
||||||
|
@ -58,7 +57,7 @@ impl Actionable for SystemdSysextMerge {
|
||||||
|
|
||||||
execute_command(Command::new("systemd-sysext").arg("merge").arg(device))
|
execute_command(Command::new("systemd-sysext").arg("merge").arg(device))
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::Command)?;
|
.map_err(|e| SystemdSysextMergeError::Command(e).boxed())?;
|
||||||
|
|
||||||
tracing::trace!("Merged systemd-sysext");
|
tracing::trace!("Merged systemd-sysext");
|
||||||
*action_state = ActionState::Completed;
|
*action_state = ActionState::Completed;
|
||||||
|
@ -81,7 +80,7 @@ impl Actionable for SystemdSysextMerge {
|
||||||
#[tracing::instrument(skip_all, fields(
|
#[tracing::instrument(skip_all, fields(
|
||||||
device = %self.device.display(),
|
device = %self.device.display(),
|
||||||
))]
|
))]
|
||||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
async fn revert(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
device,
|
device,
|
||||||
action_state,
|
action_state,
|
||||||
|
@ -95,7 +94,7 @@ impl Actionable for SystemdSysextMerge {
|
||||||
// TODO(@Hoverbear): Handle proxy vars
|
// TODO(@Hoverbear): Handle proxy vars
|
||||||
execute_command(Command::new("systemd-sysext").arg("unmerge").arg(device))
|
execute_command(Command::new("systemd-sysext").arg("unmerge").arg(device))
|
||||||
.await
|
.await
|
||||||
.map_err(SystemdSysextMergeError::Command)?;
|
.map_err(|e| SystemdSysextMergeError::Command(e).boxed())?;
|
||||||
|
|
||||||
tracing::trace!("Unmerged systemd-sysext");
|
tracing::trace!("Unmerged systemd-sysext");
|
||||||
*action_state = ActionState::Completed;
|
*action_state = ActionState::Completed;
|
||||||
|
@ -103,12 +102,6 @@ impl Actionable for SystemdSysextMerge {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SystemdSysextMerge> for Action {
|
|
||||||
fn from(v: SystemdSysextMerge) -> Self {
|
|
||||||
Action::SystemdSysextMerge(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, Serialize)]
|
#[derive(Debug, thiserror::Error, Serialize)]
|
||||||
pub enum SystemdSysextMergeError {
|
pub enum SystemdSysextMergeError {
|
||||||
#[error("Failed to execute command")]
|
#[error("Failed to execute command")]
|
||||||
|
|
|
@ -12,12 +12,12 @@ use crate::{
|
||||||
ConfigureShellProfile, ConfigureShellProfileError, PlaceChannelConfiguration,
|
ConfigureShellProfile, ConfigureShellProfileError, PlaceChannelConfiguration,
|
||||||
PlaceChannelConfigurationError, PlaceNixConfiguration, PlaceNixConfigurationError,
|
PlaceChannelConfigurationError, PlaceNixConfiguration, PlaceNixConfigurationError,
|
||||||
},
|
},
|
||||||
Action, ActionState,
|
ActionState,
|
||||||
},
|
},
|
||||||
cli::arg::ChannelValue,
|
cli::arg::ChannelValue,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::actions::{ActionDescription, Actionable};
|
use crate::actions::{ActionDescription, ActionError, Actionable};
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||||
pub struct ConfigureNix {
|
pub struct ConfigureNix {
|
||||||
|
@ -31,7 +31,9 @@ pub struct ConfigureNix {
|
||||||
|
|
||||||
impl ConfigureNix {
|
impl ConfigureNix {
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub async fn plan(settings: CommonSettings) -> Result<Self, ConfigureNixError> {
|
pub async fn plan(
|
||||||
|
settings: CommonSettings,
|
||||||
|
) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let channels: Vec<(String, Url)> = settings
|
let channels: Vec<(String, Url)> = settings
|
||||||
.channels
|
.channels
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -39,7 +41,9 @@ impl ConfigureNix {
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let setup_default_profile =
|
let setup_default_profile =
|
||||||
SetupDefaultProfile::plan(channels.iter().map(|(v, _k)| v.clone()).collect()).await?;
|
SetupDefaultProfile::plan(channels.iter().map(|(v, _k)| v.clone()).collect())
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.boxed())?;
|
||||||
|
|
||||||
let configure_shell_profile = if settings.modify_profile {
|
let configure_shell_profile = if settings.modify_profile {
|
||||||
Some(ConfigureShellProfile::plan().await?)
|
Some(ConfigureShellProfile::plan().await?)
|
||||||
|
@ -68,8 +72,8 @@ impl ConfigureNix {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
#[typetag::serde(name = "configure-nix")]
|
||||||
impl Actionable for ConfigureNix {
|
impl Actionable for ConfigureNix {
|
||||||
type Error = ConfigureNixError;
|
|
||||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||||
let Self {
|
let Self {
|
||||||
setup_default_profile,
|
setup_default_profile,
|
||||||
|
@ -95,7 +99,7 @@ impl Actionable for ConfigureNix {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
async fn execute(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
setup_default_profile,
|
setup_default_profile,
|
||||||
configure_nix_daemon_service,
|
configure_nix_daemon_service,
|
||||||
|
@ -113,51 +117,16 @@ impl Actionable for ConfigureNix {
|
||||||
|
|
||||||
if let Some(configure_shell_profile) = configure_shell_profile {
|
if let Some(configure_shell_profile) = configure_shell_profile {
|
||||||
tokio::try_join!(
|
tokio::try_join!(
|
||||||
async move {
|
async move { setup_default_profile.execute().await },
|
||||||
setup_default_profile
|
async move { place_nix_configuration.execute().await },
|
||||||
.execute()
|
async move { place_channel_configuration.execute().await },
|
||||||
.await
|
async move { configure_shell_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 {
|
} else {
|
||||||
tokio::try_join!(
|
tokio::try_join!(
|
||||||
async move {
|
async move { setup_default_profile.execute().await },
|
||||||
setup_default_profile
|
async move { place_nix_configuration.execute().await },
|
||||||
.execute()
|
async move { place_channel_configuration.execute().await },
|
||||||
.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?;
|
configure_nix_daemon_service.execute().await?;
|
||||||
|
@ -194,7 +163,7 @@ impl Actionable for ConfigureNix {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
async fn revert(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
setup_default_profile,
|
setup_default_profile,
|
||||||
configure_nix_daemon_service,
|
configure_nix_daemon_service,
|
||||||
|
@ -223,43 +192,3 @@ impl Actionable for ConfigureNix {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ConfigureNix> for Action {
|
|
||||||
fn from(v: ConfigureNix) -> Self {
|
|
||||||
Action::ConfigureNix(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, Serialize)]
|
|
||||||
pub enum ConfigureNixError {
|
|
||||||
#[error("Setting up default profile")]
|
|
||||||
SetupDefaultProfile(
|
|
||||||
#[source]
|
|
||||||
#[from]
|
|
||||||
SetupDefaultProfileError,
|
|
||||||
),
|
|
||||||
#[error("Placing Nix configuration")]
|
|
||||||
PlaceNixConfiguration(
|
|
||||||
#[source]
|
|
||||||
#[from]
|
|
||||||
PlaceNixConfigurationError,
|
|
||||||
),
|
|
||||||
#[error("Placing channel configuration")]
|
|
||||||
PlaceChannelConfiguration(
|
|
||||||
#[source]
|
|
||||||
#[from]
|
|
||||||
PlaceChannelConfigurationError,
|
|
||||||
),
|
|
||||||
#[error("Configuring Nix daemon")]
|
|
||||||
ConfigureNixDaemonService(
|
|
||||||
#[source]
|
|
||||||
#[from]
|
|
||||||
ConfigureNixDaemonServiceError,
|
|
||||||
),
|
|
||||||
#[error("Configuring shell profile")]
|
|
||||||
ConfigureShellProfile(
|
|
||||||
#[source]
|
|
||||||
#[from]
|
|
||||||
ConfigureShellProfileError,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ use serde::Serialize;
|
||||||
use tokio::task::{JoinError, JoinSet};
|
use tokio::task::{JoinError, JoinSet};
|
||||||
|
|
||||||
use crate::actions::base::{CreateOrAppendFile, CreateOrAppendFileError};
|
use crate::actions::base::{CreateOrAppendFile, CreateOrAppendFileError};
|
||||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
use crate::actions::{ActionDescription, ActionError, ActionState, Actionable};
|
||||||
|
|
||||||
const PROFILE_TARGETS: &[&str] = &[
|
const PROFILE_TARGETS: &[&str] = &[
|
||||||
"/etc/bashrc",
|
"/etc/bashrc",
|
||||||
|
@ -24,7 +24,7 @@ pub struct ConfigureShellProfile {
|
||||||
|
|
||||||
impl ConfigureShellProfile {
|
impl ConfigureShellProfile {
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub async fn plan() -> Result<Self, ConfigureShellProfileError> {
|
pub async fn plan() -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let mut create_or_append_files = Vec::default();
|
let mut create_or_append_files = Vec::default();
|
||||||
for profile_target in PROFILE_TARGETS {
|
for profile_target in PROFILE_TARGETS {
|
||||||
let path = Path::new(profile_target);
|
let path = Path::new(profile_target);
|
||||||
|
@ -41,8 +41,11 @@ impl ConfigureShellProfile {
|
||||||
# End Nix\n
|
# End Nix\n
|
||||||
\n",
|
\n",
|
||||||
);
|
);
|
||||||
create_or_append_files
|
create_or_append_files.push(
|
||||||
.push(CreateOrAppendFile::plan(path, None, None, 0o0644, buf).await?);
|
CreateOrAppendFile::plan(path, None, None, 0o0644, buf)
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.boxed())?,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
@ -53,9 +56,8 @@ impl ConfigureShellProfile {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
#[typetag::serde(name = "configure-shell-profile")]
|
||||||
impl Actionable for ConfigureShellProfile {
|
impl Actionable for ConfigureShellProfile {
|
||||||
type Error = ConfigureShellProfileError;
|
|
||||||
|
|
||||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||||
if self.action_state == ActionState::Completed {
|
if self.action_state == ActionState::Completed {
|
||||||
vec![]
|
vec![]
|
||||||
|
@ -68,7 +70,7 @@ impl Actionable for ConfigureShellProfile {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
async fn execute(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
create_or_append_files,
|
create_or_append_files,
|
||||||
action_state,
|
action_state,
|
||||||
|
@ -87,7 +89,10 @@ impl Actionable for ConfigureShellProfile {
|
||||||
let mut create_or_append_file_clone = create_or_append_file.clone();
|
let mut create_or_append_file_clone = create_or_append_file.clone();
|
||||||
let _abort_handle = set.spawn(async move {
|
let _abort_handle = set.spawn(async move {
|
||||||
create_or_append_file_clone.execute().await?;
|
create_or_append_file_clone.execute().await?;
|
||||||
Result::<_, CreateOrAppendFileError>::Ok((idx, create_or_append_file_clone))
|
Result::<_, Box<dyn std::error::Error + Send + Sync>>::Ok((
|
||||||
|
idx,
|
||||||
|
create_or_append_file_clone,
|
||||||
|
))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,7 +102,7 @@ impl Actionable for ConfigureShellProfile {
|
||||||
create_or_append_files[idx] = create_or_append_file
|
create_or_append_files[idx] = create_or_append_file
|
||||||
},
|
},
|
||||||
Ok(Err(e)) => errors.push(e),
|
Ok(Err(e)) => errors.push(e),
|
||||||
Err(e) => return Err(e.into()),
|
Err(e) => return Err(e.boxed()),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,9 +110,7 @@ impl Actionable for ConfigureShellProfile {
|
||||||
if errors.len() == 1 {
|
if errors.len() == 1 {
|
||||||
return Err(errors.into_iter().next().unwrap().into());
|
return Err(errors.into_iter().next().unwrap().into());
|
||||||
} else {
|
} else {
|
||||||
return Err(ConfigureShellProfileError::MultipleCreateOrAppendFile(
|
return Err(ConfigureShellProfileError::MultipleCreateOrAppendFile(errors).boxed());
|
||||||
errors,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,7 +131,7 @@ impl Actionable for ConfigureShellProfile {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
async fn revert(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
create_or_append_files,
|
create_or_append_files,
|
||||||
action_state,
|
action_state,
|
||||||
|
@ -147,7 +150,10 @@ impl Actionable for ConfigureShellProfile {
|
||||||
let mut create_or_append_file_clone = create_or_append_file.clone();
|
let mut create_or_append_file_clone = create_or_append_file.clone();
|
||||||
let _abort_handle = set.spawn(async move {
|
let _abort_handle = set.spawn(async move {
|
||||||
create_or_append_file_clone.revert().await?;
|
create_or_append_file_clone.revert().await?;
|
||||||
Result::<_, CreateOrAppendFileError>::Ok((idx, create_or_append_file_clone))
|
Result::<_, Box<dyn std::error::Error + Send + Sync>>::Ok((
|
||||||
|
idx,
|
||||||
|
create_or_append_file_clone,
|
||||||
|
))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +163,7 @@ impl Actionable for ConfigureShellProfile {
|
||||||
create_or_append_files[idx] = create_or_append_file
|
create_or_append_files[idx] = create_or_append_file
|
||||||
},
|
},
|
||||||
Ok(Err(e)) => errors.push(e),
|
Ok(Err(e)) => errors.push(e),
|
||||||
Err(e) => return Err(e.into()),
|
Err(e) => return Err(e.boxed()),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,9 +171,7 @@ impl Actionable for ConfigureShellProfile {
|
||||||
if errors.len() == 1 {
|
if errors.len() == 1 {
|
||||||
return Err(errors.into_iter().next().unwrap().into());
|
return Err(errors.into_iter().next().unwrap().into());
|
||||||
} else {
|
} else {
|
||||||
return Err(ConfigureShellProfileError::MultipleCreateOrAppendFile(
|
return Err(ConfigureShellProfileError::MultipleCreateOrAppendFile(errors).boxed());
|
||||||
errors,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,13 +181,7 @@ impl Actionable for ConfigureShellProfile {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ConfigureShellProfile> for Action {
|
#[derive(Debug, thiserror::Error)]
|
||||||
fn from(v: ConfigureShellProfile) -> Self {
|
|
||||||
Action::ConfigureShellProfile(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, Serialize)]
|
|
||||||
pub enum ConfigureShellProfileError {
|
pub enum ConfigureShellProfileError {
|
||||||
#[error("Creating or appending to file")]
|
#[error("Creating or appending to file")]
|
||||||
CreateOrAppendFile(
|
CreateOrAppendFile(
|
||||||
|
@ -192,12 +190,11 @@ pub enum ConfigureShellProfileError {
|
||||||
CreateOrAppendFileError,
|
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<Box<dyn std::error::Error + Send + Sync>>),
|
||||||
#[error("Joining spawned async task")]
|
#[error("Joining spawned async task")]
|
||||||
Join(
|
Join(
|
||||||
#[source]
|
#[source]
|
||||||
#[from]
|
#[from]
|
||||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
|
||||||
JoinError,
|
JoinError,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::actions::base::{CreateDirectory, CreateDirectoryError};
|
use crate::actions::base::{CreateDirectory, CreateDirectoryError};
|
||||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
use crate::actions::{ActionDescription, ActionError, ActionState, Actionable};
|
||||||
|
|
||||||
const PATHS: &[&str] = &[
|
const PATHS: &[&str] = &[
|
||||||
"/nix/var",
|
"/nix/var",
|
||||||
|
@ -27,7 +27,7 @@ pub struct CreateNixTree {
|
||||||
|
|
||||||
impl CreateNixTree {
|
impl CreateNixTree {
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub async fn plan() -> Result<Self, CreateNixTreeError> {
|
pub async fn plan() -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let mut create_directories = Vec::default();
|
let mut create_directories = Vec::default();
|
||||||
for path in PATHS {
|
for path in PATHS {
|
||||||
// We use `create_dir` over `create_dir_all` to ensure we always set permissions right
|
// We use `create_dir` over `create_dir_all` to ensure we always set permissions right
|
||||||
|
@ -42,9 +42,8 @@ impl CreateNixTree {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
#[typetag::serde(name = "creat-nix-tree")]
|
||||||
impl Actionable for CreateNixTree {
|
impl Actionable for CreateNixTree {
|
||||||
type Error = CreateNixTreeError;
|
|
||||||
|
|
||||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||||
if self.action_state == ActionState::Completed {
|
if self.action_state == ActionState::Completed {
|
||||||
vec![]
|
vec![]
|
||||||
|
@ -69,7 +68,7 @@ impl Actionable for CreateNixTree {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
async fn execute(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
create_directories,
|
create_directories,
|
||||||
action_state,
|
action_state,
|
||||||
|
@ -116,7 +115,7 @@ impl Actionable for CreateNixTree {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
async fn revert(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
create_directories,
|
create_directories,
|
||||||
action_state,
|
action_state,
|
||||||
|
@ -139,12 +138,6 @@ impl Actionable for CreateNixTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<CreateNixTree> for Action {
|
|
||||||
fn from(v: CreateNixTree) -> Self {
|
|
||||||
Action::CreateNixTree(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, Serialize)]
|
#[derive(Debug, thiserror::Error, Serialize)]
|
||||||
pub enum CreateNixTreeError {
|
pub enum CreateNixTreeError {
|
||||||
#[error("Creating directory")]
|
#[error("Creating directory")]
|
||||||
|
|
|
@ -2,7 +2,7 @@ use serde::Serialize;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use crate::actions::base::{CreateDirectory, CreateDirectoryError, CreateFile, CreateFileError};
|
use crate::actions::base::{CreateDirectory, CreateDirectoryError, CreateFile, CreateFileError};
|
||||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
use crate::actions::{ActionDescription, ActionError, ActionState, Actionable};
|
||||||
|
|
||||||
const PATHS: &[&str] = &[
|
const PATHS: &[&str] = &[
|
||||||
"usr",
|
"usr",
|
||||||
|
@ -23,7 +23,9 @@ pub struct CreateSystemdSysext {
|
||||||
|
|
||||||
impl CreateSystemdSysext {
|
impl CreateSystemdSysext {
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub async fn plan(destination: impl AsRef<Path>) -> Result<Self, CreateSystemdSysextError> {
|
pub async fn plan(
|
||||||
|
destination: impl AsRef<Path>,
|
||||||
|
) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let destination = destination.as_ref();
|
let destination = destination.as_ref();
|
||||||
|
|
||||||
let mut create_directories =
|
let mut create_directories =
|
||||||
|
@ -43,8 +45,8 @@ impl CreateSystemdSysext {
|
||||||
false => None,
|
false => None,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.map_err(CreateSystemdSysextError::ReadingOsRelease)?
|
.map_err(|e| CreateSystemdSysextError::ReadingOsRelease(e).boxed())?
|
||||||
.ok_or(CreateSystemdSysextError::NoVersionId)?;
|
.ok_or_else(|| CreateSystemdSysextError::NoVersionId.boxed())?;
|
||||||
let extension_release_buf =
|
let extension_release_buf =
|
||||||
format!("SYSEXT_LEVEL=1.0\nID=steamos\nVERSION_ID={version_id}");
|
format!("SYSEXT_LEVEL=1.0\nID=steamos\nVERSION_ID={version_id}");
|
||||||
let create_extension_release = CreateFile::plan(
|
let create_extension_release = CreateFile::plan(
|
||||||
|
@ -88,9 +90,8 @@ impl CreateSystemdSysext {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
#[typetag::serde(name = "create-systemd-sysext")]
|
||||||
impl Actionable for CreateSystemdSysext {
|
impl Actionable for CreateSystemdSysext {
|
||||||
type Error = CreateSystemdSysextError;
|
|
||||||
|
|
||||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||||
let Self {
|
let Self {
|
||||||
action_state: _,
|
action_state: _,
|
||||||
|
@ -112,7 +113,7 @@ impl Actionable for CreateSystemdSysext {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all, fields(destination,))]
|
#[tracing::instrument(skip_all, fields(destination,))]
|
||||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
async fn execute(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
destination: _,
|
destination: _,
|
||||||
action_state,
|
action_state,
|
||||||
|
@ -156,7 +157,7 @@ impl Actionable for CreateSystemdSysext {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all, fields(destination,))]
|
#[tracing::instrument(skip_all, fields(destination,))]
|
||||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
async fn revert(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
destination: _,
|
destination: _,
|
||||||
action_state,
|
action_state,
|
||||||
|
@ -184,12 +185,6 @@ impl Actionable for CreateSystemdSysext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<CreateSystemdSysext> for Action {
|
|
||||||
fn from(v: CreateSystemdSysext) -> Self {
|
|
||||||
Action::CreateSystemdSysext(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, Serialize)]
|
#[derive(Debug, thiserror::Error, Serialize)]
|
||||||
pub enum CreateSystemdSysextError {
|
pub enum CreateSystemdSysextError {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
|
|
|
@ -4,7 +4,7 @@ use tokio::task::{JoinError, JoinSet};
|
||||||
use crate::CommonSettings;
|
use crate::CommonSettings;
|
||||||
|
|
||||||
use crate::actions::base::{CreateGroup, CreateGroupError, CreateUserError};
|
use crate::actions::base::{CreateGroup, CreateGroupError, CreateUserError};
|
||||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable, CreateUser};
|
use crate::actions::{ActionDescription, ActionError, ActionState, Actionable, CreateUser};
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||||
pub struct CreateUsersAndGroup {
|
pub struct CreateUsersAndGroup {
|
||||||
|
@ -51,9 +51,8 @@ impl CreateUsersAndGroup {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
#[typetag::serde(name = "create-users-and-group")]
|
||||||
impl Actionable for CreateUsersAndGroup {
|
impl Actionable for CreateUsersAndGroup {
|
||||||
type Error = CreateUsersAndGroupError;
|
|
||||||
|
|
||||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||||
let Self {
|
let Self {
|
||||||
daemon_user_count,
|
daemon_user_count,
|
||||||
|
@ -88,7 +87,7 @@ impl Actionable for CreateUsersAndGroup {
|
||||||
nix_build_user_prefix = self.nix_build_user_prefix,
|
nix_build_user_prefix = self.nix_build_user_prefix,
|
||||||
nix_build_user_id_base = self.nix_build_user_id_base,
|
nix_build_user_id_base = self.nix_build_user_id_base,
|
||||||
))]
|
))]
|
||||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
async fn execute(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
create_users,
|
create_users,
|
||||||
create_group,
|
create_group,
|
||||||
|
@ -173,7 +172,7 @@ impl Actionable for CreateUsersAndGroup {
|
||||||
nix_build_user_prefix = self.nix_build_user_prefix,
|
nix_build_user_prefix = self.nix_build_user_prefix,
|
||||||
nix_build_user_id_base = self.nix_build_user_id_base,
|
nix_build_user_id_base = self.nix_build_user_id_base,
|
||||||
))]
|
))]
|
||||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
async fn revert(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
create_users,
|
create_users,
|
||||||
create_group,
|
create_group,
|
||||||
|
@ -199,7 +198,7 @@ impl Actionable for CreateUsersAndGroup {
|
||||||
let mut create_user_clone = create_user.clone();
|
let mut create_user_clone = create_user.clone();
|
||||||
let _abort_handle = set.spawn(async move {
|
let _abort_handle = set.spawn(async move {
|
||||||
create_user_clone.revert().await?;
|
create_user_clone.revert().await?;
|
||||||
Result::<_, CreateUserError>::Ok((idx, create_user_clone))
|
Result::<_, Box<dyn std::error::Error + Send + Sync>>::Ok((idx, create_user_clone))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,7 +206,7 @@ impl Actionable for CreateUsersAndGroup {
|
||||||
match result {
|
match result {
|
||||||
Ok(Ok((idx, success))) => create_users[idx] = success,
|
Ok(Ok((idx, success))) => create_users[idx] = success,
|
||||||
Ok(Err(e)) => errors.push(e),
|
Ok(Err(e)) => errors.push(e),
|
||||||
Err(e) => return Err(e)?,
|
Err(e) => return Err(e.boxed())?,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,7 +214,7 @@ impl Actionable for CreateUsersAndGroup {
|
||||||
if errors.len() == 1 {
|
if errors.len() == 1 {
|
||||||
return Err(errors.into_iter().next().unwrap().into());
|
return Err(errors.into_iter().next().unwrap().into());
|
||||||
} else {
|
} else {
|
||||||
return Err(CreateUsersAndGroupError::CreateUsers(errors));
|
return Err(CreateUsersAndGroupError::CreateUsers(errors).boxed());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,13 +227,7 @@ impl Actionable for CreateUsersAndGroup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<CreateUsersAndGroup> for Action {
|
#[derive(Debug, thiserror::Error)]
|
||||||
fn from(v: CreateUsersAndGroup) -> Self {
|
|
||||||
Action::CreateUsersAndGroup(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, Serialize)]
|
|
||||||
pub enum CreateUsersAndGroupError {
|
pub enum CreateUsersAndGroupError {
|
||||||
#[error("Creating user")]
|
#[error("Creating user")]
|
||||||
CreateUser(
|
CreateUser(
|
||||||
|
@ -243,7 +236,7 @@ pub enum CreateUsersAndGroupError {
|
||||||
CreateUserError,
|
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<Box<dyn std::error::Error + Send + Sync>>),
|
||||||
#[error("Creating group")]
|
#[error("Creating group")]
|
||||||
CreateGroup(
|
CreateGroup(
|
||||||
#[source]
|
#[source]
|
||||||
|
@ -254,7 +247,6 @@ pub enum CreateUsersAndGroupError {
|
||||||
Join(
|
Join(
|
||||||
#[source]
|
#[source]
|
||||||
#[from]
|
#[from]
|
||||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
|
||||||
JoinError,
|
JoinError,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,15 +5,19 @@ use std::{
|
||||||
};
|
};
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
|
|
||||||
use crate::actions::base::{
|
use crate::actions::{
|
||||||
|
base::{
|
||||||
darwin::{
|
darwin::{
|
||||||
BootstrapVolume, BootstrapVolumeError, CreateSyntheticObjects, CreateSyntheticObjectsError,
|
BootstrapVolume, BootstrapVolumeError, CreateSyntheticObjects,
|
||||||
CreateVolume, CreateVolumeError, EnableOwnership, EnableOwnershipError, EncryptVolume,
|
CreateSyntheticObjectsError, CreateVolume, CreateVolumeError, EnableOwnership,
|
||||||
EncryptVolumeError, UnmountVolume, UnmountVolumeError,
|
EnableOwnershipError, EncryptVolume, EncryptVolumeError, UnmountVolume,
|
||||||
|
UnmountVolumeError,
|
||||||
},
|
},
|
||||||
CreateFile, CreateFileError, CreateOrAppendFile, CreateOrAppendFileError,
|
CreateFile, CreateFileError, CreateOrAppendFile, CreateOrAppendFileError,
|
||||||
|
},
|
||||||
|
ActionError,
|
||||||
};
|
};
|
||||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
use crate::actions::{ActionDescription, ActionState, Actionable};
|
||||||
|
|
||||||
const NIX_VOLUME_MOUNTD_DEST: &str = "/Library/LaunchDaemons/org.nixos.darwin-store.plist";
|
const NIX_VOLUME_MOUNTD_DEST: &str = "/Library/LaunchDaemons/org.nixos.darwin-store.plist";
|
||||||
|
|
||||||
|
@ -42,7 +46,7 @@ impl CreateApfsVolume {
|
||||||
name: String,
|
name: String,
|
||||||
case_sensitive: bool,
|
case_sensitive: bool,
|
||||||
encrypt: Option<String>,
|
encrypt: Option<String>,
|
||||||
) -> Result<Self, CreateApfsVolumeError> {
|
) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let disk = disk.as_ref();
|
let disk = disk.as_ref();
|
||||||
let create_or_append_synthetic_conf = CreateOrAppendFile::plan(
|
let create_or_append_synthetic_conf = CreateOrAppendFile::plan(
|
||||||
"/etc/synthetic.conf",
|
"/etc/synthetic.conf",
|
||||||
|
@ -51,7 +55,8 @@ impl CreateApfsVolume {
|
||||||
0o0655,
|
0o0655,
|
||||||
"nix\n".into(), /* The newline is required otherwise it segfaults */
|
"nix\n".into(), /* The newline is required otherwise it segfaults */
|
||||||
)
|
)
|
||||||
.await?;
|
.await
|
||||||
|
.map_err(|e| e.boxed())?;
|
||||||
|
|
||||||
let create_synthetic_objects = CreateSyntheticObjects::plan().await?;
|
let create_synthetic_objects = CreateSyntheticObjects::plan().await?;
|
||||||
|
|
||||||
|
@ -66,7 +71,8 @@ impl CreateApfsVolume {
|
||||||
0o0655,
|
0o0655,
|
||||||
format!("NAME=\"{name}\" /nix apfs rw,noauto,nobrowse,suid,owners"),
|
format!("NAME=\"{name}\" /nix apfs rw,noauto,nobrowse,suid,owners"),
|
||||||
)
|
)
|
||||||
.await?;
|
.await
|
||||||
|
.map_err(|e| e.boxed())?;
|
||||||
|
|
||||||
let encrypt_volume = if let Some(password) = encrypt.as_ref() {
|
let encrypt_volume = if let Some(password) = encrypt.as_ref() {
|
||||||
Some(EncryptVolume::plan(disk, password.to_string()).await?)
|
Some(EncryptVolume::plan(disk, password.to_string()).await?)
|
||||||
|
@ -140,9 +146,8 @@ impl CreateApfsVolume {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
#[typetag::serde(name = "create-apfs-volume")]
|
||||||
impl Actionable for CreateApfsVolume {
|
impl Actionable for CreateApfsVolume {
|
||||||
type Error = CreateApfsVolumeError;
|
|
||||||
|
|
||||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||||
let Self {
|
let Self {
|
||||||
disk,
|
disk,
|
||||||
|
@ -163,7 +168,7 @@ impl Actionable for CreateApfsVolume {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all, fields(destination,))]
|
#[tracing::instrument(skip_all, fields(destination,))]
|
||||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
async fn execute(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
disk: _,
|
disk: _,
|
||||||
name: _,
|
name: _,
|
||||||
|
@ -207,7 +212,7 @@ impl Actionable for CreateApfsVolume {
|
||||||
.stdout(std::process::Stdio::null())
|
.stdout(std::process::Stdio::null())
|
||||||
.status()
|
.status()
|
||||||
.await
|
.await
|
||||||
.map_err(Self::Error::Command)?;
|
.map_err(|e| CreateApfsVolumeError::Command(e).boxed())?;
|
||||||
if status.success() || retry_tokens == 0 {
|
if status.success() || retry_tokens == 0 {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
@ -243,7 +248,7 @@ impl Actionable for CreateApfsVolume {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all, fields(disk, name))]
|
#[tracing::instrument(skip_all, fields(disk, name))]
|
||||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
async fn revert(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
disk: _,
|
disk: _,
|
||||||
name: _,
|
name: _,
|
||||||
|
@ -287,12 +292,6 @@ impl Actionable for CreateApfsVolume {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<CreateApfsVolume> for Action {
|
|
||||||
fn from(v: CreateApfsVolume) -> Self {
|
|
||||||
Action::CreateApfsVolume(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, Serialize)]
|
#[derive(Debug, thiserror::Error, Serialize)]
|
||||||
pub enum CreateApfsVolumeError {
|
pub enum CreateApfsVolumeError {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
|
|
|
@ -10,7 +10,7 @@ mod place_channel_configuration;
|
||||||
mod place_nix_configuration;
|
mod place_nix_configuration;
|
||||||
mod provision_nix;
|
mod provision_nix;
|
||||||
|
|
||||||
pub use configure_nix::{ConfigureNix, ConfigureNixError};
|
pub use configure_nix::ConfigureNix;
|
||||||
pub use configure_shell_profile::{ConfigureShellProfile, ConfigureShellProfileError};
|
pub use configure_shell_profile::{ConfigureShellProfile, ConfigureShellProfileError};
|
||||||
pub use create_nix_tree::{CreateNixTree, CreateNixTreeError};
|
pub use create_nix_tree::{CreateNixTree, CreateNixTreeError};
|
||||||
pub use create_systemd_sysext::{CreateSystemdSysext, CreateSystemdSysextError};
|
pub use create_systemd_sysext::{CreateSystemdSysext, CreateSystemdSysextError};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use reqwest::Url;
|
use reqwest::Url;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
use crate::actions::{ActionDescription, ActionError, ActionState, Actionable};
|
||||||
|
|
||||||
use crate::actions::base::{CreateFile, CreateFileError};
|
use crate::actions::base::{CreateFile, CreateFileError};
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ impl PlaceChannelConfiguration {
|
||||||
pub async fn plan(
|
pub async fn plan(
|
||||||
channels: Vec<(String, Url)>,
|
channels: Vec<(String, Url)>,
|
||||||
force: bool,
|
force: bool,
|
||||||
) -> Result<Self, PlaceChannelConfigurationError> {
|
) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let buf = channels
|
let buf = channels
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(name, url)| format!("{} {}", url, name))
|
.map(|(name, url)| format!("{} {}", url, name))
|
||||||
|
@ -25,7 +25,7 @@ impl PlaceChannelConfiguration {
|
||||||
.join("\n");
|
.join("\n");
|
||||||
let create_file = CreateFile::plan(
|
let create_file = CreateFile::plan(
|
||||||
dirs::home_dir()
|
dirs::home_dir()
|
||||||
.ok_or(PlaceChannelConfigurationError::NoRootHome)?
|
.ok_or_else(|| PlaceChannelConfigurationError::NoRootHome.boxed())?
|
||||||
.join(".nix-channels"),
|
.join(".nix-channels"),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
@ -43,9 +43,8 @@ impl PlaceChannelConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
#[typetag::serde(name = "place-channel-configuration")]
|
||||||
impl Actionable for PlaceChannelConfiguration {
|
impl Actionable for PlaceChannelConfiguration {
|
||||||
type Error = PlaceChannelConfigurationError;
|
|
||||||
|
|
||||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||||
let Self {
|
let Self {
|
||||||
channels: _,
|
channels: _,
|
||||||
|
@ -68,7 +67,7 @@ impl Actionable for PlaceChannelConfiguration {
|
||||||
#[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(", "),
|
||||||
))]
|
))]
|
||||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
async fn execute(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
create_file,
|
create_file,
|
||||||
channels: _,
|
channels: _,
|
||||||
|
@ -110,7 +109,7 @@ impl Actionable for PlaceChannelConfiguration {
|
||||||
#[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(", "),
|
||||||
))]
|
))]
|
||||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
async fn revert(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
create_file,
|
create_file,
|
||||||
channels: _,
|
channels: _,
|
||||||
|
@ -131,12 +130,6 @@ impl Actionable for PlaceChannelConfiguration {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<PlaceChannelConfiguration> for Action {
|
|
||||||
fn from(v: PlaceChannelConfiguration) -> Self {
|
|
||||||
Action::PlaceChannelConfiguration(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, Serialize)]
|
#[derive(Debug, thiserror::Error, Serialize)]
|
||||||
pub enum PlaceChannelConfigurationError {
|
pub enum PlaceChannelConfigurationError {
|
||||||
#[error("Creating file")]
|
#[error("Creating file")]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
use crate::actions::{ActionDescription, ActionError, ActionState, Actionable};
|
||||||
|
|
||||||
use crate::actions::base::{CreateDirectory, CreateDirectoryError, CreateFile, CreateFileError};
|
use crate::actions::base::{CreateDirectory, CreateDirectoryError, CreateFile, CreateFileError};
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ impl PlaceNixConfiguration {
|
||||||
nix_build_group_name: String,
|
nix_build_group_name: String,
|
||||||
extra_conf: Option<String>,
|
extra_conf: Option<String>,
|
||||||
force: bool,
|
force: bool,
|
||||||
) -> Result<Self, PlaceNixConfigurationError> {
|
) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let buf = format!(
|
let buf = format!(
|
||||||
"\
|
"\
|
||||||
{extra_conf}\n\
|
{extra_conf}\n\
|
||||||
|
@ -44,9 +44,8 @@ impl PlaceNixConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
#[typetag::serde(name = "place-nix-configuration")]
|
||||||
impl Actionable for PlaceNixConfiguration {
|
impl Actionable for PlaceNixConfiguration {
|
||||||
type Error = PlaceNixConfigurationError;
|
|
||||||
|
|
||||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||||
if self.action_state == ActionState::Completed {
|
if self.action_state == ActionState::Completed {
|
||||||
vec![]
|
vec![]
|
||||||
|
@ -62,7 +61,7 @@ impl Actionable for PlaceNixConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
async fn execute(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
create_file,
|
create_file,
|
||||||
create_directory,
|
create_directory,
|
||||||
|
@ -98,7 +97,7 @@ impl Actionable for PlaceNixConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
async fn revert(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
create_file,
|
create_file,
|
||||||
create_directory,
|
create_directory,
|
||||||
|
@ -120,12 +119,6 @@ impl Actionable for PlaceNixConfiguration {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<PlaceNixConfiguration> for Action {
|
|
||||||
fn from(v: PlaceNixConfiguration) -> Self {
|
|
||||||
Action::PlaceNixConfiguration(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, Serialize)]
|
#[derive(Debug, thiserror::Error, Serialize)]
|
||||||
pub enum PlaceNixConfigurationError {
|
pub enum PlaceNixConfigurationError {
|
||||||
#[error("Creating file")]
|
#[error("Creating file")]
|
||||||
|
|
|
@ -8,7 +8,7 @@ use crate::actions::base::{
|
||||||
};
|
};
|
||||||
use crate::CommonSettings;
|
use crate::CommonSettings;
|
||||||
|
|
||||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
use crate::actions::{ActionDescription, ActionError, ActionState, Actionable};
|
||||||
|
|
||||||
use super::{CreateNixTree, CreateNixTreeError, CreateUsersAndGroup, CreateUsersAndGroupError};
|
use super::{CreateNixTree, CreateNixTreeError, CreateUsersAndGroup, CreateUsersAndGroupError};
|
||||||
|
|
||||||
|
@ -23,16 +23,22 @@ pub struct ProvisionNix {
|
||||||
|
|
||||||
impl ProvisionNix {
|
impl ProvisionNix {
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub async fn plan(settings: CommonSettings) -> Result<Self, ProvisionNixError> {
|
pub async fn plan(
|
||||||
|
settings: CommonSettings,
|
||||||
|
) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let fetch_nix = FetchNix::plan(
|
let fetch_nix = FetchNix::plan(
|
||||||
settings.nix_package_url.clone(),
|
settings.nix_package_url.clone(),
|
||||||
PathBuf::from("/nix/temp-install-dir"),
|
PathBuf::from("/nix/temp-install-dir"),
|
||||||
)
|
)
|
||||||
.await?;
|
.await
|
||||||
let create_users_and_group = CreateUsersAndGroup::plan(settings.clone()).await?;
|
.map_err(|e| e.boxed())?;
|
||||||
|
let create_users_and_group = CreateUsersAndGroup::plan(settings.clone())
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.boxed())?;
|
||||||
let create_nix_tree = CreateNixTree::plan().await?;
|
let create_nix_tree = CreateNixTree::plan().await?;
|
||||||
let move_unpacked_nix =
|
let move_unpacked_nix = MoveUnpackedNix::plan(PathBuf::from("/nix/temp-install-dir"))
|
||||||
MoveUnpackedNix::plan(PathBuf::from("/nix/temp-install-dir")).await?;
|
.await
|
||||||
|
.map_err(|e| e.boxed())?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
fetch_nix,
|
fetch_nix,
|
||||||
create_users_and_group,
|
create_users_and_group,
|
||||||
|
@ -44,8 +50,8 @@ impl ProvisionNix {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
#[typetag::serde(name = "provision-nix")]
|
||||||
impl Actionable for ProvisionNix {
|
impl Actionable for ProvisionNix {
|
||||||
type Error = ProvisionNixError;
|
|
||||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||||
let Self {
|
let Self {
|
||||||
fetch_nix,
|
fetch_nix,
|
||||||
|
@ -68,7 +74,7 @@ impl Actionable for ProvisionNix {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
async fn execute(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
fetch_nix,
|
fetch_nix,
|
||||||
create_nix_tree,
|
create_nix_tree,
|
||||||
|
@ -87,16 +93,13 @@ impl Actionable for ProvisionNix {
|
||||||
let mut fetch_nix_clone = fetch_nix.clone();
|
let mut fetch_nix_clone = fetch_nix.clone();
|
||||||
let fetch_nix_handle = tokio::task::spawn(async {
|
let fetch_nix_handle = tokio::task::spawn(async {
|
||||||
fetch_nix_clone.execute().await?;
|
fetch_nix_clone.execute().await?;
|
||||||
Result::<_, Self::Error>::Ok(fetch_nix_clone)
|
Result::<_, Box<dyn std::error::Error + Send + Sync>>::Ok(fetch_nix_clone)
|
||||||
});
|
});
|
||||||
|
|
||||||
create_users_and_group.execute().await?;
|
create_users_and_group.execute().await?;
|
||||||
create_nix_tree
|
create_nix_tree.execute().await?;
|
||||||
.execute()
|
|
||||||
.await
|
|
||||||
.map_err(ProvisionNixError::from)?;
|
|
||||||
|
|
||||||
*fetch_nix = fetch_nix_handle.await.map_err(ProvisionNixError::from)??;
|
*fetch_nix = fetch_nix_handle.await.map_err(|e| e.boxed())??;
|
||||||
move_unpacked_nix.execute().await?;
|
move_unpacked_nix.execute().await?;
|
||||||
|
|
||||||
tracing::trace!("Provisioned Nix");
|
tracing::trace!("Provisioned Nix");
|
||||||
|
@ -125,7 +128,7 @@ impl Actionable for ProvisionNix {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
async fn revert(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let Self {
|
let Self {
|
||||||
fetch_nix,
|
fetch_nix,
|
||||||
create_nix_tree,
|
create_nix_tree,
|
||||||
|
@ -144,19 +147,19 @@ impl Actionable for ProvisionNix {
|
||||||
let mut fetch_nix_clone = fetch_nix.clone();
|
let mut fetch_nix_clone = fetch_nix.clone();
|
||||||
let fetch_nix_handle = tokio::task::spawn(async {
|
let fetch_nix_handle = tokio::task::spawn(async {
|
||||||
fetch_nix_clone.revert().await?;
|
fetch_nix_clone.revert().await?;
|
||||||
Result::<_, Self::Error>::Ok(fetch_nix_clone)
|
Result::<_, Box<dyn std::error::Error + Send + Sync>>::Ok(fetch_nix_clone)
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Err(err) = create_users_and_group.revert().await {
|
if let Err(err) = create_users_and_group.revert().await {
|
||||||
fetch_nix_handle.abort();
|
fetch_nix_handle.abort();
|
||||||
return Err(Self::Error::from(err));
|
return Err(err);
|
||||||
}
|
}
|
||||||
if let Err(err) = create_nix_tree.revert().await {
|
if let Err(err) = create_nix_tree.revert().await {
|
||||||
fetch_nix_handle.abort();
|
fetch_nix_handle.abort();
|
||||||
return Err(Self::Error::from(err));
|
return Err(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
*fetch_nix = fetch_nix_handle.await.map_err(ProvisionNixError::from)??;
|
*fetch_nix = fetch_nix_handle.await.map_err(|e| e.boxed())??;
|
||||||
move_unpacked_nix.revert().await?;
|
move_unpacked_nix.revert().await?;
|
||||||
|
|
||||||
tracing::trace!("Unprovisioned Nix");
|
tracing::trace!("Unprovisioned Nix");
|
||||||
|
@ -165,13 +168,7 @@ impl Actionable for ProvisionNix {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ProvisionNix> for Action {
|
#[derive(Debug, thiserror::Error)]
|
||||||
fn from(v: ProvisionNix) -> Self {
|
|
||||||
Action::ProvisionNix(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, Serialize)]
|
|
||||||
pub enum ProvisionNixError {
|
pub enum ProvisionNixError {
|
||||||
#[error("Fetching Nix")]
|
#[error("Fetching Nix")]
|
||||||
FetchNix(
|
FetchNix(
|
||||||
|
@ -183,7 +180,6 @@ pub enum ProvisionNixError {
|
||||||
Join(
|
Join(
|
||||||
#[source]
|
#[source]
|
||||||
#[from]
|
#[from]
|
||||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
|
||||||
JoinError,
|
JoinError,
|
||||||
),
|
),
|
||||||
#[error("Creating directory")]
|
#[error("Creating directory")]
|
||||||
|
|
|
@ -11,26 +11,37 @@ use base::{
|
||||||
};
|
};
|
||||||
use meta::{
|
use meta::{
|
||||||
darwin::{CreateApfsVolume, CreateApfsVolumeError},
|
darwin::{CreateApfsVolume, CreateApfsVolumeError},
|
||||||
ConfigureNix, ConfigureNixError, ConfigureShellProfile, ConfigureShellProfileError,
|
ConfigureNix, ConfigureShellProfile, ConfigureShellProfileError, CreateNixTree,
|
||||||
CreateNixTree, CreateNixTreeError, CreateSystemdSysext, CreateSystemdSysextError,
|
CreateNixTreeError, CreateSystemdSysext, CreateSystemdSysextError, CreateUsersAndGroup,
|
||||||
CreateUsersAndGroup, CreateUsersAndGroupError, PlaceChannelConfiguration,
|
CreateUsersAndGroupError, PlaceChannelConfiguration, PlaceChannelConfigurationError,
|
||||||
PlaceChannelConfigurationError, PlaceNixConfiguration, PlaceNixConfigurationError,
|
PlaceNixConfiguration, PlaceNixConfigurationError, ProvisionNix, ProvisionNixError,
|
||||||
ProvisionNix, ProvisionNixError,
|
|
||||||
};
|
};
|
||||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
pub trait ActionError: std::error::Error + Send + Sync {
|
||||||
pub trait Actionable: DeserializeOwned + Serialize + Into<Action> {
|
fn boxed(self) -> Box<dyn std::error::Error + Send + Sync>
|
||||||
type Error: std::error::Error + std::fmt::Debug + Serialize + Into<ActionError>;
|
where
|
||||||
|
Self: Sized + 'static,
|
||||||
|
{
|
||||||
|
Box::new(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E> ActionError for E where E: std::error::Error + Send + Sized + Sync {}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
#[typetag::serde(tag = "action")]
|
||||||
|
pub trait Actionable: Send + Sync + std::fmt::Debug + dyn_clone::DynClone {
|
||||||
fn describe_execute(&self) -> Vec<ActionDescription>;
|
fn describe_execute(&self) -> Vec<ActionDescription>;
|
||||||
fn describe_revert(&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<(), Box<dyn std::error::Error + Send + Sync>>;
|
||||||
async fn revert(&mut self) -> Result<(), Self::Error>;
|
async fn revert(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dyn_clone::clone_trait_object!(Actionable);
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||||
pub enum ActionState {
|
pub enum ActionState {
|
||||||
Completed,
|
Completed,
|
||||||
|
@ -54,232 +65,3 @@ impl ActionDescription {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
|
||||||
pub enum Action {
|
|
||||||
DarwinBootstrapVolume(base::darwin::BootstrapVolume),
|
|
||||||
DarwinCreateSyntheticObjects(base::darwin::CreateSyntheticObjects),
|
|
||||||
DarwinCreateVolume(base::darwin::CreateVolume),
|
|
||||||
DarwinEnableOwnership(base::darwin::EnableOwnership),
|
|
||||||
DarwinEncryptVolume(base::darwin::EncryptVolume),
|
|
||||||
DarwinKickStartLaunchctlService(base::darwin::KickstartLaunchctlService),
|
|
||||||
DarwinUnmountVolume(base::darwin::UnmountVolume),
|
|
||||||
ConfigureNix(ConfigureNix),
|
|
||||||
ConfigureNixDaemonService(ConfigureNixDaemonService),
|
|
||||||
ConfigureShellProfile(ConfigureShellProfile),
|
|
||||||
CreateApfsVolume(CreateApfsVolume),
|
|
||||||
CreateDirectory(CreateDirectory),
|
|
||||||
CreateFile(CreateFile),
|
|
||||||
CreateGroup(CreateGroup),
|
|
||||||
CreateNixTree(CreateNixTree),
|
|
||||||
CreateOrAppendFile(CreateOrAppendFile),
|
|
||||||
CreateSystemdSysext(CreateSystemdSysext),
|
|
||||||
CreateUser(CreateUser),
|
|
||||||
CreateUsersAndGroup(CreateUsersAndGroup),
|
|
||||||
FetchNix(FetchNix),
|
|
||||||
MoveUnpackedNix(MoveUnpackedNix),
|
|
||||||
PlaceChannelConfiguration(PlaceChannelConfiguration),
|
|
||||||
PlaceNixConfiguration(PlaceNixConfiguration),
|
|
||||||
ProvisionNix(ProvisionNix),
|
|
||||||
SetupDefaultProfile(SetupDefaultProfile),
|
|
||||||
StartSystemdUnit(StartSystemdUnit),
|
|
||||||
SystemdSysextMerge(SystemdSysextMerge),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, serde::Serialize)]
|
|
||||||
pub enum ActionError {
|
|
||||||
#[error(transparent)]
|
|
||||||
DarwinBootstrapVolume(#[from] base::darwin::BootstrapVolumeError),
|
|
||||||
#[error(transparent)]
|
|
||||||
DarwinCreateSyntheticObjects(#[from] base::darwin::CreateSyntheticObjectsError),
|
|
||||||
#[error(transparent)]
|
|
||||||
DarwinCreateVolume(#[from] base::darwin::CreateVolumeError),
|
|
||||||
#[error(transparent)]
|
|
||||||
DarwinEnableOwnership(#[from] base::darwin::EnableOwnershipError),
|
|
||||||
#[error(transparent)]
|
|
||||||
DarwinEncryptVolume(#[from] base::darwin::EncryptVolumeError),
|
|
||||||
#[error(transparent)]
|
|
||||||
DarwinKickStartLaunchctlService(#[from] base::darwin::KickstartLaunchctlServiceError),
|
|
||||||
#[error(transparent)]
|
|
||||||
DarwinUnmountVolume(#[from] base::darwin::UnmountVolumeError),
|
|
||||||
#[error("Attempted to revert an unexecuted action")]
|
|
||||||
NotExecuted(Action),
|
|
||||||
#[error("Attempted to execute an already executed action")]
|
|
||||||
AlreadyExecuted(Action),
|
|
||||||
#[error("Attempted to revert an already reverted action")]
|
|
||||||
AlreadyReverted(Action),
|
|
||||||
#[error(transparent)]
|
|
||||||
CreateApfsVolume(#[from] CreateApfsVolumeError),
|
|
||||||
#[error(transparent)]
|
|
||||||
ConfigureNixDaemonService(#[from] ConfigureNixDaemonServiceError),
|
|
||||||
#[error(transparent)]
|
|
||||||
ConfigureNix(#[from] ConfigureNixError),
|
|
||||||
#[error(transparent)]
|
|
||||||
ConfigureShellProfile(#[from] ConfigureShellProfileError),
|
|
||||||
#[error(transparent)]
|
|
||||||
CreateDirectory(#[from] CreateDirectoryError),
|
|
||||||
#[error(transparent)]
|
|
||||||
CreateSystemdSysext(#[from] CreateSystemdSysextError),
|
|
||||||
#[error(transparent)]
|
|
||||||
CreateFile(#[from] CreateFileError),
|
|
||||||
#[error(transparent)]
|
|
||||||
CreateGroup(#[from] CreateGroupError),
|
|
||||||
#[error(transparent)]
|
|
||||||
CreateOrAppendFile(#[from] CreateOrAppendFileError),
|
|
||||||
#[error(transparent)]
|
|
||||||
CreateNixTree(#[from] CreateNixTreeError),
|
|
||||||
#[error(transparent)]
|
|
||||||
CreateUser(#[from] CreateUserError),
|
|
||||||
#[error(transparent)]
|
|
||||||
CreateUsersAndGroup(#[from] CreateUsersAndGroupError),
|
|
||||||
#[error(transparent)]
|
|
||||||
FetchNix(#[from] FetchNixError),
|
|
||||||
#[error(transparent)]
|
|
||||||
MoveUnpackedNix(#[from] MoveUnpackedNixError),
|
|
||||||
#[error(transparent)]
|
|
||||||
PlaceChannelConfiguration(#[from] PlaceChannelConfigurationError),
|
|
||||||
#[error(transparent)]
|
|
||||||
PlaceNixConfiguration(#[from] PlaceNixConfigurationError),
|
|
||||||
#[error(transparent)]
|
|
||||||
SetupDefaultProfile(#[from] SetupDefaultProfileError),
|
|
||||||
#[error(transparent)]
|
|
||||||
StartSystemdUnit(#[from] StartSystemdUnitError),
|
|
||||||
#[error(transparent)]
|
|
||||||
SystemdSysExtMerge(#[from] SystemdSysextMergeError),
|
|
||||||
#[error(transparent)]
|
|
||||||
ProvisionNix(#[from] ProvisionNixError),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Actionable for Action {
|
|
||||||
type Error = ActionError;
|
|
||||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
|
||||||
match self {
|
|
||||||
Action::DarwinBootstrapVolume(i) => i.describe_execute(),
|
|
||||||
Action::DarwinCreateSyntheticObjects(i) => i.describe_execute(),
|
|
||||||
Action::DarwinCreateVolume(i) => i.describe_execute(),
|
|
||||||
Action::DarwinEnableOwnership(i) => i.describe_execute(),
|
|
||||||
Action::DarwinEncryptVolume(i) => i.describe_execute(),
|
|
||||||
Action::DarwinUnmountVolume(i) => i.describe_execute(),
|
|
||||||
Action::ConfigureNix(i) => i.describe_execute(),
|
|
||||||
Action::ConfigureNixDaemonService(i) => i.describe_execute(),
|
|
||||||
Action::ConfigureShellProfile(i) => i.describe_execute(),
|
|
||||||
Action::CreateApfsVolume(i) => i.describe_execute(),
|
|
||||||
Action::CreateDirectory(i) => i.describe_execute(),
|
|
||||||
Action::CreateFile(i) => i.describe_execute(),
|
|
||||||
Action::CreateGroup(i) => i.describe_execute(),
|
|
||||||
Action::CreateNixTree(i) => i.describe_execute(),
|
|
||||||
Action::CreateOrAppendFile(i) => i.describe_execute(),
|
|
||||||
Action::CreateSystemdSysext(i) => i.describe_execute(),
|
|
||||||
Action::CreateUser(i) => i.describe_execute(),
|
|
||||||
Action::CreateUsersAndGroup(i) => i.describe_execute(),
|
|
||||||
Action::FetchNix(i) => i.describe_execute(),
|
|
||||||
Action::MoveUnpackedNix(i) => i.describe_execute(),
|
|
||||||
Action::PlaceChannelConfiguration(i) => i.describe_execute(),
|
|
||||||
Action::PlaceNixConfiguration(i) => i.describe_execute(),
|
|
||||||
Action::ProvisionNix(i) => i.describe_execute(),
|
|
||||||
Action::SetupDefaultProfile(i) => i.describe_execute(),
|
|
||||||
Action::DarwinKickStartLaunchctlService(i) => i.describe_execute(),
|
|
||||||
Action::StartSystemdUnit(i) => i.describe_execute(),
|
|
||||||
Action::SystemdSysextMerge(i) => i.describe_execute(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
|
||||||
match self {
|
|
||||||
Action::DarwinBootstrapVolume(i) => i.execute().await?,
|
|
||||||
Action::DarwinCreateSyntheticObjects(i) => i.execute().await?,
|
|
||||||
Action::DarwinCreateVolume(i) => i.execute().await?,
|
|
||||||
Action::DarwinEnableOwnership(i) => i.execute().await?,
|
|
||||||
Action::DarwinEncryptVolume(i) => i.execute().await?,
|
|
||||||
Action::DarwinUnmountVolume(i) => i.execute().await?,
|
|
||||||
Action::ConfigureNix(i) => i.execute().await?,
|
|
||||||
Action::ConfigureNixDaemonService(i) => i.execute().await?,
|
|
||||||
Action::ConfigureShellProfile(i) => i.execute().await?,
|
|
||||||
Action::CreateApfsVolume(i) => i.execute().await?,
|
|
||||||
Action::CreateDirectory(i) => i.execute().await?,
|
|
||||||
Action::CreateFile(i) => i.execute().await?,
|
|
||||||
Action::CreateGroup(i) => i.execute().await?,
|
|
||||||
Action::CreateNixTree(i) => i.execute().await?,
|
|
||||||
Action::CreateOrAppendFile(i) => i.execute().await?,
|
|
||||||
Action::CreateSystemdSysext(i) => i.execute().await?,
|
|
||||||
Action::CreateUser(i) => i.execute().await?,
|
|
||||||
Action::CreateUsersAndGroup(i) => i.execute().await?,
|
|
||||||
Action::FetchNix(i) => i.execute().await?,
|
|
||||||
Action::MoveUnpackedNix(i) => i.execute().await?,
|
|
||||||
Action::PlaceChannelConfiguration(i) => i.execute().await?,
|
|
||||||
Action::PlaceNixConfiguration(i) => i.execute().await?,
|
|
||||||
Action::ProvisionNix(i) => i.execute().await?,
|
|
||||||
Action::SetupDefaultProfile(i) => i.execute().await?,
|
|
||||||
Action::DarwinKickStartLaunchctlService(i) => i.execute().await?,
|
|
||||||
Action::StartSystemdUnit(i) => i.execute().await?,
|
|
||||||
Action::SystemdSysextMerge(i) => i.execute().await?,
|
|
||||||
};
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn describe_revert(&self) -> Vec<ActionDescription> {
|
|
||||||
match self {
|
|
||||||
Action::DarwinBootstrapVolume(i) => i.describe_revert(),
|
|
||||||
Action::DarwinCreateSyntheticObjects(i) => i.describe_revert(),
|
|
||||||
Action::DarwinCreateVolume(i) => i.describe_revert(),
|
|
||||||
Action::DarwinEnableOwnership(i) => i.describe_revert(),
|
|
||||||
Action::DarwinEncryptVolume(i) => i.describe_revert(),
|
|
||||||
Action::DarwinUnmountVolume(i) => i.describe_revert(),
|
|
||||||
Action::ConfigureNix(i) => i.describe_revert(),
|
|
||||||
Action::ConfigureNixDaemonService(i) => i.describe_revert(),
|
|
||||||
Action::ConfigureShellProfile(i) => i.describe_revert(),
|
|
||||||
Action::CreateApfsVolume(i) => i.describe_revert(),
|
|
||||||
Action::CreateDirectory(i) => i.describe_revert(),
|
|
||||||
Action::CreateFile(i) => i.describe_revert(),
|
|
||||||
Action::CreateGroup(i) => i.describe_revert(),
|
|
||||||
Action::CreateNixTree(i) => i.describe_revert(),
|
|
||||||
Action::CreateOrAppendFile(i) => i.describe_revert(),
|
|
||||||
Action::CreateSystemdSysext(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::ProvisionNix(i) => i.describe_revert(),
|
|
||||||
Action::SetupDefaultProfile(i) => i.describe_revert(),
|
|
||||||
Action::DarwinKickStartLaunchctlService(i) => i.describe_revert(),
|
|
||||||
Action::StartSystemdUnit(i) => i.describe_revert(),
|
|
||||||
Action::SystemdSysextMerge(i) => i.describe_revert(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
|
||||||
match self {
|
|
||||||
Action::DarwinBootstrapVolume(i) => i.revert().await?,
|
|
||||||
Action::DarwinCreateSyntheticObjects(i) => i.revert().await?,
|
|
||||||
Action::DarwinCreateVolume(i) => i.revert().await?,
|
|
||||||
Action::DarwinEnableOwnership(i) => i.revert().await?,
|
|
||||||
Action::DarwinEncryptVolume(i) => i.revert().await?,
|
|
||||||
Action::DarwinUnmountVolume(i) => i.revert().await?,
|
|
||||||
Action::ConfigureNix(i) => i.revert().await?,
|
|
||||||
Action::ConfigureNixDaemonService(i) => i.revert().await?,
|
|
||||||
Action::ConfigureShellProfile(i) => i.revert().await?,
|
|
||||||
Action::CreateApfsVolume(i) => i.revert().await?,
|
|
||||||
Action::CreateDirectory(i) => i.revert().await?,
|
|
||||||
Action::CreateFile(i) => i.revert().await?,
|
|
||||||
Action::CreateGroup(i) => i.revert().await?,
|
|
||||||
Action::CreateNixTree(i) => i.revert().await?,
|
|
||||||
Action::CreateOrAppendFile(i) => i.revert().await?,
|
|
||||||
Action::CreateSystemdSysext(i) => i.revert().await?,
|
|
||||||
Action::CreateUser(i) => i.revert().await?,
|
|
||||||
Action::CreateUsersAndGroup(i) => i.revert().await?,
|
|
||||||
Action::FetchNix(i) => i.revert().await?,
|
|
||||||
Action::MoveUnpackedNix(i) => i.revert().await?,
|
|
||||||
Action::PlaceChannelConfiguration(i) => i.revert().await?,
|
|
||||||
Action::PlaceNixConfiguration(i) => i.revert().await?,
|
|
||||||
Action::ProvisionNix(i) => i.revert().await?,
|
|
||||||
Action::SetupDefaultProfile(i) => i.revert().await?,
|
|
||||||
Action::DarwinKickStartLaunchctlService(i) => i.revert().await?,
|
|
||||||
Action::StartSystemdUnit(i) => i.revert().await?,
|
|
||||||
Action::SystemdSysextMerge(i) => i.revert().await?,
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::actions::ActionError;
|
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum HarmonicError {
|
pub enum HarmonicError {
|
||||||
#[error("Error executing action")]
|
#[error("Error executing action")]
|
||||||
ActionError(
|
ActionError(
|
||||||
#[source]
|
#[source]
|
||||||
#[from]
|
#[from]
|
||||||
ActionError,
|
Box<dyn std::error::Error + Send + Sync>,
|
||||||
),
|
),
|
||||||
#[error("Recording install receipt")]
|
#[error("Recording install receipt")]
|
||||||
RecordingReceipt(PathBuf, #[source] std::io::Error),
|
RecordingReceipt(PathBuf, #[source] std::io::Error),
|
||||||
|
|
11
src/plan.rs
11
src/plan.rs
|
@ -1,13 +1,13 @@
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
actions::{Action, ActionDescription, ActionError, Actionable},
|
actions::{ActionDescription, Actionable},
|
||||||
BuiltinPlanner, HarmonicError,
|
BuiltinPlanner, HarmonicError,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||||
pub struct InstallPlan {
|
pub struct InstallPlan {
|
||||||
pub(crate) actions: Vec<Action>,
|
pub(crate) actions: Vec<Box<dyn Actionable>>,
|
||||||
|
|
||||||
pub(crate) planner: BuiltinPlanner,
|
pub(crate) planner: BuiltinPlanner,
|
||||||
}
|
}
|
||||||
|
@ -70,11 +70,12 @@ impl InstallPlan {
|
||||||
if let Err(err) = write_receipt(self.clone()).await {
|
if let Err(err) = write_receipt(self.clone()).await {
|
||||||
tracing::error!("Error saving receipt: {:?}", err);
|
tracing::error!("Error saving receipt: {:?}", err);
|
||||||
}
|
}
|
||||||
return Err(ActionError::from(err).into());
|
return Err(HarmonicError::ActionError(err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
write_receipt(self.clone()).await
|
write_receipt(self.clone()).await?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
|
@ -134,7 +135,7 @@ impl InstallPlan {
|
||||||
if let Err(err) = write_receipt(self.clone()).await {
|
if let Err(err) = write_receipt(self.clone()).await {
|
||||||
tracing::error!("Error saving receipt: {:?}", err);
|
tracing::error!("Error saving receipt: {:?}", err);
|
||||||
}
|
}
|
||||||
return Err(ActionError::from(err).into());
|
return Err(HarmonicError::ActionError(err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,11 +7,10 @@ use crate::{
|
||||||
actions::{
|
actions::{
|
||||||
base::darwin::KickstartLaunchctlService,
|
base::darwin::KickstartLaunchctlService,
|
||||||
meta::{darwin::CreateApfsVolume, ConfigureNix, ProvisionNix},
|
meta::{darwin::CreateApfsVolume, ConfigureNix, ProvisionNix},
|
||||||
Action, ActionError,
|
|
||||||
},
|
},
|
||||||
execute_command,
|
execute_command,
|
||||||
os::darwin::DiskUtilOutput,
|
os::darwin::DiskUtilOutput,
|
||||||
planner::{Plannable, PlannerError},
|
planner::{BuiltinPlannerError, Plannable},
|
||||||
BuiltinPlanner, CommonSettings, InstallPlan,
|
BuiltinPlanner, CommonSettings, InstallPlan,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -32,7 +31,7 @@ pub struct DarwinMulti {
|
||||||
root_disk: Option<String>,
|
root_disk: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn default_root_disk() -> Result<String, PlannerError> {
|
async fn default_root_disk() -> Result<String, BuiltinPlannerError> {
|
||||||
let buf = execute_command(Command::new("/usr/sbin/diskutil").args(["info", "-plist", "/"]))
|
let buf = execute_command(Command::new("/usr/sbin/diskutil").args(["info", "-plist", "/"]))
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -46,8 +45,9 @@ async fn default_root_disk() -> Result<String, PlannerError> {
|
||||||
impl Plannable for DarwinMulti {
|
impl Plannable for DarwinMulti {
|
||||||
const DISPLAY_STRING: &'static str = "Darwin Multi-User";
|
const DISPLAY_STRING: &'static str = "Darwin Multi-User";
|
||||||
const SLUG: &'static str = "darwin-multi";
|
const SLUG: &'static str = "darwin-multi";
|
||||||
|
type Error = BuiltinPlannerError;
|
||||||
|
|
||||||
async fn default() -> Result<Self, PlannerError> {
|
async fn default() -> Result<Self, Self::Error> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
settings: CommonSettings::default()?,
|
settings: CommonSettings::default()?,
|
||||||
root_disk: Some(default_root_disk().await?),
|
root_disk: Some(default_root_disk().await?),
|
||||||
|
@ -56,7 +56,7 @@ impl Plannable for DarwinMulti {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn plan(self) -> Result<crate::InstallPlan, crate::planner::PlannerError> {
|
async fn plan(self) -> Result<crate::InstallPlan, Self::Error> {
|
||||||
let root_disk = {
|
let root_disk = {
|
||||||
let buf =
|
let buf =
|
||||||
execute_command(Command::new("/usr/sbin/diskutil").args(["info", "-plist", "/"]))
|
execute_command(Command::new("/usr/sbin/diskutil").args(["info", "-plist", "/"]))
|
||||||
|
@ -77,22 +77,12 @@ impl Plannable for DarwinMulti {
|
||||||
//
|
//
|
||||||
// setup_Synthetic -> create_synthetic_objects
|
// setup_Synthetic -> create_synthetic_objects
|
||||||
// Unmount -> create_volume -> Setup_fstab -> maybe encrypt_volume -> launchctl bootstrap -> launchctl kickstart -> await_volume -> maybe enableOwnership
|
// Unmount -> create_volume -> Setup_fstab -> maybe encrypt_volume -> launchctl bootstrap -> launchctl kickstart -> await_volume -> maybe enableOwnership
|
||||||
CreateApfsVolume::plan(root_disk, volume_label, false, None)
|
Box::new(CreateApfsVolume::plan(root_disk, volume_label, false, None).await?),
|
||||||
.await
|
Box::new(ProvisionNix::plan(self.settings.clone()).await?),
|
||||||
.map(Action::from)
|
Box::new(ConfigureNix::plan(self.settings).await?),
|
||||||
.map_err(ActionError::from)?,
|
Box::new(
|
||||||
ProvisionNix::plan(self.settings.clone())
|
KickstartLaunchctlService::plan("system/org.nixos.nix-daemon".into()).await?,
|
||||||
.await
|
),
|
||||||
.map(Action::from)
|
|
||||||
.map_err(ActionError::from)?,
|
|
||||||
ConfigureNix::plan(self.settings)
|
|
||||||
.await
|
|
||||||
.map(Action::from)
|
|
||||||
.map_err(ActionError::from)?,
|
|
||||||
KickstartLaunchctlService::plan("system/org.nixos.nix-daemon".into())
|
|
||||||
.await
|
|
||||||
.map(Action::from)
|
|
||||||
.map_err(ActionError::from)?,
|
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,8 @@ use crate::{
|
||||||
actions::{
|
actions::{
|
||||||
base::{CreateDirectory, StartSystemdUnit},
|
base::{CreateDirectory, StartSystemdUnit},
|
||||||
meta::{ConfigureNix, ProvisionNix},
|
meta::{ConfigureNix, ProvisionNix},
|
||||||
Action, ActionError,
|
|
||||||
},
|
},
|
||||||
planner::{Plannable, PlannerError},
|
planner::{BuiltinPlannerError, Plannable},
|
||||||
BuiltinPlanner, CommonSettings, InstallPlan,
|
BuiltinPlanner, CommonSettings, InstallPlan,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,33 +17,22 @@ pub struct LinuxMulti {
|
||||||
impl Plannable for LinuxMulti {
|
impl Plannable for LinuxMulti {
|
||||||
const DISPLAY_STRING: &'static str = "Linux Multi-User";
|
const DISPLAY_STRING: &'static str = "Linux Multi-User";
|
||||||
const SLUG: &'static str = "linux-multi";
|
const SLUG: &'static str = "linux-multi";
|
||||||
|
type Error = BuiltinPlannerError;
|
||||||
|
|
||||||
async fn default() -> Result<Self, PlannerError> {
|
async fn default() -> Result<Self, Self::Error> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
settings: CommonSettings::default()?,
|
settings: CommonSettings::default()?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn plan(self) -> Result<InstallPlan, PlannerError> {
|
async fn plan(self) -> Result<InstallPlan, Self::Error> {
|
||||||
Ok(InstallPlan {
|
Ok(InstallPlan {
|
||||||
planner: self.clone().into(),
|
planner: self.clone().into(),
|
||||||
actions: vec![
|
actions: vec![
|
||||||
CreateDirectory::plan("/nix", None, None, 0o0755, true)
|
Box::new(CreateDirectory::plan("/nix", None, None, 0o0755, true).await?),
|
||||||
.await
|
Box::new(ProvisionNix::plan(self.settings.clone()).await?),
|
||||||
.map(Action::from)
|
Box::new(ConfigureNix::plan(self.settings).await?),
|
||||||
.map_err(ActionError::from)?,
|
Box::new(StartSystemdUnit::plan("nix-daemon.socket".into()).await?),
|
||||||
ProvisionNix::plan(self.settings.clone())
|
|
||||||
.await
|
|
||||||
.map(Action::from)
|
|
||||||
.map_err(ActionError::from)?,
|
|
||||||
ConfigureNix::plan(self.settings)
|
|
||||||
.await
|
|
||||||
.map(Action::from)
|
|
||||||
.map_err(ActionError::from)?,
|
|
||||||
StartSystemdUnit::plan("nix-daemon.socket".into())
|
|
||||||
.await
|
|
||||||
.map(Action::from)
|
|
||||||
.map_err(ActionError::from)?,
|
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ pub enum BuiltinPlanner {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BuiltinPlanner {
|
impl BuiltinPlanner {
|
||||||
pub async fn default() -> Result<Self, PlannerError> {
|
pub async fn default() -> Result<Self, BuiltinPlannerError> {
|
||||||
use target_lexicon::{Architecture, OperatingSystem};
|
use target_lexicon::{Architecture, OperatingSystem};
|
||||||
match (Architecture::host(), OperatingSystem::host()) {
|
match (Architecture::host(), OperatingSystem::host()) {
|
||||||
(Architecture::X86_64, OperatingSystem::Linux) => {
|
(Architecture::X86_64, OperatingSystem::Linux) => {
|
||||||
|
@ -29,11 +29,13 @@ impl BuiltinPlanner {
|
||||||
| (Architecture::Aarch64(_), OperatingSystem::Darwin) => {
|
| (Architecture::Aarch64(_), OperatingSystem::Darwin) => {
|
||||||
Ok(Self::DarwinMulti(darwin::DarwinMulti::default().await?))
|
Ok(Self::DarwinMulti(darwin::DarwinMulti::default().await?))
|
||||||
},
|
},
|
||||||
_ => Err(PlannerError::UnsupportedArchitecture(target_lexicon::HOST)),
|
_ => Err(BuiltinPlannerError::UnsupportedArchitecture(
|
||||||
|
target_lexicon::HOST,
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn plan(self) -> Result<InstallPlan, PlannerError> {
|
pub async fn plan(self) -> Result<InstallPlan, BuiltinPlannerError> {
|
||||||
match self {
|
match self {
|
||||||
BuiltinPlanner::LinuxMulti(planner) => planner.plan().await,
|
BuiltinPlanner::LinuxMulti(planner) => planner.plan().await,
|
||||||
BuiltinPlanner::DarwinMulti(planner) => planner.plan().await,
|
BuiltinPlanner::DarwinMulti(planner) => planner.plan().await,
|
||||||
|
@ -43,26 +45,27 @@ impl BuiltinPlanner {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
trait Plannable: Into<BuiltinPlanner>
|
trait Plannable
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
const DISPLAY_STRING: &'static str;
|
const DISPLAY_STRING: &'static str;
|
||||||
const SLUG: &'static str;
|
const SLUG: &'static str;
|
||||||
|
type Error: std::error::Error;
|
||||||
|
|
||||||
async fn default() -> Result<Self, PlannerError>;
|
async fn default() -> Result<Self, Self::Error>;
|
||||||
async fn plan(self) -> Result<InstallPlan, PlannerError>;
|
async fn plan(self) -> Result<InstallPlan, Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum PlannerError {
|
pub enum BuiltinPlannerError {
|
||||||
#[error("Harmonic does not have a default planner for the `{0}` architecture right now, pass a specific archetype")]
|
#[error("Harmonic does not have a default planner for the `{0}` architecture right now, pass a specific archetype")]
|
||||||
UnsupportedArchitecture(target_lexicon::Triple),
|
UnsupportedArchitecture(target_lexicon::Triple),
|
||||||
#[error("Error executing action")]
|
#[error("Error executing action")]
|
||||||
ActionError(
|
ActionError(
|
||||||
#[source]
|
#[source]
|
||||||
#[from]
|
#[from]
|
||||||
ActionError,
|
Box<dyn std::error::Error + Send + Sync>,
|
||||||
),
|
),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
InstallSettings(#[from] InstallSettingsError),
|
InstallSettings(#[from] InstallSettingsError),
|
||||||
|
|
|
@ -2,9 +2,8 @@ use crate::{
|
||||||
actions::{
|
actions::{
|
||||||
base::{CreateDirectory, StartSystemdUnit},
|
base::{CreateDirectory, StartSystemdUnit},
|
||||||
meta::{CreateSystemdSysext, ProvisionNix},
|
meta::{CreateSystemdSysext, ProvisionNix},
|
||||||
Action, ActionError,
|
|
||||||
},
|
},
|
||||||
planner::{Plannable, PlannerError},
|
planner::{BuiltinPlannerError, Plannable},
|
||||||
BuiltinPlanner, CommonSettings, InstallPlan,
|
BuiltinPlanner, CommonSettings, InstallPlan,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,33 +17,22 @@ pub struct SteamDeck {
|
||||||
impl Plannable for SteamDeck {
|
impl Plannable for SteamDeck {
|
||||||
const DISPLAY_STRING: &'static str = "Steam Deck (x86_64 Linux Multi-User)";
|
const DISPLAY_STRING: &'static str = "Steam Deck (x86_64 Linux Multi-User)";
|
||||||
const SLUG: &'static str = "steam-deck";
|
const SLUG: &'static str = "steam-deck";
|
||||||
|
type Error = BuiltinPlannerError;
|
||||||
|
|
||||||
async fn default() -> Result<Self, PlannerError> {
|
async fn default() -> Result<Self, Self::Error> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
settings: CommonSettings::default()?,
|
settings: CommonSettings::default()?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn plan(self) -> Result<crate::InstallPlan, PlannerError> {
|
async fn plan(self) -> Result<crate::InstallPlan, Self::Error> {
|
||||||
Ok(InstallPlan {
|
Ok(InstallPlan {
|
||||||
planner: self.clone().into(),
|
planner: self.clone().into(),
|
||||||
actions: vec![
|
actions: vec![
|
||||||
CreateSystemdSysext::plan("/var/lib/extensions")
|
Box::new(CreateSystemdSysext::plan("/var/lib/extensions").await?),
|
||||||
.await
|
Box::new(CreateDirectory::plan("/nix", None, None, 0o0755, true).await?),
|
||||||
.map(Action::from)
|
Box::new(ProvisionNix::plan(self.settings.clone()).await?),
|
||||||
.map_err(ActionError::from)?,
|
Box::new(StartSystemdUnit::plan("nix-daemon.socket".into()).await?),
|
||||||
CreateDirectory::plan("/nix", None, None, 0o0755, true)
|
|
||||||
.await
|
|
||||||
.map(Action::from)
|
|
||||||
.map_err(ActionError::from)?,
|
|
||||||
ProvisionNix::plan(self.settings.clone())
|
|
||||||
.await
|
|
||||||
.map(Action::from)
|
|
||||||
.map_err(ActionError::from)?,
|
|
||||||
StartSystemdUnit::plan("nix-daemon.socket".into())
|
|
||||||
.await
|
|
||||||
.map(Action::from)
|
|
||||||
.map_err(ActionError::from)?,
|
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue