1use anyhow::{Context as _, Result, anyhow};2use camino::Utf8PathBuf;3use tabled::Tabled;4use time::UtcDateTime;56use crate::host::ConfigHost;78#[derive(Debug, Clone, Copy)]9pub enum GenerationStorage {10 Deployer,11 Machine,12 Pusher,13}14impl GenerationStorage {15 fn prefix(&self) -> &'static str {16 match self {17 GenerationStorage::Deployer => "deployer.",18 GenerationStorage::Machine => "",19 GenerationStorage::Pusher => "pusher.",20 }21 }22}2324#[derive(Tabled, Debug)]25pub struct Generation {26 #[tabled(rename = "ID", format("{}", self.rollback_id()))]27 pub id: u32,28 #[tabled(rename = "Current")]29 pub current: bool,30 #[tabled(rename = "Created at")]31 pub datetime: UtcDateTime,32 #[tabled(format = "{:?}")]33 pub store_path: Utf8PathBuf,34 #[tabled(skip)]35 pub location: GenerationStorage,36}37impl Generation {38 pub fn rollback_id(&self) -> String {39 format!("{}{}", self.location.prefix(), self.id)40 }41}42impl ConfigHost {43 pub async fn list_generations(&self, profile: &str) -> Result<Vec<Generation>> {44 let nix = self.nix_client().await?;45 let raw = nix46 .list_generations(profile.to_owned())47 .await48 .map_err(|e| anyhow!("{e:?}"))?49 .map_err(|e| anyhow!("{e}"))?;50 raw.into_iter()51 .map(|g| {52 let id: u32 =53 g.id.try_into()54 .with_context(|| format!("generation id {} doesn't fit in u32", g.id))?;55 let datetime = UtcDateTime::from_unix_timestamp(g.creation_time_unix)56 .with_context(|| {57 format!("invalid generation timestamp {}", g.creation_time_unix)58 })?;59 Ok(Generation {60 id,61 current: g.current,62 datetime,63 store_path: g.store_path,64 location: GenerationStorage::Machine,65 })66 })67 .collect()68 }69}