host: Add get_current_system_profile

This commit is contained in:
Zhaofeng Li 2022-05-22 02:15:33 -07:00
parent c8b79e7e2d
commit e239cbd260
7 changed files with 43 additions and 13 deletions

View file

@ -6,7 +6,7 @@ use std::process::ExitStatus;
use snafu::Snafu; use snafu::Snafu;
use validator::ValidationErrors; use validator::ValidationErrors;
use crate::nix::{key, StorePath}; use crate::nix::{key, StorePath, Profile};
pub type ColmenaResult<T> = Result<T, ColmenaError>; pub type ColmenaResult<T> = Result<T, ColmenaError>;
@ -43,8 +43,8 @@ pub enum ColmenaError {
#[snafu(display("Invalid NixOS system profile"))] #[snafu(display("Invalid NixOS system profile"))]
InvalidProfile, InvalidProfile,
#[snafu(display("Unknown active profile: {:?}", store_path))] #[snafu(display("Unknown active profile: {:?}", profile))]
ActiveProfileUnknown { store_path: StorePath }, ActiveProfileUnknown { profile: Profile },
#[snafu(display("Could not determine current profile"))] #[snafu(display("Could not determine current profile"))]
FailedToGetCurrentProfile, FailedToGetCurrentProfile,

View file

@ -538,13 +538,13 @@ impl Deployment {
let profile = host.get_main_system_profile().await?; let profile = host.get_main_system_profile().await?;
if profile.exists() { if profile.as_store_path().exists() {
job.message("Remote profile known".to_string())?; job.message("Remote profile known".to_string())?;
} else if arc_self.options.force_replace_unknown_profiles { } else if arc_self.options.force_replace_unknown_profiles {
job.message("Warning: Remote profile is unknown, but unknown profiles are being ignored".to_string())?; job.message("Warning: Remote profile is unknown, but unknown profiles are being ignored".to_string())?;
} else { } else {
return Err(ColmenaError::ActiveProfileUnknown { return Err(ColmenaError::ActiveProfileUnknown {
store_path: profile, profile,
}); });
} }
} }

View file

@ -92,7 +92,21 @@ impl Host for Local {
result result
} }
async fn get_main_system_profile(&mut self) -> ColmenaResult<StorePath> { async fn get_current_system_profile(&mut self) -> ColmenaResult<Profile> {
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<Profile> {
let paths = Command::new("sh") let paths = Command::new("sh")
.args(&["-c", &format!("readlink -e {} || readlink -e {}", SYSTEM_PROFILE, CURRENT_PROFILE)]) .args(&["-c", &format!("readlink -e {} || readlink -e {}", SYSTEM_PROFILE, CURRENT_PROFILE)])
.capture_output() .capture_output()
@ -103,7 +117,7 @@ impl Host for Local {
.to_string() .to_string()
.try_into()?; .try_into()?;
Ok(path) Ok(Profile::from_store_path_unchecked(path))
} }
fn set_job(&mut self, job: Option<JobHandle>) { fn set_job(&mut self, job: Option<JobHandle>) {

View file

@ -111,12 +111,15 @@ pub trait Host: Send + Sync + std::fmt::Debug {
Err(ColmenaError::Unsupported) Err(ColmenaError::Unsupported)
} }
/// Returns the current system profile on the host.
async fn get_current_system_profile(&mut self) -> ColmenaResult<Profile>;
/// Returns the main system profile on the host. /// Returns the main system profile on the host.
/// ///
/// This may _not_ be the system profile that's currently activated! /// This may _not_ be the system profile that's currently activated!
/// It will first try `/nix/var/nix/profiles/system`, falling back /// It will first try `/nix/var/nix/profiles/system`, falling back
/// to `/run/current-system` if it doesn't exist. /// to `/run/current-system` if it doesn't exist.
async fn get_main_system_profile(&mut self) -> ColmenaResult<StorePath>; async fn get_main_system_profile(&mut self) -> ColmenaResult<Profile>;
/// Activates a system profile on the host, if it runs NixOS. /// Activates a system profile on the host, if it runs NixOS.
/// ///

View file

@ -82,7 +82,20 @@ impl Host for Ssh {
self.run_command(command).await self.run_command(command).await
} }
async fn get_main_system_profile(&mut self) -> ColmenaResult<StorePath> { async fn get_current_system_profile(&mut self) -> ColmenaResult<Profile> {
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<Profile> {
let command = format!("\"readlink -e {} || readlink -e {}\"", SYSTEM_PROFILE, CURRENT_PROFILE); let command = format!("\"readlink -e {} || readlink -e {}\"", SYSTEM_PROFILE, CURRENT_PROFILE);
let paths = self.ssh(&["sh", "-c", &command]) let paths = self.ssh(&["sh", "-c", &command])
@ -94,7 +107,7 @@ impl Host for Ssh {
.to_string() .to_string()
.try_into()?; .try_into()?;
Ok(path) Ok(Profile::from_store_path_unchecked(path))
} }
async fn run_command(&mut self, command: &[&str]) -> ColmenaResult<()> { async fn run_command(&mut self, command: &[&str]) -> ColmenaResult<()> {

View file

@ -16,7 +16,7 @@ use super::{
pub type ProfileDerivation = StoreDerivation<Profile>; pub type ProfileDerivation = StoreDerivation<Profile>;
/// A NixOS system profile. /// A NixOS system profile.
#[derive(Clone, Debug)] #[derive(Clone, Debug, PartialEq, Eq)]
pub struct Profile(StorePath); pub struct Profile(StorePath);
impl Profile { impl Profile {
@ -77,7 +77,7 @@ impl Profile {
Ok(()) Ok(())
} }
fn from_store_path_unchecked(path: StorePath) -> Self { pub(super) fn from_store_path_unchecked(path: StorePath) -> Self {
Self(path) Self(path)
} }
} }

View file

@ -12,7 +12,7 @@ use crate::util::CommandExt;
use super::Host; use super::Host;
/// A Nix store path. /// A Nix store path.
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct StorePath(PathBuf); pub struct StorePath(PathBuf);
/// A store derivation (.drv) that will result in a T when built. /// A store derivation (.drv) that will result in a T when built.