Use a vec for the plan instead of specifics

This commit is contained in:
Ana Hobden 2022-10-13 10:34:19 -07:00
parent cdec8549ff
commit 2bd6cf1e65
7 changed files with 140 additions and 120 deletions

55
Cargo.lock generated
View file

@ -390,6 +390,15 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "erased-serde"
version = "0.3.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54558e0ba96fbe24280072642eceb9d7d442e32c7ec0ea9e7ecd7b4ea2cf4e11"
dependencies = [
"serde",
]
[[package]]
name = "event-listener"
version = "2.5.3"
@ -558,6 +567,17 @@ dependencies = [
"slab",
]
[[package]]
name = "ghost"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb19fe8de3ea0920d282f7b77dd4227aea6b8b999b42cdf0ca41b2472b14443a"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "gimli"
version = "0.26.2"
@ -629,6 +649,7 @@ dependencies = [
"tracing",
"tracing-error",
"tracing-subscriber",
"typetag",
"url",
"valuable",
"walkdir",
@ -762,6 +783,16 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "inventory"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e21e0a36a4dc4b469422ee17f715e8313f4a637675656d6a13637954278c6f55"
dependencies = [
"ctor",
"ghost",
]
[[package]]
name = "iovec"
version = "0.1.4"
@ -1652,6 +1683,30 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
[[package]]
name = "typetag"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23c8909f61359cac318f10dc9a3f9a7ee2155b6511f2a0c973460222ae5a00bb"
dependencies = [
"erased-serde",
"inventory",
"once_cell",
"serde",
"typetag-impl",
]
[[package]]
name = "typetag-impl"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd4d8ff674190866d3437d2f725355d49e99e3b1a513bf7ee43dcfe7effc36f4"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "unicode-bidi"
version = "0.3.8"

View file

@ -34,3 +34,4 @@ walkdir = "2.3.2"
serde = { version = "1.0.144", features = ["derive"] }
url = { version = "2.3.1", features = ["serde"] }
serde_json = "1.0.85"
typetag = "0.2.3"

View file

@ -8,6 +8,7 @@ use base::{
FetchNixError, MoveUnpackedNix, MoveUnpackedNixError, SetupDefaultProfile,
SetupDefaultProfileError,
};
use futures::Future;
use meta::{
ConfigureNix, ConfigureNixError, ConfigureShellProfile, ConfigureShellProfileError,
CreateNixTree, CreateNixTreeError, CreateUsersAndGroup, CreateUsersAndGroupError,

View file

@ -22,7 +22,7 @@ pub(crate) struct Execute {
default_value = "false",
global = true
)]
pub(crate) explain: bool,
explain: bool,
#[clap(default_value = "/dev/stdin")]
plan: PathBuf,
}

View file

@ -18,7 +18,7 @@ pub(crate) struct Plan {
env = "HARMONIC_CHANNEL",
default_value = "nixpkgs=https://nixos.org/channels/nixpkgs-unstable"
)]
pub(crate) channel: Vec<crate::cli::arg::ChannelValue>,
channel: Vec<crate::cli::arg::ChannelValue>,
/// Don't modify the user profile to automatically load nix
#[clap(
long,
@ -26,17 +26,17 @@ pub(crate) struct Plan {
default_value = "false",
global = true
)]
pub(crate) no_modify_profile: bool,
no_modify_profile: bool,
/// Number of build users to create
#[clap(long, default_value = "32", env = "HARMONIC_NIX_DAEMON_USER_COUNT")]
pub(crate) daemon_user_count: usize,
daemon_user_count: usize,
#[clap(
long,
action(ArgAction::SetTrue),
default_value = "false",
global = true
)]
pub(crate) force: bool,
force: bool,
#[clap(default_value = "/dev/stdout")]
plan: PathBuf,
}

View file

@ -22,7 +22,7 @@ pub(crate) struct Uninstall {
default_value = "false",
global = true
)]
pub(crate) explain: bool,
explain: bool,
#[clap(default_value = "/nix/receipt.json")]
receipt: PathBuf,
}

View file

@ -3,7 +3,7 @@ use std::path::PathBuf;
use crate::{
actions::{
meta::{ConfigureNix, ProvisionNix, StartNixDaemon},
ActionDescription, ActionError, Actionable,
Action, ActionDescription, ActionError, Actionable,
},
settings::InstallSettings,
HarmonicError,
@ -13,52 +13,33 @@ use crate::{
pub struct InstallPlan {
settings: InstallSettings,
/** Bootstrap the install
* There are roughly three phases:
* "Create nix tree"":
* download_nix --------------------------------------> move_downloaded_nix
* create_group -> create_users -> create_directories -> move_downloaded_nix
* place_channel_configuration
* place_nix_configuration
* ---
* "Configure Nix":
* setup_default_profile
* configure_nix_daemon_service
* configure_shell_profile
* ---
* "Start Nix"
* start_nix_daemon_service
*/
provision_nix: ProvisionNix,
configure_nix: ConfigureNix,
start_nix_daemon: StartNixDaemon,
actions: Vec<Action>,
}
impl InstallPlan {
pub async fn new(settings: InstallSettings) -> Result<Self, HarmonicError> {
Ok(Self {
settings: settings.clone(),
provision_nix: ProvisionNix::plan(settings.clone())
.await
.map_err(|e| ActionError::from(e))?,
configure_nix: ConfigureNix::plan(settings)
.await
.map_err(|e| ActionError::from(e))?,
start_nix_daemon: StartNixDaemon::plan()
.await
.map_err(|e| ActionError::from(e))?,
actions: vec![
ProvisionNix::plan(settings.clone())
.await
.map(Action::from)
.map_err(ActionError::from)?,
ConfigureNix::plan(settings)
.await
.map(Action::from)
.map_err(ActionError::from)?,
StartNixDaemon::plan()
.await
.map(Action::from)
.map_err(ActionError::from)?,
],
})
}
#[tracing::instrument(skip_all)]
pub fn describe_execute(&self, explain: bool) -> String {
let Self {
settings,
provision_nix,
configure_nix,
start_nix_daemon,
} = self;
let Self { settings, actions } = self;
format!(
"\
This Nix install is for:\n\
@ -77,66 +58,53 @@ impl InstallPlan {
.map(|(name, url)| format!("{name}={url}"))
.collect::<Vec<_>>()
.join(","),
actions = {
let mut buf = provision_nix.describe_execute();
buf.append(&mut configure_nix.describe_execute());
buf.append(&mut start_nix_daemon.describe_execute());
buf.iter()
.map(|desc| {
let ActionDescription {
description,
explanation,
} = desc;
actions = actions
.iter()
.map(|v| v.describe_execute())
.flatten()
.map(|desc| {
let ActionDescription {
description,
explanation,
} = desc;
let mut buf = String::default();
buf.push_str(&format!("* {description}\n"));
if explain {
for line in explanation {
buf.push_str(&format!(" {line}\n"));
}
let mut buf = String::default();
buf.push_str(&format!("* {description}\n"));
if explain {
for line in explanation {
buf.push_str(&format!(" {line}\n"));
}
buf
})
.collect::<Vec<_>>()
.join("\n")
},
}
buf
})
.collect::<Vec<_>>()
.join("\n"),
)
}
#[tracing::instrument(skip_all)]
pub async fn install(&mut self) -> Result<(), HarmonicError> {
let Self {
actions,
settings: _,
} = self;
// This is **deliberately sequential**.
// Actions which are parallelizable are represented by "group actions" like CreateUsers
// The plan itself represents the concept of the sequence of stages.
if let Err(err) = self.provision_nix.execute().await {
write_receipt(self.clone()).await?;
return Err(ActionError::from(err).into());
for action in actions {
if let Err(err) = action.execute().await {
write_receipt(self.clone()).await?;
return Err(ActionError::from(err).into());
}
}
if let Err(err) = self.configure_nix.execute().await {
write_receipt(self.clone()).await?;
return Err(ActionError::from(err).into());
}
if let Err(err) = self.start_nix_daemon.execute().await {
write_receipt(self.clone()).await?;
return Err(ActionError::from(err).into());
}
write_receipt(self.clone()).await?;
Ok(())
write_receipt(self.clone()).await
}
#[tracing::instrument(skip_all)]
pub fn describe_revert(&self, explain: bool) -> String {
let Self {
settings,
provision_nix,
configure_nix,
start_nix_daemon,
} = self;
let Self { settings, actions } = self;
format!(
"\
This Nix uninstall is for:\n\
@ -155,50 +123,45 @@ impl InstallPlan {
.map(|(name, url)| format!("{name}={url}"))
.collect::<Vec<_>>()
.join(","),
actions = {
let mut buf = provision_nix.describe_revert();
buf.append(&mut configure_nix.describe_revert());
buf.append(&mut start_nix_daemon.describe_revert());
buf.iter()
.map(|desc| {
let ActionDescription {
description,
explanation,
} = desc;
actions = actions
.iter()
.map(|v| v.describe_revert())
.flatten()
.map(|desc| {
let ActionDescription {
description,
explanation,
} = desc;
let mut buf = String::default();
buf.push_str(&format!("* {description}\n"));
if explain {
for line in explanation {
buf.push_str(&format!(" {line}\n"));
}
let mut buf = String::default();
buf.push_str(&format!("* {description}\n"));
if explain {
for line in explanation {
buf.push_str(&format!(" {line}\n"));
}
buf
})
.collect::<Vec<_>>()
.join("\n")
},
}
buf
})
.collect::<Vec<_>>()
.join("\n"),
)
}
#[tracing::instrument(skip_all)]
pub async fn revert(&mut self) -> Result<(), HarmonicError> {
let Self {
actions,
settings: _,
} = self;
// This is **deliberately sequential**.
// Actions which are parallelizable are represented by "group actions" like CreateUsers
// The plan itself represents the concept of the sequence of stages.
if let Err(err) = self.start_nix_daemon.revert().await {
write_receipt(self.clone()).await?;
return Err(ActionError::from(err).into());
}
if let Err(err) = self.configure_nix.revert().await {
write_receipt(self.clone()).await?;
return Err(ActionError::from(err).into());
}
if let Err(err) = self.provision_nix.revert().await {
write_receipt(self.clone()).await?;
return Err(ActionError::from(err).into());
for action in actions {
if let Err(err) = action.revert().await {
write_receipt(self.clone()).await?;
return Err(ActionError::from(err).into());
}
}
Ok(())