Explore planner pattern using steam deck example
This commit is contained in:
parent
144af153f6
commit
64e7423a0a
|
@ -14,6 +14,7 @@ pub struct CreateDirectory {
|
|||
group: String,
|
||||
mode: u32,
|
||||
action_state: ActionState,
|
||||
force_prune_on_revert: bool,
|
||||
}
|
||||
|
||||
impl CreateDirectory {
|
||||
|
@ -23,23 +24,37 @@ impl CreateDirectory {
|
|||
user: String,
|
||||
group: String,
|
||||
mode: u32,
|
||||
force: bool,
|
||||
force_prune_on_revert: bool,
|
||||
) -> Result<Self, CreateDirectoryError> {
|
||||
let path = path.as_ref();
|
||||
|
||||
if path.exists() && !force {
|
||||
return Err(CreateDirectoryError::Exists(std::io::Error::new(
|
||||
std::io::ErrorKind::AlreadyExists,
|
||||
format!("Directory `{}` already exists", path.display()),
|
||||
)));
|
||||
}
|
||||
let action_state = if path.exists() {
|
||||
let metadata = tokio::fs::metadata(path)
|
||||
.await
|
||||
.map_err(|e| CreateDirectoryError::GettingMetadata(path.to_path_buf(), e))?;
|
||||
if metadata.is_dir() {
|
||||
// TODO: Validate owner/group...
|
||||
ActionState::Completed
|
||||
} else {
|
||||
return Err(CreateDirectoryError::Exists(std::io::Error::new(
|
||||
std::io::ErrorKind::AlreadyExists,
|
||||
format!(
|
||||
"Path `{}` already exists and is not directory",
|
||||
path.display()
|
||||
),
|
||||
)));
|
||||
}
|
||||
} else {
|
||||
ActionState::Uncompleted
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
path: path.to_path_buf(),
|
||||
user,
|
||||
group,
|
||||
mode,
|
||||
action_state: ActionState::Uncompleted,
|
||||
force_prune_on_revert,
|
||||
action_state,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -54,6 +69,7 @@ impl Actionable for CreateDirectory {
|
|||
user,
|
||||
group,
|
||||
mode,
|
||||
force_prune_on_revert: _,
|
||||
action_state: _,
|
||||
} = &self;
|
||||
if self.action_state == ActionState::Completed {
|
||||
|
@ -81,6 +97,7 @@ impl Actionable for CreateDirectory {
|
|||
user,
|
||||
group,
|
||||
mode,
|
||||
force_prune_on_revert: _,
|
||||
action_state,
|
||||
} = self;
|
||||
if *action_state == ActionState::Completed {
|
||||
|
@ -118,13 +135,22 @@ impl Actionable for CreateDirectory {
|
|||
user: _,
|
||||
group: _,
|
||||
mode: _,
|
||||
force_prune_on_revert,
|
||||
action_state: _,
|
||||
} = &self;
|
||||
if self.action_state == ActionState::Uncompleted {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ActionDescription::new(
|
||||
format!("Remove the directory `{}`", path.display()),
|
||||
format!(
|
||||
"Remove the directory `{}`{}",
|
||||
path.display(),
|
||||
if *force_prune_on_revert {
|
||||
""
|
||||
} else {
|
||||
" if no other contents exists"
|
||||
}
|
||||
),
|
||||
vec![],
|
||||
)]
|
||||
}
|
||||
|
@ -142,6 +168,7 @@ impl Actionable for CreateDirectory {
|
|||
user: _,
|
||||
group: _,
|
||||
mode: _,
|
||||
force_prune_on_revert,
|
||||
action_state,
|
||||
} = self;
|
||||
if *action_state == ActionState::Uncompleted {
|
||||
|
@ -151,9 +178,18 @@ impl Actionable for CreateDirectory {
|
|||
tracing::debug!("Removing directory");
|
||||
|
||||
tracing::trace!(path = %path.display(), "Removing directory");
|
||||
remove_dir_all(path.clone())
|
||||
.await
|
||||
.map_err(|e| Self::Error::Removing(path.clone(), e))?;
|
||||
|
||||
let is_empty = path
|
||||
.read_dir()
|
||||
.map_err(|e| CreateDirectoryError::ReadDir(path.clone(), e))?
|
||||
.next()
|
||||
.is_some();
|
||||
match (is_empty, force_prune_on_revert) {
|
||||
(true, _) | (false, true) => remove_dir_all(path.clone())
|
||||
.await
|
||||
.map_err(|e| Self::Error::Removing(path.clone(), e))?,
|
||||
(false, false) => {},
|
||||
};
|
||||
|
||||
tracing::trace!("Removed directory");
|
||||
*action_state = ActionState::Uncompleted;
|
||||
|
@ -185,6 +221,20 @@ pub enum CreateDirectoryError {
|
|||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
std::io::Error,
|
||||
),
|
||||
#[error("Getting metadata for {0}`")]
|
||||
GettingMetadata(
|
||||
std::path::PathBuf,
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
std::io::Error,
|
||||
),
|
||||
#[error("Reading directory `{0}``")]
|
||||
ReadDir(
|
||||
std::path::PathBuf,
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
std::io::Error,
|
||||
),
|
||||
#[error("Set mode `{0}` on `{1}`")]
|
||||
SetPermissions(
|
||||
u32,
|
||||
|
|
|
@ -10,6 +10,7 @@ mod fetch_nix;
|
|||
mod move_unpacked_nix;
|
||||
mod setup_default_profile;
|
||||
mod start_systemd_unit;
|
||||
mod systemd_sysext_merge;
|
||||
|
||||
pub use configure_nix_daemon_service::{ConfigureNixDaemonService, ConfigureNixDaemonServiceError};
|
||||
pub use create_directory::{CreateDirectory, CreateDirectoryError};
|
||||
|
@ -21,3 +22,4 @@ pub use fetch_nix::{FetchNix, FetchNixError};
|
|||
pub use move_unpacked_nix::{MoveUnpackedNix, MoveUnpackedNixError};
|
||||
pub use setup_default_profile::{SetupDefaultProfile, SetupDefaultProfileError};
|
||||
pub use start_systemd_unit::{StartSystemdUnit, StartSystemdUnitError};
|
||||
pub use systemd_sysext_merge::{SystemdSysextMerge, SystemdSysextMergeError};
|
||||
|
|
120
src/actions/base/systemd_sysext_merge.rs
Normal file
120
src/actions/base/systemd_sysext_merge.rs
Normal file
|
@ -0,0 +1,120 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use serde::Serialize;
|
||||
use tokio::process::Command;
|
||||
|
||||
use crate::execute_command;
|
||||
|
||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
||||
|
||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||
pub struct SystemdSysextMerge {
|
||||
device: PathBuf,
|
||||
action_state: ActionState,
|
||||
}
|
||||
|
||||
impl SystemdSysextMerge {
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub async fn plan(device: PathBuf) -> Result<Self, SystemdSysextMergeError> {
|
||||
Ok(Self {
|
||||
device,
|
||||
action_state: ActionState::Uncompleted,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl Actionable for SystemdSysextMerge {
|
||||
type Error = SystemdSysextMergeError;
|
||||
|
||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||
let Self {
|
||||
action_state,
|
||||
device,
|
||||
} = self;
|
||||
if *action_state == ActionState::Completed {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ActionDescription::new(
|
||||
format!("Run `systemd-sysext merge `{}`", device.display()),
|
||||
vec![],
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(
|
||||
device = %self.device.display(),
|
||||
))]
|
||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
||||
let Self {
|
||||
device,
|
||||
action_state,
|
||||
} = self;
|
||||
if *action_state == ActionState::Completed {
|
||||
tracing::trace!("Already completed: Merging systemd-sysext");
|
||||
return Ok(());
|
||||
}
|
||||
tracing::debug!("Merging systemd-sysext");
|
||||
|
||||
execute_command(Command::new("systemd-sysext").arg("merge").arg(device))
|
||||
.await
|
||||
.map_err(SystemdSysextMergeError::Command)?;
|
||||
|
||||
tracing::trace!("Merged systemd-sysext");
|
||||
*action_state = ActionState::Completed;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn describe_revert(&self) -> Vec<ActionDescription> {
|
||||
if self.action_state == ActionState::Uncompleted {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ActionDescription::new(
|
||||
"Stop the systemd Nix service and socket".to_string(),
|
||||
vec![
|
||||
"The `nix` command line tool communicates with a running Nix daemon managed by your init system".to_string()
|
||||
]
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(
|
||||
device = %self.device.display(),
|
||||
))]
|
||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
||||
let Self {
|
||||
device,
|
||||
action_state,
|
||||
} = self;
|
||||
if *action_state == ActionState::Uncompleted {
|
||||
tracing::trace!("Already reverted: Stopping systemd unit");
|
||||
return Ok(());
|
||||
}
|
||||
tracing::debug!("Unmrging systemd-sysext");
|
||||
|
||||
// TODO(@Hoverbear): Handle proxy vars
|
||||
execute_command(Command::new("systemd-sysext").arg("unmerge").arg(device))
|
||||
.await
|
||||
.map_err(SystemdSysextMergeError::Command)?;
|
||||
|
||||
tracing::trace!("Unmerged systemd-sysext");
|
||||
*action_state = ActionState::Completed;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SystemdSysextMerge> for Action {
|
||||
fn from(v: SystemdSysextMerge) -> Self {
|
||||
Action::SystemdSysextMerge(v)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum SystemdSysextMergeError {
|
||||
#[error("Failed to execute command")]
|
||||
Command(
|
||||
#[source]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
std::io::Error,
|
||||
),
|
||||
}
|
|
@ -27,12 +27,12 @@ pub struct CreateNixTree {
|
|||
|
||||
impl CreateNixTree {
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub async fn plan(force: bool) -> Result<Self, CreateNixTreeError> {
|
||||
pub async fn plan() -> Result<Self, CreateNixTreeError> {
|
||||
let mut create_directories = Vec::default();
|
||||
for path in PATHS {
|
||||
// We use `create_dir` over `create_dir_all` to ensure we always set permissions right
|
||||
create_directories.push(
|
||||
CreateDirectory::plan(path, "root".into(), "root".into(), 0o0755, force).await?,
|
||||
CreateDirectory::plan(path, "root".into(), "root".into(), 0o0755, false).await?,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
216
src/actions/meta/create_systemd_sysext.rs
Normal file
216
src/actions/meta/create_systemd_sysext.rs
Normal file
|
@ -0,0 +1,216 @@
|
|||
use serde::Serialize;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use crate::actions::base::{CreateDirectory, CreateDirectoryError, CreateFile, CreateFileError};
|
||||
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
|
||||
|
||||
const PATHS: &[&str] = &[
|
||||
"usr",
|
||||
"usr/lib",
|
||||
"usr/lib/extension-release.d",
|
||||
"usr/lib/systemd",
|
||||
"usr/lib/systemd/system",
|
||||
];
|
||||
|
||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||
pub struct CreateSystemdSysext {
|
||||
destination: PathBuf,
|
||||
create_directories: Vec<CreateDirectory>,
|
||||
create_extension_release: CreateFile,
|
||||
create_bind_mount_unit: CreateFile,
|
||||
action_state: ActionState,
|
||||
}
|
||||
|
||||
impl CreateSystemdSysext {
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub async fn plan(destination: impl AsRef<Path>) -> Result<Self, CreateSystemdSysextError> {
|
||||
let destination = destination.as_ref();
|
||||
|
||||
let mut create_directories = vec![
|
||||
CreateDirectory::plan(destination, "root".into(), "root".into(), 0o0755, true).await?,
|
||||
];
|
||||
for path in PATHS {
|
||||
create_directories.push(
|
||||
CreateDirectory::plan(
|
||||
destination.join(path),
|
||||
"root".into(),
|
||||
"root".into(),
|
||||
0o0755,
|
||||
false,
|
||||
)
|
||||
.await?,
|
||||
)
|
||||
}
|
||||
|
||||
let version_id = tokio::fs::read_to_string("/etc/os-release")
|
||||
.await
|
||||
.map(|buf| {
|
||||
buf.lines()
|
||||
.find_map(|line| match line.starts_with("VERSION_ID") {
|
||||
true => line.rsplit("=").next().map(|inner| inner.to_owned()),
|
||||
false => None,
|
||||
})
|
||||
})
|
||||
.map_err(CreateSystemdSysextError::ReadingOsRelease)?
|
||||
.ok_or(CreateSystemdSysextError::NoVersionId)?;
|
||||
let extension_release_buf =
|
||||
format!("SYSEXT_LEVEL=1.0\nID=steamos\nVERSION_ID={version_id}");
|
||||
let create_extension_release = CreateFile::plan(
|
||||
destination.join("usr/lib/extension-release.d/extension-release.nix"),
|
||||
"root".into(),
|
||||
"root".into(),
|
||||
0o0755,
|
||||
extension_release_buf,
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let create_bind_mount_buf = format!(
|
||||
"
|
||||
[Mount]\n\
|
||||
What={}\n\
|
||||
Where=/nix\n\
|
||||
Type=none\n\
|
||||
Options=bind\n\
|
||||
",
|
||||
destination.display(),
|
||||
);
|
||||
let create_bind_mount_unit = CreateFile::plan(
|
||||
destination.join("usr/lib/systemd/system/nix.mount"),
|
||||
"root".into(),
|
||||
"root".into(),
|
||||
0o0755,
|
||||
create_bind_mount_buf,
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(Self {
|
||||
destination: destination.to_path_buf(),
|
||||
create_directories,
|
||||
create_extension_release,
|
||||
create_bind_mount_unit,
|
||||
action_state: ActionState::Uncompleted,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl Actionable for CreateSystemdSysext {
|
||||
type Error = CreateSystemdSysextError;
|
||||
|
||||
fn describe_execute(&self) -> Vec<ActionDescription> {
|
||||
let Self {
|
||||
action_state: _,
|
||||
destination,
|
||||
create_bind_mount_unit: _,
|
||||
create_directories: _,
|
||||
create_extension_release: _,
|
||||
} = &self;
|
||||
if self.action_state == ActionState::Completed {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ActionDescription::new(
|
||||
format!("Create a systemd sysext at `{}`", destination.display()),
|
||||
vec![format!(
|
||||
"Create a writable, persistent systemd system extension.",
|
||||
)],
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(destination,))]
|
||||
async fn execute(&mut self) -> Result<(), Self::Error> {
|
||||
let Self {
|
||||
destination: _,
|
||||
action_state,
|
||||
create_directories,
|
||||
create_extension_release,
|
||||
create_bind_mount_unit,
|
||||
} = self;
|
||||
if *action_state == ActionState::Completed {
|
||||
tracing::trace!("Already completed: Creating sysext");
|
||||
return Ok(());
|
||||
}
|
||||
tracing::debug!("Creating sysext");
|
||||
|
||||
for create_directory in create_directories {
|
||||
create_directory.execute().await?;
|
||||
}
|
||||
create_extension_release.execute().await?;
|
||||
create_bind_mount_unit.execute().await?;
|
||||
|
||||
tracing::trace!("Created sysext");
|
||||
*action_state = ActionState::Completed;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn describe_revert(&self) -> Vec<ActionDescription> {
|
||||
let Self {
|
||||
destination,
|
||||
action_state: _,
|
||||
create_directories: _,
|
||||
create_extension_release: _,
|
||||
create_bind_mount_unit: _,
|
||||
} = &self;
|
||||
if self.action_state == ActionState::Uncompleted {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ActionDescription::new(
|
||||
format!("Remove the sysext located at `{}`", destination.display()),
|
||||
vec![],
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(destination,))]
|
||||
async fn revert(&mut self) -> Result<(), Self::Error> {
|
||||
let Self {
|
||||
destination: _,
|
||||
action_state,
|
||||
create_directories,
|
||||
create_extension_release,
|
||||
create_bind_mount_unit,
|
||||
} = self;
|
||||
if *action_state == ActionState::Uncompleted {
|
||||
tracing::trace!("Already reverted: Removing sysext");
|
||||
return Ok(());
|
||||
}
|
||||
tracing::debug!("Removing sysext");
|
||||
|
||||
create_bind_mount_unit.revert().await?;
|
||||
|
||||
create_extension_release.revert().await?;
|
||||
|
||||
for create_directory in create_directories.iter_mut().rev() {
|
||||
create_directory.revert().await?;
|
||||
}
|
||||
|
||||
tracing::trace!("Removed sysext");
|
||||
*action_state = ActionState::Uncompleted;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CreateSystemdSysext> for Action {
|
||||
fn from(v: CreateSystemdSysext) -> Self {
|
||||
Action::CreateSystemdSysext(v)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum CreateSystemdSysextError {
|
||||
#[error(transparent)]
|
||||
CreateDirectory(#[from] CreateDirectoryError),
|
||||
#[error(transparent)]
|
||||
CreateFile(#[from] CreateFileError),
|
||||
#[error("Reading /etc/os-release")]
|
||||
ReadingOsRelease(
|
||||
#[source]
|
||||
#[from]
|
||||
#[serde(serialize_with = "crate::serialize_error_to_display")]
|
||||
std::io::Error,
|
||||
),
|
||||
#[error("No `VERSION_ID` line in /etc/os-release")]
|
||||
NoVersionId,
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
mod configure_nix;
|
||||
mod configure_shell_profile;
|
||||
mod create_nix_tree;
|
||||
mod create_systemd_sysext;
|
||||
mod create_users_and_group;
|
||||
mod place_channel_configuration;
|
||||
mod place_nix_configuration;
|
||||
|
@ -12,6 +13,7 @@ mod start_nix_daemon;
|
|||
pub use configure_nix::{ConfigureNix, ConfigureNixError};
|
||||
pub use configure_shell_profile::{ConfigureShellProfile, ConfigureShellProfileError};
|
||||
pub use create_nix_tree::{CreateNixTree, CreateNixTreeError};
|
||||
pub use create_systemd_sysext::{CreateSystemdSysext, CreateSystemdSysextError};
|
||||
pub use create_users_and_group::{CreateUsersAndGroup, CreateUsersAndGroupError};
|
||||
pub use place_channel_configuration::{PlaceChannelConfiguration, PlaceChannelConfigurationError};
|
||||
pub use place_nix_configuration::{PlaceNixConfiguration, PlaceNixConfigurationError};
|
||||
|
|
|
@ -27,8 +27,7 @@ impl ProvisionNix {
|
|||
#[tracing::instrument(skip_all)]
|
||||
pub async fn plan(settings: InstallSettings) -> Result<Self, ProvisionNixError> {
|
||||
let create_nix_dir =
|
||||
CreateDirectory::plan("/nix", "root".into(), "root".into(), 0o0755, settings.force)
|
||||
.await?;
|
||||
CreateDirectory::plan("/nix", "root".into(), "root".into(), 0o0755, true).await?;
|
||||
|
||||
let fetch_nix = FetchNix::plan(
|
||||
settings.nix_package_url.clone(),
|
||||
|
@ -36,7 +35,7 @@ impl ProvisionNix {
|
|||
)
|
||||
.await?;
|
||||
let create_users_and_group = CreateUsersAndGroup::plan(settings.clone()).await?;
|
||||
let create_nix_tree = CreateNixTree::plan(settings.force).await?;
|
||||
let create_nix_tree = CreateNixTree::plan().await?;
|
||||
let move_unpacked_nix =
|
||||
MoveUnpackedNix::plan(PathBuf::from("/nix/temp-install-dir")).await?;
|
||||
Ok(Self {
|
||||
|
|
|
@ -6,19 +6,18 @@ use base::{
|
|||
CreateDirectoryError, CreateFile, CreateFileError, CreateGroup, CreateGroupError,
|
||||
CreateOrAppendFile, CreateOrAppendFileError, CreateUser, CreateUserError, FetchNix,
|
||||
FetchNixError, MoveUnpackedNix, MoveUnpackedNixError, SetupDefaultProfile,
|
||||
SetupDefaultProfileError,
|
||||
SetupDefaultProfileError, StartSystemdUnit, StartSystemdUnitError, SystemdSysextMerge,
|
||||
SystemdSysextMergeError,
|
||||
};
|
||||
use meta::{
|
||||
ConfigureNix, ConfigureNixError, ConfigureShellProfile, ConfigureShellProfileError,
|
||||
CreateNixTree, CreateNixTreeError, CreateUsersAndGroup, CreateUsersAndGroupError,
|
||||
PlaceChannelConfiguration, PlaceChannelConfigurationError, PlaceNixConfiguration,
|
||||
PlaceNixConfigurationError, ProvisionNix, ProvisionNixError, StartNixDaemon,
|
||||
StartNixDaemonError,
|
||||
CreateNixTree, CreateNixTreeError, CreateSystemdSysext, CreateSystemdSysextError,
|
||||
CreateUsersAndGroup, CreateUsersAndGroupError, PlaceChannelConfiguration,
|
||||
PlaceChannelConfigurationError, PlaceNixConfiguration, PlaceNixConfigurationError,
|
||||
ProvisionNix, ProvisionNixError, StartNixDaemon, StartNixDaemonError,
|
||||
};
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
|
||||
use self::base::{StartSystemdUnit, StartSystemdUnitError};
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait Actionable: DeserializeOwned + Serialize + Into<Action> {
|
||||
type Error: std::error::Error + std::fmt::Debug + Serialize + Into<ActionError>;
|
||||
|
@ -61,6 +60,7 @@ pub enum Action {
|
|||
ConfigureNix(ConfigureNix),
|
||||
ConfigureShellProfile(ConfigureShellProfile),
|
||||
CreateDirectory(CreateDirectory),
|
||||
CreateSystemdSysext(CreateSystemdSysext),
|
||||
CreateFile(CreateFile),
|
||||
CreateGroup(CreateGroup),
|
||||
CreateOrAppendFile(CreateOrAppendFile),
|
||||
|
@ -74,6 +74,7 @@ pub enum Action {
|
|||
SetupDefaultProfile(SetupDefaultProfile),
|
||||
StartNixDaemon(StartNixDaemon),
|
||||
StartSystemdUnit(StartSystemdUnit),
|
||||
SystemdSysextMerge(SystemdSysextMerge),
|
||||
ProvisionNix(ProvisionNix),
|
||||
}
|
||||
|
||||
|
@ -94,6 +95,8 @@ pub enum ActionError {
|
|||
#[error(transparent)]
|
||||
CreateDirectory(#[from] CreateDirectoryError),
|
||||
#[error(transparent)]
|
||||
CreateSystemdSysext(#[from] CreateSystemdSysextError),
|
||||
#[error(transparent)]
|
||||
CreateFile(#[from] CreateFileError),
|
||||
#[error(transparent)]
|
||||
CreateGroup(#[from] CreateGroupError),
|
||||
|
@ -120,6 +123,8 @@ pub enum ActionError {
|
|||
#[error(transparent)]
|
||||
StartSystemdUnit(#[from] StartSystemdUnitError),
|
||||
#[error(transparent)]
|
||||
SystemdSysExtMerge(#[from] SystemdSysextMergeError),
|
||||
#[error(transparent)]
|
||||
ProvisionNix(#[from] ProvisionNixError),
|
||||
}
|
||||
|
||||
|
@ -132,6 +137,7 @@ impl Actionable for Action {
|
|||
Action::ConfigureNix(i) => i.describe_execute(),
|
||||
Action::ConfigureShellProfile(i) => i.describe_execute(),
|
||||
Action::CreateDirectory(i) => i.describe_execute(),
|
||||
Action::CreateSystemdSysext(i) => i.describe_execute(),
|
||||
Action::CreateFile(i) => i.describe_execute(),
|
||||
Action::CreateGroup(i) => i.describe_execute(),
|
||||
Action::CreateOrAppendFile(i) => i.describe_execute(),
|
||||
|
@ -145,6 +151,7 @@ impl Actionable for Action {
|
|||
Action::SetupDefaultProfile(i) => i.describe_execute(),
|
||||
Action::StartNixDaemon(i) => i.describe_execute(),
|
||||
Action::StartSystemdUnit(i) => i.describe_execute(),
|
||||
Action::SystemdSysextMerge(i) => i.describe_execute(),
|
||||
Action::ProvisionNix(i) => i.describe_execute(),
|
||||
}
|
||||
}
|
||||
|
@ -155,6 +162,7 @@ impl Actionable for Action {
|
|||
Action::ConfigureNix(i) => i.execute().await?,
|
||||
Action::ConfigureShellProfile(i) => i.execute().await?,
|
||||
Action::CreateDirectory(i) => i.execute().await?,
|
||||
Action::CreateSystemdSysext(i) => i.execute().await?,
|
||||
Action::CreateFile(i) => i.execute().await?,
|
||||
Action::CreateGroup(i) => i.execute().await?,
|
||||
Action::CreateOrAppendFile(i) => i.execute().await?,
|
||||
|
@ -168,6 +176,7 @@ impl Actionable for Action {
|
|||
Action::SetupDefaultProfile(i) => i.execute().await?,
|
||||
Action::StartNixDaemon(i) => i.execute().await?,
|
||||
Action::StartSystemdUnit(i) => i.execute().await?,
|
||||
Action::SystemdSysextMerge(i) => i.execute().await?,
|
||||
Action::ProvisionNix(i) => i.execute().await?,
|
||||
};
|
||||
Ok(())
|
||||
|
@ -179,6 +188,7 @@ impl Actionable for Action {
|
|||
Action::ConfigureNix(i) => i.describe_revert(),
|
||||
Action::ConfigureShellProfile(i) => i.describe_revert(),
|
||||
Action::CreateDirectory(i) => i.describe_revert(),
|
||||
Action::CreateSystemdSysext(i) => i.describe_revert(),
|
||||
Action::CreateFile(i) => i.describe_revert(),
|
||||
Action::CreateGroup(i) => i.describe_revert(),
|
||||
Action::CreateOrAppendFile(i) => i.describe_revert(),
|
||||
|
@ -192,6 +202,7 @@ impl Actionable for Action {
|
|||
Action::SetupDefaultProfile(i) => i.describe_revert(),
|
||||
Action::StartNixDaemon(i) => i.describe_revert(),
|
||||
Action::StartSystemdUnit(i) => i.describe_revert(),
|
||||
Action::SystemdSysextMerge(i) => i.describe_revert(),
|
||||
Action::ProvisionNix(i) => i.describe_revert(),
|
||||
}
|
||||
}
|
||||
|
@ -202,6 +213,7 @@ impl Actionable for Action {
|
|||
Action::ConfigureNix(i) => i.revert().await?,
|
||||
Action::ConfigureShellProfile(i) => i.revert().await?,
|
||||
Action::CreateDirectory(i) => i.revert().await?,
|
||||
Action::CreateSystemdSysext(i) => i.revert().await?,
|
||||
Action::CreateFile(i) => i.revert().await?,
|
||||
Action::CreateGroup(i) => i.revert().await?,
|
||||
Action::CreateOrAppendFile(i) => i.revert().await?,
|
||||
|
@ -215,6 +227,7 @@ impl Actionable for Action {
|
|||
Action::SetupDefaultProfile(i) => i.revert().await?,
|
||||
Action::StartNixDaemon(i) => i.revert().await?,
|
||||
Action::StartSystemdUnit(i) => i.revert().await?,
|
||||
Action::SystemdSysextMerge(i) => i.revert().await?,
|
||||
Action::ProvisionNix(i) => i.revert().await?,
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use crate::{
|
||||
actions::{
|
||||
meta::{ConfigureNix, ProvisionNix, StartNixDaemon},
|
||||
Action, ActionDescription, ActionError, Actionable,
|
||||
},
|
||||
actions::{Action, ActionDescription, ActionError, Actionable},
|
||||
planner::PlannerError,
|
||||
settings::InstallSettings,
|
||||
HarmonicError, Planner,
|
||||
|
|
|
@ -2,9 +2,7 @@ mod darwin;
|
|||
mod linux;
|
||||
mod specific;
|
||||
|
||||
use std::{ffi::OsStr, str::FromStr};
|
||||
|
||||
use crate::{actions::ActionError, HarmonicError, InstallPlan, InstallSettings};
|
||||
use crate::{actions::ActionError, InstallPlan, InstallSettings};
|
||||
|
||||
#[derive(Debug, Clone, clap::ValueEnum, serde::Serialize, serde::Deserialize)]
|
||||
pub enum Planner {
|
||||
|
|
|
@ -1,4 +1,11 @@
|
|||
use crate::{planner::Plannable, Planner};
|
||||
use crate::{
|
||||
actions::{
|
||||
meta::{CreateSystemdSysext, ProvisionNix, StartNixDaemon},
|
||||
Action, ActionError,
|
||||
},
|
||||
planner::Plannable,
|
||||
InstallPlan, Planner,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
||||
pub struct SteamDeck;
|
||||
|
@ -11,7 +18,24 @@ impl Plannable for SteamDeck {
|
|||
async fn plan(
|
||||
settings: crate::InstallSettings,
|
||||
) -> Result<crate::InstallPlan, crate::planner::PlannerError> {
|
||||
todo!()
|
||||
Ok(InstallPlan {
|
||||
planner: Self.into(),
|
||||
settings: settings.clone(),
|
||||
actions: vec![
|
||||
CreateSystemdSysext::plan("/var/lib/extensions")
|
||||
.await
|
||||
.map(Action::from)
|
||||
.map_err(ActionError::from)?,
|
||||
ProvisionNix::plan(settings.clone())
|
||||
.await
|
||||
.map(Action::from)
|
||||
.map_err(ActionError::from)?,
|
||||
StartNixDaemon::plan()
|
||||
.await
|
||||
.map(Action::from)
|
||||
.map_err(ActionError::from)?,
|
||||
],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{planner, Planner};
|
||||
use crate::planner;
|
||||
use target_lexicon::Triple;
|
||||
use url::Url;
|
||||
|
||||
|
|
Loading…
Reference in a new issue