Merge pull request 'Make flakes optional.' (#9) from optional_flakes into main
Reviewed-on: #9 Reviewed-by: Qyriad <qyriad+lix@fastmail.com>
This commit is contained in:
commit
1352eddc39
558
Cargo.lock
generated
558
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -29,7 +29,7 @@ clap = { version = "4", features = ["std", "color", "usage", "help", "error-cont
|
||||||
color-eyre = { version = "0.6.2", default-features = false, features = [ "track-caller", "issue-url", "tracing-error", "capture-spantrace", "color-spantrace" ], optional = true }
|
color-eyre = { version = "0.6.2", default-features = false, features = [ "track-caller", "issue-url", "tracing-error", "capture-spantrace", "color-spantrace" ], optional = true }
|
||||||
eyre = { version = "0.6.8", default-features = false, features = [ "track-caller" ], optional = true }
|
eyre = { version = "0.6.8", default-features = false, features = [ "track-caller" ], optional = true }
|
||||||
glob = { version = "0.3.0", default-features = false }
|
glob = { version = "0.3.0", default-features = false }
|
||||||
nix = { version = "0.27.0", default-features = false, features = ["user", "fs", "process", "term"] }
|
nix = { version = "0.28.0", default-features = false, features = ["user", "fs", "process", "term"] }
|
||||||
owo-colors = { version = "4.0.0", default-features = false, features = [ "supports-colors" ] }
|
owo-colors = { version = "4.0.0", default-features = false, features = [ "supports-colors" ] }
|
||||||
reqwest = { version = "0.11.11", default-features = false, features = ["rustls-tls-native-roots", "stream", "socks"] }
|
reqwest = { version = "0.11.11", default-features = false, features = ["rustls-tls-native-roots", "stream", "socks"] }
|
||||||
serde = { version = "1.0.144", default-features = false, features = [ "std", "derive" ] }
|
serde = { version = "1.0.144", default-features = false, features = [ "std", "derive" ] }
|
||||||
|
|
35
flake.lock
35
flake.lock
|
@ -8,16 +8,17 @@
|
||||||
"rust-analyzer-src": "rust-analyzer-src"
|
"rust-analyzer-src": "rust-analyzer-src"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1706768574,
|
"lastModified": 1714890282,
|
||||||
"narHash": "sha256-4o6TMpzBHO659EiJTzd/EGQGUDdbgwKwhqf3u6b23U8=",
|
"narHash": "sha256-0dRK2ChvkhWrLM6H3d4r+rXP/UDxTJ6Vkdr22uGb1H0=",
|
||||||
"rev": "668102037129923cd0fc239d864fce71eabdc6a3",
|
"owner": "nix-community",
|
||||||
"revCount": 1762,
|
"repo": "fenix",
|
||||||
"type": "tarball",
|
"rev": "24d83329e95a3bc48cbe9f3cd23813c210a25ea6",
|
||||||
"url": "https://api.flakehub.com/f/pinned/nix-community/fenix/0.1.1762%2Brev-668102037129923cd0fc239d864fce71eabdc6a3/018d63bb-6455-7a2f-98c6-74a36b8216a4/source.tar.gz"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"type": "tarball",
|
"owner": "nix-community",
|
||||||
"url": "https://flakehub.com/f/nix-community/fenix/0.1.1584.tar.gz"
|
"repo": "fenix",
|
||||||
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flake-compat": {
|
"flake-compat": {
|
||||||
|
@ -140,16 +141,18 @@
|
||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1704538339,
|
"lastModified": 1714763106,
|
||||||
"narHash": "sha256-1734d3mQuux9ySvwf6axRWZRBhtcZA9Q8eftD6EZg6U=",
|
"narHash": "sha256-DrDHo74uTycfpAF+/qxZAMlP/Cpe04BVioJb6fdI0YY=",
|
||||||
"rev": "46ae0210ce163b3cba6c7da08840c1d63de9c701",
|
"owner": "NixOS",
|
||||||
"revCount": 567011,
|
"repo": "nixpkgs",
|
||||||
"type": "tarball",
|
"rev": "e9be42459999a253a9f92559b1f5b72e1b44c13d",
|
||||||
"url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.1.567011%2Brev-46ae0210ce163b3cba6c7da08840c1d63de9c701/018ce71d-40cb-7594-bc00-f31ffedcdfa4/source.tar.gz"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"type": "tarball",
|
"owner": "NixOS",
|
||||||
"url": "https://flakehub.com/f/NixOS/nixpkgs/0.1.0.tar.gz"
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": {
|
"root": {
|
||||||
|
|
|
@ -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())
|
if let Some(group) = Group::from_name(name.as_str())
|
||||||
.map_err(|e| ActionErrorKind::GettingGroupId(name.clone(), e))
|
.map_err(|e| ActionErrorKind::GettingGroupId(name.clone(), e))
|
||||||
.map_err(Self::error)?
|
.map_err(Self::error)?
|
||||||
|
|
|
@ -17,7 +17,7 @@ use crate::action::{
|
||||||
|
|
||||||
/// The `nix.conf` configuration names that are safe to merge.
|
/// The `nix.conf` configuration names that are safe to merge.
|
||||||
// FIXME(@cole-h): make configurable by downstream users?
|
// 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_MODE: u32 = 0o664;
|
||||||
const NIX_CONF_COMMENT_CHAR: char = '#';
|
const NIX_CONF_COMMENT_CHAR: char = '#';
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,7 @@ impl ConfigureNix {
|
||||||
settings.proxy.clone(),
|
settings.proxy.clone(),
|
||||||
settings.ssl_cert_file.clone(),
|
settings.ssl_cert_file.clone(),
|
||||||
settings.extra_conf.clone(),
|
settings.extra_conf.clone(),
|
||||||
|
settings.enable_flakes,
|
||||||
settings.force,
|
settings.force,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
|
|
@ -30,6 +30,7 @@ impl PlaceNixConfiguration {
|
||||||
proxy: Option<Url>,
|
proxy: Option<Url>,
|
||||||
ssl_cert_file: Option<PathBuf>,
|
ssl_cert_file: Option<PathBuf>,
|
||||||
extra_conf: Vec<UrlOrPathOrString>,
|
extra_conf: Vec<UrlOrPathOrString>,
|
||||||
|
enable_flakes: bool,
|
||||||
force: bool,
|
force: bool,
|
||||||
) -> Result<StatefulAction<Self>, ActionError> {
|
) -> Result<StatefulAction<Self>, ActionError> {
|
||||||
let mut extra_conf_text = vec![];
|
let mut extra_conf_text = vec![];
|
||||||
|
@ -91,7 +92,13 @@ impl PlaceNixConfiguration {
|
||||||
let settings = nix_config.settings_mut();
|
let settings = nix_config.settings_mut();
|
||||||
|
|
||||||
settings.insert("build-users-group".to_string(), nix_build_group_name);
|
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()) {
|
match settings.entry("experimental-features".to_string()) {
|
||||||
Entry::Occupied(mut slot) => {
|
Entry::Occupied(mut slot) => {
|
||||||
let slot_mut = slot.get_mut();
|
let slot_mut = slot.get_mut();
|
||||||
|
@ -125,10 +132,24 @@ impl PlaceNixConfiguration {
|
||||||
ssl_cert_file_canonical.display().to_string(),
|
ssl_cert_file_canonical.display().to_string(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set up our substituters.
|
||||||
|
settings.insert(
|
||||||
|
"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(
|
settings.insert(
|
||||||
"extra-nix-path".to_string(),
|
"extra-nix-path".to_string(),
|
||||||
"nixpkgs=flake:nixpkgs".to_string(),
|
"nixpkgs=flake:nixpkgs".to_string(),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let create_directory = CreateDirectory::plan(NIX_CONF_FOLDER, None, None, 0o0755, force)
|
let create_directory = CreateDirectory::plan(NIX_CONF_FOLDER, None, None, 0o0755, force)
|
||||||
.await
|
.await
|
||||||
.map_err(Self::error)?;
|
.map_err(Self::error)?;
|
||||||
|
|
|
@ -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
|
// 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(
|
pub(crate) async fn prompt(
|
||||||
question: impl AsRef<str>,
|
question: impl AsRef<str>,
|
||||||
|
prompt_text: impl AsRef<str>,
|
||||||
default: PromptChoice,
|
default: PromptChoice,
|
||||||
currently_explaining: bool,
|
currently_explaining: bool,
|
||||||
) -> eyre::Result<PromptChoice> {
|
) -> eyre::Result<PromptChoice> {
|
||||||
|
@ -29,7 +30,7 @@ pub(crate) async fn prompt(
|
||||||
{are_you_sure} ({yes}/{no}{maybe_explain}): \
|
{are_you_sure} ({yes}/{no}{maybe_explain}): \
|
||||||
",
|
",
|
||||||
question = question.as_ref(),
|
question = question.as_ref(),
|
||||||
are_you_sure = "Proceed?".bold(),
|
are_you_sure = prompt_text.as_ref().bold(),
|
||||||
no = if default == PromptChoice::No {
|
no = if default == PromptChoice::No {
|
||||||
"[N]o"
|
"[N]o"
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -92,7 +92,7 @@ pub fn ensure_root() -> eyre::Result<()> {
|
||||||
if !is_root() {
|
if !is_root() {
|
||||||
eprintln!(
|
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()
|
.yellow()
|
||||||
.dimmed()
|
.dimmed()
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use std::{
|
use std::{
|
||||||
|
io::{stdout, Write},
|
||||||
os::unix::prelude::PermissionsExt,
|
os::unix::prelude::PermissionsExt,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
process::ExitCode,
|
process::ExitCode,
|
||||||
|
@ -80,6 +81,22 @@ impl CommandExecute for Install {
|
||||||
explain,
|
explain,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
|
// Get our terminal object, explaining what to do if it's not there.
|
||||||
|
let term =
|
||||||
|
term::terminfo::TerminfoTerminal::new(stdout());
|
||||||
|
if term.is_none() && !no_confirm {
|
||||||
|
eprintln!(
|
||||||
|
"{}",
|
||||||
|
format!("\
|
||||||
|
\n\
|
||||||
|
Couldn't figure out which terminal you're using -- check the value of the $TERM variable.\n\n\
|
||||||
|
If you're using an interactive terminal, it's probably safe to set TERM to \"xterm\",\n\
|
||||||
|
by e.g. running 'export TERM=xterm'.\n\
|
||||||
|
").red()
|
||||||
|
);
|
||||||
|
interaction::clean_exit_with_message("Couldn't get the terminal! Aborting.").await;
|
||||||
|
}
|
||||||
|
|
||||||
ensure_root()?;
|
ensure_root()?;
|
||||||
|
|
||||||
let existing_receipt: Option<InstallPlan> = match Path::new(RECEIPT_LOCATION).exists() {
|
let existing_receipt: Option<InstallPlan> = match Path::new(RECEIPT_LOCATION).exists() {
|
||||||
|
@ -153,7 +170,39 @@ impl CommandExecute for Install {
|
||||||
serde_json::from_str(&install_plan_string)?
|
serde_json::from_str(&install_plan_string)?
|
||||||
},
|
},
|
||||||
(None, None) => {
|
(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
|
.await
|
||||||
.map_err(|e| eyre::eyre!(e))?;
|
.map_err(|e| eyre::eyre!(e))?;
|
||||||
|
|
||||||
|
@ -219,6 +268,7 @@ impl CommandExecute for Install {
|
||||||
.describe_install(currently_explaining)
|
.describe_install(currently_explaining)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| eyre!(e))?,
|
.map_err(|e| eyre!(e))?,
|
||||||
|
"Proceed?",
|
||||||
PromptChoice::Yes,
|
PromptChoice::Yes,
|
||||||
currently_explaining,
|
currently_explaining,
|
||||||
)
|
)
|
||||||
|
@ -259,6 +309,7 @@ impl CommandExecute for Install {
|
||||||
.describe_uninstall(currently_explaining)
|
.describe_uninstall(currently_explaining)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| eyre!(e))?,
|
.map_err(|e| eyre!(e))?,
|
||||||
|
"Proceed?",
|
||||||
PromptChoice::Yes,
|
PromptChoice::Yes,
|
||||||
currently_explaining,
|
currently_explaining,
|
||||||
)
|
)
|
||||||
|
|
|
@ -169,6 +169,7 @@ impl CommandExecute for Uninstall {
|
||||||
plan.describe_uninstall(currently_explaining)
|
plan.describe_uninstall(currently_explaining)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| eyre!(e))?,
|
.map_err(|e| eyre!(e))?,
|
||||||
|
"Proceed?",
|
||||||
PromptChoice::Yes,
|
PromptChoice::Yes,
|
||||||
currently_explaining,
|
currently_explaining,
|
||||||
)
|
)
|
||||||
|
|
|
@ -203,6 +203,20 @@ pub struct CommonSettings {
|
||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
pub force: bool,
|
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 {
|
impl CommonSettings {
|
||||||
|
@ -270,6 +284,7 @@ impl CommonSettings {
|
||||||
proxy: Default::default(),
|
proxy: Default::default(),
|
||||||
extra_conf: Default::default(),
|
extra_conf: Default::default(),
|
||||||
force: false,
|
force: false,
|
||||||
|
enable_flakes: true,
|
||||||
ssl_cert_file: Default::default(),
|
ssl_cert_file: Default::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -287,6 +302,7 @@ impl CommonSettings {
|
||||||
proxy,
|
proxy,
|
||||||
extra_conf,
|
extra_conf,
|
||||||
force,
|
force,
|
||||||
|
enable_flakes,
|
||||||
ssl_cert_file,
|
ssl_cert_file,
|
||||||
} = self;
|
} = self;
|
||||||
let mut map = HashMap::default();
|
let mut map = HashMap::default();
|
||||||
|
@ -322,6 +338,7 @@ impl CommonSettings {
|
||||||
map.insert("proxy".into(), serde_json::to_value(proxy)?);
|
map.insert("proxy".into(), serde_json::to_value(proxy)?);
|
||||||
map.insert("ssl_cert_file".into(), serde_json::to_value(ssl_cert_file)?);
|
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("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)?);
|
map.insert("force".into(), serde_json::to_value(force)?);
|
||||||
Ok(map)
|
Ok(map)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue