Make plans versioned (#62)
* Make plans versioned * Delint * speeeeeeeeling * remove file that was dead
This commit is contained in:
parent
ad44b85c97
commit
7cc71f1ccd
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -797,6 +797,7 @@ dependencies = [
|
||||||
"plist",
|
"plist",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
|
"semver",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_with",
|
"serde_with",
|
||||||
|
@ -1633,6 +1634,15 @@ dependencies = [
|
||||||
"untrusted",
|
"untrusted",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "semver"
|
||||||
|
version = "1.0.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.147"
|
version = "1.0.147"
|
||||||
|
|
|
@ -49,3 +49,4 @@ erased-serde = "0.3.23"
|
||||||
typetag = "0.2.3"
|
typetag = "0.2.3"
|
||||||
dyn-clone = "1.0.9"
|
dyn-clone = "1.0.9"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
|
semver = { version = "1.0.14", features = ["serde"] }
|
||||||
|
|
|
@ -23,7 +23,7 @@ pub struct ConfigureNix {
|
||||||
impl ConfigureNix {
|
impl ConfigureNix {
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub async fn plan(
|
pub async fn plan(
|
||||||
settings: CommonSettings,
|
settings: &CommonSettings,
|
||||||
) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let channels: Vec<(String, Url)> = settings
|
let channels: Vec<(String, Url)> = settings
|
||||||
.channels
|
.channels
|
||||||
|
@ -44,8 +44,8 @@ impl ConfigureNix {
|
||||||
let place_channel_configuration =
|
let place_channel_configuration =
|
||||||
PlaceChannelConfiguration::plan(channels, settings.force).await?;
|
PlaceChannelConfiguration::plan(channels, settings.force).await?;
|
||||||
let place_nix_configuration = PlaceNixConfiguration::plan(
|
let place_nix_configuration = PlaceNixConfiguration::plan(
|
||||||
settings.nix_build_group_name,
|
settings.nix_build_group_name.clone(),
|
||||||
settings.extra_conf,
|
settings.extra_conf.clone(),
|
||||||
settings.force,
|
settings.force,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
|
@ -23,7 +23,7 @@ pub struct ProvisionNix {
|
||||||
impl ProvisionNix {
|
impl ProvisionNix {
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub async fn plan(
|
pub async fn plan(
|
||||||
settings: CommonSettings,
|
settings: &CommonSettings,
|
||||||
) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let fetch_nix = FetchNix::plan(
|
let fetch_nix = FetchNix::plan(
|
||||||
settings.nix_package_url.clone(),
|
settings.nix_package_url.clone(),
|
||||||
|
|
|
@ -83,7 +83,7 @@ impl CommandExecute for Install {
|
||||||
existing_receipt
|
existing_receipt
|
||||||
} ,
|
} ,
|
||||||
None => {
|
None => {
|
||||||
planner.plan().await.map_err(|e| eyre!(e))?
|
InstallPlan::plan(planner.boxed()).await.map_err(|e| eyre!(e))?
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -97,7 +97,7 @@ impl CommandExecute for Install {
|
||||||
let builtin_planner = BuiltinPlanner::default()
|
let builtin_planner = BuiltinPlanner::default()
|
||||||
.await
|
.await
|
||||||
.map_err(|e| eyre::eyre!(e))?;
|
.map_err(|e| eyre::eyre!(e))?;
|
||||||
builtin_planner.plan().await.map_err(|e| eyre!(e))?
|
InstallPlan::plan(builtin_planner.boxed()).await.map_err(|e| eyre!(e))?
|
||||||
},
|
},
|
||||||
(Some(_), Some(_)) => return Err(eyre!("`--plan` conflicts with passing a planner, a planner creates plans, so passing an existing plan doesn't make sense")),
|
(Some(_), Some(_)) => return Err(eyre!("`--plan` conflicts with passing a planner, a planner creates plans, so passing an existing plan doesn't make sense")),
|
||||||
};
|
};
|
||||||
|
|
105
src/plan.rs
105
src/plan.rs
|
@ -1,33 +1,51 @@
|
||||||
use std::path::PathBuf;
|
use std::{path::PathBuf, str::FromStr};
|
||||||
|
|
||||||
use crossterm::style::Stylize;
|
|
||||||
use tokio::sync::broadcast::Receiver;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
action::{Action, ActionDescription, ActionImplementation},
|
action::{Action, ActionDescription, ActionImplementation},
|
||||||
planner::Planner,
|
planner::Planner,
|
||||||
HarmonicError,
|
HarmonicError,
|
||||||
};
|
};
|
||||||
|
use crossterm::style::Stylize;
|
||||||
|
use semver::{Version, VersionReq};
|
||||||
|
use serde::{de::Error, Deserialize, Deserializer};
|
||||||
|
use tokio::sync::broadcast::Receiver;
|
||||||
|
|
||||||
pub const RECEIPT_LOCATION: &str = "/nix/receipt.json";
|
pub const RECEIPT_LOCATION: &str = "/nix/receipt.json";
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||||
pub struct InstallPlan {
|
pub struct InstallPlan {
|
||||||
|
#[serde(deserialize_with = "ensure_version")]
|
||||||
|
pub(crate) version: Version,
|
||||||
|
|
||||||
pub(crate) actions: Vec<Box<dyn Action>>,
|
pub(crate) actions: Vec<Box<dyn Action>>,
|
||||||
|
|
||||||
pub(crate) planner: Box<dyn Planner>,
|
pub(crate) planner: Box<dyn Planner>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InstallPlan {
|
impl InstallPlan {
|
||||||
|
pub async fn plan(
|
||||||
|
planner: Box<dyn Planner>,
|
||||||
|
) -> Result<Self, Box<dyn std::error::Error + Sync + Send>> {
|
||||||
|
let actions = planner.plan().await?;
|
||||||
|
Ok(Self {
|
||||||
|
planner,
|
||||||
|
actions,
|
||||||
|
version: current_version()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub fn describe_execute(
|
pub fn describe_execute(
|
||||||
&self,
|
&self,
|
||||||
explain: bool,
|
explain: bool,
|
||||||
) -> Result<String, Box<dyn std::error::Error + Sync + Send>> {
|
) -> Result<String, Box<dyn std::error::Error + Sync + Send>> {
|
||||||
let Self { planner, actions } = self;
|
let Self {
|
||||||
|
planner,
|
||||||
|
actions,
|
||||||
|
version,
|
||||||
|
} = self;
|
||||||
let buf = format!(
|
let buf = format!(
|
||||||
"\
|
"\
|
||||||
Nix install plan\n\
|
Nix install plan (v{version})\n\
|
||||||
\n\
|
\n\
|
||||||
Planner: {planner}\n\
|
Planner: {planner}\n\
|
||||||
\n\
|
\n\
|
||||||
|
@ -82,6 +100,7 @@ impl InstallPlan {
|
||||||
cancel_channel: impl Into<Option<Receiver<()>>>,
|
cancel_channel: impl Into<Option<Receiver<()>>>,
|
||||||
) -> Result<(), HarmonicError> {
|
) -> Result<(), HarmonicError> {
|
||||||
let Self {
|
let Self {
|
||||||
|
version: _,
|
||||||
actions,
|
actions,
|
||||||
planner: _,
|
planner: _,
|
||||||
} = self;
|
} = self;
|
||||||
|
@ -119,7 +138,11 @@ impl InstallPlan {
|
||||||
&self,
|
&self,
|
||||||
explain: bool,
|
explain: bool,
|
||||||
) -> Result<String, Box<dyn std::error::Error + Sync + Send>> {
|
) -> Result<String, Box<dyn std::error::Error + Sync + Send>> {
|
||||||
let Self { planner, actions } = self;
|
let Self {
|
||||||
|
version: _,
|
||||||
|
planner,
|
||||||
|
actions,
|
||||||
|
} = self;
|
||||||
let buf = format!(
|
let buf = format!(
|
||||||
"\
|
"\
|
||||||
Nix uninstall plan\n\
|
Nix uninstall plan\n\
|
||||||
|
@ -178,6 +201,7 @@ impl InstallPlan {
|
||||||
cancel_channel: impl Into<Option<Receiver<()>>>,
|
cancel_channel: impl Into<Option<Receiver<()>>>,
|
||||||
) -> Result<(), HarmonicError> {
|
) -> Result<(), HarmonicError> {
|
||||||
let Self {
|
let Self {
|
||||||
|
version: _,
|
||||||
actions,
|
actions,
|
||||||
planner: _,
|
planner: _,
|
||||||
} = self;
|
} = self;
|
||||||
|
@ -222,3 +246,70 @@ async fn write_receipt(plan: InstallPlan) -> Result<(), HarmonicError> {
|
||||||
.map_err(|e| HarmonicError::RecordingReceipt(install_receipt_path, e))?;
|
.map_err(|e| HarmonicError::RecordingReceipt(install_receipt_path, e))?;
|
||||||
Result::<(), HarmonicError>::Ok(())
|
Result::<(), HarmonicError>::Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn current_version() -> Result<Version, semver::Error> {
|
||||||
|
let harmonic_version_str = env!("CARGO_PKG_VERSION");
|
||||||
|
Version::from_str(harmonic_version_str)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ensure_version<'de, D: Deserializer<'de>>(d: D) -> Result<Version, D::Error> {
|
||||||
|
let plan_version = Version::deserialize(d)?;
|
||||||
|
let req = VersionReq::parse(&plan_version.to_string()).map_err(|_e| {
|
||||||
|
D::Error::custom(&format!(
|
||||||
|
"Could not parse version `{plan_version}` as a version requirement, please report this",
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
let harmonic_version = current_version().map_err(|_e| {
|
||||||
|
D::Error::custom(&format!(
|
||||||
|
"Could not parse Harmonic's version `{}` as a valid version according to Semantic Versioning, therefore the plan version ({plan_version}) compatibility cannot be checked", env!("CARGO_PKG_VERSION")
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
if req.matches(&harmonic_version) {
|
||||||
|
Ok(plan_version)
|
||||||
|
} else {
|
||||||
|
Err(D::Error::custom(&format!(
|
||||||
|
"This version of Harmonic ({harmonic_version}) is not compatible with this plan's version ({plan_version}), please use a compatible version (according to Semantic Versioning)",
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use semver::Version;
|
||||||
|
|
||||||
|
use crate::{planner::BuiltinPlanner, InstallPlan};
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn ensure_version_allows_compatible() -> eyre::Result<()> {
|
||||||
|
let planner = BuiltinPlanner::default()
|
||||||
|
.await
|
||||||
|
.map_err(|e| eyre::eyre!(e))?;
|
||||||
|
let good_version = Version::parse(env!("CARGO_PKG_VERSION"))?;
|
||||||
|
let value = serde_json::json!({
|
||||||
|
"planner": planner.boxed(),
|
||||||
|
"version": good_version,
|
||||||
|
"actions": [],
|
||||||
|
});
|
||||||
|
let maybe_plan: Result<InstallPlan, serde_json::Error> = serde_json::from_value(value);
|
||||||
|
maybe_plan.unwrap();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn ensure_version_denies_incompatible() -> eyre::Result<()> {
|
||||||
|
let planner = BuiltinPlanner::default()
|
||||||
|
.await
|
||||||
|
.map_err(|e| eyre::eyre!(e))?;
|
||||||
|
let bad_version = Version::parse("9999999999999.9999999999.99999999")?;
|
||||||
|
let value = serde_json::json!({
|
||||||
|
"planner": planner.boxed(),
|
||||||
|
"version": bad_version,
|
||||||
|
"actions": [],
|
||||||
|
});
|
||||||
|
let maybe_plan: Result<InstallPlan, serde_json::Error> = serde_json::from_value(value);
|
||||||
|
assert!(maybe_plan.is_err());
|
||||||
|
let err = maybe_plan.unwrap_err();
|
||||||
|
assert!(err.is_data());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ use crate::{
|
||||||
execute_command,
|
execute_command,
|
||||||
os::darwin::DiskUtilOutput,
|
os::darwin::DiskUtilOutput,
|
||||||
planner::{BuiltinPlannerError, Planner},
|
planner::{BuiltinPlannerError, Planner},
|
||||||
BuiltinPlanner, CommonSettings, InstallPlan,
|
Action, BuiltinPlanner, CommonSettings,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, clap::Parser, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, clap::Parser, serde::Serialize, serde::Deserialize)]
|
||||||
|
@ -67,11 +67,9 @@ impl Planner for DarwinMulti {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn plan(
|
async fn plan(&self) -> Result<Vec<Box<dyn Action>>, Box<dyn std::error::Error + Sync + Send>> {
|
||||||
mut self,
|
let root_disk = match &self.root_disk {
|
||||||
) -> Result<crate::InstallPlan, Box<dyn std::error::Error + Sync + Send>> {
|
root_disk @ Some(_) => root_disk.clone(),
|
||||||
self.root_disk = match self.root_disk {
|
|
||||||
root_disk @ Some(_) => root_disk,
|
|
||||||
None => {
|
None => {
|
||||||
let buf = execute_command(
|
let buf = execute_command(
|
||||||
Command::new("/usr/sbin/diskutil")
|
Command::new("/usr/sbin/diskutil")
|
||||||
|
@ -99,29 +97,24 @@ impl Planner for DarwinMulti {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(InstallPlan {
|
Ok(vec![
|
||||||
planner: Box::new(self.clone()),
|
|
||||||
actions: vec![
|
|
||||||
// Create Volume step:
|
// Create Volume step:
|
||||||
//
|
//
|
||||||
// setup_Synthetic -> create_synthetic_objects
|
// setup_Synthetic -> create_synthetic_objects
|
||||||
// Unmount -> create_volume -> Setup_fstab -> maybe encrypt_volume -> launchctl bootstrap -> launchctl kickstart -> await_volume -> maybe enableOwnership
|
// Unmount -> create_volume -> Setup_fstab -> maybe encrypt_volume -> launchctl bootstrap -> launchctl kickstart -> await_volume -> maybe enableOwnership
|
||||||
Box::new(
|
Box::new(
|
||||||
CreateApfsVolume::plan(
|
CreateApfsVolume::plan(
|
||||||
self.root_disk.unwrap(), /* We just ensured it was populated */
|
root_disk.unwrap(), /* We just ensured it was populated */
|
||||||
self.volume_label,
|
self.volume_label.clone(),
|
||||||
false,
|
false,
|
||||||
encrypt,
|
encrypt,
|
||||||
)
|
)
|
||||||
.await?,
|
.await?,
|
||||||
),
|
),
|
||||||
Box::new(ProvisionNix::plan(self.settings.clone()).await?),
|
Box::new(ProvisionNix::plan(&self.settings).await?),
|
||||||
Box::new(ConfigureNix::plan(self.settings).await?),
|
Box::new(ConfigureNix::plan(&self.settings).await?),
|
||||||
Box::new(
|
Box::new(KickstartLaunchctlService::plan("system/org.nixos.nix-daemon".into()).await?),
|
||||||
KickstartLaunchctlService::plan("system/org.nixos.nix-daemon".into()).await?,
|
])
|
||||||
),
|
|
||||||
],
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn settings(
|
fn settings(
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
||||||
common::{ConfigureNix, ProvisionNix},
|
common::{ConfigureNix, ProvisionNix},
|
||||||
},
|
},
|
||||||
planner::Planner,
|
planner::Planner,
|
||||||
BuiltinPlanner, CommonSettings, InstallPlan,
|
Action, BuiltinPlanner, CommonSettings,
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, path::Path};
|
use std::{collections::HashMap, path::Path};
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ impl Planner for LinuxMulti {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn plan(self) -> Result<InstallPlan, Box<dyn std::error::Error + Sync + Send>> {
|
async fn plan(&self) -> Result<Vec<Box<dyn Action>>, Box<dyn std::error::Error + Sync + Send>> {
|
||||||
// If on NixOS, running `harmonic` is pointless
|
// If on NixOS, running `harmonic` is pointless
|
||||||
// NixOS always sets up this file as part of setting up /etc itself: https://github.com/NixOS/nixpkgs/blob/bdd39e5757d858bd6ea58ed65b4a2e52c8ed11ca/nixos/modules/system/etc/setup-etc.pl#L145
|
// NixOS always sets up this file as part of setting up /etc itself: https://github.com/NixOS/nixpkgs/blob/bdd39e5757d858bd6ea58ed65b4a2e52c8ed11ca/nixos/modules/system/etc/setup-etc.pl#L145
|
||||||
if Path::new("/etc/NIXOS").exists() {
|
if Path::new("/etc/NIXOS").exists() {
|
||||||
|
@ -40,26 +40,23 @@ impl Planner for LinuxMulti {
|
||||||
return Err(Error::NixExists.into());
|
return Err(Error::NixExists.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(InstallPlan {
|
Ok(vec![
|
||||||
planner: Box::new(self.clone()),
|
|
||||||
actions: vec![
|
|
||||||
Box::new(
|
Box::new(
|
||||||
CreateDirectory::plan("/nix", None, None, 0o0755, true)
|
CreateDirectory::plan("/nix", None, None, 0o0755, true)
|
||||||
.await
|
.await
|
||||||
.map_err(|v| Error::Action(v.into()))?,
|
.map_err(|v| Error::Action(v.into()))?,
|
||||||
),
|
),
|
||||||
Box::new(
|
Box::new(
|
||||||
ProvisionNix::plan(self.settings.clone())
|
ProvisionNix::plan(&self.settings.clone())
|
||||||
.await
|
.await
|
||||||
.map_err(|v| Error::Action(v.into()))?,
|
.map_err(|v| Error::Action(v.into()))?,
|
||||||
),
|
),
|
||||||
Box::new(
|
Box::new(
|
||||||
ConfigureNix::plan(self.settings)
|
ConfigureNix::plan(&self.settings)
|
||||||
.await
|
.await
|
||||||
.map_err(|v| Error::Action(v.into()))?,
|
.map_err(|v| Error::Action(v.into()))?,
|
||||||
),
|
),
|
||||||
],
|
])
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn settings(
|
fn settings(
|
||||||
|
|
|
@ -4,7 +4,7 @@ pub mod specific;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::{settings::InstallSettingsError, BoxableError, InstallPlan};
|
use crate::{settings::InstallSettingsError, Action, BoxableError};
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
#[typetag::serde(tag = "planner")]
|
#[typetag::serde(tag = "planner")]
|
||||||
|
@ -12,7 +12,7 @@ pub trait Planner: std::fmt::Debug + Send + Sync + dyn_clone::DynClone {
|
||||||
async fn default() -> Result<Self, Box<dyn std::error::Error + Sync + Send>>
|
async fn default() -> Result<Self, Box<dyn std::error::Error + Sync + Send>>
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
async fn plan(self) -> Result<InstallPlan, Box<dyn std::error::Error + Sync + Send>>;
|
async fn plan(&self) -> Result<Vec<Box<dyn Action>>, Box<dyn std::error::Error + Sync + Send>>;
|
||||||
fn settings(
|
fn settings(
|
||||||
&self,
|
&self,
|
||||||
) -> Result<HashMap<String, serde_json::Value>, Box<dyn std::error::Error + Sync + Send>>;
|
) -> Result<HashMap<String, serde_json::Value>, Box<dyn std::error::Error + Sync + Send>>;
|
||||||
|
@ -55,7 +55,9 @@ impl BuiltinPlanner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn plan(self) -> Result<InstallPlan, Box<dyn std::error::Error + Sync + Send>> {
|
pub async fn plan(
|
||||||
|
self,
|
||||||
|
) -> Result<Vec<Box<dyn Action>>, Box<dyn std::error::Error + Sync + Send>> {
|
||||||
match self {
|
match self {
|
||||||
BuiltinPlanner::LinuxMulti(planner) => planner.plan().await,
|
BuiltinPlanner::LinuxMulti(planner) => planner.plan().await,
|
||||||
BuiltinPlanner::DarwinMulti(planner) => planner.plan().await,
|
BuiltinPlanner::DarwinMulti(planner) => planner.plan().await,
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
||||||
linux::{CreateSystemdSysext, StartSystemdUnit},
|
linux::{CreateSystemdSysext, StartSystemdUnit},
|
||||||
},
|
},
|
||||||
planner::Planner,
|
planner::Planner,
|
||||||
BuiltinPlanner, CommonSettings, InstallPlan,
|
Action, BuiltinPlanner, CommonSettings,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, clap::Parser, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, clap::Parser, serde::Serialize, serde::Deserialize)]
|
||||||
|
@ -25,16 +25,13 @@ impl Planner for SteamDeck {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn plan(self) -> Result<crate::InstallPlan, Box<dyn std::error::Error + Sync + Send>> {
|
async fn plan(&self) -> Result<Vec<Box<dyn Action>>, Box<dyn std::error::Error + Sync + Send>> {
|
||||||
Ok(InstallPlan {
|
Ok(vec![
|
||||||
planner: Box::new(self.clone()),
|
|
||||||
actions: vec![
|
|
||||||
Box::new(CreateSystemdSysext::plan("/var/lib/extensions/nix").await?),
|
Box::new(CreateSystemdSysext::plan("/var/lib/extensions/nix").await?),
|
||||||
Box::new(CreateDirectory::plan("/nix", None, None, 0o0755, true).await?),
|
Box::new(CreateDirectory::plan("/nix", None, None, 0o0755, true).await?),
|
||||||
Box::new(ProvisionNix::plan(self.settings.clone()).await?),
|
Box::new(ProvisionNix::plan(&self.settings.clone()).await?),
|
||||||
Box::new(StartSystemdUnit::plan("nix-daemon.socket".into()).await?),
|
Box::new(StartSystemdUnit::plan("nix-daemon.socket".into()).await?),
|
||||||
],
|
])
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn settings(
|
fn settings(
|
||||||
|
|
Loading…
Reference in a new issue