Create all actions

This commit is contained in:
Ana Hobden 2022-09-15 12:11:46 -07:00
parent 0e843d3e5d
commit 38cc094381
26 changed files with 963 additions and 235 deletions

12
rustfmt.toml Normal file
View file

@ -0,0 +1,12 @@
# Put a trailing comma after a block based match arm (non-block arms are not affected)
match_block_trailing_comma = true
# Merge multiple derives into a single one.
merge_derives = true
# Reorder import and extern crate statements alphabetically in groups (a group is separated by a newline).
reorder_imports = true
# Reorder mod declarations alphabetically in group.
reorder_modules = true
# Use field initialize shorthand if possible.
use_field_init_shorthand = true
# Replace uses of the try! macro by the ? shorthand
use_try_shorthand = true

View file

@ -0,0 +1,53 @@
use crate::{HarmonicError, InstallSettings};
use super::{ActionDescription, ActionReceipt, Actionable, Revertable};
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct ConfigureNix {}
impl ConfigureNix {
pub fn plan(settings: InstallSettings) -> Self {
Self {}
}
}
#[async_trait::async_trait]
impl<'a> Actionable<'a> for ConfigureNix {
fn description(&self) -> Vec<ActionDescription> {
vec![
ActionDescription::new(
"Start the systemd Nix daemon".to_string(),
vec![
"The `nix` command line tool communicates with a running Nix daemon managed by your init system".to_string()
]
),
]
}
async fn execute(self) -> Result<ActionReceipt, HarmonicError> {
todo!()
}
}
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct ConfigureNixReceipt {}
#[async_trait::async_trait]
impl<'a> Revertable<'a> for ConfigureNixReceipt {
fn description(&self) -> Vec<ActionDescription> {
vec![
ActionDescription::new(
"Stop the systemd Nix daemon".to_string(),
vec![
"The `nix` command line tool communicates with a running Nix daemon managed by your init system".to_string()
]
),
]
}
async fn revert(self) -> Result<(), HarmonicError> {
todo!();
Ok(())
}
}

View file

@ -0,0 +1,53 @@
use crate::HarmonicError;
use super::{ActionDescription, ActionReceipt, Actionable, Revertable};
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct ConfigureNixDaemonService {}
impl ConfigureNixDaemonService {
pub fn plan() -> Self {
Self {}
}
}
#[async_trait::async_trait]
impl<'a> Actionable<'a> for ConfigureNixDaemonService {
fn description(&self) -> Vec<ActionDescription> {
vec![
ActionDescription::new(
"Start the systemd Nix daemon".to_string(),
vec![
"The `nix` command line tool communicates with a running Nix daemon managed by your init system".to_string()
]
),
]
}
async fn execute(self) -> Result<ActionReceipt, HarmonicError> {
todo!()
}
}
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct ConfigureNixDaemonServiceReceipt {}
#[async_trait::async_trait]
impl<'a> Revertable<'a> for ConfigureNixDaemonServiceReceipt {
fn description(&self) -> Vec<ActionDescription> {
vec![
ActionDescription::new(
"Stop the systemd Nix daemon".to_string(),
vec![
"The `nix` command line tool communicates with a running Nix daemon managed by your init system".to_string()
]
),
]
}
async fn revert(self) -> Result<(), HarmonicError> {
todo!();
Ok(())
}
}

View file

@ -0,0 +1,53 @@
use crate::HarmonicError;
use super::{ActionDescription, ActionReceipt, Actionable, Revertable};
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct ConfigureShellProfile {}
impl ConfigureShellProfile {
pub fn plan() -> Self {
Self {}
}
}
#[async_trait::async_trait]
impl<'a> Actionable<'a> for ConfigureShellProfile {
fn description(&self) -> Vec<ActionDescription> {
vec![
ActionDescription::new(
"Start the systemd Nix daemon".to_string(),
vec![
"The `nix` command line tool communicates with a running Nix daemon managed by your init system".to_string()
]
),
]
}
async fn execute(self) -> Result<ActionReceipt, HarmonicError> {
todo!()
}
}
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct ConfigureShellProfileReceipt {}
#[async_trait::async_trait]
impl<'a> Revertable<'a> for ConfigureShellProfileReceipt {
fn description(&self) -> Vec<ActionDescription> {
vec![
ActionDescription::new(
"Stop the systemd Nix daemon".to_string(),
vec![
"The `nix` command line tool communicates with a running Nix daemon managed by your init system".to_string()
]
),
]
}
async fn revert(self) -> Result<(), HarmonicError> {
todo!();
Ok(())
}
}

View file

@ -0,0 +1,89 @@
use std::{
fs::Permissions,
path::{Path, PathBuf},
};
use crate::HarmonicError;
use super::{ActionDescription, ActionReceipt, Actionable, Revertable};
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct CreateDirectory {
path: PathBuf,
user: String,
group: String,
mode: u32,
}
impl CreateDirectory {
pub fn plan(path: impl AsRef<Path>, user: String, group: String, mode: u32) -> Self {
let path = path.as_ref().to_path_buf();
Self {
path,
user,
group,
mode,
}
}
}
#[async_trait::async_trait]
impl<'a> Actionable<'a> for CreateDirectory {
fn description(&self) -> Vec<ActionDescription> {
vec![ActionDescription::new(
format!("Create the directory `/nix`"),
vec![format!(
"Nix and the Nix daemon require a Nix Store, which will be stored at `/nix`"
)],
)]
}
async fn execute(self) -> Result<ActionReceipt, HarmonicError> {
let Self {
path,
user,
group,
mode,
} = self;
todo!();
Ok(ActionReceipt::CreateDirectory(CreateDirectoryReceipt {
path,
user,
group,
mode,
}))
}
}
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct CreateDirectoryReceipt {
path: PathBuf,
user: String,
group: String,
mode: u32,
}
#[async_trait::async_trait]
impl<'a> Revertable<'a> for CreateDirectoryReceipt {
fn description(&self) -> Vec<ActionDescription> {
vec![ActionDescription::new(
format!("Create the directory `/nix`"),
vec![format!(
"Nix and the Nix daemon require a Nix Store, which will be stored at `/nix`"
)],
)]
}
async fn revert(self) -> Result<(), HarmonicError> {
let Self {
path,
user,
group,
mode,
} = self;
todo!();
Ok(())
}
}

View file

@ -0,0 +1,53 @@
use crate::HarmonicError;
use super::{ActionDescription, ActionReceipt, Actionable, Revertable};
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct CreateGroup {
name: String,
uid: usize,
}
impl CreateGroup {
pub fn plan(name: String, uid: usize) -> Self {
Self { name, uid }
}
}
#[async_trait::async_trait]
impl<'a> Actionable<'a> for CreateGroup {
fn description(&self) -> Vec<ActionDescription> {
let name = &self.name;
let uid = &self.uid;
vec![ActionDescription::new(
format!("Create group {name} with UID {uid}"),
vec![format!(
"The nix daemon requires a system user group its system users can be part of"
)],
)]
}
async fn execute(self) -> Result<ActionReceipt, HarmonicError> {
let Self { name, uid } = self;
Ok(ActionReceipt::CreateGroup(CreateGroupReceipt { name, uid }))
}
}
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct CreateGroupReceipt {
name: String,
uid: usize,
}
#[async_trait::async_trait]
impl<'a> Revertable<'a> for CreateGroupReceipt {
fn description(&self) -> Vec<ActionDescription> {
todo!()
}
async fn revert(self) -> Result<(), HarmonicError> {
todo!();
Ok(())
}
}

View file

@ -0,0 +1,47 @@
use crate::{HarmonicError, InstallSettings};
use super::{ActionDescription, ActionReceipt, Actionable, Revertable};
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct CreateNixTree {
settings: InstallSettings,
}
impl CreateNixTree {
pub fn plan(settings: InstallSettings) -> Self {
Self { settings }
}
}
#[async_trait::async_trait]
impl<'a> Actionable<'a> for CreateNixTree {
fn description(&self) -> Vec<ActionDescription> {
vec![ActionDescription::new(
format!("Create a directory tree in `/nix`"),
vec![format!(
"Nix and the Nix daemon require a Nix Store, which will be stored at `/nix`"
)],
)]
}
async fn execute(self) -> Result<ActionReceipt, HarmonicError> {
let Self { settings: _ } = self;
Ok(ActionReceipt::CreateNixTree(CreateNixTreeReceipt {}))
}
}
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct CreateNixTreeReceipt {}
#[async_trait::async_trait]
impl<'a> Revertable<'a> for CreateNixTreeReceipt {
fn description(&self) -> Vec<ActionDescription> {
todo!()
}
async fn revert(self) -> Result<(), HarmonicError> {
todo!();
Ok(())
}
}

View file

@ -0,0 +1,47 @@
use crate::HarmonicError;
use super::{ActionDescription, ActionReceipt, Actionable, Revertable};
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct CreateNixTreeDirs {}
impl CreateNixTreeDirs {
pub fn plan(name: String, uid: usize) -> Self {
Self {}
}
}
#[async_trait::async_trait]
impl<'a> Actionable<'a> for CreateNixTreeDirs {
fn description(&self) -> Vec<ActionDescription> {
vec![ActionDescription::new(
format!("Create a directory tree in `/nix`"),
vec![format!(
"Nix and the Nix daemon require a Nix Store, which will be stored at `/nix`"
)],
)]
}
async fn execute(self) -> Result<ActionReceipt, HarmonicError> {
let Self {} = self;
Ok(ActionReceipt::CreateNixTreeDirs(
CreateNixTreeDirsReceipt {},
))
}
}
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct CreateNixTreeDirsReceipt {}
#[async_trait::async_trait]
impl<'a> Revertable<'a> for CreateNixTreeDirsReceipt {
fn description(&self) -> Vec<ActionDescription> {
todo!()
}
async fn revert(self) -> Result<(), HarmonicError> {
todo!();
Ok(())
}
}

View file

@ -1,7 +1,6 @@
use crate::{settings::InstallSettings, HarmonicError}; use crate::HarmonicError;
use super::{Actionable, ActionReceipt, Revertable, ActionDescription};
use super::{ActionDescription, ActionReceipt, Actionable, Revertable};
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)] #[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct CreateUser { pub struct CreateUser {
@ -9,12 +8,6 @@ pub struct CreateUser {
uid: usize, uid: usize,
} }
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct CreateUserReceipt {
name: String,
uid: usize,
}
impl CreateUser { impl CreateUser {
pub fn plan(name: String, uid: usize) -> Self { pub fn plan(name: String, uid: usize) -> Self {
Self { name, uid } Self { name, uid }
@ -26,14 +19,12 @@ impl<'a> Actionable<'a> for CreateUser {
fn description(&self) -> Vec<ActionDescription> { fn description(&self) -> Vec<ActionDescription> {
let name = &self.name; let name = &self.name;
let uid = &self.uid; let uid = &self.uid;
vec![ vec![ActionDescription::new(
ActionDescription::new( format!("Create user {name} with UID {uid}"),
format!("Create user {name} with UID {uid}"), vec![format!(
vec![ "The nix daemon requires system users it can act as in order to build"
format!("The nix daemon requires system users it can act as in order to build"), )],
] )]
)
]
} }
async fn execute(self) -> Result<ActionReceipt, HarmonicError> { async fn execute(self) -> Result<ActionReceipt, HarmonicError> {
@ -42,6 +33,11 @@ impl<'a> Actionable<'a> for CreateUser {
} }
} }
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct CreateUserReceipt {
name: String,
uid: usize,
}
#[async_trait::async_trait] #[async_trait::async_trait]
impl<'a> Revertable<'a> for CreateUserReceipt { impl<'a> Revertable<'a> for CreateUserReceipt {
@ -51,7 +47,7 @@ impl<'a> Revertable<'a> for CreateUserReceipt {
async fn revert(self) -> Result<(), HarmonicError> { async fn revert(self) -> Result<(), HarmonicError> {
todo!(); todo!();
Ok(()) Ok(())
} }
} }

View file

@ -1,9 +1,8 @@
use tokio::task::JoinSet; use tokio::task::JoinSet;
use crate::{settings::InstallSettings, HarmonicError}; use crate::HarmonicError;
use super::{Actionable, CreateUser, ActionReceipt, create_user::CreateUserReceipt, Revertable, ActionDescription};
use super::{ActionDescription, ActionReceipt, Actionable, CreateUser, Revertable};
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)] #[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct CreateUsers { pub struct CreateUsers {
@ -13,18 +12,26 @@ pub struct CreateUsers {
children: Vec<CreateUser>, children: Vec<CreateUser>,
} }
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct CreateUsersReceipt {
children: Vec<ActionReceipt>,
}
impl CreateUsers { impl CreateUsers {
pub fn plan(nix_build_user_prefix: String, nix_build_user_id_base: usize, daemon_user_count: usize) -> Self { pub fn plan(
let children = (0..daemon_user_count).map(|count| CreateUser::plan( nix_build_user_prefix: String,
format!("{nix_build_user_prefix}{count}"), nix_build_user_id_base: usize,
nix_build_user_id_base + count daemon_user_count: usize,
)).collect(); ) -> Self {
Self { nix_build_user_prefix, nix_build_user_id_base, daemon_user_count, children } let children = (0..daemon_user_count)
.map(|count| {
CreateUser::plan(
format!("{nix_build_user_prefix}{count}"),
nix_build_user_id_base + count,
)
})
.collect();
Self {
nix_build_user_prefix,
nix_build_user_id_base,
daemon_user_count,
children,
}
} }
} }
@ -79,16 +86,22 @@ impl<'a> Actionable<'a> for CreateUsers {
} }
if errors.len() == 1 { if errors.len() == 1 {
return Err(errors.into_iter().next().unwrap()) return Err(errors.into_iter().next().unwrap());
} else { } else {
return Err(HarmonicError::Multiple(errors)) return Err(HarmonicError::Multiple(errors));
} }
} }
Ok(ActionReceipt::CreateUsers(CreateUsersReceipt{ children: successes })) Ok(ActionReceipt::CreateUsers(CreateUsersReceipt {
children: successes,
}))
} }
} }
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct CreateUsersReceipt {
children: Vec<ActionReceipt>,
}
#[async_trait::async_trait] #[async_trait::async_trait]
impl<'a> Revertable<'a> for CreateUsersReceipt { impl<'a> Revertable<'a> for CreateUsersReceipt {
@ -98,7 +111,7 @@ impl<'a> Revertable<'a> for CreateUsersReceipt {
async fn revert(self) -> Result<(), HarmonicError> { async fn revert(self) -> Result<(), HarmonicError> {
todo!(); todo!();
Ok(()) Ok(())
} }
} }

View file

@ -1,77 +1,38 @@
mod start_nix_daemon_service; mod configure_nix;
mod create_users; mod configure_nix_daemon_service;
mod configure_shell_profile;
mod create_directory;
mod create_group;
mod create_nix_tree;
mod create_nix_tree_dirs;
mod create_user; mod create_user;
pub use start_nix_daemon_service::{StartNixDaemonService, StartNixDaemonServiceReceipt}; mod create_users;
mod place_channel_configuration;
mod place_nix_configuration;
mod setup_default_profile;
mod start_nix_daemon;
mod start_systemd_service;
pub use configure_nix::{ConfigureNix, ConfigureNixReceipt};
pub use configure_nix_daemon_service::{
ConfigureNixDaemonService, ConfigureNixDaemonServiceReceipt,
};
pub use configure_shell_profile::{ConfigureShellProfile, ConfigureShellProfileReceipt};
pub use create_directory::{CreateDirectory, CreateDirectoryReceipt};
pub use create_group::{CreateGroup, CreateGroupReceipt};
pub use create_nix_tree::{CreateNixTree, CreateNixTreeReceipt};
pub use create_nix_tree_dirs::{CreateNixTreeDirs, CreateNixTreeDirsReceipt};
pub use create_user::{CreateUser, CreateUserReceipt}; pub use create_user::{CreateUser, CreateUserReceipt};
pub use create_users::{CreateUsers, CreateUsersReceipt}; pub use create_users::{CreateUsers, CreateUsersReceipt};
pub use place_channel_configuration::{
PlaceChannelConfiguration, PlaceChannelConfigurationReceipt,
};
pub use place_nix_configuration::{PlaceNixConfiguration, PlaceNixConfigurationReceipt};
pub use setup_default_profile::{SetupDefaultProfile, SetupDefaultProfileReceipt};
pub use start_nix_daemon::{StartNixDaemon, StartNixDaemonReceipt};
pub use start_systemd_service::{StartSystemdService, StartSystemdServiceReceipt};
use crate::{HarmonicError, settings::InstallSettings}; use crate::HarmonicError;
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct ActionDescription {
pub description: String,
pub explanation: Vec<String>,
}
impl ActionDescription {
fn new(description: String, explanation: Vec<String>) -> Self {
Self { description, explanation }
}
}
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub enum Action {
CreateUsers(CreateUsers),
CreateUser(CreateUser),
StartNixDaemonService(StartNixDaemonService),
}
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub enum ActionReceipt {
CreateUsers(CreateUsersReceipt),
CreateUser(CreateUserReceipt),
StartNixDaemonService(StartNixDaemonServiceReceipt),
}
#[async_trait::async_trait]
impl<'a> Actionable<'a> for Action {
fn description(&self) -> Vec<ActionDescription> {
match self {
Action::StartNixDaemonService(i) => i.description(),
Action::CreateUser(i) => i.description(),
Action::CreateUsers(i) => i.description(),
}
}
async fn execute(self) -> Result<ActionReceipt, HarmonicError> {
match self {
Action::StartNixDaemonService(i) => i.execute().await,
Action::CreateUser(i) => i.execute().await,
Action::CreateUsers(i) => i.execute().await,
}
}
}
#[async_trait::async_trait]
impl<'a> Revertable<'a> for ActionReceipt {
fn description(&self) -> Vec<ActionDescription> {
match self {
ActionReceipt::StartNixDaemonService(i) => i.description(),
ActionReceipt::CreateUser(i) => i.description(),
ActionReceipt::CreateUsers(i) => i.description(),
}
}
async fn revert(self) -> Result<(), HarmonicError> {
match self {
ActionReceipt::StartNixDaemonService(i) => i.revert().await,
ActionReceipt::CreateUser(i) => i.revert().await,
ActionReceipt::CreateUsers(i) => i.revert().await,
}
}
}
#[async_trait::async_trait] #[async_trait::async_trait]
pub trait Actionable<'a>: serde::de::Deserialize<'a> + serde::Serialize { pub trait Actionable<'a>: serde::de::Deserialize<'a> + serde::Serialize {
@ -84,3 +45,137 @@ pub trait Revertable<'a>: serde::de::Deserialize<'a> + serde::Serialize {
fn description(&self) -> Vec<ActionDescription>; fn description(&self) -> Vec<ActionDescription>;
async fn revert(self) -> Result<(), HarmonicError>; async fn revert(self) -> Result<(), HarmonicError>;
} }
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct ActionDescription {
pub description: String,
pub explanation: Vec<String>,
}
impl ActionDescription {
fn new(description: String, explanation: Vec<String>) -> Self {
Self {
description,
explanation,
}
}
}
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub enum Action {
ConfigureNixDaemonService(ConfigureNixDaemonService),
ConfigureNix(ConfigureNix),
ConfigureShellProfile(ConfigureShellProfile),
CreateDirectory(CreateUser),
CreateGroup(CreateGroup),
CreateNixTreeDirs(CreateNixTreeDirs),
CreateNixTree(CreateNixTree),
CreateUser(CreateUser),
CreateUsers(CreateUsers),
PlaceChannelConfiguration(PlaceChannelConfiguration),
PlaceNixConfiguration(PlaceNixConfiguration),
SetupDefaultProfile(SetupDefaultProfile),
StartNixDaemon(StartNixDaemon),
StartSystemdService(StartNixDaemon),
}
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub enum ActionReceipt {
ConfigureNixDaemonService(ConfigureNixDaemonServiceReceipt),
ConfigureNix(ConfigureNixReceipt),
ConfigureShellProfile(ConfigureShellProfileReceipt),
CreateDirectory(CreateDirectoryReceipt),
CreateGroup(CreateGroupReceipt),
CreateNixTreeDirs(CreateNixTreeDirsReceipt),
CreateNixTree(CreateNixTreeReceipt),
CreateUser(CreateUserReceipt),
CreateUsers(CreateUsersReceipt),
PlaceChannelConfiguration(PlaceChannelConfigurationReceipt),
PlaceNixConfiguration(PlaceNixConfigurationReceipt),
SetupDefaultProfile(SetupDefaultProfileReceipt),
StartNixDaemon(StartNixDaemonReceipt),
StartSystemdService(StartNixDaemonReceipt),
}
#[async_trait::async_trait]
impl<'a> Actionable<'a> for Action {
fn description(&self) -> Vec<ActionDescription> {
match self {
Action::ConfigureNixDaemonService(i) => i.description(),
Action::ConfigureNix(i) => i.description(),
Action::ConfigureShellProfile(i) => i.description(),
Action::CreateDirectory(i) => i.description(),
Action::CreateGroup(i) => i.description(),
Action::CreateNixTreeDirs(i) => i.description(),
Action::CreateNixTree(i) => i.description(),
Action::CreateUser(i) => i.description(),
Action::CreateUsers(i) => i.description(),
Action::PlaceChannelConfiguration(i) => i.description(),
Action::PlaceNixConfiguration(i) => i.description(),
Action::SetupDefaultProfile(i) => i.description(),
Action::StartNixDaemon(i) => i.description(),
Action::StartSystemdService(i) => i.description(),
}
}
async fn execute(self) -> Result<ActionReceipt, HarmonicError> {
match self {
Action::ConfigureNixDaemonService(i) => i.execute().await,
Action::ConfigureNix(i) => i.execute().await,
Action::ConfigureShellProfile(i) => i.execute().await,
Action::CreateDirectory(i) => i.execute().await,
Action::CreateGroup(i) => i.execute().await,
Action::CreateNixTreeDirs(i) => i.execute().await,
Action::CreateNixTree(i) => i.execute().await,
Action::CreateUser(i) => i.execute().await,
Action::CreateUsers(i) => i.execute().await,
Action::PlaceChannelConfiguration(i) => i.execute().await,
Action::PlaceNixConfiguration(i) => i.execute().await,
Action::SetupDefaultProfile(i) => i.execute().await,
Action::StartNixDaemon(i) => i.execute().await,
Action::StartSystemdService(i) => i.execute().await,
}
}
}
#[async_trait::async_trait]
impl<'a> Revertable<'a> for ActionReceipt {
fn description(&self) -> Vec<ActionDescription> {
match self {
ActionReceipt::ConfigureNixDaemonService(i) => i.description(),
ActionReceipt::ConfigureNix(i) => i.description(),
ActionReceipt::ConfigureShellProfile(i) => i.description(),
ActionReceipt::CreateDirectory(i) => i.description(),
ActionReceipt::CreateGroup(i) => i.description(),
ActionReceipt::CreateNixTreeDirs(i) => i.description(),
ActionReceipt::CreateNixTree(i) => i.description(),
ActionReceipt::CreateUser(i) => i.description(),
ActionReceipt::CreateUsers(i) => i.description(),
ActionReceipt::PlaceChannelConfiguration(i) => i.description(),
ActionReceipt::PlaceNixConfiguration(i) => i.description(),
ActionReceipt::SetupDefaultProfile(i) => i.description(),
ActionReceipt::StartNixDaemon(i) => i.description(),
ActionReceipt::StartSystemdService(i) => i.description(),
}
}
async fn revert(self) -> Result<(), HarmonicError> {
match self {
ActionReceipt::ConfigureNixDaemonService(i) => i.revert().await,
ActionReceipt::ConfigureNix(i) => i.revert().await,
ActionReceipt::ConfigureShellProfile(i) => i.revert().await,
ActionReceipt::CreateDirectory(i) => i.revert().await,
ActionReceipt::CreateGroup(i) => i.revert().await,
ActionReceipt::CreateNixTreeDirs(i) => i.revert().await,
ActionReceipt::CreateNixTree(i) => i.revert().await,
ActionReceipt::CreateUser(i) => i.revert().await,
ActionReceipt::CreateUsers(i) => i.revert().await,
ActionReceipt::PlaceChannelConfiguration(i) => i.revert().await,
ActionReceipt::PlaceNixConfiguration(i) => i.revert().await,
ActionReceipt::SetupDefaultProfile(i) => i.revert().await,
ActionReceipt::StartNixDaemon(i) => i.revert().await,
ActionReceipt::StartSystemdService(i) => i.revert().await,
}
}
}

View file

@ -0,0 +1,53 @@
use crate::HarmonicError;
use super::{ActionDescription, ActionReceipt, Actionable, Revertable};
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct PlaceChannelConfiguration {}
impl PlaceChannelConfiguration {
pub fn plan() -> Self {
Self {}
}
}
#[async_trait::async_trait]
impl<'a> Actionable<'a> for PlaceChannelConfiguration {
fn description(&self) -> Vec<ActionDescription> {
vec![
ActionDescription::new(
"Start the systemd Nix daemon".to_string(),
vec![
"The `nix` command line tool communicates with a running Nix daemon managed by your init system".to_string()
]
),
]
}
async fn execute(self) -> Result<ActionReceipt, HarmonicError> {
todo!()
}
}
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct PlaceChannelConfigurationReceipt {}
#[async_trait::async_trait]
impl<'a> Revertable<'a> for PlaceChannelConfigurationReceipt {
fn description(&self) -> Vec<ActionDescription> {
vec![
ActionDescription::new(
"Stop the systemd Nix daemon".to_string(),
vec![
"The `nix` command line tool communicates with a running Nix daemon managed by your init system".to_string()
]
),
]
}
async fn revert(self) -> Result<(), HarmonicError> {
todo!();
Ok(())
}
}

View file

@ -0,0 +1,53 @@
use crate::HarmonicError;
use super::{ActionDescription, ActionReceipt, Actionable, Revertable};
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct PlaceNixConfiguration {}
impl PlaceNixConfiguration {
pub fn plan() -> Self {
Self {}
}
}
#[async_trait::async_trait]
impl<'a> Actionable<'a> for PlaceNixConfiguration {
fn description(&self) -> Vec<ActionDescription> {
vec![
ActionDescription::new(
"Start the systemd Nix daemon".to_string(),
vec![
"The `nix` command line tool communicates with a running Nix daemon managed by your init system".to_string()
]
),
]
}
async fn execute(self) -> Result<ActionReceipt, HarmonicError> {
todo!()
}
}
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct PlaceNixConfigurationReceipt {}
#[async_trait::async_trait]
impl<'a> Revertable<'a> for PlaceNixConfigurationReceipt {
fn description(&self) -> Vec<ActionDescription> {
vec![
ActionDescription::new(
"Stop the systemd Nix daemon".to_string(),
vec![
"The `nix` command line tool communicates with a running Nix daemon managed by your init system".to_string()
]
),
]
}
async fn revert(self) -> Result<(), HarmonicError> {
todo!();
Ok(())
}
}

View file

@ -1,28 +1,18 @@
use reqwest::redirect::Action; use crate::HarmonicError;
use crate::{settings::InstallSettings, HarmonicError};
use super::{Actionable, ActionReceipt, Revertable, ActionDescription};
use super::{ActionDescription, ActionReceipt, Actionable, Revertable};
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)] #[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct StartNixDaemonService { pub struct SetupDefaultProfile {}
}
impl SetupDefaultProfile {
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct StartNixDaemonServiceReceipt {
}
impl StartNixDaemonService {
pub fn plan() -> Self { pub fn plan() -> Self {
Self {} Self {}
} }
} }
#[async_trait::async_trait] #[async_trait::async_trait]
impl<'a> Actionable<'a> for StartNixDaemonService { impl<'a> Actionable<'a> for SetupDefaultProfile {
fn description(&self) -> Vec<ActionDescription> { fn description(&self) -> Vec<ActionDescription> {
vec![ vec![
ActionDescription::new( ActionDescription::new(
@ -39,16 +29,25 @@ impl<'a> Actionable<'a> for StartNixDaemonService {
} }
} }
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct SetupDefaultProfileReceipt {}
#[async_trait::async_trait] #[async_trait::async_trait]
impl<'a> Revertable<'a> for StartNixDaemonServiceReceipt { impl<'a> Revertable<'a> for SetupDefaultProfileReceipt {
fn description(&self) -> Vec<ActionDescription> { fn description(&self) -> Vec<ActionDescription> {
todo!() vec![
ActionDescription::new(
"Stop the systemd Nix daemon".to_string(),
vec![
"The `nix` command line tool communicates with a running Nix daemon managed by your init system".to_string()
]
),
]
} }
async fn revert(self) -> Result<(), HarmonicError> { async fn revert(self) -> Result<(), HarmonicError> {
todo!(); todo!();
Ok(()) Ok(())
} }
} }

View file

@ -0,0 +1,53 @@
use crate::{settings, HarmonicError, InstallSettings};
use super::{ActionDescription, ActionReceipt, Actionable, Revertable};
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct StartNixDaemon {}
impl StartNixDaemon {
pub fn plan(settings: InstallSettings) -> Self {
Self {}
}
}
#[async_trait::async_trait]
impl<'a> Actionable<'a> for StartNixDaemon {
fn description(&self) -> Vec<ActionDescription> {
vec![
ActionDescription::new(
"Start the systemd Nix daemon".to_string(),
vec![
"The `nix` command line tool communicates with a running Nix daemon managed by your init system".to_string()
]
),
]
}
async fn execute(self) -> Result<ActionReceipt, HarmonicError> {
todo!()
}
}
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct StartNixDaemonReceipt {}
#[async_trait::async_trait]
impl<'a> Revertable<'a> for StartNixDaemonReceipt {
fn description(&self) -> Vec<ActionDescription> {
vec![
ActionDescription::new(
"Stop the systemd Nix daemon".to_string(),
vec![
"The `nix` command line tool communicates with a running Nix daemon managed by your init system".to_string()
]
),
]
}
async fn revert(self) -> Result<(), HarmonicError> {
todo!();
Ok(())
}
}

View file

@ -0,0 +1,53 @@
use crate::HarmonicError;
use super::{ActionDescription, ActionReceipt, Actionable, Revertable};
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct StartSystemdService {}
impl StartSystemdService {
pub fn plan() -> Self {
Self {}
}
}
#[async_trait::async_trait]
impl<'a> Actionable<'a> for StartSystemdService {
fn description(&self) -> Vec<ActionDescription> {
vec![
ActionDescription::new(
"Start the systemd Nix daemon".to_string(),
vec![
"The `nix` command line tool communicates with a running Nix daemon managed by your init system".to_string()
]
),
]
}
async fn execute(self) -> Result<ActionReceipt, HarmonicError> {
todo!()
}
}
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct StartSystemdServiceReceipt {}
#[async_trait::async_trait]
impl<'a> Revertable<'a> for StartSystemdServiceReceipt {
fn description(&self) -> Vec<ActionDescription> {
vec![
ActionDescription::new(
"Stop the systemd Nix daemon".to_string(),
vec![
"The `nix` command line tool communicates with a running Nix daemon managed by your init system".to_string()
]
),
]
}
async fn revert(self) -> Result<(), HarmonicError> {
todo!();
Ok(())
}
}

View file

@ -57,7 +57,7 @@ impl<'a> Instrumentation {
} }
} }
EnvFilter::try_new(&format!("{}={}", env!("CARGO_PKG_NAME"), self.log_level()))? EnvFilter::try_new(&format!("{}={}", env!("CARGO_PKG_NAME"), self.log_level()))?
} },
}; };
Ok(filter_layer) Ok(filter_layer)

View file

@ -8,7 +8,6 @@ use std::process::ExitCode;
use self::subcommand::HarmonicSubcommand; use self::subcommand::HarmonicSubcommand;
#[async_trait::async_trait] #[async_trait::async_trait]
pub(crate) trait CommandExecute { pub(crate) trait CommandExecute {
async fn execute(self) -> eyre::Result<ExitCode>; async fn execute(self) -> eyre::Result<ExitCode>;
@ -70,42 +69,32 @@ impl CommandExecute for HarmonicCli {
} = self; } = self;
match subcommand { match subcommand {
Some(HarmonicSubcommand::Plan(plan)) => { Some(HarmonicSubcommand::Plan(plan)) => plan.execute().await,
return plan.execute().await Some(HarmonicSubcommand::Execute(execute)) => execute.execute().await,
None => {
let mut settings = InstallSettings::default();
settings.explain(explain);
settings.daemon_user_count(daemon_user_count);
settings.channels(
channel
.into_iter()
.map(|ChannelValue(name, url)| (name, url)),
);
settings.modify_profile(!no_modify_profile);
let plan = InstallPlan::new(settings).await?;
// TODO(@Hoverbear): Make this smarter
if !interaction::confirm(plan.description()).await? {
interaction::clean_exit_with_message("Okay, didn't do anything! Bye!").await;
}
let _receipt = plan.install().await?;
Ok(ExitCode::SUCCESS)
}, },
Some(HarmonicSubcommand::Execute(execute)) => {
return execute.execute().await
}
None => (),
} }
let mut settings = InstallSettings::default();
settings.explain(explain);
settings.daemon_user_count(daemon_user_count);
settings.nix_build_group_name("nixbld".to_string());
settings.nix_build_group_id(30000);
settings.nix_build_user_prefix("nixbld".to_string());
settings.nix_build_user_id_base(30001);
settings.channels(
channel
.into_iter()
.map(|ChannelValue(name, url)| (name, url)),
);
settings.modify_profile(!no_modify_profile);
let plan = InstallPlan::new(settings).await?;
// TODO(@Hoverbear): Make this smarter
if !interaction::confirm(
plan.description()
)
.await?
{
interaction::clean_exit_with_message("Okay, didn't do anything! Bye!").await;
}
// let mut harmonic = Harmonic::default(); // let mut harmonic = Harmonic::default();
// harmonic.dry_run(dry_run); // harmonic.dry_run(dry_run);
@ -118,8 +107,6 @@ impl CommandExecute for HarmonicCli {
// ); // );
// harmonic.modify_profile(!no_modify_profile); // harmonic.modify_profile(!no_modify_profile);
// // TODO(@Hoverbear): Make this smarter // // TODO(@Hoverbear): Make this smarter
// if !interaction::confirm( // if !interaction::confirm(
// "\ // "\
@ -151,7 +138,5 @@ impl CommandExecute for HarmonicCli {
// harmonic.setup_default_profile().await?; // harmonic.setup_default_profile().await?;
// harmonic.place_nix_configuration().await?; // harmonic.place_nix_configuration().await?;
// harmonic.configure_nix_daemon_service().await?; // harmonic.configure_nix_daemon_service().await?;
Ok(ExitCode::SUCCESS)
} }
} }

View file

@ -1,10 +1,13 @@
use std::process::ExitCode; use std::process::ExitCode;
use clap::{Parser, ArgAction}; use clap::{ArgAction, Parser};
use harmonic::{InstallSettings, InstallPlan}; use harmonic::{InstallPlan, InstallSettings};
use tokio::io::{AsyncWriteExt, AsyncReadExt}; use tokio::io::{AsyncReadExt, AsyncWriteExt};
use crate::{cli::{arg::ChannelValue, CommandExecute}, interaction}; use crate::{
cli::{arg::ChannelValue, CommandExecute},
interaction,
};
/// An opinionated, experimental Nix installer /// An opinionated, experimental Nix installer
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
@ -15,34 +18,26 @@ pub(crate) struct Execute {
default_value = "false", default_value = "false",
global = true global = true
)] )]
no_confirm: bool no_confirm: bool,
} }
#[async_trait::async_trait] #[async_trait::async_trait]
impl CommandExecute for Execute { impl CommandExecute for Execute {
#[tracing::instrument(skip_all, fields( #[tracing::instrument(skip_all, fields())]
))]
async fn execute(self) -> eyre::Result<ExitCode> { async fn execute(self) -> eyre::Result<ExitCode> {
let Self { no_confirm } = self; let Self { no_confirm } = self;
let mut stdin = tokio::io::stdin(); let mut stdin = tokio::io::stdin();
let mut json = String::default(); let mut json = String::default();
stdin.read_to_string(&mut json).await?; stdin.read_to_string(&mut json).await?;
let plan: InstallPlan = serde_json::from_str(&json)?; let plan: InstallPlan = serde_json::from_str(&json)?;
if !no_confirm { if !no_confirm {
if !interaction::confirm( if !interaction::confirm(plan.description()).await? {
plan.description()
)
.await?
{
interaction::clean_exit_with_message("Okay, didn't do anything! Bye!").await; interaction::clean_exit_with_message("Okay, didn't do anything! Bye!").await;
} }
} }
Ok(ExitCode::SUCCESS) Ok(ExitCode::SUCCESS)
} }
} }

View file

@ -3,10 +3,8 @@ use plan::Plan;
mod execute; mod execute;
use execute::Execute; use execute::Execute;
#[derive(Debug, clap::Subcommand)] #[derive(Debug, clap::Subcommand)]
pub(crate) enum HarmonicSubcommand { pub(crate) enum HarmonicSubcommand {
Plan(Plan), Plan(Plan),
Execute(Execute), Execute(Execute),
} }

View file

@ -1,7 +1,7 @@
use std::process::ExitCode; use std::process::ExitCode;
use clap::{Parser, ArgAction}; use clap::{ArgAction, Parser};
use harmonic::{InstallSettings, InstallPlan}; use harmonic::{InstallPlan, InstallSettings};
use tokio::io::AsyncWriteExt; use tokio::io::AsyncWriteExt;
use crate::cli::{arg::ChannelValue, CommandExecute}; use crate::cli::{arg::ChannelValue, CommandExecute};
@ -39,15 +39,15 @@ impl CommandExecute for Plan {
no_modify_profile = %self.no_modify_profile, no_modify_profile = %self.no_modify_profile,
))] ))]
async fn execute(self) -> eyre::Result<ExitCode> { async fn execute(self) -> eyre::Result<ExitCode> {
let Self { channel, no_modify_profile, daemon_user_count } = self; let Self {
channel,
no_modify_profile,
daemon_user_count,
} = self;
let mut settings = InstallSettings::default(); let mut settings = InstallSettings::default();
settings.daemon_user_count(daemon_user_count); settings.daemon_user_count(daemon_user_count);
settings.nix_build_group_name("nixbld".to_string());
settings.nix_build_group_id(30000);
settings.nix_build_user_prefix("nixbld".to_string());
settings.nix_build_user_id_base(30001);
settings.channels( settings.channels(
channel channel
.into_iter() .into_iter()
@ -62,4 +62,4 @@ impl CommandExecute for Plan {
stdout.write_all(json.as_bytes()).await?; stdout.write_all(json.as_bytes()).await?;
Ok(ExitCode::SUCCESS) Ok(ExitCode::SUCCESS)
} }
} }

View file

@ -52,5 +52,5 @@ pub enum HarmonicError {
#[error("Errors with additional failures during reverts: {}\nDuring Revert:{}", .0.iter().map(|v| format!("{v}")).collect::<Vec<_>>().join(" & "), .1.iter().map(|v| format!("{v}")).collect::<Vec<_>>().join(" & "))] #[error("Errors with additional failures during reverts: {}\nDuring Revert:{}", .0.iter().map(|v| format!("{v}")).collect::<Vec<_>>().join(" & "), .1.iter().map(|v| format!("{v}")).collect::<Vec<_>>().join(" & "))]
FailedReverts(Vec<HarmonicError>, Vec<HarmonicError>), FailedReverts(Vec<HarmonicError>, Vec<HarmonicError>),
#[error("Multiple errors: {}", .0.iter().map(|v| format!("{v}")).collect::<Vec<_>>().join(" & "))] #[error("Multiple errors: {}", .0.iter().map(|v| format!("{v}")).collect::<Vec<_>>().join(" & "))]
Multiple(Vec<HarmonicError>) Multiple(Vec<HarmonicError>),
} }

View file

@ -34,10 +34,10 @@ pub(crate) async fn confirm(question: impl AsRef<str>) -> eyre::Result<bool> {
.await?; .await?;
stdout.flush().await?; stdout.flush().await?;
break Ok(false); break Ok(false);
} },
} }
} }
} },
Some(Err(err)) => return Err(err).wrap_err("Getting response"), Some(Err(err)) => return Err(err).wrap_err("Getting response"),
None => return Err(eyre!("Bailed, no confirmation event")), None => return Err(eyre!("Bailed, no confirmation event")),
} }

View file

@ -1,5 +1,5 @@
mod error;
mod actions; mod actions;
mod error;
mod plan; mod plan;
mod settings; mod settings;
@ -258,7 +258,7 @@ impl Harmonic {
// TODO(@Hoverbear): Should probably ensure is unique // TODO(@Hoverbear): Should probably ensure is unique
found_pkg = Some(path); found_pkg = Some(path);
break; break;
} },
Err(_) => continue, /* Ignore it */ Err(_) => continue, /* Ignore it */
}; };
} }
@ -291,7 +291,7 @@ impl Harmonic {
// TODO(@Hoverbear): Should probably ensure is unique // TODO(@Hoverbear): Should probably ensure is unique
found_pkg = Some(path); found_pkg = Some(path);
break; break;
} },
Err(_) => continue, /* Ignore it */ Err(_) => continue, /* Ignore it */
}; };
} }

View file

@ -1,8 +1,13 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{settings::InstallSettings, actions::{Action, StartNixDaemonService, Actionable, ActionReceipt, Revertable, CreateUsers, ActionDescription}, HarmonicError}; use crate::{
actions::{
Action, ActionDescription, ActionReceipt, Actionable, ConfigureNix, CreateNixTree,
Revertable, StartNixDaemon,
},
settings::InstallSettings,
HarmonicError,
};
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)] #[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct InstallPlan { pub struct InstallPlan {
@ -11,15 +16,18 @@ pub struct InstallPlan {
/** Bootstrap the install /** Bootstrap the install
* There are roughly three phases: * There are roughly three phases:
* "Create nix tree"":
* download_nix --------------------------------------> move_downloaded_nix * download_nix --------------------------------------> move_downloaded_nix
* create_group -> create_users -> create_directories -> move_downloaded_nix * create_group -> create_users -> create_directories -> move_downloaded_nix
* place_channel_configuration * place_channel_configuration
* place_nix_configuration * place_nix_configuration
* --- * ---
* "Configure Nix":
* setup_default_profile * setup_default_profile
* configure_nix_daemon_service * configure_nix_daemon_service
* configure_shell_profile * configure_shell_profile
* --- * ---
* "Start Nix"
* start_nix_daemon_service * start_nix_daemon_service
*/ */
actions: Vec<Action>, actions: Vec<Action>,
@ -27,7 +35,8 @@ pub struct InstallPlan {
impl InstallPlan { impl InstallPlan {
pub fn description(&self) -> String { pub fn description(&self) -> String {
format!("\ format!(
"\
This Nix install is for:\n\ This Nix install is for:\n\
Operating System: {os_type}\n\ Operating System: {os_type}\n\
Init system: {init_type}\n\ Init system: {init_type}\n\
@ -35,34 +44,44 @@ impl InstallPlan {
\n\ \n\
The following actions will be taken:\n\ The following actions will be taken:\n\
{actions} {actions}
", ",
os_type = "Linux", os_type = "Linux",
init_type = "systemd", init_type = "systemd",
nix_channels = self.settings.channels.iter().map(|(name,url)| format!("{name}={url}")).collect::<Vec<_>>().join(","), nix_channels = self
actions = self.actions.iter().flat_map(|action| action.description()).map(|desc| { .settings
let ActionDescription { .channels
description, .iter()
explanation, .map(|(name, url)| format!("{name}={url}"))
} = desc; .collect::<Vec<_>>()
.join(","),
let mut buf = String::default(); actions = self
buf.push_str(&format!("* {description}\n")); .actions
if self.settings.explain { .iter()
for line in explanation { .flat_map(|action| action.description())
buf.push_str(&format!(" {line}\n")); .map(|desc| {
let ActionDescription {
description,
explanation,
} = desc;
let mut buf = String::default();
buf.push_str(&format!("* {description}\n"));
if self.settings.explain {
for line in explanation {
buf.push_str(&format!(" {line}\n"));
}
} }
} buf
buf })
}).collect::<Vec<_>>().join("\n"), .collect::<Vec<_>>()
.join("\n"),
) )
} }
pub async fn new(settings: InstallSettings) -> Result<Self, HarmonicError> { pub async fn new(settings: InstallSettings) -> Result<Self, HarmonicError> {
let start_nix_daemon_service = StartNixDaemonService::plan();
let create_users = CreateUsers::plan(settings.nix_build_user_prefix.clone(), settings.nix_build_user_id_base, settings.daemon_user_count);
let actions = vec![ let actions = vec![
Action::CreateUsers(create_users), Action::CreateNixTree(CreateNixTree::plan(settings.clone())),
Action::StartNixDaemonService(start_nix_daemon_service), Action::ConfigureNix(ConfigureNix::plan(settings.clone())),
Action::StartNixDaemon(StartNixDaemon::plan(settings.clone())),
]; ];
Ok(Self { settings, actions }) Ok(Self { settings, actions })
} }
@ -83,15 +102,14 @@ impl InstallPlan {
} }
} }
if !revert_errs.is_empty() { if !revert_errs.is_empty() {
return Err(HarmonicError::FailedReverts(vec![err], revert_errs)) return Err(HarmonicError::FailedReverts(vec![err], revert_errs));
} }
return Err(err) return Err(err);
}, },
}; };
} }
Ok(receipt) Ok(receipt)
} }
} }

View file

@ -1,8 +1,7 @@
use url::Url; use url::Url;
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone, Default)] #[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct InstallSettings { pub struct InstallSettings {
pub(crate) dry_run: bool,
pub(crate) explain: bool, pub(crate) explain: bool,
pub(crate) daemon_user_count: usize, pub(crate) daemon_user_count: usize,
pub(crate) channels: Vec<(String, Url)>, pub(crate) channels: Vec<(String, Url)>,
@ -13,16 +12,27 @@ pub struct InstallSettings {
pub(crate) nix_build_user_id_base: usize, pub(crate) nix_build_user_id_base: usize,
} }
impl Default for InstallSettings {
fn default() -> Self {
Self {
explain: Default::default(),
daemon_user_count: Default::default(),
channels: Default::default(),
modify_profile: Default::default(),
nix_build_group_name: String::from("nixbld"),
nix_build_group_id: 3000,
nix_build_user_prefix: String::from("nixbld"),
nix_build_user_id_base: 3001,
}
}
}
// Builder Pattern // Builder Pattern
impl InstallSettings { impl InstallSettings {
pub fn explain(&mut self, explain: bool) -> &mut Self { pub fn explain(&mut self, explain: bool) -> &mut Self {
self.explain = explain; self.explain = explain;
self self
} }
pub fn dry_run(&mut self, dry_run: bool) -> &mut Self {
self.dry_run = dry_run;
self
}
pub fn daemon_user_count(&mut self, count: usize) -> &mut Self { pub fn daemon_user_count(&mut self, count: usize) -> &mut Self {
self.daemon_user_count = count; self.daemon_user_count = count;
self self
@ -57,4 +67,4 @@ impl InstallSettings {
self.nix_build_user_id_base = count; self.nix_build_user_id_base = count;
self self
} }
} }