diff --git a/src/action/base/setup_default_profile.rs b/src/action/base/setup_default_profile.rs index 0f4447f..4bf504c 100644 --- a/src/action/base/setup_default_profile.rs +++ b/src/action/base/setup_default_profile.rs @@ -54,9 +54,7 @@ impl Action for SetupDefaultProfile { // Find an `nix` package let nix_pkg_glob = format!("{}/nix-*/store/*-nix-*.*.*", self.unpacked_path.display()); let mut found_nix_pkg = None; - for entry in glob(&nix_pkg_glob) - .map_err(|e| Self::error(SetupDefaultProfileError::GlobPatternError(e)))? - { + for entry in glob(&nix_pkg_glob).map_err(|e| Self::error(e))? { match entry { Ok(path) => { // If we are curing, the user may have multiple of these installed @@ -85,9 +83,7 @@ impl Action for SetupDefaultProfile { self.unpacked_path.display() ); let mut found_nss_ca_cert_pkg = None; - for entry in glob(&nss_ca_cert_pkg_glob) - .map_err(|e| Self::error(SetupDefaultProfileError::GlobPatternError(e)))? - { + for entry in glob(&nss_ca_cert_pkg_glob).map_err(|e| Self::error(e))? { match entry { Ok(path) => { // If we are curing, the user may have multiple of these installed @@ -113,9 +109,9 @@ impl Action for SetupDefaultProfile { }; let found_nix_paths = glob::glob(&format!("{}/nix-*", self.unpacked_path.display())) - .map_err(|e| Self::error(SetupDefaultProfileError::from(e)))? + .map_err(|e| Self::error(e))? .collect::, _>>() - .map_err(|e| Self::error(SetupDefaultProfileError::from(e)))?; + .map_err(|e| Self::error(e))?; if found_nix_paths.len() != 1 { return Err(Self::error(ActionErrorKind::MalformedBinaryTarball)); } @@ -240,18 +236,6 @@ impl Action for SetupDefaultProfile { #[non_exhaustive] #[derive(Debug, thiserror::Error)] pub enum SetupDefaultProfileError { - #[error("Glob pattern error")] - GlobPatternError( - #[from] - #[source] - glob::PatternError, - ), - #[error("Glob globbing error")] - GlobGlobError( - #[from] - #[source] - glob::GlobError, - ), #[error("Unarchived Nix store did not appear to include a `nss-cacert` location")] NoNssCacert, #[error("Unarchived Nix store did not appear to include a `nix` location")] diff --git a/src/action/linux/mod.rs b/src/action/linux/mod.rs index 875e4be..47dfc99 100644 --- a/src/action/linux/mod.rs +++ b/src/action/linux/mod.rs @@ -1,9 +1,11 @@ pub(crate) mod ensure_steamos_nix_directory; pub(crate) mod provision_selinux; +pub(crate) mod revert_clean_steamos_nix_offload; pub(crate) mod start_systemd_unit; pub(crate) mod systemctl_daemon_reload; pub use ensure_steamos_nix_directory::EnsureSteamosNixDirectory; pub use provision_selinux::ProvisionSelinux; +pub use revert_clean_steamos_nix_offload::RevertCleanSteamosNixOffload; pub use start_systemd_unit::{StartSystemdUnit, StartSystemdUnitError}; pub use systemctl_daemon_reload::SystemctlDaemonReload; diff --git a/src/action/linux/revert_clean_steamos_nix_offload.rs b/src/action/linux/revert_clean_steamos_nix_offload.rs new file mode 100644 index 0000000..b64479f --- /dev/null +++ b/src/action/linux/revert_clean_steamos_nix_offload.rs @@ -0,0 +1,79 @@ +use std::path::Path; + +use tracing::{span, Span}; + +use crate::action::{ActionError, ActionErrorKind, ActionTag}; + +use crate::action::{Action, ActionDescription, StatefulAction}; + +const OFFLOAD_PATH: &'static str = "/home/.steamos/offload/nix"; + +/** +Clean out the `/home/.steamos/offload/nix` + +In SteamOS build ID 20230522.1000 (and, presumably, later) a `/home/.steamos/offload/nix` directory +exists by default and needs to be cleaned out on uninstall, otherwise uninstall won't work. +*/ +#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)] +pub struct RevertCleanSteamosNixOffload; + +impl RevertCleanSteamosNixOffload { + #[tracing::instrument(level = "debug", skip_all)] + pub async fn plan() -> Result, ActionError> { + if Path::new(OFFLOAD_PATH).exists() { + Ok(StatefulAction::uncompleted(RevertCleanSteamosNixOffload)) + } else { + Ok(StatefulAction::completed(RevertCleanSteamosNixOffload)) + } + } +} + +#[async_trait::async_trait] +#[typetag::serde(name = "revert_clean_steamos_nix_offload")] +impl Action for RevertCleanSteamosNixOffload { + fn action_tag() -> ActionTag { + ActionTag("revert_clean_steamos_nix_offload") + } + fn tracing_synopsis(&self) -> String { + format!("Clean the `{OFFLOAD_PATH}` directory") + } + + fn tracing_span(&self) -> Span { + span!(tracing::Level::DEBUG, "revert_clean_steamos_nix_offload",) + } + + fn execute_description(&self) -> Vec { + vec![] + } + + #[tracing::instrument(level = "debug", skip_all)] + async fn execute(&mut self) -> Result<(), ActionError> { + // noop + + Ok(()) + } + + fn revert_description(&self) -> Vec { + vec![ActionDescription::new( + self.tracing_synopsis(), + vec![ + format!("On more recent versions of SteamOS, the `{OFFLOAD_PATH}` folder contains the Nix store, and needs to be cleaned on uninstall."), + ], + )] + } + + #[tracing::instrument(level = "debug", skip_all)] + async fn revert(&mut self) -> Result<(), ActionError> { + let paths = glob::glob(OFFLOAD_PATH).map_err(Self::error)?; + + for path in paths { + let path = path.map_err(Self::error)?; + tracing::trace!(path = %path.display(), "Removing"); + tokio::fs::remove_dir_all(&path) + .await + .map_err(|e| Self::error(ActionErrorKind::Remove(path.into(), e)))?; + } + + Ok(()) + } +} diff --git a/src/action/mod.rs b/src/action/mod.rs index c33ba14..1eb9c9b 100644 --- a/src/action/mod.rs +++ b/src/action/mod.rs @@ -473,6 +473,18 @@ pub enum ActionErrorKind { NoGroup(String), #[error("Chowning path `{0}`")] Chown(std::path::PathBuf, #[source] nix::errno::Errno), + #[error("Glob globbing error")] + GlobGlobError( + #[from] + #[source] + glob::GlobError, + ), + #[error("Glob pattern error")] + GlobPatternError( + #[from] + #[source] + glob::PatternError, + ), /// Failed to execute command #[error("Failed to execute command `{command}`", command = .command, diff --git a/src/planner/steam_deck.rs b/src/planner/steam_deck.rs index e1242c5..142a6c2 100644 --- a/src/planner/steam_deck.rs +++ b/src/planner/steam_deck.rs @@ -104,7 +104,10 @@ use crate::{ action::{ base::{CreateDirectory, CreateFile, RemoveDirectory}, common::{ConfigureInitService, ConfigureNix, ProvisionNix}, - linux::{EnsureSteamosNixDirectory, StartSystemdUnit, SystemctlDaemonReload}, + linux::{ + EnsureSteamosNixDirectory, RevertCleanSteamosNixOffload, StartSystemdUnit, + SystemctlDaemonReload, + }, Action, StatefulAction, }, planner::{Planner, PlannerError}, @@ -248,10 +251,16 @@ impl Planner for SteamDeck { .map_err(PlannerError::Action)?; actions.push(create_bind_mount_unit.boxed()); } else { + let revert_clean_streamos_nix_offload = RevertCleanSteamosNixOffload::plan() + .await + .map_err(PlannerError::Action)?; + actions.push(revert_clean_streamos_nix_offload.boxed()); + let ensure_steamos_nix_directory = EnsureSteamosNixDirectory::plan() .await .map_err(PlannerError::Action)?; actions.push(ensure_steamos_nix_directory.boxed()); + let start_nix_mount = StartSystemdUnit::plan("nix.mount".to_string(), true) .await .map_err(PlannerError::Action)?;