forked from lix-project/lix-installer
Tidy up command structure somewhat
This commit is contained in:
parent
2bd6cf1e65
commit
42dd62452a
|
@ -8,7 +8,6 @@ use base::{
|
|||
FetchNixError, MoveUnpackedNix, MoveUnpackedNixError, SetupDefaultProfile,
|
||||
SetupDefaultProfileError,
|
||||
};
|
||||
use futures::Future;
|
||||
use meta::{
|
||||
ConfigureNix, ConfigureNixError, ConfigureShellProfile, ConfigureShellProfileError,
|
||||
CreateNixTree, CreateNixTreeError, CreateUsersAndGroup, CreateUsersAndGroupError,
|
||||
|
|
133
src/cli/mod.rs
133
src/cli/mod.rs
|
@ -1,10 +1,7 @@
|
|||
pub(crate) mod arg;
|
||||
pub(crate) mod subcommand;
|
||||
|
||||
use crate::{cli::arg::ChannelValue, interaction};
|
||||
use clap::{ArgAction, Parser};
|
||||
use eyre::eyre;
|
||||
use harmonic::{InstallPlan, InstallSettings};
|
||||
use clap::Parser;
|
||||
use std::process::ExitCode;
|
||||
|
||||
use self::subcommand::HarmonicSubcommand;
|
||||
|
@ -22,140 +19,24 @@ pub(crate) trait CommandExecute {
|
|||
pub(crate) struct HarmonicCli {
|
||||
#[clap(flatten)]
|
||||
pub(crate) instrumentation: arg::Instrumentation,
|
||||
/// Channel(s) to add by default, pass multiple times for multiple channels
|
||||
#[clap(
|
||||
long,
|
||||
value_parser,
|
||||
action = clap::ArgAction::Append,
|
||||
env = "HARMONIC_CHANNEL",
|
||||
default_value = "nixpkgs=https://nixos.org/channels/nixpkgs-unstable"
|
||||
)]
|
||||
pub(crate) channel: Vec<arg::ChannelValue>,
|
||||
/// Don't modify the user profile to automatically load nix
|
||||
#[clap(
|
||||
long,
|
||||
action(ArgAction::SetTrue),
|
||||
default_value = "false",
|
||||
global = true
|
||||
)]
|
||||
pub(crate) 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,
|
||||
#[clap(
|
||||
long,
|
||||
action(ArgAction::SetTrue),
|
||||
default_value = "false",
|
||||
global = true
|
||||
)]
|
||||
pub(crate) explain: bool,
|
||||
#[clap(
|
||||
long,
|
||||
action(ArgAction::SetTrue),
|
||||
default_value = "false",
|
||||
global = true
|
||||
)]
|
||||
pub(crate) force: bool,
|
||||
|
||||
#[clap(subcommand)]
|
||||
subcommand: Option<HarmonicSubcommand>,
|
||||
subcommand: HarmonicSubcommand,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl CommandExecute for HarmonicCli {
|
||||
#[tracing::instrument(skip_all, fields(
|
||||
channels = %self.channel.iter().map(|ChannelValue(name, url)| format!("{name} {url}")).collect::<Vec<_>>().join(", "),
|
||||
daemon_user_count = %self.daemon_user_count,
|
||||
no_modify_profile = %self.no_modify_profile,
|
||||
explain = %self.explain,
|
||||
))]
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn execute(self) -> eyre::Result<ExitCode> {
|
||||
let Self {
|
||||
instrumentation: _,
|
||||
daemon_user_count,
|
||||
channel,
|
||||
no_modify_profile,
|
||||
explain,
|
||||
subcommand,
|
||||
force,
|
||||
} = self;
|
||||
|
||||
match subcommand {
|
||||
Some(HarmonicSubcommand::Plan(plan)) => plan.execute().await,
|
||||
Some(HarmonicSubcommand::Execute(execute)) => execute.execute().await,
|
||||
Some(HarmonicSubcommand::Uninstall(revert)) => revert.execute().await,
|
||||
None => {
|
||||
let mut settings = InstallSettings::default();
|
||||
|
||||
settings.force(force);
|
||||
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 mut plan = InstallPlan::new(settings).await?;
|
||||
|
||||
// TODO(@Hoverbear): Make this smarter
|
||||
if !interaction::confirm(plan.describe_execute(explain)).await? {
|
||||
interaction::clean_exit_with_message("Okay, didn't do anything! Bye!").await;
|
||||
}
|
||||
|
||||
if let Err(err) = plan.install().await {
|
||||
tracing::error!("{:?}", eyre!(err));
|
||||
if !interaction::confirm(plan.describe_revert(explain)).await? {
|
||||
interaction::clean_exit_with_message("Okay, didn't do anything! Bye!")
|
||||
.await;
|
||||
}
|
||||
plan.revert().await?
|
||||
}
|
||||
|
||||
Ok(ExitCode::SUCCESS)
|
||||
},
|
||||
HarmonicSubcommand::Plan(plan) => plan.execute().await,
|
||||
HarmonicSubcommand::Install(install) => install.execute().await,
|
||||
HarmonicSubcommand::Uninstall(revert) => revert.execute().await,
|
||||
}
|
||||
// let mut harmonic = Harmonic::default();
|
||||
|
||||
// harmonic.dry_run(dry_run);
|
||||
// harmonic.explain(explain);
|
||||
// harmonic.daemon_user_count(daemon_user_count);
|
||||
// harmonic.channels(
|
||||
// channel
|
||||
// .into_iter()
|
||||
// .map(|ChannelValue(name, url)| (name, url)),
|
||||
// );
|
||||
// harmonic.modify_profile(!no_modify_profile);
|
||||
|
||||
// // TODO(@Hoverbear): Make this smarter
|
||||
// if !interaction::confirm(
|
||||
// "\
|
||||
// Ready to install nix?\n\
|
||||
// \n\
|
||||
// This installer will:\n\
|
||||
// \n\
|
||||
// * Create a `nixbld` group\n\
|
||||
// * Create several `nixbld*` users\n\
|
||||
// * Create several Nix related directories\n\
|
||||
// * Place channel configurations\n\
|
||||
// * Fetch a copy of Nix and unpack it\n\
|
||||
// * Configure the shell profiles of various shells\n\
|
||||
// * Place a Nix configuration\n\
|
||||
// * Configure the Nix daemon to work with your init\
|
||||
// ",
|
||||
// )
|
||||
// .await?
|
||||
// {
|
||||
// interaction::clean_exit_with_message("Okay, didn't do anything! Bye!").await;
|
||||
// }
|
||||
|
||||
// harmonic.create_group().await?;
|
||||
// harmonic.create_users().await?;
|
||||
// harmonic.create_directories().await?;
|
||||
// harmonic.place_channel_configuration().await?;
|
||||
// harmonic.fetch_nix().await?;
|
||||
// harmonic.configure_shell_profile().await?;
|
||||
// harmonic.setup_default_profile().await?;
|
||||
// harmonic.place_nix_configuration().await?;
|
||||
// harmonic.configure_nix_daemon_service().await?;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,13 +2,16 @@ use std::{path::PathBuf, process::ExitCode};
|
|||
|
||||
use clap::{ArgAction, Parser};
|
||||
use eyre::{eyre, WrapErr};
|
||||
use harmonic::InstallPlan;
|
||||
use harmonic::{InstallPlan, InstallSettings};
|
||||
|
||||
use crate::{cli::CommandExecute, interaction};
|
||||
use crate::{
|
||||
cli::{arg::ChannelValue, CommandExecute},
|
||||
interaction,
|
||||
};
|
||||
|
||||
/// Execute an install using an existing plan
|
||||
/// Execute an install (possibly using an existing plan)
|
||||
#[derive(Debug, Parser)]
|
||||
pub(crate) struct Execute {
|
||||
pub(crate) struct Install {
|
||||
#[clap(
|
||||
long,
|
||||
action(ArgAction::SetTrue),
|
||||
|
@ -16,31 +19,83 @@ pub(crate) struct Execute {
|
|||
global = true
|
||||
)]
|
||||
no_confirm: bool,
|
||||
/// Channel(s) to add by default, pass multiple times for multiple channels
|
||||
#[clap(
|
||||
long,
|
||||
value_parser,
|
||||
action = clap::ArgAction::Append,
|
||||
env = "HARMONIC_CHANNEL",
|
||||
default_value = "nixpkgs=https://nixos.org/channels/nixpkgs-unstable"
|
||||
)]
|
||||
pub(crate) channel: Vec<ChannelValue>,
|
||||
/// Don't modify the user profile to automatically load nix
|
||||
#[clap(
|
||||
long,
|
||||
action(ArgAction::SetTrue),
|
||||
default_value = "false",
|
||||
global = true
|
||||
)]
|
||||
explain: bool,
|
||||
#[clap(default_value = "/dev/stdin")]
|
||||
plan: PathBuf,
|
||||
pub(crate) 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,
|
||||
#[clap(
|
||||
long,
|
||||
action(ArgAction::SetTrue),
|
||||
default_value = "false",
|
||||
global = true
|
||||
)]
|
||||
pub(crate) explain: bool,
|
||||
#[clap(
|
||||
long,
|
||||
action(ArgAction::SetTrue),
|
||||
default_value = "false",
|
||||
global = true
|
||||
)]
|
||||
pub(crate) force: bool,
|
||||
#[clap(
|
||||
conflicts_with_all = [ "no_modify_profile", "daemon_user_count", "channel" ],
|
||||
env = "HARMONIC_PLAN",
|
||||
)]
|
||||
plan: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl CommandExecute for Execute {
|
||||
impl CommandExecute for Install {
|
||||
#[tracing::instrument(skip_all, fields())]
|
||||
async fn execute(self) -> eyre::Result<ExitCode> {
|
||||
let Self {
|
||||
no_confirm,
|
||||
plan,
|
||||
explain,
|
||||
channel,
|
||||
no_modify_profile,
|
||||
daemon_user_count,
|
||||
force,
|
||||
} = self;
|
||||
|
||||
let install_plan_string = tokio::fs::read_to_string(plan)
|
||||
.await
|
||||
.wrap_err("Reading plan")?;
|
||||
let mut plan: InstallPlan = serde_json::from_str(&install_plan_string)?;
|
||||
let mut plan = match &plan {
|
||||
Some(plan_path) => {
|
||||
let install_plan_string = tokio::fs::read_to_string(&plan_path)
|
||||
.await
|
||||
.wrap_err("Reading plan")?;
|
||||
serde_json::from_str(&install_plan_string)?
|
||||
},
|
||||
None => {
|
||||
let mut settings = InstallSettings::default()?;
|
||||
|
||||
settings.force(force);
|
||||
settings.daemon_user_count(daemon_user_count);
|
||||
settings.channels(
|
||||
channel
|
||||
.into_iter()
|
||||
.map(|ChannelValue(name, url)| (name, url)),
|
||||
);
|
||||
settings.modify_profile(!no_modify_profile);
|
||||
|
||||
InstallPlan::new(settings).await?
|
||||
},
|
||||
};
|
||||
|
||||
if !no_confirm {
|
||||
if !interaction::confirm(plan.describe_execute(explain)).await? {
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
mod plan;
|
||||
use plan::Plan;
|
||||
mod install;
|
||||
use install::Execute;
|
||||
use install::Install;
|
||||
mod uninstall;
|
||||
use uninstall::Uninstall;
|
||||
|
||||
#[derive(Debug, clap::Subcommand)]
|
||||
pub(crate) enum HarmonicSubcommand {
|
||||
Plan(Plan),
|
||||
Execute(Execute),
|
||||
Install(Install),
|
||||
Uninstall(Uninstall),
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ impl CommandExecute for Plan {
|
|||
plan,
|
||||
} = self;
|
||||
|
||||
let mut settings = InstallSettings::default();
|
||||
let mut settings = InstallSettings::default()?;
|
||||
|
||||
settings.force(force);
|
||||
settings.daemon_user_count(daemon_user_count);
|
||||
|
|
|
@ -14,9 +14,32 @@ pub struct InstallSettings {
|
|||
pub(crate) force: bool,
|
||||
}
|
||||
|
||||
impl Default for InstallSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
impl InstallSettings {
|
||||
pub fn default() -> Result<Self, InstallSettingsError> {
|
||||
let url;
|
||||
|
||||
use target_lexicon::{Architecture, OperatingSystem};
|
||||
match (Architecture::host(), OperatingSystem::host()) {
|
||||
(Architecture::X86_64, OperatingSystem::Linux) => {
|
||||
url = "https://releases.nixos.org/nix/nix-2.11.0/nix-2.11.0-x86_64-linux.tar.xz";
|
||||
},
|
||||
(Architecture::Aarch64(_), OperatingSystem::Linux) => {
|
||||
url = "https://releases.nixos.org/nix/nix-2.11.0/nix-2.11.0-aarch64-linux.tar.xz";
|
||||
},
|
||||
(Architecture::X86_64, OperatingSystem::MacOSX { .. }) => {
|
||||
url = "https://releases.nixos.org/nix/nix-2.11.0/nix-2.11.0-x86_64-darwin.tar.xz";
|
||||
},
|
||||
(Architecture::Aarch64(_), OperatingSystem::MacOSX { .. }) => {
|
||||
url = "https://releases.nixos.org/nix/nix-2.11.0/nix-2.11.0-aarch64-darwin.tar.xz";
|
||||
},
|
||||
_ => {
|
||||
return Err(InstallSettingsError::UnsupportedArchitecture(
|
||||
target_lexicon::HOST,
|
||||
))
|
||||
},
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
daemon_user_count: Default::default(),
|
||||
channels: Default::default(),
|
||||
modify_profile: Default::default(),
|
||||
|
@ -24,13 +47,12 @@ impl Default for InstallSettings {
|
|||
nix_build_group_id: 3000,
|
||||
nix_build_user_prefix: String::from("nixbld"),
|
||||
nix_build_user_id_base: 3001,
|
||||
nix_package_url:
|
||||
"https://releases.nixos.org/nix/nix-2.11.0/nix-2.11.0-x86_64-linux.tar.xz"
|
||||
.parse()
|
||||
.expect("Could not parse default Nix archive url, please report this issue"),
|
||||
nix_package_url: url
|
||||
.parse()
|
||||
.expect("Could not parse default Nix archive url, please report this issue"),
|
||||
extra_conf: Default::default(),
|
||||
force: false,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,3 +105,9 @@ impl InstallSettings {
|
|||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum InstallSettingsError {
|
||||
#[error("Harmonic does not support the `{0}` architecture right now")]
|
||||
UnsupportedArchitecture(target_lexicon::Triple),
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue