diff --git a/src/error.rs b/src/error.rs index 9db31c7..4f78543 100644 --- a/src/error.rs +++ b/src/error.rs @@ -6,7 +6,7 @@ use std::process::ExitStatus; use snafu::Snafu; use validator::ValidationErrors; -use crate::nix::{key, StorePath}; +use crate::nix::{key, StorePath, Profile}; pub type ColmenaResult = Result; @@ -43,8 +43,8 @@ pub enum ColmenaError { #[snafu(display("Invalid NixOS system profile"))] InvalidProfile, - #[snafu(display("Unknown active profile: {:?}", store_path))] - ActiveProfileUnknown { store_path: StorePath }, + #[snafu(display("Unknown active profile: {:?}", profile))] + ActiveProfileUnknown { profile: Profile }, #[snafu(display("Could not determine current profile"))] FailedToGetCurrentProfile, diff --git a/src/nix/deployment/mod.rs b/src/nix/deployment/mod.rs index 3e9f6fa..da7d815 100644 --- a/src/nix/deployment/mod.rs +++ b/src/nix/deployment/mod.rs @@ -538,13 +538,13 @@ impl Deployment { let profile = host.get_main_system_profile().await?; - if profile.exists() { + if profile.as_store_path().exists() { job.message("Remote profile known".to_string())?; } else if arc_self.options.force_replace_unknown_profiles { job.message("Warning: Remote profile is unknown, but unknown profiles are being ignored".to_string())?; } else { return Err(ColmenaError::ActiveProfileUnknown { - store_path: profile, + profile, }); } } diff --git a/src/nix/host/local.rs b/src/nix/host/local.rs index 73b4be1..56529b8 100644 --- a/src/nix/host/local.rs +++ b/src/nix/host/local.rs @@ -92,7 +92,21 @@ impl Host for Local { result } - async fn get_main_system_profile(&mut self) -> ColmenaResult { + async fn get_current_system_profile(&mut self) -> ColmenaResult { + let paths = Command::new("readlink") + .args(&["-e", CURRENT_PROFILE]) + .capture_output() + .await?; + + let path = paths.lines().into_iter().next() + .ok_or(ColmenaError::FailedToGetCurrentProfile)? + .to_string() + .try_into()?; + + Ok(Profile::from_store_path_unchecked(path)) + } + + async fn get_main_system_profile(&mut self) -> ColmenaResult { let paths = Command::new("sh") .args(&["-c", &format!("readlink -e {} || readlink -e {}", SYSTEM_PROFILE, CURRENT_PROFILE)]) .capture_output() @@ -103,7 +117,7 @@ impl Host for Local { .to_string() .try_into()?; - Ok(path) + Ok(Profile::from_store_path_unchecked(path)) } fn set_job(&mut self, job: Option) { diff --git a/src/nix/host/mod.rs b/src/nix/host/mod.rs index b92de4f..b721ced 100644 --- a/src/nix/host/mod.rs +++ b/src/nix/host/mod.rs @@ -111,12 +111,15 @@ pub trait Host: Send + Sync + std::fmt::Debug { Err(ColmenaError::Unsupported) } + /// Returns the current system profile on the host. + async fn get_current_system_profile(&mut self) -> ColmenaResult; + /// Returns the main system profile on the host. /// /// This may _not_ be the system profile that's currently activated! /// It will first try `/nix/var/nix/profiles/system`, falling back /// to `/run/current-system` if it doesn't exist. - async fn get_main_system_profile(&mut self) -> ColmenaResult; + async fn get_main_system_profile(&mut self) -> ColmenaResult; /// Activates a system profile on the host, if it runs NixOS. /// diff --git a/src/nix/host/ssh.rs b/src/nix/host/ssh.rs index bf05214..1ce2871 100644 --- a/src/nix/host/ssh.rs +++ b/src/nix/host/ssh.rs @@ -82,7 +82,20 @@ impl Host for Ssh { self.run_command(command).await } - async fn get_main_system_profile(&mut self) -> ColmenaResult { + async fn get_current_system_profile(&mut self) -> ColmenaResult { + let paths = self.ssh(&["readlink", "-e", CURRENT_PROFILE]) + .capture_output() + .await?; + + let path = paths.lines().into_iter().next() + .ok_or(ColmenaError::FailedToGetCurrentProfile)? + .to_string() + .try_into()?; + + Ok(Profile::from_store_path_unchecked(path)) + } + + async fn get_main_system_profile(&mut self) -> ColmenaResult { let command = format!("\"readlink -e {} || readlink -e {}\"", SYSTEM_PROFILE, CURRENT_PROFILE); let paths = self.ssh(&["sh", "-c", &command]) @@ -94,7 +107,7 @@ impl Host for Ssh { .to_string() .try_into()?; - Ok(path) + Ok(Profile::from_store_path_unchecked(path)) } async fn run_command(&mut self, command: &[&str]) -> ColmenaResult<()> { diff --git a/src/nix/profile.rs b/src/nix/profile.rs index f0ed0d4..70dd1d6 100644 --- a/src/nix/profile.rs +++ b/src/nix/profile.rs @@ -16,7 +16,7 @@ use super::{ pub type ProfileDerivation = StoreDerivation; /// A NixOS system profile. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct Profile(StorePath); impl Profile { @@ -77,7 +77,7 @@ impl Profile { Ok(()) } - fn from_store_path_unchecked(path: StorePath) -> Self { + pub(super) fn from_store_path_unchecked(path: StorePath) -> Self { Self(path) } } diff --git a/src/nix/store.rs b/src/nix/store.rs index 4dcfaf9..d49f7d4 100644 --- a/src/nix/store.rs +++ b/src/nix/store.rs @@ -12,7 +12,7 @@ use crate::util::CommandExt; use super::Host; /// A Nix store path. -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct StorePath(PathBuf); /// A store derivation (.drv) that will result in a T when built.