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,
} = self;
let mut explanation = vec![
"This file is read by the Nix daemon to set its configuration options at runtime." "This file is read by the Nix daemon to set its configuration options at runtime."
.to_string(), .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"
} }
} }