Integrate nix-config-parser (#263)

Co-authored-by: Ana Hobden <operator@hoverbear.org>
This commit is contained in:
Cole Helbling 2023-03-06 09:29:44 -08:00 committed by GitHub
parent d9dfb3c063
commit 2594316750
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 984 additions and 229 deletions

11
Cargo.lock generated
View file

@ -932,6 +932,16 @@ dependencies = [
"static_assertions", "static_assertions",
] ]
[[package]]
name = "nix-config-parser"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfd0a73a9c5f1f960f435be5ade7dd728d5039e6e92dbd5764f8c3d701491fc1"
dependencies = [
"serde",
"thiserror",
]
[[package]] [[package]]
name = "nix-installer" name = "nix-installer"
version = "0.4.0" version = "0.4.0"
@ -947,6 +957,7 @@ dependencies = [
"glob", "glob",
"is_ci", "is_ci",
"nix", "nix",
"nix-config-parser",
"os-release", "os-release",
"owo-colors", "owo-colors",
"plist", "plist",

View file

@ -57,6 +57,7 @@ uuid = { version = "1.2.2", features = ["serde"] }
os-release = { version = "0.1.0", default-features = false, optional = true } os-release = { version = "0.1.0", default-features = false, optional = true }
is_ci = { version = "1.1.1", default-features = false, optional = true } is_ci = { version = "1.1.1", default-features = false, optional = true }
strum = { version = "0.24.1", features = ["derive"] } strum = { version = "0.24.1", features = ["derive"] }
nix-config-parser = { version = "0.1.2", features = ["serde"] }
[dev-dependencies] [dev-dependencies]
eyre = { version = "0.6.8", default-features = false, features = [ "track-caller" ] } eyre = { version = "0.6.8", default-features = false, features = [ "track-caller" ] }

View file

@ -0,0 +1,685 @@
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, 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 = 0o644;
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),
}
/// 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| ActionError::GettingMetadata(path.clone(), e))?;
if !metadata.is_file() {
return Err(ActionError::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(ActionError::PathModeMismatch(
path,
discovered_mode,
NIX_CONF_MODE,
));
}
let existing_nix_config = NixConfig::parse_file(&path)
.map_err(CreateOrMergeNixConfigError::ParseNixConfig)
.map_err(|e| ActionError::Custom(Box::new(e)))?;
let (merged_nix_config, existing_nix_config) = Self::merge_pending_and_existing_nix_config(
&pending_nix_config,
&existing_nix_config,
&path,
)
.map_err(|e| ActionError::Custom(Box::new(e)))?;
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| {
ActionError::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| ActionError::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| ActionError::Write(temp_file_path.clone(), e))?;
tokio::fs::set_permissions(&temp_file_path, PermissionsExt::from_mode(NIX_CONF_MODE))
.await
.map_err(|e| ActionError::SetPermissions(NIX_CONF_MODE, path.to_owned(), e))?;
tokio::fs::rename(&temp_file_path, &path)
.await
.map_err(|e| ActionError::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| ActionError::Remove(path.to_owned(), e))?;
Ok(())
}
}
#[cfg(test)]
mod test {
use super::*;
use 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?;
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(ActionError::Custom(e)) => 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?;
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?;
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(())
}
}

View file

@ -5,6 +5,7 @@ pub(crate) mod create_directory;
pub(crate) mod create_file; pub(crate) mod create_file;
pub(crate) mod create_group; pub(crate) mod create_group;
pub(crate) mod create_or_insert_into_file; pub(crate) mod create_or_insert_into_file;
pub(crate) mod create_or_merge_nix_config;
pub(crate) mod create_user; pub(crate) mod create_user;
pub(crate) mod fetch_and_unpack_nix; pub(crate) mod fetch_and_unpack_nix;
pub(crate) mod move_unpacked_nix; pub(crate) mod move_unpacked_nix;
@ -15,6 +16,7 @@ pub use create_directory::CreateDirectory;
pub use create_file::CreateFile; pub use create_file::CreateFile;
pub use create_group::CreateGroup; pub use create_group::CreateGroup;
pub use create_or_insert_into_file::CreateOrInsertIntoFile; pub use create_or_insert_into_file::CreateOrInsertIntoFile;
pub use create_or_merge_nix_config::CreateOrMergeNixConfig;
pub use create_user::CreateUser; pub use create_user::CreateUser;
pub use fetch_and_unpack_nix::{FetchAndUnpackNix, FetchUrlError}; pub use fetch_and_unpack_nix::{FetchAndUnpackNix, FetchUrlError};
pub use move_unpacked_nix::{MoveUnpackedNix, MoveUnpackedNixError}; pub use move_unpacked_nix::{MoveUnpackedNix, MoveUnpackedNixError};

View file

@ -1,6 +1,7 @@
use tracing::{span, Span}; use tracing::{span, Span};
use crate::action::base::{CreateDirectory, CreateFile}; use crate::action::base::create_or_merge_nix_config::CreateOrMergeNixConfigError;
use crate::action::base::{CreateDirectory, CreateOrMergeNixConfig};
use crate::action::{Action, ActionDescription, ActionError, ActionTag, StatefulAction}; use crate::action::{Action, ActionDescription, ActionError, ActionTag, StatefulAction};
const NIX_CONF_FOLDER: &str = "/etc/nix"; const NIX_CONF_FOLDER: &str = "/etc/nix";
@ -12,7 +13,7 @@ Place the `/etc/nix.conf` file
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)] #[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct PlaceNixConfiguration { pub struct PlaceNixConfiguration {
create_directory: StatefulAction<CreateDirectory>, create_directory: StatefulAction<CreateDirectory>,
create_file: StatefulAction<CreateFile>, create_or_merge_nix_config: StatefulAction<CreateOrMergeNixConfig>,
} }
impl PlaceNixConfiguration { impl PlaceNixConfiguration {
@ -22,34 +23,38 @@ impl PlaceNixConfiguration {
extra_conf: Vec<String>, extra_conf: Vec<String>,
force: bool, force: bool,
) -> Result<StatefulAction<Self>, ActionError> { ) -> Result<StatefulAction<Self>, ActionError> {
let buf = format!( let extra_conf = extra_conf.join("\n");
"\ let mut nix_config = nix_config_parser::NixConfig::parse_string(extra_conf, None)
# Generated by https://github.com/DeterminateSystems/nix-installer, version {version}.\n\ .map_err(CreateOrMergeNixConfigError::ParseNixConfig)
\n\ .map_err(|e| ActionError::Custom(Box::new(e)))?;
{extra_conf}\n\ let settings = nix_config.settings_mut();
\n\
build-users-group = {nix_build_group_name}\n\ settings.insert("build-users-group".to_string(), nix_build_group_name);
\n\ settings.insert(
experimental-features = nix-command flakes\n\ "experimental-features".to_string(),
\n\ "nix-command flakes".to_string(),
auto-optimise-store = true\n\
\n\
bash-prompt-prefix = (nix:$name)\\040\n\
\n\
extra-nix-path = nixpkgs=flake:nixpkgs\n\
",
extra_conf = extra_conf.join("\n"),
version = env!("CARGO_PKG_VERSION"),
); );
settings.insert("auto-optimise-store".to_string(), "true".to_string());
settings.insert(
"bash-prompt-prefix".to_string(),
"(nix:$name)\\040".to_string(),
);
settings.insert(
"extra-nix-path".to_string(),
"nixpkgs=flake:nixpkgs".to_string(),
);
let create_directory = CreateDirectory::plan(NIX_CONF_FOLDER, None, None, 0o0755, force) let create_directory = CreateDirectory::plan(NIX_CONF_FOLDER, None, None, 0o0755, force)
.await .await
.map_err(|e| ActionError::Child(CreateDirectory::action_tag(), Box::new(e)))?; .map_err(|e| ActionError::Child(CreateDirectory::action_tag(), Box::new(e)))?;
let create_file = CreateFile::plan(NIX_CONF, None, None, 0o0664, buf, force) let create_or_merge_nix_config = CreateOrMergeNixConfig::plan(NIX_CONF, nix_config)
.await .await
.map_err(|e| ActionError::Child(CreateFile::action_tag(), Box::new(e)))?; .map_err(|e| {
ActionError::Child(CreateOrMergeNixConfig::action_tag(), Box::new(e))
})?;
Ok(Self { Ok(Self {
create_directory, create_directory,
create_file, create_or_merge_nix_config,
} }
.into()) .into())
} }
@ -70,13 +75,24 @@ impl Action for PlaceNixConfiguration {
} }
fn execute_description(&self) -> Vec<ActionDescription> { fn execute_description(&self) -> Vec<ActionDescription> {
vec![ActionDescription::new( let Self {
self.tracing_synopsis(), create_or_merge_nix_config,
vec![ create_directory,
"This file is read by the Nix daemon to set its configuration options at runtime." } = self;
.to_string(),
], 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().iter().next() {
explanation.push(val.description.clone())
}
for val in create_or_merge_nix_config.describe_execute().iter() {
explanation.push(val.description.clone())
}
vec![ActionDescription::new(self.tracing_synopsis(), explanation)]
} }
#[tracing::instrument(level = "debug", skip_all)] #[tracing::instrument(level = "debug", skip_all)]
@ -85,10 +101,12 @@ impl Action for PlaceNixConfiguration {
.try_execute() .try_execute()
.await .await
.map_err(|e| ActionError::Child(self.create_directory.action_tag(), Box::new(e)))?; .map_err(|e| ActionError::Child(self.create_directory.action_tag(), Box::new(e)))?;
self.create_file self.create_or_merge_nix_config
.try_execute() .try_execute()
.await .await
.map_err(|e| ActionError::Child(self.create_file.action_tag(), Box::new(e)))?; .map_err(|e| {
ActionError::Child(self.create_or_merge_nix_config.action_tag(), Box::new(e))
})?;
Ok(()) Ok(())
} }
@ -105,10 +123,12 @@ impl Action for PlaceNixConfiguration {
#[tracing::instrument(level = "debug", skip_all)] #[tracing::instrument(level = "debug", skip_all)]
async fn revert(&mut self) -> Result<(), ActionError> { async fn revert(&mut self) -> Result<(), ActionError> {
self.create_file self.create_or_merge_nix_config
.try_revert() .try_revert()
.await .await
.map_err(|e| ActionError::Child(self.create_file.action_tag(), Box::new(e)))?; .map_err(|e| {
ActionError::Child(self.create_or_merge_nix_config.action_tag(), Box::new(e))
})?;
self.create_directory self.create_directory
.try_revert() .try_revert()
.await .await

View file

@ -17,7 +17,7 @@
"action": "provision_nix", "action": "provision_nix",
"fetch_nix": { "fetch_nix": {
"action": { "action": {
"url": "https://releases.nixos.org/nix/nix-2.12.0/nix-2.12.0-x86_64-linux.tar.xz", "url": "https://releases.nixos.org/nix/nix-2.13.2/nix-2.13.2-x86_64-linux.tar.xz",
"dest": "/nix/temp-install-dir" "dest": "/nix/temp-install-dir"
}, },
"state": "Uncompleted" "state": "Uncompleted"
@ -788,7 +788,7 @@
"path": "/etc/bashrc", "path": "/etc/bashrc",
"user": null, "user": null,
"group": null, "group": null,
"mode": 493, "mode": 33188,
"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", "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" "position": "Beginning"
}, },
@ -799,7 +799,7 @@
"path": "/etc/profile.d/nix.sh", "path": "/etc/profile.d/nix.sh",
"user": null, "user": null,
"group": null, "group": null,
"mode": 493, "mode": 33188,
"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", "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" "position": "Beginning"
}, },
@ -810,7 +810,7 @@
"path": "/etc/zshenv", "path": "/etc/zshenv",
"user": null, "user": null,
"group": null, "group": null,
"mode": 493, "mode": 33188,
"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", "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" "position": "Beginning"
}, },
@ -821,7 +821,7 @@
"path": "/etc/bash.bashrc", "path": "/etc/bash.bashrc",
"user": null, "user": null,
"group": null, "group": null,
"mode": 493, "mode": 33188,
"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", "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" "position": "Beginning"
}, },
@ -841,7 +841,7 @@
], ],
"create_file": { "create_file": {
"action": { "action": {
"path": "/home/ana/.nix-channels", "path": "/root/.nix-channels",
"user": null, "user": null,
"group": null, "group": null,
"mode": 436, "mode": 436,
@ -865,14 +865,17 @@
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
"create_file": { "create_or_merge_nix_config": {
"action": { "action": {
"path": "/etc/nix/nix.conf", "path": "/etc/nix/nix.conf",
"user": null, "pending_nix_config": {
"group": null, "settings": {
"mode": 436, "bash-prompt-prefix": "(nix:$name)\\040",
"buf": "# Generated by https://github.com/DeterminateSystems/nix-installer, version 0.1.0-unreleased.\n\n\n\nbuild-users-group = nixbld\n\nexperimental-features = nix-command flakes\n\nauto-optimise-store = true\n\nbash-prompt-prefix = (nix:$name)\\040\n", "build-users-group": "nixbld",
"force": false "auto-optimise-store": "true",
"experimental-features": "nix-command flakes"
}
}
}, },
"state": "Uncompleted" "state": "Uncompleted"
} }
@ -906,7 +909,7 @@
"nix_build_group_id": 3000, "nix_build_group_id": 3000,
"nix_build_user_prefix": "nixbld", "nix_build_user_prefix": "nixbld",
"nix_build_user_id_base": 3000, "nix_build_user_id_base": 3000,
"nix_package_url": "https://releases.nixos.org/nix/nix-2.12.0/nix-2.12.0-x86_64-linux.tar.xz", "nix_package_url": "https://releases.nixos.org/nix/nix-2.13.2/nix-2.13.2-x86_64-linux.tar.xz",
"extra_conf": [], "extra_conf": [],
"force": false "force": false
}, },

View file

@ -4,7 +4,7 @@
{ {
"action": { "action": {
"action": "create_directory", "action": "create_directory",
"path": "/nix", "path": "/home/nix",
"user": null, "user": null,
"group": null, "group": null,
"mode": 493, "mode": 493,
@ -12,6 +12,50 @@
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{
"action": {
"action": "create_file",
"path": "/etc/systemd/system/nix-directory.service",
"user": null,
"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
},
"state": "Uncompleted"
},
{
"action": {
"action": "create_file",
"path": "/etc/systemd/system/nix.mount",
"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
},
"state": "Uncompleted"
},
{
"action": {
"action": "create_file",
"path": "/etc/systemd/system/ensure-symlinked-units-resolve.service",
"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
},
"state": "Uncompleted"
},
{
"action": {
"action": "start_systemd_unit",
"unit": "nix.mount",
"enable": false
},
"state": "Uncompleted"
},
{ {
"action": { "action": {
"action": "provision_nix", "action": "provision_nix",
@ -26,13 +70,13 @@
"action": { "action": {
"nix_build_user_count": 32, "nix_build_user_count": 32,
"nix_build_group_name": "nixbld", "nix_build_group_name": "nixbld",
"nix_build_group_id": 3000, "nix_build_group_id": 30000,
"nix_build_user_prefix": "nixbld", "nix_build_user_prefix": "nixbld",
"nix_build_user_id_base": 3000, "nix_build_user_id_base": 30000,
"create_group": { "create_group": {
"action": { "action": {
"name": "nixbld", "name": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
@ -40,288 +84,288 @@
{ {
"action": { "action": {
"name": "nixbld0", "name": "nixbld0",
"uid": 3000, "uid": 30000,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld1", "name": "nixbld1",
"uid": 3001, "uid": 30001,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld2", "name": "nixbld2",
"uid": 3002, "uid": 30002,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld3", "name": "nixbld3",
"uid": 3003, "uid": 30003,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld4", "name": "nixbld4",
"uid": 3004, "uid": 30004,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld5", "name": "nixbld5",
"uid": 3005, "uid": 30005,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld6", "name": "nixbld6",
"uid": 3006, "uid": 30006,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld7", "name": "nixbld7",
"uid": 3007, "uid": 30007,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld8", "name": "nixbld8",
"uid": 3008, "uid": 30008,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld9", "name": "nixbld9",
"uid": 3009, "uid": 30009,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld10", "name": "nixbld10",
"uid": 3010, "uid": 30010,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld11", "name": "nixbld11",
"uid": 3011, "uid": 30011,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld12", "name": "nixbld12",
"uid": 3012, "uid": 30012,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld13", "name": "nixbld13",
"uid": 3013, "uid": 30013,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld14", "name": "nixbld14",
"uid": 3014, "uid": 30014,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld15", "name": "nixbld15",
"uid": 3015, "uid": 30015,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld16", "name": "nixbld16",
"uid": 3016, "uid": 30016,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld17", "name": "nixbld17",
"uid": 3017, "uid": 30017,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld18", "name": "nixbld18",
"uid": 3018, "uid": 30018,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld19", "name": "nixbld19",
"uid": 3019, "uid": 30019,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld20", "name": "nixbld20",
"uid": 3020, "uid": 30020,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld21", "name": "nixbld21",
"uid": 3021, "uid": 30021,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld22", "name": "nixbld22",
"uid": 3022, "uid": 30022,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld23", "name": "nixbld23",
"uid": 3023, "uid": 30023,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld24", "name": "nixbld24",
"uid": 3024, "uid": 30024,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld25", "name": "nixbld25",
"uid": 3025, "uid": 30025,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld26", "name": "nixbld26",
"uid": 3026, "uid": 30026,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld27", "name": "nixbld27",
"uid": 3027, "uid": 30027,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld28", "name": "nixbld28",
"uid": 3028, "uid": 30028,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld29", "name": "nixbld29",
"uid": 3029, "uid": 30029,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld30", "name": "nixbld30",
"uid": 3030, "uid": 30030,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld31", "name": "nixbld31",
"uid": 3031, "uid": 30031,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
} }
@ -330,288 +374,288 @@
{ {
"action": { "action": {
"name": "nixbld0", "name": "nixbld0",
"uid": 3000, "uid": 30000,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld1", "name": "nixbld1",
"uid": 3001, "uid": 30001,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld2", "name": "nixbld2",
"uid": 3002, "uid": 30002,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld3", "name": "nixbld3",
"uid": 3003, "uid": 30003,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld4", "name": "nixbld4",
"uid": 3004, "uid": 30004,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld5", "name": "nixbld5",
"uid": 3005, "uid": 30005,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld6", "name": "nixbld6",
"uid": 3006, "uid": 30006,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld7", "name": "nixbld7",
"uid": 3007, "uid": 30007,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld8", "name": "nixbld8",
"uid": 3008, "uid": 30008,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld9", "name": "nixbld9",
"uid": 3009, "uid": 30009,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld10", "name": "nixbld10",
"uid": 3010, "uid": 30010,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld11", "name": "nixbld11",
"uid": 3011, "uid": 30011,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld12", "name": "nixbld12",
"uid": 3012, "uid": 30012,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld13", "name": "nixbld13",
"uid": 3013, "uid": 30013,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld14", "name": "nixbld14",
"uid": 3014, "uid": 30014,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld15", "name": "nixbld15",
"uid": 3015, "uid": 30015,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld16", "name": "nixbld16",
"uid": 3016, "uid": 30016,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld17", "name": "nixbld17",
"uid": 3017, "uid": 30017,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld18", "name": "nixbld18",
"uid": 3018, "uid": 30018,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld19", "name": "nixbld19",
"uid": 3019, "uid": 30019,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld20", "name": "nixbld20",
"uid": 3020, "uid": 30020,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld21", "name": "nixbld21",
"uid": 3021, "uid": 30021,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld22", "name": "nixbld22",
"uid": 3022, "uid": 30022,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld23", "name": "nixbld23",
"uid": 3023, "uid": 30023,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld24", "name": "nixbld24",
"uid": 3024, "uid": 30024,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld25", "name": "nixbld25",
"uid": 3025, "uid": 30025,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld26", "name": "nixbld26",
"uid": 3026, "uid": 30026,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld27", "name": "nixbld27",
"uid": 3027, "uid": 30027,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld28", "name": "nixbld28",
"uid": 3028, "uid": 30028,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld29", "name": "nixbld29",
"uid": 3029, "uid": 30029,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld30", "name": "nixbld30",
"uid": 3030, "uid": 30030,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
{ {
"action": { "action": {
"name": "nixbld31", "name": "nixbld31",
"uid": 3031, "uid": 30031,
"groupname": "nixbld", "groupname": "nixbld",
"gid": 3000 "gid": 30000
}, },
"state": "Uncompleted" "state": "Uncompleted"
} }
@ -781,18 +825,7 @@
}, },
"configure_shell_profile": { "configure_shell_profile": {
"action": { "action": {
"create_directories": [ "create_directories": [],
{
"action": {
"path": "/etc/fish/conf.d",
"user": null,
"group": null,
"mode": 420,
"force_prune_on_revert": false
},
"state": "Skipped"
}
],
"create_or_insert_into_files": [ "create_or_insert_into_files": [
{ {
"action": { "action": {
@ -837,17 +870,6 @@
"position": "Beginning" "position": "Beginning"
}, },
"state": "Uncompleted" "state": "Uncompleted"
},
{
"action": {
"path": "/etc/fish/conf.d/nix.fish",
"user": null,
"group": null,
"mode": 33188,
"buf": "\n# Nix\nif test -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.fish'\n . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.fish'\nend\n# End Nix\n\n",
"position": "Beginning"
},
"state": "Uncompleted"
} }
] ]
}, },
@ -863,7 +885,7 @@
], ],
"create_file": { "create_file": {
"action": { "action": {
"path": "/home/deck/.nix-channels", "path": "/home/ubuntu/.nix-channels",
"user": null, "user": null,
"group": null, "group": null,
"mode": 436, "mode": 436,
@ -887,14 +909,17 @@
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
"create_file": { "create_or_merge_nix_config": {
"action": { "action": {
"path": "/etc/nix/nix.conf", "path": "/etc/nix/nix.conf",
"user": null, "pending_nix_config": {
"group": null, "settings": {
"mode": 436, "bash-prompt-prefix": "(nix:$name)\\040",
"buf": "# Generated by https://github.com/DeterminateSystems/nix-installer, version 0.3.0.\n\n\n\nbuild-users-group = nixbld\n\nexperimental-features = nix-command flakes\n\nauto-optimise-store = true\n\nbash-prompt-prefix = (nix:$name)\\040\n", "build-users-group": "nixbld",
"force": false "auto-optimise-store": "true",
"experimental-features": "nix-command flakes"
}
}
}, },
"state": "Uncompleted" "state": "Uncompleted"
} }
@ -911,10 +936,19 @@
"start_daemon": true "start_daemon": true
}, },
"state": "Uncompleted" "state": "Uncompleted"
},
{
"action": {
"action": "start_systemd_unit",
"unit": "ensure-symlinked-units-resolve.service",
"enable": true
},
"state": "Uncompleted"
} }
], ],
"planner": { "planner": {
"planner": "linux", "planner": "steam-deck",
"persistence": "/home/nix",
"settings": { "settings": {
"channels": [ "channels": [
[ [
@ -925,16 +959,12 @@
"modify_profile": true, "modify_profile": true,
"nix_build_user_count": 32, "nix_build_user_count": 32,
"nix_build_group_name": "nixbld", "nix_build_group_name": "nixbld",
"nix_build_group_id": 3000, "nix_build_group_id": 30000,
"nix_build_user_prefix": "nixbld", "nix_build_user_prefix": "nixbld",
"nix_build_user_id_base": 3000, "nix_build_user_id_base": 30000,
"nix_package_url": "https://releases.nixos.org/nix/nix-2.13.2/nix-2.13.2-x86_64-linux.tar.xz", "nix_package_url": "https://releases.nixos.org/nix/nix-2.13.2/nix-2.13.2-x86_64-linux.tar.xz",
"extra_conf": [], "extra_conf": [],
"force": false "force": false
},
"init": {
"init": "Systemd",
"start_daemon": true
} }
} }
} }

View file

@ -4,7 +4,7 @@
{ {
"action": { "action": {
"action": "create_apfs_volume", "action": "create_apfs_volume",
"disk": "disk3", "disk": "disk1",
"name": "Nix Store", "name": "Nix Store",
"case_sensitive": false, "case_sensitive": false,
"encrypt": true, "encrypt": true,
@ -25,14 +25,14 @@
}, },
"unmount_volume": { "unmount_volume": {
"action": { "action": {
"disk": "disk3", "disk": "disk1",
"name": "Nix Store" "name": "Nix Store"
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
"create_volume": { "create_volume": {
"action": { "action": {
"disk": "disk3", "disk": "disk1",
"name": "Nix Store", "name": "Nix Store",
"case_sensitive": false "case_sensitive": false
}, },
@ -46,7 +46,7 @@
}, },
"encrypt_volume": { "encrypt_volume": {
"action": { "action": {
"disk": "disk3", "disk": "disk1",
"name": "Nix Store" "name": "Nix Store"
}, },
"state": "Uncompleted" "state": "Uncompleted"
@ -82,7 +82,7 @@
"action": "provision_nix", "action": "provision_nix",
"fetch_nix": { "fetch_nix": {
"action": { "action": {
"url": "https://releases.nixos.org/nix/nix-2.13.2/nix-2.13.2-aarch64-darwin.tar.xz", "url": "https://releases.nixos.org/nix/nix-2.13.2/nix-2.13.2-x86_64-darwin.tar.xz",
"dest": "/nix/temp-install-dir" "dest": "/nix/temp-install-dir"
}, },
"state": "Uncompleted" "state": "Uncompleted"
@ -919,14 +919,17 @@
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },
"create_file": { "create_or_merge_nix_config": {
"action": { "action": {
"path": "/etc/nix/nix.conf", "path": "/etc/nix/nix.conf",
"user": null, "pending_nix_config": {
"group": null, "settings": {
"mode": 436, "bash-prompt-prefix": "(nix:$name)\\040",
"buf": "# Generated by https://github.com/DeterminateSystems/nix-installer, version 0.3.0.\n\n\n\nbuild-users-group = nixbld\n\nexperimental-features = nix-command flakes\n\nauto-optimise-store = true\n\nbash-prompt-prefix = (nix:$name)\\040\n", "auto-optimise-store": "true",
"force": false "build-users-group": "nixbld",
"experimental-features": "nix-command flakes"
}
}
}, },
"state": "Uncompleted" "state": "Uncompleted"
} }
@ -960,13 +963,13 @@
"nix_build_group_id": 3000, "nix_build_group_id": 3000,
"nix_build_user_prefix": "_nixbld", "nix_build_user_prefix": "_nixbld",
"nix_build_user_id_base": 300, "nix_build_user_id_base": 300,
"nix_package_url": "https://releases.nixos.org/nix/nix-2.13.2/nix-2.13.2-aarch64-darwin.tar.xz", "nix_package_url": "https://releases.nixos.org/nix/nix-2.13.2/nix-2.13.2-x86_64-darwin.tar.xz",
"extra_conf": [], "extra_conf": [],
"force": false "force": false
}, },
"encrypt": null, "encrypt": null,
"case_sensitive": false, "case_sensitive": false,
"volume_label": "Nix Store", "volume_label": "Nix Store",
"root_disk": "disk3" "root_disk": "disk1"
} }
} }