Make nix.conf changes deterministic (#620)
* Make nix.conf changes deterministic * Add mac fixture * Warn/error if user settings don't match our needs * Repair mac fixture * fmt * clipster * Tidy up some feedback * fmt * resolve some nits
This commit is contained in:
parent
0cd1d4bb03
commit
05571a4990
11
Cargo.lock
generated
11
Cargo.lock
generated
|
@ -932,16 +932,6 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix-config-parser"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a94767d6f881412ae02a87a4b6136b4079cbda9d3eab8f4ae272c9db740902c"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix-installer"
|
||||
version = "0.11.0"
|
||||
|
@ -956,7 +946,6 @@ dependencies = [
|
|||
"glob",
|
||||
"is_ci",
|
||||
"nix",
|
||||
"nix-config-parser",
|
||||
"os-release",
|
||||
"owo-colors",
|
||||
"plist",
|
||||
|
|
|
@ -56,7 +56,6 @@ uuid = { version = "1.2.2", features = ["serde"] }
|
|||
os-release = { version = "0.1.0", default-features = false }
|
||||
is_ci = { version = "1.1.1", default-features = false, optional = true }
|
||||
strum = { version = "0.25.0", features = ["derive"] }
|
||||
nix-config-parser = { version = "0.1.2", features = ["serde"] }
|
||||
which = "4.4.0"
|
||||
sysctl = "0.5.4"
|
||||
walkdir = "2.3.3"
|
||||
|
|
|
@ -27,7 +27,7 @@ pub struct CreateFile {
|
|||
group: Option<String>,
|
||||
mode: Option<u32>,
|
||||
buf: String,
|
||||
force: bool,
|
||||
replace: bool,
|
||||
}
|
||||
|
||||
impl CreateFile {
|
||||
|
@ -38,7 +38,7 @@ impl CreateFile {
|
|||
group: impl Into<Option<String>>,
|
||||
mode: impl Into<Option<u32>>,
|
||||
buf: String,
|
||||
force: bool,
|
||||
replace: bool,
|
||||
) -> Result<StatefulAction<Self>, ActionError> {
|
||||
let path = path.as_ref().to_path_buf();
|
||||
let mode = mode.into();
|
||||
|
@ -50,7 +50,7 @@ impl CreateFile {
|
|||
group,
|
||||
mode,
|
||||
buf,
|
||||
force,
|
||||
replace,
|
||||
};
|
||||
|
||||
if this.path.exists() {
|
||||
|
@ -128,7 +128,7 @@ impl CreateFile {
|
|||
.map_err(|e| ActionErrorKind::Read(this.path.clone(), e))
|
||||
.map_err(Self::error)?;
|
||||
|
||||
if discovered_buf != this.buf {
|
||||
if discovered_buf != this.buf && !this.replace {
|
||||
return Err(Self::error(ActionErrorKind::DifferentContent(
|
||||
this.path.clone(),
|
||||
)));
|
||||
|
@ -183,7 +183,8 @@ impl Action for CreateFile {
|
|||
group,
|
||||
mode,
|
||||
buf,
|
||||
force: _,
|
||||
// If `replace` was not set, and the file existed, the `plan` step would have errored
|
||||
replace: _,
|
||||
} = self;
|
||||
|
||||
if tracing::enabled!(tracing::Level::TRACE) {
|
||||
|
@ -247,7 +248,7 @@ impl Action for CreateFile {
|
|||
group: _,
|
||||
mode: _,
|
||||
buf: _,
|
||||
force: _,
|
||||
replace: _,
|
||||
} = &self;
|
||||
|
||||
vec![ActionDescription::new(
|
||||
|
@ -264,7 +265,7 @@ impl Action for CreateFile {
|
|||
group: _,
|
||||
mode: _,
|
||||
buf: _,
|
||||
force: _,
|
||||
replace: _,
|
||||
} = self;
|
||||
// The user already deleted it
|
||||
if !path.exists() {
|
||||
|
|
|
@ -19,6 +19,10 @@ use tracing::{span, Span};
|
|||
pub enum Position {
|
||||
Beginning,
|
||||
End,
|
||||
Before {
|
||||
index: usize,
|
||||
expected_content: String,
|
||||
},
|
||||
}
|
||||
|
||||
/** Create a file at the given location with the provided `buf` as
|
||||
|
@ -140,6 +144,20 @@ impl CreateOrInsertIntoFile {
|
|||
return Ok(StatefulAction::completed(this));
|
||||
}
|
||||
|
||||
if let Position::Before {
|
||||
index,
|
||||
expected_content,
|
||||
} = &this.position
|
||||
{
|
||||
if discovered_buf.lines().nth(*index) != Some(expected_content.as_str()) {
|
||||
return Err(ActionErrorKind::DifferentLineContent(
|
||||
this.path.clone(),
|
||||
this.position.clone(),
|
||||
))
|
||||
.map_err(Self::error);
|
||||
}
|
||||
}
|
||||
|
||||
// If not, we can't skip this, so we still do it
|
||||
}
|
||||
|
||||
|
@ -221,33 +239,75 @@ impl Action for CreateOrInsertIntoFile {
|
|||
ActionErrorKind::Open(temp_file_path.clone(), e)
|
||||
}).map_err(Self::error)?;
|
||||
|
||||
if *position == Position::End {
|
||||
if let Some(ref mut orig_file) = orig_file {
|
||||
tokio::io::copy(orig_file, &mut temp_file)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
ActionErrorKind::Copy(path.to_owned(), temp_file_path.to_owned(), e)
|
||||
})
|
||||
.map_err(Self::error)?;
|
||||
}
|
||||
}
|
||||
match position {
|
||||
Position::End => {
|
||||
if let Some(ref mut orig_file) = orig_file {
|
||||
tokio::io::copy(orig_file, &mut temp_file)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
ActionErrorKind::Copy(path.to_owned(), temp_file_path.to_owned(), e)
|
||||
})
|
||||
.map_err(Self::error)?;
|
||||
}
|
||||
|
||||
temp_file
|
||||
.write_all(buf.as_bytes())
|
||||
.await
|
||||
.map_err(|e| ActionErrorKind::Write(temp_file_path.clone(), e))
|
||||
.map_err(Self::error)?;
|
||||
|
||||
if *position == Position::Beginning {
|
||||
if let Some(ref mut orig_file) = orig_file {
|
||||
tokio::io::copy(orig_file, &mut temp_file)
|
||||
temp_file
|
||||
.write_all(buf.as_bytes())
|
||||
.await
|
||||
.map_err(|e| {
|
||||
ActionErrorKind::Copy(path.to_owned(), temp_file_path.to_owned(), e)
|
||||
})
|
||||
.map_err(|e| ActionErrorKind::Write(temp_file_path.clone(), e))
|
||||
.map_err(Self::error)?;
|
||||
}
|
||||
}
|
||||
},
|
||||
Position::Beginning => {
|
||||
temp_file
|
||||
.write_all(buf.as_bytes())
|
||||
.await
|
||||
.map_err(|e| ActionErrorKind::Write(temp_file_path.clone(), e))
|
||||
.map_err(Self::error)?;
|
||||
|
||||
if let Some(ref mut orig_file) = orig_file {
|
||||
tokio::io::copy(orig_file, &mut temp_file)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
ActionErrorKind::Copy(path.to_owned(), temp_file_path.to_owned(), e)
|
||||
})
|
||||
.map_err(Self::error)?;
|
||||
}
|
||||
},
|
||||
Position::Before {
|
||||
index,
|
||||
expected_content,
|
||||
} => {
|
||||
let mut original_content_buf = Vec::new();
|
||||
if let Some(ref mut orig_file) = orig_file {
|
||||
tokio::io::copy(orig_file, &mut original_content_buf)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
ActionErrorKind::Copy(path.to_owned(), temp_file_path.to_owned(), e)
|
||||
})
|
||||
.map_err(Self::error)?;
|
||||
}
|
||||
let original_content = String::from_utf8(original_content_buf)
|
||||
.map_err(ActionErrorKind::FromUtf8)
|
||||
.map_err(Self::error)?;
|
||||
let mut original_content_lines = original_content.lines().collect::<Vec<_>>();
|
||||
// The last line should match expected
|
||||
if original_content_lines.get(*index).copied() != Some(expected_content.as_str()) {
|
||||
return Err(ActionErrorKind::DifferentLineContent(
|
||||
path.clone(),
|
||||
position.clone(),
|
||||
))
|
||||
.map_err(Self::error);
|
||||
}
|
||||
|
||||
original_content_lines.insert(*index, buf);
|
||||
let new_content = original_content_lines.join("\n");
|
||||
|
||||
temp_file
|
||||
.write_all(new_content.as_bytes())
|
||||
.await
|
||||
.map_err(|e| ActionErrorKind::Write(temp_file_path.clone(), e))
|
||||
.map_err(Self::error)?;
|
||||
},
|
||||
};
|
||||
|
||||
let gid = if let Some(group) = group {
|
||||
Some(
|
||||
|
|
|
@ -1,716 +0,0 @@
|
|||
use std::{
|
||||
os::unix::fs::PermissionsExt,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use nix_config_parser::NixConfig;
|
||||
use rand::Rng;
|
||||
use tokio::{
|
||||
fs::{remove_file, OpenOptions},
|
||||
io::AsyncWriteExt,
|
||||
};
|
||||
use tracing::{span, Span};
|
||||
|
||||
use crate::action::{
|
||||
Action, ActionDescription, ActionError, ActionErrorKind, ActionTag, StatefulAction,
|
||||
};
|
||||
|
||||
/// 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 NIX_CONF_MODE: u32 = 0o664;
|
||||
const NIX_CONF_COMMENT_CHAR: char = '#';
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum CreateOrMergeNixConfigError {
|
||||
#[error(transparent)]
|
||||
ParseNixConfig(#[from] nix_config_parser::ParseError),
|
||||
#[error("Could not merge Nix configuration for key(s) {}; consider removing them from `{1}` in your editor, or removing your existing configuration with `rm {1}`",
|
||||
.0
|
||||
.iter()
|
||||
.map(|v| format!("`{v}`"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "))]
|
||||
UnmergeableConfig(Vec<String>, std::path::PathBuf),
|
||||
}
|
||||
|
||||
impl From<CreateOrMergeNixConfigError> for ActionErrorKind {
|
||||
fn from(val: CreateOrMergeNixConfigError) -> Self {
|
||||
ActionErrorKind::Custom(Box::new(val))
|
||||
}
|
||||
}
|
||||
|
||||
/// Create or merge an existing `nix.conf` at the specified path.
|
||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||
pub struct CreateOrMergeNixConfig {
|
||||
pub(crate) path: PathBuf,
|
||||
pending_nix_config: NixConfig,
|
||||
}
|
||||
|
||||
impl CreateOrMergeNixConfig {
|
||||
#[tracing::instrument(level = "debug", skip_all)]
|
||||
pub async fn plan(
|
||||
path: impl AsRef<Path>,
|
||||
pending_nix_config: NixConfig,
|
||||
) -> Result<StatefulAction<Self>, ActionError> {
|
||||
let path = path.as_ref().to_path_buf();
|
||||
|
||||
let this = Self {
|
||||
path,
|
||||
pending_nix_config,
|
||||
};
|
||||
|
||||
if this.path.exists() {
|
||||
let (merged_nix_config, _) =
|
||||
Self::validate_existing_nix_config(&this.pending_nix_config, &this.path)?;
|
||||
|
||||
if !merged_nix_config.settings().is_empty() {
|
||||
return Ok(StatefulAction::uncompleted(this));
|
||||
} else {
|
||||
tracing::debug!(
|
||||
"Setting Nix configurations in `{}` already complete",
|
||||
this.path.display()
|
||||
);
|
||||
return Ok(StatefulAction::completed(this));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(StatefulAction::uncompleted(this))
|
||||
}
|
||||
|
||||
fn merge_pending_and_existing_nix_config(
|
||||
pending_nix_config: &NixConfig,
|
||||
existing_nix_config: &NixConfig,
|
||||
path: &Path,
|
||||
) -> Result<(NixConfig, NixConfig), CreateOrMergeNixConfigError> {
|
||||
let mut merged_nix_config = NixConfig::new();
|
||||
let mut unmergeable_config_names = Vec::new();
|
||||
|
||||
for (pending_conf_name, pending_conf_value) in pending_nix_config.settings() {
|
||||
if let Some(existing_conf_value) = existing_nix_config.settings().get(pending_conf_name)
|
||||
{
|
||||
let pending_conf_value = pending_conf_value.split(' ').collect::<Vec<_>>();
|
||||
let existing_conf_value = existing_conf_value.split(' ').collect::<Vec<_>>();
|
||||
|
||||
if pending_conf_value
|
||||
.iter()
|
||||
.all(|e| existing_conf_value.contains(e))
|
||||
{
|
||||
// If _all_ the values we want are present in the existing config,
|
||||
// merged_nix_config will be empty and this will be marked as completed. We
|
||||
// don't return early here because there may be more config options to
|
||||
// check.
|
||||
} else if MERGEABLE_CONF_NAMES.contains(&pending_conf_name.as_str()) {
|
||||
let mut merged_conf_value =
|
||||
Vec::with_capacity(pending_conf_value.len() + existing_conf_value.len());
|
||||
merged_conf_value.extend(pending_conf_value);
|
||||
merged_conf_value.extend(existing_conf_value);
|
||||
merged_conf_value.dedup();
|
||||
let merged_conf_value = merged_conf_value.join(" ");
|
||||
let merged_conf_value = merged_conf_value.trim();
|
||||
|
||||
merged_nix_config
|
||||
.settings_mut()
|
||||
.insert(pending_conf_name.to_owned(), merged_conf_value.to_owned());
|
||||
} else {
|
||||
unmergeable_config_names.push(pending_conf_name.to_owned());
|
||||
}
|
||||
} else {
|
||||
merged_nix_config
|
||||
.settings_mut()
|
||||
.insert(pending_conf_name.to_owned(), pending_conf_value.to_owned());
|
||||
}
|
||||
}
|
||||
|
||||
if !unmergeable_config_names.is_empty() {
|
||||
return Err(CreateOrMergeNixConfigError::UnmergeableConfig(
|
||||
unmergeable_config_names,
|
||||
path.to_path_buf(),
|
||||
));
|
||||
}
|
||||
|
||||
Ok((merged_nix_config, existing_nix_config.clone()))
|
||||
}
|
||||
|
||||
fn validate_existing_nix_config(
|
||||
pending_nix_config: &NixConfig,
|
||||
path: &Path,
|
||||
) -> Result<(NixConfig, NixConfig), ActionError> {
|
||||
let path = path.to_path_buf();
|
||||
let metadata = path
|
||||
.metadata()
|
||||
.map_err(|e| Self::error(ActionErrorKind::GettingMetadata(path.clone(), e)))?;
|
||||
|
||||
if !metadata.is_file() {
|
||||
return Err(Self::error(ActionErrorKind::PathWasNotFile(path)));
|
||||
}
|
||||
|
||||
// Does the file have the right permissions?
|
||||
let discovered_mode = metadata.permissions().mode();
|
||||
// We only care about user-group-other permissions
|
||||
let discovered_mode = discovered_mode & 0o777;
|
||||
|
||||
if discovered_mode != NIX_CONF_MODE {
|
||||
return Err(Self::error(ActionErrorKind::PathModeMismatch(
|
||||
path,
|
||||
discovered_mode,
|
||||
NIX_CONF_MODE,
|
||||
)));
|
||||
}
|
||||
|
||||
let existing_nix_config = NixConfig::parse_file(&path)
|
||||
.map_err(CreateOrMergeNixConfigError::ParseNixConfig)
|
||||
.map_err(Self::error)?;
|
||||
|
||||
let (merged_nix_config, existing_nix_config) = Self::merge_pending_and_existing_nix_config(
|
||||
pending_nix_config,
|
||||
&existing_nix_config,
|
||||
&path,
|
||||
)
|
||||
.map_err(Self::error)?;
|
||||
|
||||
Ok((merged_nix_config, existing_nix_config))
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
#[typetag::serde(name = "create_or_merge_nix_config")]
|
||||
impl Action for CreateOrMergeNixConfig {
|
||||
fn action_tag() -> ActionTag {
|
||||
ActionTag("create_or_merge_nix_config")
|
||||
}
|
||||
fn tracing_synopsis(&self) -> String {
|
||||
format!(
|
||||
"Merge or create nix.conf file `{path}`",
|
||||
path = self.path.display(),
|
||||
)
|
||||
}
|
||||
|
||||
fn tracing_span(&self) -> Span {
|
||||
let span = span!(
|
||||
tracing::Level::DEBUG,
|
||||
"create_or_merge_nix_config",
|
||||
path = tracing::field::display(self.path.display()),
|
||||
mode = tracing::field::display(format!("{:#o}", NIX_CONF_MODE)),
|
||||
pending_nix_config = tracing::field::Empty,
|
||||
);
|
||||
|
||||
if tracing::enabled!(tracing::Level::TRACE) {
|
||||
span.record(
|
||||
"pending_nix_config",
|
||||
&self
|
||||
.pending_nix_config
|
||||
.settings()
|
||||
.iter()
|
||||
.map(|(k, v)| format!("{k}=\"{v}\""))
|
||||
.collect::<Vec<_>>()
|
||||
.join(","),
|
||||
);
|
||||
}
|
||||
span
|
||||
}
|
||||
|
||||
fn execute_description(&self) -> Vec<ActionDescription> {
|
||||
vec![ActionDescription::new(
|
||||
self.tracing_synopsis(),
|
||||
vec![format!(
|
||||
"Added settings: {settings}",
|
||||
settings = self
|
||||
.pending_nix_config
|
||||
.settings()
|
||||
.iter()
|
||||
.map(|(k, v)| format!("{k}=\"{v}\""))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "),
|
||||
)],
|
||||
)]
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip_all)]
|
||||
async fn execute(&mut self) -> Result<(), ActionError> {
|
||||
let Self {
|
||||
path,
|
||||
pending_nix_config,
|
||||
} = self;
|
||||
|
||||
if tracing::enabled!(tracing::Level::TRACE) {
|
||||
let span = tracing::Span::current();
|
||||
span.record(
|
||||
"pending_nix_config",
|
||||
pending_nix_config
|
||||
.settings()
|
||||
.iter()
|
||||
.map(|(k, v)| format!("{k}='{v}'"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(" "),
|
||||
);
|
||||
}
|
||||
|
||||
// Create a temporary file in the same directory as the one
|
||||
// that the final file goes in, so that we can rename it
|
||||
// atomically
|
||||
let parent_dir = path.parent().expect("File must be in a directory");
|
||||
let mut temp_file_path = parent_dir.to_owned();
|
||||
{
|
||||
let mut rng = rand::thread_rng();
|
||||
temp_file_path.push(format!("nix-installer-tmp.{}", rng.gen::<u32>()));
|
||||
}
|
||||
let mut temp_file = OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
// If the file is created, ensure that it has harmless
|
||||
// permissions regardless of whether the mode will be
|
||||
// changed later (if we ever create setuid executables,
|
||||
// they should only become setuid once they are owned by
|
||||
// the appropriate user)
|
||||
.mode(0o600)
|
||||
.open(&temp_file_path)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
Self::error(ActionErrorKind::Open(temp_file_path.clone(), e))
|
||||
})?;
|
||||
|
||||
let (mut merged_nix_config, mut existing_nix_config) = if path.exists() {
|
||||
let (merged_nix_config, existing_nix_config) =
|
||||
Self::validate_existing_nix_config(pending_nix_config, path)?;
|
||||
(merged_nix_config, Some(existing_nix_config))
|
||||
} else {
|
||||
(pending_nix_config.clone(), None)
|
||||
};
|
||||
|
||||
let mut new_config = String::new();
|
||||
|
||||
if let Some(existing_nix_config) = existing_nix_config.as_mut() {
|
||||
let mut discovered_buf = tokio::fs::read_to_string(&path)
|
||||
.await
|
||||
.map_err(|e| Self::error(ActionErrorKind::Read(path.to_path_buf(), e)))?;
|
||||
|
||||
// We append a newline to ensure that, in the case there are comments at the end of the
|
||||
// file and _NO_ trailing newline, we still preserve the entire block of comments.
|
||||
discovered_buf.push('\n');
|
||||
|
||||
let (associated_lines, _, _) = discovered_buf.split('\n').fold(
|
||||
(Vec::new(), Vec::new(), false),
|
||||
|(mut all_assoc, mut current_assoc, mut associating): (
|
||||
Vec<Vec<String>>,
|
||||
Vec<String>,
|
||||
bool,
|
||||
),
|
||||
line| {
|
||||
let line = line.trim();
|
||||
|
||||
// Don't associate our "Generated by" comment if it appears
|
||||
if line.starts_with("# Generated by") {
|
||||
return (all_assoc, current_assoc, associating);
|
||||
}
|
||||
|
||||
if line.starts_with(NIX_CONF_COMMENT_CHAR) {
|
||||
associating = true;
|
||||
} else if line.is_empty() || !line.starts_with(NIX_CONF_COMMENT_CHAR) {
|
||||
associating = false;
|
||||
}
|
||||
|
||||
current_assoc.push(line.to_string());
|
||||
|
||||
if !associating {
|
||||
all_assoc.push(current_assoc);
|
||||
current_assoc = Vec::new();
|
||||
}
|
||||
|
||||
(all_assoc, current_assoc, associating)
|
||||
},
|
||||
);
|
||||
|
||||
for line_group in associated_lines {
|
||||
if line_group.is_empty() || line_group.iter().all(|line| line.is_empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// This expect should never reasonably panic, because we would need a line group
|
||||
// consisting solely of a comment and nothing else, but unconditionally appending a
|
||||
// newline to the config string before grouping above prevents this from occurring.
|
||||
let line_idx = line_group
|
||||
.iter()
|
||||
.position(|line| !line.starts_with(NIX_CONF_COMMENT_CHAR))
|
||||
.expect("There should always be one line without a comment character");
|
||||
|
||||
let setting_line = &line_group[line_idx];
|
||||
let comments = line_group[..line_idx].join("\n");
|
||||
|
||||
// If we're here, but the line without a comment char is empty, we have
|
||||
// standalone comments to preserve, but no settings with inline comments.
|
||||
if setting_line.is_empty() {
|
||||
for line in &line_group {
|
||||
new_config.push_str(line);
|
||||
new_config.push('\n');
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Preserve inline comments for settings we've merged
|
||||
let to_remove = if let Some((name, value)) = existing_nix_config
|
||||
.settings()
|
||||
.iter()
|
||||
.find(|(name, _value)| setting_line.starts_with(*name))
|
||||
{
|
||||
let inline_comment_idx =
|
||||
if let Some(idx) = setting_line.find(NIX_CONF_COMMENT_CHAR) {
|
||||
idx
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let inline_comment = &setting_line[inline_comment_idx..];
|
||||
|
||||
new_config.push_str(&comments);
|
||||
new_config.push('\n');
|
||||
new_config.push_str(name);
|
||||
new_config.push_str(" = ");
|
||||
|
||||
if let Some(merged_value) = merged_nix_config.settings_mut().remove(name) {
|
||||
new_config.push_str(&merged_value);
|
||||
new_config.push(' ');
|
||||
} else {
|
||||
new_config.push_str(value);
|
||||
}
|
||||
|
||||
new_config.push_str(inline_comment);
|
||||
new_config.push('\n');
|
||||
|
||||
Some(name.clone())
|
||||
} else {
|
||||
new_config.push_str(&comments);
|
||||
new_config.push('\n');
|
||||
new_config.push_str(setting_line);
|
||||
new_config.push('\n');
|
||||
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(to_remove) = to_remove {
|
||||
existing_nix_config.settings_mut().remove(&to_remove);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the leftover existing nix config
|
||||
for (name, value) in existing_nix_config.settings() {
|
||||
if merged_nix_config.settings().get(name).is_some() {
|
||||
continue;
|
||||
}
|
||||
|
||||
new_config.push_str(name);
|
||||
new_config.push_str(" = ");
|
||||
new_config.push_str(value);
|
||||
new_config.push('\n');
|
||||
}
|
||||
|
||||
new_config.push('\n');
|
||||
}
|
||||
|
||||
new_config.push_str(&format!(
|
||||
"# Generated by https://github.com/DeterminateSystems/nix-installer, version {version}.\n",
|
||||
version = env!("CARGO_PKG_VERSION"),
|
||||
));
|
||||
|
||||
for (name, value) in merged_nix_config.settings() {
|
||||
new_config.push_str(name);
|
||||
new_config.push_str(" = ");
|
||||
new_config.push_str(value);
|
||||
new_config.push('\n');
|
||||
}
|
||||
|
||||
temp_file
|
||||
.write_all(new_config.as_bytes())
|
||||
.await
|
||||
.map_err(|e| Self::error(ActionErrorKind::Write(temp_file_path.clone(), e)))?;
|
||||
tokio::fs::set_permissions(&temp_file_path, PermissionsExt::from_mode(NIX_CONF_MODE))
|
||||
.await
|
||||
.map_err(|e| {
|
||||
Self::error(ActionErrorKind::SetPermissions(
|
||||
NIX_CONF_MODE,
|
||||
path.to_owned(),
|
||||
e,
|
||||
))
|
||||
})?;
|
||||
temp_file
|
||||
.sync_all()
|
||||
.await
|
||||
.map_err(|e| Self::error(ActionErrorKind::Sync(temp_file_path.clone(), e)))?;
|
||||
tokio::fs::rename(&temp_file_path, &path)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
Self::error(ActionErrorKind::Rename(
|
||||
temp_file_path.to_owned(),
|
||||
path.to_owned(),
|
||||
e,
|
||||
))
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn revert_description(&self) -> Vec<ActionDescription> {
|
||||
let Self {
|
||||
path,
|
||||
pending_nix_config: _,
|
||||
} = &self;
|
||||
|
||||
vec![ActionDescription::new(
|
||||
format!("Delete file `{}`", path.display()),
|
||||
vec![format!("Delete file `{}`", path.display())],
|
||||
)]
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip_all)]
|
||||
async fn revert(&mut self) -> Result<(), ActionError> {
|
||||
let Self {
|
||||
path,
|
||||
pending_nix_config: _,
|
||||
} = self;
|
||||
|
||||
remove_file(&path)
|
||||
.await
|
||||
.map_err(|e| Self::error(ActionErrorKind::Remove(path.to_owned(), e)))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use color_eyre::eyre::eyre;
|
||||
use tokio::fs::write;
|
||||
|
||||
#[tokio::test]
|
||||
async fn creates_and_deletes_file() -> eyre::Result<()> {
|
||||
let temp_dir = tempfile::TempDir::new()?;
|
||||
let test_file = temp_dir.path().join("creates_and_deletes_file");
|
||||
let mut nix_config = NixConfig::new();
|
||||
nix_config
|
||||
.settings_mut()
|
||||
.insert("experimental-features".into(), "ca-references".into());
|
||||
let mut action = CreateOrMergeNixConfig::plan(&test_file, nix_config).await?;
|
||||
|
||||
action.try_execute().await?;
|
||||
|
||||
let s = std::fs::read_to_string(&test_file)?;
|
||||
assert!(s.contains("# Generated by"));
|
||||
assert!(s.contains("ca-references"));
|
||||
assert!(NixConfig::parse_file(&test_file).is_ok());
|
||||
|
||||
action.try_revert().await?;
|
||||
|
||||
assert!(!test_file.exists(), "File should have been deleted");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn creates_and_deletes_file_even_if_edited() -> eyre::Result<()> {
|
||||
let temp_dir = tempfile::TempDir::new()?;
|
||||
let test_file = temp_dir
|
||||
.path()
|
||||
.join("creates_and_deletes_file_even_if_edited");
|
||||
let mut nix_config = NixConfig::new();
|
||||
nix_config
|
||||
.settings_mut()
|
||||
.insert("experimental-features".into(), "ca-references".into());
|
||||
let mut action = CreateOrMergeNixConfig::plan(&test_file, nix_config).await?;
|
||||
|
||||
action.try_execute().await?;
|
||||
|
||||
write(test_file.as_path(), "More content").await?;
|
||||
|
||||
action.try_revert().await?;
|
||||
|
||||
assert!(!test_file.exists(), "File should have been deleted");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn recognizes_existing_exact_files_and_reverts_them() -> eyre::Result<()> {
|
||||
let temp_dir = tempfile::TempDir::new()?;
|
||||
let test_file = temp_dir
|
||||
.path()
|
||||
.join("recognizes_existing_exact_files_and_reverts_them");
|
||||
|
||||
let test_content = "experimental-features = flakes";
|
||||
write(test_file.as_path(), test_content).await?;
|
||||
tokio::fs::set_permissions(&test_file, PermissionsExt::from_mode(NIX_CONF_MODE)).await?;
|
||||
|
||||
let mut nix_config = NixConfig::new();
|
||||
nix_config
|
||||
.settings_mut()
|
||||
.insert("experimental-features".into(), "flakes".into());
|
||||
let mut action = CreateOrMergeNixConfig::plan(&test_file, nix_config).await?;
|
||||
|
||||
action.try_execute().await?;
|
||||
|
||||
action.try_revert().await?;
|
||||
|
||||
assert!(!test_file.exists(), "File should have been deleted");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn recognizes_existing_different_files_and_merges() -> eyre::Result<()> {
|
||||
let temp_dir = tempfile::TempDir::new()?;
|
||||
let test_file = temp_dir
|
||||
.path()
|
||||
.join("recognizes_existing_different_files_and_merges");
|
||||
|
||||
write(
|
||||
test_file.as_path(),
|
||||
"experimental-features = flakes\nwarn-dirty = true\n",
|
||||
)
|
||||
.await?;
|
||||
tokio::fs::set_permissions(&test_file, PermissionsExt::from_mode(NIX_CONF_MODE)).await?;
|
||||
|
||||
let mut nix_config = NixConfig::new();
|
||||
nix_config
|
||||
.settings_mut()
|
||||
.insert("experimental-features".into(), "nix-command flakes".into());
|
||||
nix_config
|
||||
.settings_mut()
|
||||
.insert("allow-dirty".into(), "false".into());
|
||||
let mut action = CreateOrMergeNixConfig::plan(&test_file, nix_config).await?;
|
||||
|
||||
action.try_execute().await?;
|
||||
|
||||
let s = std::fs::read_to_string(&test_file)?;
|
||||
assert!(s.contains("# Generated by"));
|
||||
assert!(s.contains("flakes"));
|
||||
assert!(s.contains("nix-command"));
|
||||
assert_eq!(
|
||||
s.matches("flakes").count(),
|
||||
1,
|
||||
"we should not duplicate strings"
|
||||
);
|
||||
assert!(s.contains("allow-dirty = false"));
|
||||
assert!(s.contains("warn-dirty = true"));
|
||||
assert!(NixConfig::parse_file(&test_file).is_ok());
|
||||
|
||||
action.try_revert().await?;
|
||||
|
||||
assert!(!test_file.exists(), "File should have been deleted");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn recognizes_existing_different_files_and_fails_to_merge() -> eyre::Result<()> {
|
||||
let temp_dir = tempfile::TempDir::new()?;
|
||||
let test_file = temp_dir
|
||||
.path()
|
||||
.join("recognizes_existing_different_files_and_fails_to_merge");
|
||||
|
||||
write(
|
||||
test_file.as_path(),
|
||||
"experimental-features = flakes\nwarn-dirty = true\n",
|
||||
)
|
||||
.await?;
|
||||
tokio::fs::set_permissions(&test_file, PermissionsExt::from_mode(NIX_CONF_MODE)).await?;
|
||||
|
||||
let mut nix_config = NixConfig::new();
|
||||
nix_config
|
||||
.settings_mut()
|
||||
.insert("experimental-features".into(), "nix-command flakes".into());
|
||||
nix_config
|
||||
.settings_mut()
|
||||
.insert("warn-dirty".into(), "false".into());
|
||||
match CreateOrMergeNixConfig::plan(&test_file, nix_config).await {
|
||||
Err(err) => {
|
||||
if let ActionErrorKind::Custom(e) = err.kind() {
|
||||
match e.downcast_ref::<CreateOrMergeNixConfigError>() {
|
||||
Some(CreateOrMergeNixConfigError::UnmergeableConfig(_, path)) => {
|
||||
assert_eq!(path, test_file.as_path())
|
||||
},
|
||||
_ => {
|
||||
return Err(eyre!(
|
||||
"Should have returned CreateOrMergeNixConfigError::UnmergeableConfig"
|
||||
))
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
return Err(eyre!(
|
||||
"Should have returned CreateOrMergeNixConfigError::UnmergeableConfig"
|
||||
))
|
||||
},
|
||||
}
|
||||
|
||||
assert!(test_file.exists(), "File should not have been deleted");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn preserves_comments() -> eyre::Result<()> {
|
||||
let temp_dir = tempfile::TempDir::new()?;
|
||||
let test_file = temp_dir.path().join("preserves_comments");
|
||||
|
||||
write(
|
||||
test_file.as_path(),
|
||||
"# test 2\n# test\nexperimental-features = flakes # some inline comment about experimental-features\n# the following line should be warn-dirty = true\nwarn-dirty = true # this is an inline comment\n# this is an ungrouped comment\n# this too",
|
||||
)
|
||||
.await?;
|
||||
tokio::fs::set_permissions(&test_file, PermissionsExt::from_mode(NIX_CONF_MODE)).await?;
|
||||
let mut nix_config = NixConfig::new();
|
||||
nix_config
|
||||
.settings_mut()
|
||||
.insert("experimental-features".into(), "ca-references".into());
|
||||
let mut action = CreateOrMergeNixConfig::plan(&test_file, nix_config).await?;
|
||||
|
||||
action.try_execute().await?;
|
||||
|
||||
let s = std::fs::read_to_string(&test_file)?;
|
||||
assert!(s.contains("# the following line should be warn-dirty = true\nwarn-dirty = true"));
|
||||
assert!(s.contains("# test 2\n# test\nexperimental-features"));
|
||||
assert!(s.contains("# this is an inline comment"));
|
||||
assert!(s.contains("# some inline comment about experimental-features"));
|
||||
assert!(s.contains("# Generated by"));
|
||||
assert!(s.contains("# this is an ungrouped comment\n# this too"));
|
||||
assert!(s.contains("ca-references"));
|
||||
assert!(NixConfig::parse_file(&test_file).is_ok());
|
||||
|
||||
action.try_revert().await?;
|
||||
|
||||
assert!(!test_file.exists(), "File should have been deleted");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn preserves_comments_edge_case() -> eyre::Result<()> {
|
||||
let temp_dir = tempfile::TempDir::new()?;
|
||||
let test_file = temp_dir.path().join("preserves_comments");
|
||||
|
||||
write(test_file.as_path(), " a = b\n c = d# lol\n# e = f").await?;
|
||||
tokio::fs::set_permissions(&test_file, PermissionsExt::from_mode(NIX_CONF_MODE)).await?;
|
||||
let mut nix_config = NixConfig::new();
|
||||
nix_config
|
||||
.settings_mut()
|
||||
.insert("experimental-features".into(), "ca-references".into());
|
||||
let mut action = CreateOrMergeNixConfig::plan(&test_file, nix_config).await?;
|
||||
|
||||
action.try_execute().await?;
|
||||
|
||||
let s = std::fs::read_to_string(&test_file)?;
|
||||
assert!(s.contains("# Generated by"));
|
||||
assert!(s.contains("ca-references"));
|
||||
assert_eq!(s.matches("a = b").count(), 1);
|
||||
assert!(NixConfig::parse_file(&test_file).is_ok());
|
||||
|
||||
action.try_revert().await?;
|
||||
|
||||
assert!(!test_file.exists(), "File should have been deleted");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -5,7 +5,6 @@ pub(crate) mod create_directory;
|
|||
pub(crate) mod create_file;
|
||||
pub(crate) mod create_group;
|
||||
pub(crate) mod create_or_insert_into_file;
|
||||
pub(crate) mod create_or_merge_nix_config;
|
||||
pub(crate) mod create_user;
|
||||
pub(crate) mod delete_user;
|
||||
pub(crate) mod fetch_and_unpack_nix;
|
||||
|
@ -18,7 +17,6 @@ pub use create_directory::CreateDirectory;
|
|||
pub use create_file::CreateFile;
|
||||
pub use create_group::CreateGroup;
|
||||
pub use create_or_insert_into_file::CreateOrInsertIntoFile;
|
||||
pub use create_or_merge_nix_config::CreateOrMergeNixConfig;
|
||||
pub use create_user::CreateUser;
|
||||
pub use delete_user::DeleteUser;
|
||||
pub use fetch_and_unpack_nix::{FetchAndUnpackNix, FetchUrlError};
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
use tracing::{span, Span};
|
||||
|
||||
use crate::action::base::create_or_merge_nix_config::CreateOrMergeNixConfigError;
|
||||
use crate::action::base::{CreateDirectory, CreateOrMergeNixConfig};
|
||||
use crate::action::base::create_or_insert_into_file::Position;
|
||||
use crate::action::base::{CreateDirectory, CreateFile, CreateOrInsertIntoFile};
|
||||
use crate::action::{
|
||||
Action, ActionDescription, ActionError, ActionErrorKind, ActionTag, StatefulAction,
|
||||
};
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
const NIX_CONF_FOLDER: &str = "/etc/nix";
|
||||
const NIX_CONF: &str = "/etc/nix/nix.conf";
|
||||
|
@ -17,7 +16,8 @@ Place the `/etc/nix.conf` file
|
|||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||
pub struct PlaceNixConfiguration {
|
||||
create_directory: StatefulAction<CreateDirectory>,
|
||||
create_or_merge_nix_config: StatefulAction<CreateOrMergeNixConfig>,
|
||||
create_or_insert_nix_conf: StatefulAction<CreateOrInsertIntoFile>,
|
||||
create_defaults_conf: StatefulAction<CreateFile>,
|
||||
}
|
||||
|
||||
impl PlaceNixConfiguration {
|
||||
|
@ -28,65 +28,198 @@ impl PlaceNixConfiguration {
|
|||
extra_conf: Vec<String>,
|
||||
force: bool,
|
||||
) -> Result<StatefulAction<Self>, ActionError> {
|
||||
let extra_conf = extra_conf.join("\n");
|
||||
let mut nix_config = nix_config_parser::NixConfig::parse_string(extra_conf, None)
|
||||
.map_err(CreateOrMergeNixConfigError::ParseNixConfig)
|
||||
let create_directory = CreateDirectory::plan(NIX_CONF_FOLDER, None, None, 0o0755, force)
|
||||
.await
|
||||
.map_err(Self::error)?;
|
||||
let settings = nix_config.settings_mut();
|
||||
|
||||
settings.insert("build-users-group".to_string(), nix_build_group_name);
|
||||
let experimental_features = ["nix-command", "flakes", "auto-allocate-uids"];
|
||||
match settings.entry("experimental-features".to_string()) {
|
||||
Entry::Occupied(mut slot) => {
|
||||
let slot_mut = slot.get_mut();
|
||||
for experimental_feature in experimental_features {
|
||||
if !slot_mut.contains(experimental_feature) {
|
||||
*slot_mut += " ";
|
||||
*slot_mut += experimental_feature;
|
||||
}
|
||||
}
|
||||
},
|
||||
Entry::Vacant(slot) => {
|
||||
let _ = slot.insert(experimental_features.join(" "));
|
||||
},
|
||||
};
|
||||
let mut nix_conf_insert_settings = Vec::default();
|
||||
nix_conf_insert_settings.push("include ./nix-installer-defaults.conf".into());
|
||||
nix_conf_insert_settings.extend(extra_conf);
|
||||
let nix_conf_insert_fragment = nix_conf_insert_settings.join("\n");
|
||||
|
||||
// https://github.com/DeterminateSystems/nix-installer/issues/449#issuecomment-1551782281
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
settings.insert("auto-optimise-store".to_string(), "true".to_string());
|
||||
let mut defaults_conf_settings = vec![
|
||||
("build-users-group", nix_build_group_name),
|
||||
(
|
||||
"experimental-features",
|
||||
"nix-command flakes auto-allocate-uids".into(),
|
||||
),
|
||||
];
|
||||
|
||||
settings.insert(
|
||||
"bash-prompt-prefix".to_string(),
|
||||
"(nix:$name)\\040".to_string(),
|
||||
);
|
||||
defaults_conf_settings.push(("bash-prompt-prefix", "(nix:$name)\\040".into()));
|
||||
defaults_conf_settings.push(("extra-nix-path", "nixpkgs=flake:nixpkgs".into()));
|
||||
if let Some(ssl_cert_file) = ssl_cert_file {
|
||||
let ssl_cert_file_canonical = ssl_cert_file
|
||||
.canonicalize()
|
||||
.map_err(|e| Self::error(ActionErrorKind::Canonicalize(ssl_cert_file, e)))?;
|
||||
settings.insert(
|
||||
"ssl-cert-file".to_string(),
|
||||
defaults_conf_settings.push((
|
||||
"ssl-cert-file",
|
||||
ssl_cert_file_canonical.display().to_string(),
|
||||
);
|
||||
));
|
||||
}
|
||||
settings.insert(
|
||||
"extra-nix-path".to_string(),
|
||||
"nixpkgs=flake:nixpkgs".to_string(),
|
||||
);
|
||||
|
||||
// https://github.com/DeterminateSystems/nix-installer/issues/449#issuecomment-1551782281
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
defaults_conf_settings.push(("auto-optimise-store", "true".into()));
|
||||
// Auto-allocate uids is broken on Mac. Tools like `whoami` don't work.
|
||||
// e.g. https://github.com/NixOS/nix/issues/8444
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
settings.insert("auto-allocate-uids".to_string(), "true".to_string());
|
||||
defaults_conf_settings.push(("auto-allocate-uids", "true".into()));
|
||||
let defaults_conf_insert_fragment = defaults_conf_settings
|
||||
.iter()
|
||||
.map(|(s, v)| format!("{s} = {v}"))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
|
||||
let nix_conf_insert_position = if Path::new(NIX_CONF).exists() {
|
||||
let existing_nix_conf = tokio::fs::read_to_string(NIX_CONF)
|
||||
.await
|
||||
.map_err(|e| ActionErrorKind::Read(NIX_CONF.into(), e))
|
||||
.map_err(Self::error)?;
|
||||
tracing::trace!("Found existing `/etc/nix/nix.conf`");
|
||||
|
||||
// Find the first line that isn't just `# ...` comments
|
||||
let mut chosen_insert_after = None;
|
||||
// Warn if there seems to be a setting which is a duplicate of one we set.
|
||||
let mut existing_conf_settings = vec![];
|
||||
|
||||
for (index, line) in existing_nix_conf.lines().enumerate() {
|
||||
let line = line.trim();
|
||||
if line.starts_with('#') {
|
||||
continue;
|
||||
} else {
|
||||
chosen_insert_after = Some(Position::Before {
|
||||
index,
|
||||
expected_content: line.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
// We only scan one include of depth -- we should make this any depth, make sure to guard for loops
|
||||
if line.starts_with("include") || line.starts_with("!include") {
|
||||
let allow_not_existing = line.starts_with("!");
|
||||
// Need to read it in if it exists for settings
|
||||
let path = line
|
||||
.trim_start_matches("include")
|
||||
.trim_start_matches("!include")
|
||||
.trim();
|
||||
let path = Path::new(path);
|
||||
let path = if path.is_relative() {
|
||||
Path::new("/etc/nix/").join(path)
|
||||
} else {
|
||||
path.into()
|
||||
};
|
||||
|
||||
tracing::trace!(path = %path.display(), "Reading included nix.conf");
|
||||
let existing_included_conf = match tokio::fs::read_to_string(&path).await {
|
||||
Ok(v) => Some(v),
|
||||
Err(_e) if allow_not_existing => None,
|
||||
Err(e) => {
|
||||
return Err(ActionErrorKind::Read(path, e)).map_err(Self::error)?
|
||||
},
|
||||
};
|
||||
if let Some(existing_included_conf) = existing_included_conf {
|
||||
let lines = existing_included_conf.lines();
|
||||
for line in lines {
|
||||
let split = line.split_once('=');
|
||||
if let Some((setting_name, setting_value)) = split {
|
||||
let setting_name = setting_name.trim();
|
||||
let setting_value = setting_value.trim();
|
||||
existing_conf_settings
|
||||
.push((setting_name.to_string(), setting_value.to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let split = line.split_once('=');
|
||||
if let Some((setting_name, setting_value)) = split {
|
||||
let setting_name = setting_name.trim();
|
||||
let setting_value = setting_value.trim();
|
||||
existing_conf_settings
|
||||
.push((setting_name.to_string(), setting_value.to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
tracing::trace!(
|
||||
existing_conf_settings = existing_conf_settings
|
||||
.iter()
|
||||
.map(|(v, _)| v.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(","),
|
||||
"Found existing config settings"
|
||||
);
|
||||
|
||||
// Some settings (eg `experimental-features`) we must be able to set it.
|
||||
let mut required_settings = vec!["experimental-features"];
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
required_settings.push("auto-allocate-uids");
|
||||
for required_setting in required_settings {
|
||||
if let Some((existing_setting, existing_value)) = existing_conf_settings
|
||||
.iter()
|
||||
.find(|(k, _v)| k == required_setting)
|
||||
{
|
||||
let required_setting = defaults_conf_settings
|
||||
.iter()
|
||||
.find(|(default_setting, _v)| default_setting.starts_with(existing_setting))
|
||||
.expect("Required setting was not planned -- please report this");
|
||||
if *existing_value != required_setting.1 {
|
||||
return Err(ActionErrorKind::ConfigurationConflict {
|
||||
setting: existing_setting.to_string(),
|
||||
existing_value: existing_value.to_string(),
|
||||
planned_value: required_setting.1.clone(),
|
||||
})
|
||||
.map_err(Self::error);
|
||||
} else {
|
||||
tracing::trace!(
|
||||
"Found existing setting `{} = {existing_value}` in config, continuing",
|
||||
required_setting.0
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Other settings, it's just a warning
|
||||
for defaults_conf_setting in &defaults_conf_settings {
|
||||
// We only set plain values so no need to be complicated.
|
||||
for (existing_field, existing_value) in &existing_conf_settings {
|
||||
if defaults_conf_setting.0.trim() == *existing_field
|
||||
&& defaults_conf_setting.1.trim() != existing_value.trim()
|
||||
{
|
||||
tracing::warn!("Found existing `/etc/nix/nix.conf` setting `{existing_field} = {existing_value}` which will override a default setting from the `nix-installer`, consider unsetting it. For settings like `experimental-features` you can use an `extra-*` prefix to append to the defaults")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If `None` then the file is likely just completely empty.
|
||||
chosen_insert_after.unwrap_or(Position::Beginning)
|
||||
} else {
|
||||
tracing::trace!("Creating new `/etc/nix/nix.conf`");
|
||||
Position::Beginning
|
||||
};
|
||||
|
||||
let create_or_insert_nix_conf = CreateOrInsertIntoFile::plan(
|
||||
NIX_CONF,
|
||||
None,
|
||||
None,
|
||||
0o755,
|
||||
nix_conf_insert_fragment + "\n",
|
||||
nix_conf_insert_position,
|
||||
)
|
||||
.await
|
||||
.map_err(Self::error)?;
|
||||
|
||||
let create_defaults_conf = CreateFile::plan(
|
||||
PathBuf::from("/etc/nix/nix-installer-defaults.conf"),
|
||||
None,
|
||||
None,
|
||||
0o755,
|
||||
defaults_conf_insert_fragment + "\n",
|
||||
true,
|
||||
)
|
||||
.await
|
||||
.map_err(Self::error)?;
|
||||
|
||||
let create_directory = CreateDirectory::plan(NIX_CONF_FOLDER, None, None, 0o0755, force)
|
||||
.await
|
||||
.map_err(Self::error)?;
|
||||
let create_or_merge_nix_config = CreateOrMergeNixConfig::plan(NIX_CONF, nix_config)
|
||||
.await
|
||||
.map_err(Self::error)?;
|
||||
Ok(Self {
|
||||
create_directory,
|
||||
create_or_merge_nix_config,
|
||||
create_or_insert_nix_conf,
|
||||
create_defaults_conf,
|
||||
}
|
||||
.into())
|
||||
}
|
||||
|
@ -108,8 +241,9 @@ impl Action for PlaceNixConfiguration {
|
|||
|
||||
fn execute_description(&self) -> Vec<ActionDescription> {
|
||||
let Self {
|
||||
create_or_merge_nix_config,
|
||||
create_directory,
|
||||
create_or_insert_nix_conf,
|
||||
create_defaults_conf,
|
||||
} = self;
|
||||
|
||||
let mut explanation = vec![
|
||||
|
@ -120,7 +254,10 @@ impl Action for PlaceNixConfiguration {
|
|||
if let Some(val) = create_directory.describe_execute().first() {
|
||||
explanation.push(val.description.clone())
|
||||
}
|
||||
for val in create_or_merge_nix_config.describe_execute().iter() {
|
||||
for val in create_or_insert_nix_conf.describe_execute().iter() {
|
||||
explanation.push(val.description.clone())
|
||||
}
|
||||
for val in create_defaults_conf.describe_execute().iter() {
|
||||
explanation.push(val.description.clone())
|
||||
}
|
||||
|
||||
|
@ -133,7 +270,11 @@ impl Action for PlaceNixConfiguration {
|
|||
.try_execute()
|
||||
.await
|
||||
.map_err(Self::error)?;
|
||||
self.create_or_merge_nix_config
|
||||
self.create_or_insert_nix_conf
|
||||
.try_execute()
|
||||
.await
|
||||
.map_err(Self::error)?;
|
||||
self.create_defaults_conf
|
||||
.try_execute()
|
||||
.await
|
||||
.map_err(Self::error)?;
|
||||
|
@ -142,19 +283,40 @@ impl Action for PlaceNixConfiguration {
|
|||
}
|
||||
|
||||
fn revert_description(&self) -> Vec<ActionDescription> {
|
||||
let Self {
|
||||
create_directory,
|
||||
create_or_insert_nix_conf,
|
||||
create_defaults_conf,
|
||||
} = self;
|
||||
|
||||
let mut explanation = vec![
|
||||
"This file is read by the Nix daemon to set its configuration options at runtime."
|
||||
.to_string(),
|
||||
];
|
||||
|
||||
if let Some(val) = create_directory.describe_execute().first() {
|
||||
explanation.push(val.description.clone())
|
||||
}
|
||||
for val in create_or_insert_nix_conf.describe_execute().iter() {
|
||||
explanation.push(val.description.clone())
|
||||
}
|
||||
for val in create_defaults_conf.describe_execute().iter() {
|
||||
explanation.push(val.description.clone())
|
||||
}
|
||||
|
||||
vec![ActionDescription::new(
|
||||
format!("Remove the Nix configuration in `{NIX_CONF}`"),
|
||||
vec![
|
||||
"This file is read by the Nix daemon to set its configuration options at runtime."
|
||||
.to_string(),
|
||||
],
|
||||
explanation,
|
||||
)]
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip_all)]
|
||||
async fn revert(&mut self) -> Result<(), ActionError> {
|
||||
let mut errors = vec![];
|
||||
if let Err(err) = self.create_or_merge_nix_config.try_revert().await {
|
||||
if let Err(err) = self.create_or_insert_nix_conf.try_revert().await {
|
||||
errors.push(err);
|
||||
}
|
||||
if let Err(err) = self.create_defaults_conf.try_revert().await {
|
||||
errors.push(err);
|
||||
}
|
||||
if let Err(err) = self.create_directory.try_revert().await {
|
||||
|
|
|
@ -200,6 +200,8 @@ use tracing::Span;
|
|||
|
||||
use crate::{error::HasExpectedErrors, CertificateError};
|
||||
|
||||
use self::base::create_or_insert_into_file::Position;
|
||||
|
||||
/// An action which can be reverted or completed, with an action state
|
||||
///
|
||||
/// This trait interacts with [`StatefulAction`] which does the [`ActionState`] manipulation and provides some tracing facilities.
|
||||
|
@ -361,6 +363,21 @@ pub enum ActionErrorKind {
|
|||
/// A custom error
|
||||
#[error(transparent)]
|
||||
Custom(Box<dyn std::error::Error + Send + Sync>),
|
||||
/// An error to do with the `nix.conf` configuration having a conflict
|
||||
#[error("\
|
||||
A configuration conflict in `/etc/nix/nix.conf` exists.\n\
|
||||
The installer would set a default:\n\
|
||||
{indent}{setting} = {planned_value}\n\
|
||||
However, this setting is already set in the `nix.conf`:\n\
|
||||
{indent}{setting} = {existing_value}\n\
|
||||
\n\
|
||||
Consider unsetting the value. For lists like `experimental-features` you can append with `extra-experimental-features`.\
|
||||
", indent = " ")]
|
||||
ConfigurationConflict {
|
||||
setting: String,
|
||||
existing_value: String,
|
||||
planned_value: String,
|
||||
},
|
||||
/// An error to do with certificates
|
||||
#[error(transparent)]
|
||||
Certificate(#[from] CertificateError),
|
||||
|
@ -390,6 +407,16 @@ pub enum ActionErrorKind {
|
|||
"`{0}` exists with different content than planned, consider removing it with `rm {0}`"
|
||||
)]
|
||||
DifferentContent(std::path::PathBuf),
|
||||
/// The path already exists with a different line content that expected
|
||||
#[error(
|
||||
"`{0}` exists with different line content than planned, {position} may have changed since read",
|
||||
position = match .1 {
|
||||
Position::Beginning => "the line at the start of the file".to_string(),
|
||||
Position::End => "the line at the end of the file".to_string(),
|
||||
Position::Before { index, .. } => format!("line {index}"),
|
||||
}
|
||||
)]
|
||||
DifferentLineContent(std::path::PathBuf, Position),
|
||||
/// The file already exists
|
||||
#[error("`{0}` already exists, consider removing it with `rm {0}`")]
|
||||
FileExists(std::path::PathBuf),
|
||||
|
@ -583,8 +610,10 @@ impl HasExpectedErrors for ActionErrorKind {
|
|||
match self {
|
||||
Self::PathUserMismatch(_, _, _)
|
||||
| Self::PathGroupMismatch(_, _, _)
|
||||
| Self::PathModeMismatch(_, _, _) => Some(Box::new(self)),
|
||||
| Self::PathModeMismatch(_, _, _)
|
||||
| Self::ConfigurationConflict { .. } => Some(Box::new(self)),
|
||||
Self::SystemdMissing => Some(Box::new(self)),
|
||||
Self::Child(child) => child.kind().expected(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -441,7 +441,7 @@ impl HasExpectedErrors for PlannerError {
|
|||
fn expected<'a>(&'a self) -> Option<Box<dyn std::error::Error + 'a>> {
|
||||
match self {
|
||||
this @ PlannerError::UnsupportedArchitecture(_) => Some(Box::new(this)),
|
||||
PlannerError::Action(_) => None,
|
||||
PlannerError::Action(action_error) => action_error.kind().expected(),
|
||||
PlannerError::InstallSettings(_) => None,
|
||||
PlannerError::Plist(_) => None,
|
||||
PlannerError::Sysctl(_) => None,
|
||||
|
|
159
tests/fixtures/linux/linux.json
vendored
159
tests/fixtures/linux/linux.json
vendored
|
@ -8,7 +8,7 @@
|
|||
"user": null,
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -18,21 +18,13 @@
|
|||
"action": "provision_nix",
|
||||
"fetch_nix": {
|
||||
"action": {
|
||||
"url": "https://releases.nixos.org/nix/nix-2.15.0/nix-2.15.0-x86_64-linux.tar.xz",
|
||||
"url": "https://releases.nixos.org/nix/nix-2.17.0/nix-2.17.0-x86_64-linux.tar.xz",
|
||||
"dest": "/nix/temp-install-dir",
|
||||
"proxy": null,
|
||||
"ssl_cert_file": null
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
"delete_users": [],
|
||||
"create_group": {
|
||||
"action": {
|
||||
"name": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
"create_nix_tree": {
|
||||
"action": {
|
||||
"create_directories": [
|
||||
|
@ -42,8 +34,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -53,8 +45,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -64,8 +56,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -75,8 +67,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -86,8 +78,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -97,8 +89,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -108,8 +100,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -119,8 +111,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -130,8 +122,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -141,8 +133,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -152,8 +144,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -163,8 +155,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -174,8 +166,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
}
|
||||
|
@ -192,6 +184,26 @@
|
|||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"action": "create_users_and_group",
|
||||
"nix_build_user_count": 0,
|
||||
"nix_build_group_name": "nixbld",
|
||||
"nix_build_group_id": 30000,
|
||||
"nix_build_user_prefix": "nixbld",
|
||||
"nix_build_user_id_base": 30000,
|
||||
"create_group": {
|
||||
"action": {
|
||||
"name": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
"create_users": [],
|
||||
"add_users_to_groups": []
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"action": "configure_nix",
|
||||
|
@ -229,13 +241,24 @@
|
|||
]
|
||||
},
|
||||
"create_directories": [
|
||||
{
|
||||
"action": {
|
||||
"path": "/etc/zsh",
|
||||
"user": null,
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"path": "/usr/share/fish/vendor_conf.d",
|
||||
"user": null,
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Completed"
|
||||
|
@ -286,6 +309,17 @@
|
|||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"path": "/etc/zsh/zshrc",
|
||||
"user": null,
|
||||
"group": null,
|
||||
"mode": 420,
|
||||
"buf": "\n# Nix\nif [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then\n . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'\nfi\n# End Nix\n\n \n",
|
||||
"position": "Beginning"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"path": "/usr/share/fish/vendor_conf.d/nix.fish",
|
||||
|
@ -309,24 +343,30 @@
|
|||
"user": null,
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
"create_or_merge_nix_config": {
|
||||
"create_or_insert_nix_conf": {
|
||||
"action": {
|
||||
"path": "/etc/nix/nix.conf",
|
||||
"pending_nix_config": {
|
||||
"settings": {
|
||||
"experimental-features": "nix-command flakes auto-allocate-uids",
|
||||
"build-users-group": "nixbld",
|
||||
"auto-optimise-store": "true",
|
||||
"bash-prompt-prefix": "(nix:$name)\\040",
|
||||
"extra-nix-path": "nixpkgs=flake:nixpkgs",
|
||||
"auto-allocate-uids": "true"
|
||||
}
|
||||
}
|
||||
"user": null,
|
||||
"group": null,
|
||||
"mode": null,
|
||||
"buf": "!include ./nix-installer-defaults.conf",
|
||||
"position": "Beginning"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
"create_defaults_conf": {
|
||||
"action": {
|
||||
"path": "/etc/nix/defaults.conf",
|
||||
"user": null,
|
||||
"group": null,
|
||||
"mode": null,
|
||||
"buf": "build-users-group = nixbld\nexperimental-features = nix-command flakes auto-allocate-uids\nbash-prompt-prefix = (nix:$name)\\040\nextra-nix-path = nixpkgs=flake:nixpkgs\nauto-optimise-store = true\nauto-allocate-uids = true",
|
||||
"replace": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
}
|
||||
|
@ -336,12 +376,23 @@
|
|||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"action": "create_directory",
|
||||
"path": "/etc/tmpfiles.d",
|
||||
"user": null,
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Completed"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"action": "configure_init_service",
|
||||
"init": "Systemd",
|
||||
"start_daemon": true,
|
||||
"ssl_cert_file": null
|
||||
"start_daemon": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -359,10 +410,10 @@
|
|||
"modify_profile": true,
|
||||
"nix_build_group_name": "nixbld",
|
||||
"nix_build_group_id": 30000,
|
||||
"nix_build_user_count": 0,
|
||||
"nix_build_user_prefix": "nixbld",
|
||||
"nix_build_user_count": 0,
|
||||
"nix_build_user_id_base": 30000,
|
||||
"nix_package_url": "https://releases.nixos.org/nix/nix-2.15.0/nix-2.15.0-x86_64-linux.tar.xz",
|
||||
"nix_package_url": "https://releases.nixos.org/nix/nix-2.17.0/nix-2.17.0-x86_64-linux.tar.xz",
|
||||
"proxy": null,
|
||||
"ssl_cert_file": null,
|
||||
"extra_conf": [],
|
||||
|
@ -386,4 +437,4 @@
|
|||
"ssl_cert_file": null,
|
||||
"failure_chain": null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
170
tests/fixtures/linux/steam-deck.json
vendored
170
tests/fixtures/linux/steam-deck.json
vendored
|
@ -1,6 +1,12 @@
|
|||
{
|
||||
"version": "0.11.0",
|
||||
"actions": [
|
||||
{
|
||||
"action": {
|
||||
"action": "systemctl_daemon_reload"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"action": "create_directory",
|
||||
|
@ -8,7 +14,7 @@
|
|||
"user": null,
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
|
@ -21,7 +27,7 @@
|
|||
"group": null,
|
||||
"mode": 420,
|
||||
"buf": "[Unit]\nDescription=Create a `/nix` directory to be used for bind mounting\nPropagatesStopTo=nix-daemon.service\nPropagatesStopTo=nix.mount\nDefaultDependencies=no\nAfter=grub-recordfail.service\nAfter=steamos-finish-oobe-migration.service\n\n[Service]\nType=oneshot\nExecStart=steamos-readonly disable\nExecStart=mkdir -vp /nix\nExecStart=chmod -v 0755 /nix\nExecStart=chown -v root /nix\nExecStart=chgrp -v root /nix\nExecStart=steamos-readonly enable\nExecStop=steamos-readonly disable\nExecStop=rmdir /nix\nExecStop=steamos-readonly enable\nRemainAfterExit=true\n",
|
||||
"force": false
|
||||
"replace": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -32,8 +38,8 @@
|
|||
"user": null,
|
||||
"group": null,
|
||||
"mode": 420,
|
||||
"buf": "[Unit]\nDescription=Mount `/home/nix` on `/nix`\nPropagatesStopTo=nix-daemon.service\nPropagatesStopTo=nix-directory.service\nAfter=nix-directory.service\nRequires=nix-directory.service\nConditionPathIsDirectory=/nix\nDefaultDependencies=no\nRequiredBy=nix-daemon.service\nRequiredBy=nix-daemon.socket\n\n[Mount]\nWhat=/home/nix\nWhere=/nix\nType=none\nDirectoryMode=0755\nOptions=bind\n",
|
||||
"force": false
|
||||
"buf": "[Unit]\nDescription=Mount `/home/nix` on `/nix`\nPropagatesStopTo=nix-daemon.service\nPropagatesStopTo=nix-directory.service\nAfter=nix-directory.service\nRequires=nix-directory.service\nConditionPathIsDirectory=/nix\nDefaultDependencies=no\n\n[Mount]\nWhat=/home/nix\nWhere=/nix\nType=none\nDirectoryMode=0755\nOptions=bind\n\n[Install]\nRequiredBy=nix-daemon.service\nRequiredBy=nix-daemon.socket\n\n ",
|
||||
"replace": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -44,8 +50,8 @@
|
|||
"user": null,
|
||||
"group": null,
|
||||
"mode": 420,
|
||||
"buf": "[Unit]\nDescription=Ensure Nix related units which are symlinked resolve\nAfter=nix.mount\nRequires=nix-directory.service\nRequires=nix.mount\nDefaultDependencies=no\n\n[Service]\nType=oneshot\nRemainAfterExit=yes\nExecStart=/usr/bin/systemctl daemon-reload\nExecStart=/usr/bin/systemctl restart --no-block nix-daemon.socket\n\n[Install]\nWantedBy=sysinit.target\n",
|
||||
"force": false
|
||||
"buf": "[Unit]\nDescription=Ensure Nix related units which are symlinked resolve\nAfter=nix.mount\nRequires=nix.mount\nDefaultDependencies=no\n\n[Service]\nType=oneshot\nRemainAfterExit=yes\nExecStart=/usr/bin/systemctl daemon-reload\nExecStart=/usr/bin/systemctl restart --no-block nix-daemon.socket\n\n[Install]\nWantedBy=sysinit.target\n",
|
||||
"replace": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -62,21 +68,13 @@
|
|||
"action": "provision_nix",
|
||||
"fetch_nix": {
|
||||
"action": {
|
||||
"url": "https://releases.nixos.org/nix/nix-2.15.0/nix-2.15.0-x86_64-linux.tar.xz",
|
||||
"url": "https://releases.nixos.org/nix/nix-2.17.0/nix-2.17.0-x86_64-linux.tar.xz",
|
||||
"dest": "/nix/temp-install-dir",
|
||||
"proxy": null,
|
||||
"ssl_cert_file": null
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
"delete_users": [],
|
||||
"create_group": {
|
||||
"action": {
|
||||
"name": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
"create_nix_tree": {
|
||||
"action": {
|
||||
"create_directories": [
|
||||
|
@ -86,8 +84,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -97,8 +95,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -108,8 +106,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -119,8 +117,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -130,8 +128,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -141,8 +139,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -152,8 +150,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -163,8 +161,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -174,8 +172,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -185,8 +183,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -196,8 +194,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -207,8 +205,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -218,8 +216,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
}
|
||||
|
@ -236,6 +234,26 @@
|
|||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"action": "create_users_and_group",
|
||||
"nix_build_user_count": 0,
|
||||
"nix_build_group_name": "nixbld",
|
||||
"nix_build_group_id": 30000,
|
||||
"nix_build_user_prefix": "nixbld",
|
||||
"nix_build_user_id_base": 30000,
|
||||
"create_group": {
|
||||
"action": {
|
||||
"name": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
"create_users": [],
|
||||
"add_users_to_groups": []
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"action": "configure_nix",
|
||||
|
@ -271,7 +289,19 @@
|
|||
"/etc/zsh/zshrc"
|
||||
]
|
||||
},
|
||||
"create_directories": [],
|
||||
"create_directories": [
|
||||
{
|
||||
"action": {
|
||||
"path": "/etc/zsh",
|
||||
"user": null,
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
}
|
||||
],
|
||||
"create_or_insert_into_files": [
|
||||
{
|
||||
"action": {
|
||||
|
@ -316,6 +346,17 @@
|
|||
"position": "Beginning"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"path": "/etc/zsh/zshrc",
|
||||
"user": null,
|
||||
"group": null,
|
||||
"mode": 420,
|
||||
"buf": "\n# Nix\nif [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then\n . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'\nfi\n# End Nix\n\n \n",
|
||||
"position": "Beginning"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -329,24 +370,30 @@
|
|||
"user": null,
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
"create_or_merge_nix_config": {
|
||||
"create_or_insert_nix_conf": {
|
||||
"action": {
|
||||
"path": "/etc/nix/nix.conf",
|
||||
"pending_nix_config": {
|
||||
"settings": {
|
||||
"auto-optimise-store": "true",
|
||||
"bash-prompt-prefix": "(nix:$name)\\040",
|
||||
"build-users-group": "nixbld",
|
||||
"experimental-features": "nix-command flakes auto-allocate-uids",
|
||||
"extra-nix-path": "nixpkgs=flake:nixpkgs",
|
||||
"auto-allocate-uids": "true"
|
||||
}
|
||||
}
|
||||
"user": null,
|
||||
"group": null,
|
||||
"mode": null,
|
||||
"buf": "!include ./nix-installer-defaults.conf",
|
||||
"position": "Beginning"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
"create_defaults_conf": {
|
||||
"action": {
|
||||
"path": "/etc/nix/defaults.conf",
|
||||
"user": null,
|
||||
"group": null,
|
||||
"mode": null,
|
||||
"buf": "build-users-group = nixbld\nexperimental-features = nix-command flakes auto-allocate-uids\nbash-prompt-prefix = (nix:$name)\\040\nextra-nix-path = nixpkgs=flake:nixpkgs\nauto-optimise-store = true\nauto-allocate-uids = true",
|
||||
"replace": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
}
|
||||
|
@ -360,8 +407,7 @@
|
|||
"action": {
|
||||
"action": "configure_init_service",
|
||||
"init": "Systemd",
|
||||
"start_daemon": true,
|
||||
"ssl_cert_file": null
|
||||
"start_daemon": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -379,6 +425,12 @@
|
|||
"path": "/nix/temp-install-dir"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"action": "systemctl_daemon_reload"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
}
|
||||
],
|
||||
"planner": {
|
||||
|
@ -388,10 +440,10 @@
|
|||
"modify_profile": true,
|
||||
"nix_build_group_name": "nixbld",
|
||||
"nix_build_group_id": 30000,
|
||||
"nix_build_user_count": 0,
|
||||
"nix_build_user_prefix": "nixbld",
|
||||
"nix_build_user_count": 0,
|
||||
"nix_build_user_id_base": 30000,
|
||||
"nix_package_url": "https://releases.nixos.org/nix/nix-2.15.0/nix-2.15.0-x86_64-linux.tar.xz",
|
||||
"nix_package_url": "https://releases.nixos.org/nix/nix-2.17.0/nix-2.17.0-x86_64-linux.tar.xz",
|
||||
"proxy": null,
|
||||
"ssl_cert_file": null,
|
||||
"extra_conf": [],
|
||||
|
@ -411,4 +463,4 @@
|
|||
"ssl_cert_file": null,
|
||||
"failure_chain": null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
786
tests/fixtures/macos/macos.json
vendored
786
tests/fixtures/macos/macos.json
vendored
|
@ -4,7 +4,7 @@
|
|||
{
|
||||
"action": {
|
||||
"action": "create_apfs_volume",
|
||||
"disk": "disk3",
|
||||
"disk": "disk1",
|
||||
"name": "Nix Store",
|
||||
"case_sensitive": false,
|
||||
"encrypt": false,
|
||||
|
@ -25,14 +25,14 @@
|
|||
},
|
||||
"unmount_volume": {
|
||||
"action": {
|
||||
"disk": "disk3",
|
||||
"disk": "disk1",
|
||||
"name": "Nix Store"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
"create_volume": {
|
||||
"action": {
|
||||
"disk": "disk3",
|
||||
"disk": "disk1",
|
||||
"name": "Nix Store",
|
||||
"case_sensitive": false
|
||||
},
|
||||
|
@ -88,21 +88,13 @@
|
|||
"action": "provision_nix",
|
||||
"fetch_nix": {
|
||||
"action": {
|
||||
"url": "https://releases.nixos.org/nix/nix-2.15.0/nix-2.15.0-aarch64-darwin.tar.xz",
|
||||
"url": "https://releases.nixos.org/nix/nix-2.17.0/nix-2.17.0-x86_64-darwin.tar.xz",
|
||||
"dest": "/nix/temp-install-dir",
|
||||
"proxy": null,
|
||||
"ssl_cert_file": null
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
"delete_users_in_group": null,
|
||||
"create_group": {
|
||||
"action": {
|
||||
"name": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
"create_nix_tree": {
|
||||
"action": {
|
||||
"create_directories": [
|
||||
|
@ -112,8 +104,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -123,8 +115,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -134,8 +126,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -145,8 +137,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -156,8 +148,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -167,8 +159,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -178,8 +170,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -189,8 +181,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -200,8 +192,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -211,8 +203,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -222,8 +214,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -233,8 +225,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -244,8 +236,8 @@
|
|||
"user": "root",
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"force_prune_on_revert": false
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
}
|
||||
|
@ -262,6 +254,636 @@
|
|||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"action": "create_users_and_group",
|
||||
"nix_build_user_count": 32,
|
||||
"nix_build_group_name": "nixbld",
|
||||
"nix_build_group_id": 30000,
|
||||
"nix_build_user_prefix": "_nixbld",
|
||||
"nix_build_user_id_base": 300,
|
||||
"create_group": {
|
||||
"action": {
|
||||
"name": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
"create_users": [
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld1",
|
||||
"uid": 301,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 1"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld2",
|
||||
"uid": 302,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 2"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld3",
|
||||
"uid": 303,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 3"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld4",
|
||||
"uid": 304,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 4"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld5",
|
||||
"uid": 305,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 5"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld6",
|
||||
"uid": 306,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 6"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld7",
|
||||
"uid": 307,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 7"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld8",
|
||||
"uid": 308,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 8"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld9",
|
||||
"uid": 309,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 9"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld10",
|
||||
"uid": 310,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 10"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld11",
|
||||
"uid": 311,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 11"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld12",
|
||||
"uid": 312,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 12"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld13",
|
||||
"uid": 313,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 13"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld14",
|
||||
"uid": 314,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 14"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld15",
|
||||
"uid": 315,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 15"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld16",
|
||||
"uid": 316,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 16"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld17",
|
||||
"uid": 317,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 17"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld18",
|
||||
"uid": 318,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 18"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld19",
|
||||
"uid": 319,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 19"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld20",
|
||||
"uid": 320,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 20"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld21",
|
||||
"uid": 321,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 21"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld22",
|
||||
"uid": 322,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 22"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld23",
|
||||
"uid": 323,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 23"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld24",
|
||||
"uid": 324,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 24"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld25",
|
||||
"uid": 325,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 25"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld26",
|
||||
"uid": 326,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 26"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld27",
|
||||
"uid": 327,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 27"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld28",
|
||||
"uid": 328,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 28"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld29",
|
||||
"uid": 329,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 29"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld30",
|
||||
"uid": 330,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 30"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld31",
|
||||
"uid": 331,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 31"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld32",
|
||||
"uid": 332,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000,
|
||||
"comment": "Nix build user 32"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
}
|
||||
],
|
||||
"add_users_to_groups": [
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld1",
|
||||
"uid": 301,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld2",
|
||||
"uid": 302,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld3",
|
||||
"uid": 303,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld4",
|
||||
"uid": 304,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld5",
|
||||
"uid": 305,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld6",
|
||||
"uid": 306,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld7",
|
||||
"uid": 307,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld8",
|
||||
"uid": 308,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld9",
|
||||
"uid": 309,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld10",
|
||||
"uid": 310,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld11",
|
||||
"uid": 311,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld12",
|
||||
"uid": 312,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld13",
|
||||
"uid": 313,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld14",
|
||||
"uid": 314,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld15",
|
||||
"uid": 315,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld16",
|
||||
"uid": 316,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld17",
|
||||
"uid": 317,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld18",
|
||||
"uid": 318,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld19",
|
||||
"uid": 319,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld20",
|
||||
"uid": 320,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld21",
|
||||
"uid": 321,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld22",
|
||||
"uid": 322,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld23",
|
||||
"uid": 323,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld24",
|
||||
"uid": 324,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld25",
|
||||
"uid": 325,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld26",
|
||||
"uid": 326,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld27",
|
||||
"uid": 327,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld28",
|
||||
"uid": 328,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld29",
|
||||
"uid": 329,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld30",
|
||||
"uid": 330,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld31",
|
||||
"uid": 331,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"name": "_nixbld32",
|
||||
"uid": 332,
|
||||
"groupname": "nixbld",
|
||||
"gid": 30000
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
}
|
||||
]
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"action": "set_tmutil_exclusions",
|
||||
|
@ -318,7 +940,30 @@
|
|||
"/etc/zsh/zshrc"
|
||||
]
|
||||
},
|
||||
"create_directories": [],
|
||||
"create_directories": [
|
||||
{
|
||||
"action": {
|
||||
"path": "/etc/profile.d",
|
||||
"user": null,
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"path": "/etc/zsh",
|
||||
"user": null,
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
}
|
||||
],
|
||||
"create_or_insert_into_files": [
|
||||
{
|
||||
"action": {
|
||||
|
@ -331,6 +976,17 @@
|
|||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"path": "/etc/profile.d/nix.sh",
|
||||
"user": null,
|
||||
"group": null,
|
||||
"mode": 420,
|
||||
"buf": "\n# Nix\nif [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then\n . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'\nfi\n# End Nix\n\n \n",
|
||||
"position": "Beginning"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"path": "/etc/bash.bashrc",
|
||||
|
@ -352,6 +1008,17 @@
|
|||
"position": "Beginning"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"path": "/etc/zsh/zshrc",
|
||||
"user": null,
|
||||
"group": null,
|
||||
"mode": 420,
|
||||
"buf": "\n# Nix\nif [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then\n . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'\nfi\n# End Nix\n\n \n",
|
||||
"position": "Beginning"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -365,24 +1032,30 @@
|
|||
"user": null,
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"is_mountpoint": true,
|
||||
"is_mountpoint": false,
|
||||
"force_prune_on_revert": false
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
"create_or_merge_nix_config": {
|
||||
"create_or_insert_nix_conf": {
|
||||
"action": {
|
||||
"path": "/etc/nix/nix.conf",
|
||||
"pending_nix_config": {
|
||||
"settings": {
|
||||
"extra-nix-path": "nixpkgs=flake:nixpkgs",
|
||||
"auto-allocate-uids": "true",
|
||||
"auto-optimise-store": "true",
|
||||
"build-users-group": "nixbld",
|
||||
"bash-prompt-prefix": "(nix:$name)\\040",
|
||||
"experimental-features": "nix-command flakes auto-allocate-uids"
|
||||
}
|
||||
}
|
||||
"user": null,
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"buf": "!include ./defaults.conf\n",
|
||||
"position": "Beginning"
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
"create_defaults_conf": {
|
||||
"action": {
|
||||
"path": "/etc/nix/defaults.conf",
|
||||
"user": null,
|
||||
"group": null,
|
||||
"mode": 493,
|
||||
"buf": "build-users-group = nixbld\nexperimental-features = nix-command flakes auto-allocate-uids\nbash-prompt-prefix = (nix:$name)\\040\nextra-nix-path = nixpkgs=flake:nixpkgs\n",
|
||||
"replace": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
}
|
||||
|
@ -396,8 +1069,7 @@
|
|||
"action": {
|
||||
"action": "configure_init_service",
|
||||
"init": "Launchd",
|
||||
"start_daemon": true,
|
||||
"ssl_cert_file": null
|
||||
"start_daemon": true
|
||||
},
|
||||
"state": "Uncompleted"
|
||||
},
|
||||
|
@ -415,10 +1087,10 @@
|
|||
"modify_profile": true,
|
||||
"nix_build_group_name": "nixbld",
|
||||
"nix_build_group_id": 30000,
|
||||
"nix_build_user_count": 32,
|
||||
"nix_build_user_prefix": "_nixbld",
|
||||
"nix_build_user_count": 32,
|
||||
"nix_build_user_id_base": 300,
|
||||
"nix_package_url": "https://releases.nixos.org/nix/nix-2.15.0/nix-2.15.0-aarch64-darwin.tar.xz",
|
||||
"nix_package_url": "https://releases.nixos.org/nix/nix-2.17.0/nix-2.17.0-x86_64-darwin.tar.xz",
|
||||
"proxy": null,
|
||||
"ssl_cert_file": null,
|
||||
"extra_conf": [],
|
||||
|
@ -428,7 +1100,7 @@
|
|||
"encrypt": null,
|
||||
"case_sensitive": false,
|
||||
"volume_label": "Nix Store",
|
||||
"root_disk": "disk3"
|
||||
"root_disk": "disk1"
|
||||
},
|
||||
"diagnostic_data": {
|
||||
"version": "0.11.0",
|
||||
|
@ -436,7 +1108,7 @@
|
|||
"configured_settings": [],
|
||||
"os_name": "unknown",
|
||||
"os_version": "unknown",
|
||||
"triple": "aarch64-apple-darwin",
|
||||
"triple": "x86_64-apple-darwin",
|
||||
"is_ci": false,
|
||||
"endpoint": "https://install.determinate.systems/nix/diagnostic",
|
||||
"ssl_cert_file": null,
|
||||
|
|
Loading…
Reference in a new issue