From 7c36a83a868fc0501e1ddf8f85afe95ccb8dd4bd Mon Sep 17 00:00:00 2001 From: Kate Temkin Date: Sun, 5 May 2024 16:48:16 -0600 Subject: [PATCH] config: prompt user for flakes --- src/action/base/create_group.rs | 2 +- src/action/base/create_or_merge_nix_config.rs | 2 +- src/action/common/configure_nix.rs | 1 + src/action/common/place_nix_configuration.rs | 27 ++++++++++++-- src/cli/interaction.rs | 3 +- src/cli/mod.rs | 2 +- src/cli/subcommand/install.rs | 36 ++++++++++++++++++- src/cli/subcommand/uninstall.rs | 1 + src/settings.rs | 17 +++++++++ 9 files changed, 83 insertions(+), 8 deletions(-) diff --git a/src/action/base/create_group.rs b/src/action/base/create_group.rs index 4b47a06..a59dc8c 100644 --- a/src/action/base/create_group.rs +++ b/src/action/base/create_group.rs @@ -37,7 +37,7 @@ impl CreateGroup { }, } - // Ensure group does not exists + // Ensure group does not exist if let Some(group) = Group::from_name(name.as_str()) .map_err(|e| ActionErrorKind::GettingGroupId(name.clone(), e)) .map_err(Self::error)? diff --git a/src/action/base/create_or_merge_nix_config.rs b/src/action/base/create_or_merge_nix_config.rs index 9e97290..a3ac069 100644 --- a/src/action/base/create_or_merge_nix_config.rs +++ b/src/action/base/create_or_merge_nix_config.rs @@ -17,7 +17,7 @@ use crate::action::{ /// The `nix.conf` configuration names that are safe to merge. // FIXME(@cole-h): make configurable by downstream users? -const MERGEABLE_CONF_NAMES: &[&str] = &["experimental-features"]; +const MERGEABLE_CONF_NAMES: &[&str] = &["experimental-features", "substituters", "trusted-public-keys"]; const NIX_CONF_MODE: u32 = 0o664; const NIX_CONF_COMMENT_CHAR: char = '#'; diff --git a/src/action/common/configure_nix.rs b/src/action/common/configure_nix.rs index 9088c22..17471fc 100644 --- a/src/action/common/configure_nix.rs +++ b/src/action/common/configure_nix.rs @@ -46,6 +46,7 @@ impl ConfigureNix { settings.proxy.clone(), settings.ssl_cert_file.clone(), settings.extra_conf.clone(), + settings.enable_flakes, settings.force, ) .await diff --git a/src/action/common/place_nix_configuration.rs b/src/action/common/place_nix_configuration.rs index 403c49f..0e2ffdc 100644 --- a/src/action/common/place_nix_configuration.rs +++ b/src/action/common/place_nix_configuration.rs @@ -30,6 +30,7 @@ impl PlaceNixConfiguration { proxy: Option, ssl_cert_file: Option, extra_conf: Vec, + enable_flakes: bool, force: bool, ) -> Result, ActionError> { let mut extra_conf_text = vec![]; @@ -91,7 +92,13 @@ impl PlaceNixConfiguration { let settings = nix_config.settings_mut(); settings.insert("build-users-group".to_string(), nix_build_group_name); - let experimental_features = ["nix-command", "flakes", "repl-flake"]; + let mut experimental_features = vec!["nix-command"]; + + // Enable flakes if desired. + if enable_flakes { + experimental_features.push("flakes"); + } + match settings.entry("experimental-features".to_string()) { Entry::Occupied(mut slot) => { let slot_mut = slot.get_mut(); @@ -125,10 +132,24 @@ impl PlaceNixConfiguration { ssl_cert_file_canonical.display().to_string(), ); } + + // Set up our substituters. settings.insert( - "extra-nix-path".to_string(), - "nixpkgs=flake:nixpkgs".to_string(), + "substituters".to_string(), + "https://cache.nixos.org https://cache.lix.systems".to_string(), ); + settings.insert( + "trusted-public-keys".to_string(), + "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= cache.lix.systems:aBnZUw8zA7H35Cz2RyKFVs3H4PlGTLawyY5KRbvJR8o=".to_string() + ); + + if enable_flakes { + settings.insert( + "extra-nix-path".to_string(), + "nixpkgs=flake:nixpkgs".to_string(), + ); + } + let create_directory = CreateDirectory::plan(NIX_CONF_FOLDER, None, None, 0o0755, force) .await .map_err(Self::error)?; diff --git a/src/cli/interaction.rs b/src/cli/interaction.rs index 9c56e66..e16734e 100644 --- a/src/cli/interaction.rs +++ b/src/cli/interaction.rs @@ -16,6 +16,7 @@ pub enum PromptChoice { // The below method was adopted from Rustup at https://github.com/rust-lang/rustup/blob/3331f34c01474bf216c99a1b1706725708833de1/src/cli/term2.rs#L37 pub(crate) async fn prompt( question: impl AsRef, + prompt_text: impl AsRef, default: PromptChoice, currently_explaining: bool, ) -> eyre::Result { @@ -29,7 +30,7 @@ pub(crate) async fn prompt( {are_you_sure} ({yes}/{no}{maybe_explain}): \ ", question = question.as_ref(), - are_you_sure = "Proceed?".bold(), + are_you_sure = prompt_text.as_ref().bold(), no = if default == PromptChoice::No { "[N]o" } else { diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 4f485d2..89eb090 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -92,7 +92,7 @@ pub fn ensure_root() -> eyre::Result<()> { if !is_root() { eprintln!( "{}", - "`nix-installer` needs to run as `root`, attempting to escalate now via `sudo`..." + "`lix-installer` needs to run as `root`, attempting to escalate now via `sudo`..." .yellow() .dimmed() ); diff --git a/src/cli/subcommand/install.rs b/src/cli/subcommand/install.rs index aec2d81..1764db0 100644 --- a/src/cli/subcommand/install.rs +++ b/src/cli/subcommand/install.rs @@ -170,7 +170,39 @@ impl CommandExecute for Install { serde_json::from_str(&install_plan_string)? }, (None, None) => { - let builtin_planner = BuiltinPlanner::from_common_settings(settings.clone()) + let mut settings_to_apply = settings.clone(); + + if !no_confirm { + // Say hello. + let mut term = term.expect("Internal consistency: term should have been None checked already!"); + let hello_message = format!("{}{}", "\n\nWelcome to the Lix installer!".bold(), " Just a couple of quick questions.\n\n"); + + term.write_all(hello_message.as_bytes())?; + term.flush()?; + + // Ask about flakes. + match interaction::prompt( + "Flakes are an experimental feature, but widely used in the community.\nYou can change this later in `/etc/nix/nix.conf`.", + "Enable flakes?", + PromptChoice::Yes, + true, + ) + .await? + { + PromptChoice::Yes => settings_to_apply.enable_flakes = true, + PromptChoice::Explain => panic!("This prompt has no explanation."), + PromptChoice::No => settings_to_apply.enable_flakes = false, + } + + // Notify the user about the nix command. + let nixcmd_message = format!("{}{}{}{}{}", + "\nQUICK NOTE:".bold().yellow(), " we've enabled the experimental", " nix ".bold(), "command for you!\n", + "Be aware that commands starting with `nix ` such as `nix build` may change syntax.\n\n".green()); + term.write_all(nixcmd_message.as_bytes())?; + term.flush()?; + } + + let builtin_planner = BuiltinPlanner::from_common_settings(settings_to_apply) .await .map_err(|e| eyre::eyre!(e))?; @@ -236,6 +268,7 @@ impl CommandExecute for Install { .describe_install(currently_explaining) .await .map_err(|e| eyre!(e))?, + "Proceed?", PromptChoice::Yes, currently_explaining, ) @@ -276,6 +309,7 @@ impl CommandExecute for Install { .describe_uninstall(currently_explaining) .await .map_err(|e| eyre!(e))?, + "Proceed?", PromptChoice::Yes, currently_explaining, ) diff --git a/src/cli/subcommand/uninstall.rs b/src/cli/subcommand/uninstall.rs index e3a07b2..3de52ab 100644 --- a/src/cli/subcommand/uninstall.rs +++ b/src/cli/subcommand/uninstall.rs @@ -169,6 +169,7 @@ impl CommandExecute for Uninstall { plan.describe_uninstall(currently_explaining) .await .map_err(|e| eyre!(e))?, + "Proceed?", PromptChoice::Yes, currently_explaining, ) diff --git a/src/settings.rs b/src/settings.rs index 4d0b9b5..9b39b6d 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -203,6 +203,20 @@ pub struct CommonSettings { ) )] pub force: bool, + + /// If `nix-installer` should enable flakes. + #[cfg_attr( + feature = "cli", + clap( + long, + action(ArgAction::SetFalse), + default_value = "true", + global = true, + env = "NIX_INSTALLER_ENABLE_FLAKES" + ) + )] + pub enable_flakes: bool, + } impl CommonSettings { @@ -270,6 +284,7 @@ impl CommonSettings { proxy: Default::default(), extra_conf: Default::default(), force: false, + enable_flakes: true, ssl_cert_file: Default::default(), }) } @@ -287,6 +302,7 @@ impl CommonSettings { proxy, extra_conf, force, + enable_flakes, ssl_cert_file, } = self; let mut map = HashMap::default(); @@ -322,6 +338,7 @@ impl CommonSettings { map.insert("proxy".into(), serde_json::to_value(proxy)?); map.insert("ssl_cert_file".into(), serde_json::to_value(ssl_cert_file)?); map.insert("extra_conf".into(), serde_json::to_value(extra_conf)?); + map.insert("enable_flakes".into(), serde_json::to_value(enable_flakes)?); map.insert("force".into(), serde_json::to_value(force)?); Ok(map) }