forked from lix-project/lix-installer
Linus/ds 576 nix store should be in path directly (#148)
* CreateOrAppendFile: setuid safety * Apply a sensible default mode if the file didn't already exist * remove some incorrect docs * Implement CreateOrInsertFile and use it instead of Append for shell rcs Ubuntu's bashrc has the following lines in it: # If not running interactively, don't do anything [ -z "$PS1" ] && return This means that anything appended to the file will only take effect in interactive sessions. However, we want noninteractive shells to have Nix on PATH too, e.g. for remote builds. Therefore, we need to add our snippet to the beginning of the file, not the end. * Adjust test fixtures to match new behaviour * interaction: indicate default for confirm correctly * CreateOrInsertFile: use randomised temporary filename * Fix temp file creation * Apply permissions to temp file, not final file The final file may not exist, and the temporary file is the one whose permissions will actually be preserved. * Use the right ActionError for renaming * Test the SSH behaviour properly * cargo fmt * [DS-574] Write to zshenv instead of zshrc * CreateOrInsertFile -> CreateOrInsertIntoFile Also move appending behaviour in here. * Update Linux fixtures * update darwin-multi fixture * fix fixture * fmt
This commit is contained in:
parent
d410728461
commit
f2606d3127
|
@ -185,12 +185,6 @@ let
|
||||||
$ssh <<EOF
|
$ssh <<EOF
|
||||||
set -ex
|
set -ex
|
||||||
|
|
||||||
# FIXME: get rid of this; ideally ssh should just work.
|
|
||||||
source ~/.bash_profile || true
|
|
||||||
source ~/.bash_login || true
|
|
||||||
source ~/.profile || true
|
|
||||||
source /etc/bashrc || true
|
|
||||||
|
|
||||||
nix-env --version
|
nix-env --version
|
||||||
nix --extra-experimental-features nix-command store ping
|
nix --extra-experimental-features nix-command store ping
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use nix::unistd::{chown, Group, User};
|
use nix::unistd::{chown, Group, User};
|
||||||
|
|
||||||
use crate::action::{Action, ActionDescription, ActionError, StatefulAction};
|
use crate::action::{Action, ActionDescription, ActionError, StatefulAction};
|
||||||
|
use rand::Rng;
|
||||||
use std::{
|
use std::{
|
||||||
io::SeekFrom,
|
io::SeekFrom,
|
||||||
os::unix::prelude::PermissionsExt,
|
os::unix::prelude::PermissionsExt,
|
||||||
|
@ -12,24 +13,29 @@ use tokio::{
|
||||||
};
|
};
|
||||||
use tracing::{span, Span};
|
use tracing::{span, Span};
|
||||||
|
|
||||||
/** Create a file at the given location with the provided `buf`,
|
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone, PartialEq, Eq)]
|
||||||
optionally with an owning user, group, and mode.
|
pub enum Position {
|
||||||
|
Beginning,
|
||||||
|
End,
|
||||||
|
}
|
||||||
|
|
||||||
If the file exists, the provided `buf` will be appended.
|
/** Create a file at the given location with the provided `buf` as
|
||||||
|
contents, optionally with an owning user, group, and mode.
|
||||||
|
|
||||||
If `force` is set, the file will always be overwritten (and deleted)
|
If the file exists, the provided `buf` will be inserted at its
|
||||||
regardless of its presence prior to install.
|
beginning or end, depending on the position field.
|
||||||
*/
|
*/
|
||||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||||
pub struct CreateOrAppendFile {
|
pub struct CreateOrInsertIntoFile {
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
user: Option<String>,
|
user: Option<String>,
|
||||||
group: Option<String>,
|
group: Option<String>,
|
||||||
mode: Option<u32>,
|
mode: Option<u32>,
|
||||||
buf: String,
|
buf: String,
|
||||||
|
position: Position,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CreateOrAppendFile {
|
impl CreateOrInsertIntoFile {
|
||||||
#[tracing::instrument(level = "debug", skip_all)]
|
#[tracing::instrument(level = "debug", skip_all)]
|
||||||
pub async fn plan(
|
pub async fn plan(
|
||||||
path: impl AsRef<Path>,
|
path: impl AsRef<Path>,
|
||||||
|
@ -37,6 +43,7 @@ impl CreateOrAppendFile {
|
||||||
group: impl Into<Option<String>>,
|
group: impl Into<Option<String>>,
|
||||||
mode: impl Into<Option<u32>>,
|
mode: impl Into<Option<u32>>,
|
||||||
buf: String,
|
buf: String,
|
||||||
|
position: Position,
|
||||||
) -> Result<StatefulAction<Self>, ActionError> {
|
) -> Result<StatefulAction<Self>, ActionError> {
|
||||||
let path = path.as_ref().to_path_buf();
|
let path = path.as_ref().to_path_buf();
|
||||||
|
|
||||||
|
@ -46,22 +53,23 @@ impl CreateOrAppendFile {
|
||||||
group: group.into(),
|
group: group.into(),
|
||||||
mode: mode.into(),
|
mode: mode.into(),
|
||||||
buf,
|
buf,
|
||||||
|
position,
|
||||||
}
|
}
|
||||||
.into())
|
.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
#[typetag::serde(name = "create_or_append_file")]
|
#[typetag::serde(name = "create_or_insert_into_file")]
|
||||||
impl Action for CreateOrAppendFile {
|
impl Action for CreateOrInsertIntoFile {
|
||||||
fn tracing_synopsis(&self) -> String {
|
fn tracing_synopsis(&self) -> String {
|
||||||
format!("Create or append file `{}`", self.path.display())
|
format!("Create or insert file `{}`", self.path.display())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tracing_span(&self) -> Span {
|
fn tracing_span(&self) -> Span {
|
||||||
let span = span!(
|
let span = span!(
|
||||||
tracing::Level::DEBUG,
|
tracing::Level::DEBUG,
|
||||||
"create_or_append_file",
|
"create_or_insert_file",
|
||||||
path = tracing::field::display(self.path.display()),
|
path = tracing::field::display(self.path.display()),
|
||||||
user = self.user,
|
user = self.user,
|
||||||
group = self.group,
|
group = self.group,
|
||||||
|
@ -89,23 +97,63 @@ impl Action for CreateOrAppendFile {
|
||||||
group,
|
group,
|
||||||
mode,
|
mode,
|
||||||
buf,
|
buf,
|
||||||
|
position,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let mut file = OpenOptions::new()
|
let mut orig_file = match OpenOptions::new().read(true).open(&path).await {
|
||||||
|
Ok(f) => Some(f),
|
||||||
|
Err(e) if e.kind() == std::io::ErrorKind::NotFound => None,
|
||||||
|
Err(e) => return Err(ActionError::Open(path.to_owned(), e)),
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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)
|
.create(true)
|
||||||
.write(true)
|
.write(true)
|
||||||
.read(true)
|
// If the file is created, ensure that it has harmless
|
||||||
.open(&path)
|
// 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
|
.await
|
||||||
.map_err(|e| ActionError::Open(path.to_owned(), e))?;
|
.map_err(|e| {
|
||||||
|
ActionError::Open(temp_file_path.clone(), e)
|
||||||
|
})?;
|
||||||
|
|
||||||
file.seek(SeekFrom::End(0))
|
if *position == Position::End {
|
||||||
|
if let Some(ref mut orig_file) = orig_file {
|
||||||
|
tokio::io::copy(orig_file, &mut temp_file)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| ActionError::Seek(path.to_owned(), e))?;
|
.map_err(|e| {
|
||||||
|
ActionError::Copy(path.to_owned(), temp_file_path.to_owned(), e)
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
file.write_all(buf.as_bytes())
|
temp_file
|
||||||
|
.write_all(buf.as_bytes())
|
||||||
.await
|
.await
|
||||||
.map_err(|e| ActionError::Write(path.to_owned(), e))?;
|
.map_err(|e| ActionError::Write(temp_file_path.clone(), e))?;
|
||||||
|
|
||||||
|
if *position == Position::Beginning {
|
||||||
|
if let Some(ref mut orig_file) = orig_file {
|
||||||
|
tokio::io::copy(orig_file, &mut temp_file)
|
||||||
|
.await
|
||||||
|
.map_err(|e| {
|
||||||
|
ActionError::Copy(path.to_owned(), temp_file_path.to_owned(), e)
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let gid = if let Some(group) = group {
|
let gid = if let Some(group) = group {
|
||||||
Some(
|
Some(
|
||||||
|
@ -128,13 +176,24 @@ impl Action for CreateOrAppendFile {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Change ownership _before_ applying mode, to ensure that if
|
||||||
|
// a file needs to be setuid it will never be setuid for the
|
||||||
|
// wrong user
|
||||||
|
chown(&temp_file_path, uid, gid).map_err(|e| ActionError::Chown(path.clone(), e))?;
|
||||||
|
|
||||||
if let Some(mode) = mode {
|
if let Some(mode) = mode {
|
||||||
tokio::fs::set_permissions(&path, PermissionsExt::from_mode(*mode))
|
tokio::fs::set_permissions(&temp_file_path, PermissionsExt::from_mode(*mode))
|
||||||
.await
|
.await
|
||||||
.map_err(|e| ActionError::SetPermissions(*mode, path.to_owned(), e))?;
|
.map_err(|e| ActionError::SetPermissions(*mode, path.to_owned(), e))?;
|
||||||
|
} else if orig_file.is_some() {
|
||||||
|
tokio::fs::set_permissions(&temp_file_path, PermissionsExt::from_mode(0o644))
|
||||||
|
.await
|
||||||
|
.map_err(|e| ActionError::SetPermissions(0o644, path.to_owned(), e))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
chown(path, uid, gid).map_err(|e| ActionError::Chown(path.clone(), e))?;
|
tokio::fs::rename(&temp_file_path, &path)
|
||||||
|
.await
|
||||||
|
.map_err(|e| ActionError::Rename(path.to_owned(), temp_file_path.to_owned(), e))?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -146,6 +205,7 @@ impl Action for CreateOrAppendFile {
|
||||||
group: _,
|
group: _,
|
||||||
mode: _,
|
mode: _,
|
||||||
buf,
|
buf,
|
||||||
|
position: _,
|
||||||
} = &self;
|
} = &self;
|
||||||
vec![ActionDescription::new(
|
vec![ActionDescription::new(
|
||||||
format!("Delete Nix related fragment from file `{}`", path.display()),
|
format!("Delete Nix related fragment from file `{}`", path.display()),
|
||||||
|
@ -164,6 +224,7 @@ impl Action for CreateOrAppendFile {
|
||||||
group: _,
|
group: _,
|
||||||
mode: _,
|
mode: _,
|
||||||
buf,
|
buf,
|
||||||
|
position: _,
|
||||||
} = self;
|
} = self;
|
||||||
let mut file = OpenOptions::new()
|
let mut file = OpenOptions::new()
|
||||||
.create(false)
|
.create(false)
|
||||||
|
@ -171,12 +232,12 @@ impl Action for CreateOrAppendFile {
|
||||||
.read(true)
|
.read(true)
|
||||||
.open(&path)
|
.open(&path)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| ActionError::Read(path.to_owned(), e))?;
|
.map_err(|e| ActionError::Open(path.to_owned(), e))?;
|
||||||
|
|
||||||
let mut file_contents = String::default();
|
let mut file_contents = String::default();
|
||||||
file.read_to_string(&mut file_contents)
|
file.read_to_string(&mut file_contents)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| ActionError::Seek(path.to_owned(), e))?;
|
.map_err(|e| ActionError::Read(path.to_owned(), e))?;
|
||||||
|
|
||||||
if let Some(start) = file_contents.rfind(buf.as_str()) {
|
if let Some(start) = file_contents.rfind(buf.as_str()) {
|
||||||
let end = start + buf.len();
|
let end = start + buf.len();
|
|
@ -3,7 +3,7 @@
|
||||||
pub(crate) mod create_directory;
|
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_append_file;
|
pub(crate) mod create_or_insert_into_file;
|
||||||
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;
|
||||||
|
@ -12,7 +12,7 @@ pub(crate) mod setup_default_profile;
|
||||||
pub use create_directory::CreateDirectory;
|
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_append_file::CreateOrAppendFile;
|
pub use create_or_insert_into_file::CreateOrInsertIntoFile;
|
||||||
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};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::action::base::{CreateDirectory, CreateOrAppendFile};
|
use crate::action::base::{create_or_insert_into_file, CreateDirectory, CreateOrInsertIntoFile};
|
||||||
use crate::action::{Action, ActionDescription, ActionError, StatefulAction};
|
use crate::action::{Action, ActionDescription, ActionError, StatefulAction};
|
||||||
|
|
||||||
use nix::unistd::User;
|
use nix::unistd::User;
|
||||||
|
@ -23,9 +23,9 @@ const PROFILE_FISH_PREFIXES: &[&str] = &[
|
||||||
const PROFILE_TARGETS: &[&str] = &[
|
const PROFILE_TARGETS: &[&str] = &[
|
||||||
"/etc/bashrc",
|
"/etc/bashrc",
|
||||||
"/etc/profile.d/nix.sh",
|
"/etc/profile.d/nix.sh",
|
||||||
"/etc/zshrc",
|
"/etc/zshenv",
|
||||||
"/etc/bash.bashrc",
|
"/etc/bash.bashrc",
|
||||||
"/etc/zsh/zshrc",
|
"/etc/zsh/zshenv",
|
||||||
];
|
];
|
||||||
const PROFILE_NIX_FILE_SHELL: &str = "/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh";
|
const PROFILE_NIX_FILE_SHELL: &str = "/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh";
|
||||||
const PROFILE_NIX_FILE_FISH: &str = "/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.fish";
|
const PROFILE_NIX_FILE_FISH: &str = "/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.fish";
|
||||||
|
@ -36,13 +36,13 @@ Configure any detected shell profiles to include Nix support
|
||||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||||
pub struct ConfigureShellProfile {
|
pub struct ConfigureShellProfile {
|
||||||
create_directories: Vec<StatefulAction<CreateDirectory>>,
|
create_directories: Vec<StatefulAction<CreateDirectory>>,
|
||||||
create_or_append_files: Vec<StatefulAction<CreateOrAppendFile>>,
|
create_or_insert_into_files: Vec<StatefulAction<CreateOrInsertIntoFile>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConfigureShellProfile {
|
impl ConfigureShellProfile {
|
||||||
#[tracing::instrument(level = "debug", skip_all)]
|
#[tracing::instrument(level = "debug", skip_all)]
|
||||||
pub async fn plan() -> Result<StatefulAction<Self>, ActionError> {
|
pub async fn plan() -> Result<StatefulAction<Self>, ActionError> {
|
||||||
let mut create_or_append_files = Vec::default();
|
let mut create_or_insert_files = Vec::default();
|
||||||
let mut create_directories = Vec::default();
|
let mut create_directories = Vec::default();
|
||||||
|
|
||||||
let shell_buf = format!(
|
let shell_buf = format!(
|
||||||
|
@ -61,17 +61,18 @@ impl ConfigureShellProfile {
|
||||||
if let Some(parent) = profile_target_path.parent() {
|
if let Some(parent) = profile_target_path.parent() {
|
||||||
if !parent.exists() {
|
if !parent.exists() {
|
||||||
tracing::trace!(
|
tracing::trace!(
|
||||||
"Did not plan to edit `{profile_target}` as it's parent folder does not exist."
|
"Did not plan to edit `{profile_target}` as its parent folder does not exist."
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
create_or_append_files.push(
|
create_or_insert_files.push(
|
||||||
CreateOrAppendFile::plan(
|
CreateOrInsertIntoFile::plan(
|
||||||
profile_target_path,
|
profile_target_path,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
0o0755,
|
0o0755,
|
||||||
shell_buf.to_string(),
|
shell_buf.to_string(),
|
||||||
|
create_or_insert_into_file::Position::Beginning,
|
||||||
)
|
)
|
||||||
.await?,
|
.await?,
|
||||||
);
|
);
|
||||||
|
@ -106,8 +107,15 @@ impl ConfigureShellProfile {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
create_or_append_files.push(
|
create_or_insert_files.push(
|
||||||
CreateOrAppendFile::plan(profile_target, None, None, 0o0755, fish_buf.to_string())
|
CreateOrInsertIntoFile::plan(
|
||||||
|
profile_target,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
0o0755,
|
||||||
|
fish_buf.to_string(),
|
||||||
|
create_or_insert_into_file::Position::Beginning,
|
||||||
|
)
|
||||||
.await?,
|
.await?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -123,13 +131,22 @@ impl ConfigureShellProfile {
|
||||||
runner.name
|
runner.name
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
create_or_append_files
|
create_or_insert_files.push(
|
||||||
.push(CreateOrAppendFile::plan(&github_path, None, None, None, buf).await?)
|
CreateOrInsertIntoFile::plan(
|
||||||
|
&github_path,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
buf,
|
||||||
|
create_or_insert_into_file::Position::End,
|
||||||
|
)
|
||||||
|
.await?,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
create_directories,
|
create_directories,
|
||||||
create_or_append_files,
|
create_or_insert_into_files: create_or_insert_files,
|
||||||
}
|
}
|
||||||
.into())
|
.into())
|
||||||
}
|
}
|
||||||
|
@ -156,7 +173,7 @@ impl Action for ConfigureShellProfile {
|
||||||
#[tracing::instrument(level = "debug", skip_all)]
|
#[tracing::instrument(level = "debug", skip_all)]
|
||||||
async fn execute(&mut self) -> Result<(), ActionError> {
|
async fn execute(&mut self) -> Result<(), ActionError> {
|
||||||
let Self {
|
let Self {
|
||||||
create_or_append_files,
|
create_or_insert_into_files,
|
||||||
create_directories,
|
create_directories,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
|
@ -167,22 +184,22 @@ impl Action for ConfigureShellProfile {
|
||||||
let mut set = JoinSet::new();
|
let mut set = JoinSet::new();
|
||||||
let mut errors = Vec::default();
|
let mut errors = Vec::default();
|
||||||
|
|
||||||
for (idx, create_or_append_file) in create_or_append_files.iter().enumerate() {
|
for (idx, create_or_insert_into_file) in create_or_insert_into_files.iter().enumerate() {
|
||||||
let span = tracing::Span::current().clone();
|
let span = tracing::Span::current().clone();
|
||||||
let mut create_or_append_file_clone = create_or_append_file.clone();
|
let mut create_or_insert_into_file_clone = create_or_insert_into_file.clone();
|
||||||
let _abort_handle = set.spawn(async move {
|
let _abort_handle = set.spawn(async move {
|
||||||
create_or_append_file_clone
|
create_or_insert_into_file_clone
|
||||||
.try_execute()
|
.try_execute()
|
||||||
.instrument(span)
|
.instrument(span)
|
||||||
.await?;
|
.await?;
|
||||||
Result::<_, ActionError>::Ok((idx, create_or_append_file_clone))
|
Result::<_, ActionError>::Ok((idx, create_or_insert_into_file_clone))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
while let Some(result) = set.join_next().await {
|
while let Some(result) = set.join_next().await {
|
||||||
match result {
|
match result {
|
||||||
Ok(Ok((idx, create_or_append_file))) => {
|
Ok(Ok((idx, create_or_insert_into_file))) => {
|
||||||
create_or_append_files[idx] = create_or_append_file
|
create_or_insert_into_files[idx] = create_or_insert_into_file
|
||||||
},
|
},
|
||||||
Ok(Err(e)) => errors.push(Box::new(e)),
|
Ok(Err(e)) => errors.push(Box::new(e)),
|
||||||
Err(e) => return Err(e.into()),
|
Err(e) => return Err(e.into()),
|
||||||
|
@ -211,24 +228,24 @@ impl Action for ConfigureShellProfile {
|
||||||
async fn revert(&mut self) -> Result<(), ActionError> {
|
async fn revert(&mut self) -> Result<(), ActionError> {
|
||||||
let Self {
|
let Self {
|
||||||
create_directories,
|
create_directories,
|
||||||
create_or_append_files,
|
create_or_insert_into_files,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let mut set = JoinSet::new();
|
let mut set = JoinSet::new();
|
||||||
let mut errors: Vec<Box<ActionError>> = Vec::default();
|
let mut errors: Vec<Box<ActionError>> = Vec::default();
|
||||||
|
|
||||||
for (idx, create_or_append_file) in create_or_append_files.iter().enumerate() {
|
for (idx, create_or_insert_into_file) in create_or_insert_into_files.iter().enumerate() {
|
||||||
let mut create_or_append_file_clone = create_or_append_file.clone();
|
let mut create_or_insert_file_clone = create_or_insert_into_file.clone();
|
||||||
let _abort_handle = set.spawn(async move {
|
let _abort_handle = set.spawn(async move {
|
||||||
create_or_append_file_clone.try_revert().await?;
|
create_or_insert_file_clone.try_revert().await?;
|
||||||
Result::<_, _>::Ok((idx, create_or_append_file_clone))
|
Result::<_, _>::Ok((idx, create_or_insert_file_clone))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
while let Some(result) = set.join_next().await {
|
while let Some(result) = set.join_next().await {
|
||||||
match result {
|
match result {
|
||||||
Ok(Ok((idx, create_or_append_file))) => {
|
Ok(Ok((idx, create_or_insert_into_file))) => {
|
||||||
create_or_append_files[idx] = create_or_append_file
|
create_or_insert_into_files[idx] = create_or_insert_into_file
|
||||||
},
|
},
|
||||||
Ok(Err(e)) => errors.push(Box::new(e)),
|
Ok(Err(e)) => errors.push(Box::new(e)),
|
||||||
Err(e) => return Err(e.into()),
|
Err(e) => return Err(e.into()),
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::action::{
|
use crate::action::{
|
||||||
base::{CreateFile, CreateOrAppendFile},
|
base::{create_or_insert_into_file, CreateFile, CreateOrInsertIntoFile},
|
||||||
darwin::{
|
darwin::{
|
||||||
BootstrapApfsVolume, CreateApfsVolume, CreateSyntheticObjects, EnableOwnership,
|
BootstrapApfsVolume, CreateApfsVolume, CreateSyntheticObjects, EnableOwnership,
|
||||||
EncryptApfsVolume, UnmountApfsVolume,
|
EncryptApfsVolume, UnmountApfsVolume,
|
||||||
|
@ -22,11 +22,11 @@ pub struct CreateNixVolume {
|
||||||
name: String,
|
name: String,
|
||||||
case_sensitive: bool,
|
case_sensitive: bool,
|
||||||
encrypt: bool,
|
encrypt: bool,
|
||||||
create_or_append_synthetic_conf: StatefulAction<CreateOrAppendFile>,
|
create_or_append_synthetic_conf: StatefulAction<CreateOrInsertIntoFile>,
|
||||||
create_synthetic_objects: StatefulAction<CreateSyntheticObjects>,
|
create_synthetic_objects: StatefulAction<CreateSyntheticObjects>,
|
||||||
unmount_volume: StatefulAction<UnmountApfsVolume>,
|
unmount_volume: StatefulAction<UnmountApfsVolume>,
|
||||||
create_volume: StatefulAction<CreateApfsVolume>,
|
create_volume: StatefulAction<CreateApfsVolume>,
|
||||||
create_or_append_fstab: StatefulAction<CreateOrAppendFile>,
|
create_or_append_fstab: StatefulAction<CreateOrInsertIntoFile>,
|
||||||
encrypt_volume: Option<StatefulAction<EncryptApfsVolume>>,
|
encrypt_volume: Option<StatefulAction<EncryptApfsVolume>>,
|
||||||
setup_volume_daemon: StatefulAction<CreateFile>,
|
setup_volume_daemon: StatefulAction<CreateFile>,
|
||||||
bootstrap_volume: StatefulAction<BootstrapApfsVolume>,
|
bootstrap_volume: StatefulAction<BootstrapApfsVolume>,
|
||||||
|
@ -42,12 +42,13 @@ impl CreateNixVolume {
|
||||||
encrypt: bool,
|
encrypt: bool,
|
||||||
) -> Result<StatefulAction<Self>, ActionError> {
|
) -> Result<StatefulAction<Self>, ActionError> {
|
||||||
let disk = disk.as_ref();
|
let disk = disk.as_ref();
|
||||||
let create_or_append_synthetic_conf = CreateOrAppendFile::plan(
|
let create_or_append_synthetic_conf = CreateOrInsertIntoFile::plan(
|
||||||
"/etc/synthetic.conf",
|
"/etc/synthetic.conf",
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
0o0655,
|
0o0655,
|
||||||
"nix\n".into(), /* The newline is required otherwise it segfaults */
|
"nix\n".into(), /* The newline is required otherwise it segfaults */
|
||||||
|
create_or_insert_into_file::Position::End,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| ActionError::Child(Box::new(e)))?;
|
.map_err(|e| ActionError::Child(Box::new(e)))?;
|
||||||
|
@ -58,12 +59,13 @@ impl CreateNixVolume {
|
||||||
|
|
||||||
let create_volume = CreateApfsVolume::plan(disk, name.clone(), case_sensitive).await?;
|
let create_volume = CreateApfsVolume::plan(disk, name.clone(), case_sensitive).await?;
|
||||||
|
|
||||||
let create_or_append_fstab = CreateOrAppendFile::plan(
|
let create_or_append_fstab = CreateOrInsertIntoFile::plan(
|
||||||
"/etc/fstab",
|
"/etc/fstab",
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
0o0655,
|
0o0655,
|
||||||
format!("NAME=\"{name}\" /nix apfs rw,noauto,nobrowse,suid,owners"),
|
format!("NAME=\"{name}\" /nix apfs rw,noauto,nobrowse,suid,owners"),
|
||||||
|
create_or_insert_into_file::Position::End,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| ActionError::Child(Box::new(e)))?;
|
.map_err(|e| ActionError::Child(Box::new(e)))?;
|
||||||
|
|
|
@ -19,8 +19,8 @@ pub(crate) async fn confirm(question: impl AsRef<str>, default: bool) -> eyre::R
|
||||||
",
|
",
|
||||||
question = question.as_ref(),
|
question = question.as_ref(),
|
||||||
are_you_sure = "Proceed?".bold(),
|
are_you_sure = "Proceed?".bold(),
|
||||||
no = "N".red().bold(),
|
no = if default { "n" } else { "N" }.red(),
|
||||||
yes = "y".green(),
|
yes = if default { "Y" } else { "y" }.green(),
|
||||||
);
|
);
|
||||||
|
|
||||||
term.write_all(with_confirm.as_bytes())?;
|
term.write_all(with_confirm.as_bytes())?;
|
||||||
|
|
33
tests/fixtures/darwin/darwin-multi.json
vendored
33
tests/fixtures/darwin/darwin-multi.json
vendored
|
@ -4,7 +4,7 @@
|
||||||
{
|
{
|
||||||
"action": {
|
"action": {
|
||||||
"action": "create_apfs_volume",
|
"action": "create_apfs_volume",
|
||||||
"disk": "disk1",
|
"disk": "disk3",
|
||||||
"name": "Nix Store",
|
"name": "Nix Store",
|
||||||
"case_sensitive": false,
|
"case_sensitive": false,
|
||||||
"encrypt": true,
|
"encrypt": true,
|
||||||
|
@ -14,7 +14,8 @@
|
||||||
"user": null,
|
"user": null,
|
||||||
"group": null,
|
"group": null,
|
||||||
"mode": 429,
|
"mode": 429,
|
||||||
"buf": "nix\n"
|
"buf": "nix\n",
|
||||||
|
"position": "End"
|
||||||
},
|
},
|
||||||
"state": "Uncompleted"
|
"state": "Uncompleted"
|
||||||
},
|
},
|
||||||
|
@ -24,14 +25,14 @@
|
||||||
},
|
},
|
||||||
"unmount_volume": {
|
"unmount_volume": {
|
||||||
"action": {
|
"action": {
|
||||||
"disk": "disk1",
|
"disk": "disk3",
|
||||||
"name": "Nix Store"
|
"name": "Nix Store"
|
||||||
},
|
},
|
||||||
"state": "Uncompleted"
|
"state": "Uncompleted"
|
||||||
},
|
},
|
||||||
"create_volume": {
|
"create_volume": {
|
||||||
"action": {
|
"action": {
|
||||||
"disk": "disk1",
|
"disk": "disk3",
|
||||||
"name": "Nix Store",
|
"name": "Nix Store",
|
||||||
"case_sensitive": false
|
"case_sensitive": false
|
||||||
},
|
},
|
||||||
|
@ -43,13 +44,14 @@
|
||||||
"user": null,
|
"user": null,
|
||||||
"group": null,
|
"group": null,
|
||||||
"mode": 429,
|
"mode": 429,
|
||||||
"buf": "NAME=\"Nix Store\" /nix apfs rw,noauto,nobrowse,suid,owners"
|
"buf": "NAME=\"Nix Store\" /nix apfs rw,noauto,nobrowse,suid,owners",
|
||||||
|
"position": "End"
|
||||||
},
|
},
|
||||||
"state": "Uncompleted"
|
"state": "Uncompleted"
|
||||||
},
|
},
|
||||||
"encrypt_volume": {
|
"encrypt_volume": {
|
||||||
"action": {
|
"action": {
|
||||||
"disk": "disk1",
|
"disk": "disk3",
|
||||||
"name": "Nix Store"
|
"name": "Nix Store"
|
||||||
},
|
},
|
||||||
"state": "Uncompleted"
|
"state": "Uncompleted"
|
||||||
|
@ -85,7 +87,7 @@
|
||||||
"action": "provision_nix",
|
"action": "provision_nix",
|
||||||
"fetch_nix": {
|
"fetch_nix": {
|
||||||
"action": {
|
"action": {
|
||||||
"url": "https://releases.nixos.org/nix/nix-2.11.1/nix-2.11.1-x86_64-darwin.tar.xz",
|
"url": "https://releases.nixos.org/nix/nix-2.12.0/nix-2.12.0-aarch64-darwin.tar.xz",
|
||||||
"dest": "/nix/temp-install-dir"
|
"dest": "/nix/temp-install-dir"
|
||||||
},
|
},
|
||||||
"state": "Uncompleted"
|
"state": "Uncompleted"
|
||||||
|
@ -557,24 +559,26 @@
|
||||||
"configure_shell_profile": {
|
"configure_shell_profile": {
|
||||||
"action": {
|
"action": {
|
||||||
"create_directories": [],
|
"create_directories": [],
|
||||||
"create_or_append_files": [
|
"create_or_insert_into_files": [
|
||||||
{
|
{
|
||||||
"action": {
|
"action": {
|
||||||
"path": "/etc/bashrc",
|
"path": "/etc/bashrc",
|
||||||
"user": null,
|
"user": null,
|
||||||
"group": null,
|
"group": null,
|
||||||
"mode": 493,
|
"mode": 493,
|
||||||
"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"
|
||||||
},
|
},
|
||||||
"state": "Uncompleted"
|
"state": "Uncompleted"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"action": {
|
"action": {
|
||||||
"path": "/etc/zshrc",
|
"path": "/etc/zshenv",
|
||||||
"user": null,
|
"user": null,
|
||||||
"group": null,
|
"group": null,
|
||||||
"mode": 493,
|
"mode": 493,
|
||||||
"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"
|
||||||
},
|
},
|
||||||
"state": "Uncompleted"
|
"state": "Uncompleted"
|
||||||
},
|
},
|
||||||
|
@ -584,7 +588,8 @@
|
||||||
"user": null,
|
"user": null,
|
||||||
"group": null,
|
"group": null,
|
||||||
"mode": 493,
|
"mode": 493,
|
||||||
"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"
|
||||||
},
|
},
|
||||||
"state": "Uncompleted"
|
"state": "Uncompleted"
|
||||||
}
|
}
|
||||||
|
@ -670,13 +675,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.11.1/nix-2.11.1-x86_64-darwin.tar.xz",
|
"nix_package_url": "https://releases.nixos.org/nix/nix-2.12.0/nix-2.12.0-aarch64-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": "disk1"
|
"root_disk": "disk3"
|
||||||
}
|
}
|
||||||
}
|
}
|
29
tests/fixtures/linux/linux-multi.json
vendored
29
tests/fixtures/linux/linux-multi.json
vendored
|
@ -10,14 +10,14 @@
|
||||||
"mode": 493,
|
"mode": 493,
|
||||||
"force_prune_on_revert": true
|
"force_prune_on_revert": true
|
||||||
},
|
},
|
||||||
"state": "Uncompleted"
|
"state": "Skipped"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"action": {
|
"action": {
|
||||||
"action": "provision_nix",
|
"action": "provision_nix",
|
||||||
"fetch_nix": {
|
"fetch_nix": {
|
||||||
"action": {
|
"action": {
|
||||||
"url": "https://releases.nixos.org/nix/nix-2.11.1/nix-2.11.1-x86_64-linux.tar.xz",
|
"url": "https://releases.nixos.org/nix/nix-2.12.0/nix-2.12.0-x86_64-linux.tar.xz",
|
||||||
"dest": "/nix/temp-install-dir"
|
"dest": "/nix/temp-install-dir"
|
||||||
},
|
},
|
||||||
"state": "Uncompleted"
|
"state": "Uncompleted"
|
||||||
|
@ -489,14 +489,15 @@
|
||||||
"configure_shell_profile": {
|
"configure_shell_profile": {
|
||||||
"action": {
|
"action": {
|
||||||
"create_directories": [],
|
"create_directories": [],
|
||||||
"create_or_append_files": [
|
"create_or_insert_into_files": [
|
||||||
{
|
{
|
||||||
"action": {
|
"action": {
|
||||||
"path": "/etc/bashrc",
|
"path": "/etc/bashrc",
|
||||||
"user": null,
|
"user": null,
|
||||||
"group": null,
|
"group": null,
|
||||||
"mode": 493,
|
"mode": 493,
|
||||||
"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"
|
||||||
},
|
},
|
||||||
"state": "Uncompleted"
|
"state": "Uncompleted"
|
||||||
},
|
},
|
||||||
|
@ -506,17 +507,19 @@
|
||||||
"user": null,
|
"user": null,
|
||||||
"group": null,
|
"group": null,
|
||||||
"mode": 493,
|
"mode": 493,
|
||||||
"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"
|
||||||
},
|
},
|
||||||
"state": "Uncompleted"
|
"state": "Uncompleted"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"action": {
|
"action": {
|
||||||
"path": "/etc/zshrc",
|
"path": "/etc/zshenv",
|
||||||
"user": null,
|
"user": null,
|
||||||
"group": null,
|
"group": null,
|
||||||
"mode": 493,
|
"mode": 493,
|
||||||
"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"
|
||||||
},
|
},
|
||||||
"state": "Uncompleted"
|
"state": "Uncompleted"
|
||||||
},
|
},
|
||||||
|
@ -526,7 +529,8 @@
|
||||||
"user": null,
|
"user": null,
|
||||||
"group": null,
|
"group": null,
|
||||||
"mode": 493,
|
"mode": 493,
|
||||||
"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"
|
||||||
},
|
},
|
||||||
"state": "Uncompleted"
|
"state": "Uncompleted"
|
||||||
}
|
}
|
||||||
|
@ -588,13 +592,6 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"state": "Uncompleted"
|
"state": "Uncompleted"
|
||||||
},
|
|
||||||
{
|
|
||||||
"action": {
|
|
||||||
"action": "start_systemd_unit",
|
|
||||||
"unit": "nix-daemon.socket"
|
|
||||||
},
|
|
||||||
"state": "Uncompleted"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"planner": {
|
"planner": {
|
||||||
|
@ -612,7 +609,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.11.1/nix-2.11.1-x86_64-linux.tar.xz",
|
"nix_package_url": "https://releases.nixos.org/nix/nix-2.12.0/nix-2.12.0-x86_64-linux.tar.xz",
|
||||||
"extra_conf": [],
|
"extra_conf": [],
|
||||||
"force": false
|
"force": false
|
||||||
}
|
}
|
||||||
|
|
29
tests/fixtures/linux/steam-deck.json
vendored
29
tests/fixtures/linux/steam-deck.json
vendored
|
@ -19,7 +19,7 @@
|
||||||
"user": null,
|
"user": null,
|
||||||
"group": null,
|
"group": null,
|
||||||
"mode": 420,
|
"mode": 420,
|
||||||
"buf": "\n [Unit]\nDescription=Create a `/nix` directory to be used for bind mounting\nPropagatesStopTo=nix-daemon.service\nPropagatesStopTo=nix.mount\nDefaultDependencies=no\n\n[Service]\nType=oneshot\nExecCondition=sh -c \"if [ -d /nix ]; then exit 1; else exit 0; fi\"\n ExecStart=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",
|
"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
|
"force": false
|
||||||
},
|
},
|
||||||
"state": "Uncompleted"
|
"state": "Uncompleted"
|
||||||
|
@ -60,7 +60,7 @@
|
||||||
"action": "provision_nix",
|
"action": "provision_nix",
|
||||||
"fetch_nix": {
|
"fetch_nix": {
|
||||||
"action": {
|
"action": {
|
||||||
"url": "https://releases.nixos.org/nix/nix-2.11.1/nix-2.11.1-x86_64-linux.tar.xz",
|
"url": "https://releases.nixos.org/nix/nix-2.12.0/nix-2.12.0-x86_64-linux.tar.xz",
|
||||||
"dest": "/nix/temp-install-dir"
|
"dest": "/nix/temp-install-dir"
|
||||||
},
|
},
|
||||||
"state": "Uncompleted"
|
"state": "Uncompleted"
|
||||||
|
@ -532,14 +532,15 @@
|
||||||
"configure_shell_profile": {
|
"configure_shell_profile": {
|
||||||
"action": {
|
"action": {
|
||||||
"create_directories": [],
|
"create_directories": [],
|
||||||
"create_or_append_files": [
|
"create_or_insert_into_files": [
|
||||||
{
|
{
|
||||||
"action": {
|
"action": {
|
||||||
"path": "/etc/bashrc",
|
"path": "/etc/bashrc",
|
||||||
"user": null,
|
"user": null,
|
||||||
"group": null,
|
"group": null,
|
||||||
"mode": 493,
|
"mode": 493,
|
||||||
"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"
|
||||||
},
|
},
|
||||||
"state": "Uncompleted"
|
"state": "Uncompleted"
|
||||||
},
|
},
|
||||||
|
@ -549,17 +550,19 @@
|
||||||
"user": null,
|
"user": null,
|
||||||
"group": null,
|
"group": null,
|
||||||
"mode": 493,
|
"mode": 493,
|
||||||
"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"
|
||||||
},
|
},
|
||||||
"state": "Uncompleted"
|
"state": "Uncompleted"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"action": {
|
"action": {
|
||||||
"path": "/etc/zshrc",
|
"path": "/etc/zshenv",
|
||||||
"user": null,
|
"user": null,
|
||||||
"group": null,
|
"group": null,
|
||||||
"mode": 493,
|
"mode": 493,
|
||||||
"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"
|
||||||
},
|
},
|
||||||
"state": "Uncompleted"
|
"state": "Uncompleted"
|
||||||
},
|
},
|
||||||
|
@ -569,7 +572,8 @@
|
||||||
"user": null,
|
"user": null,
|
||||||
"group": null,
|
"group": null,
|
||||||
"mode": 493,
|
"mode": 493,
|
||||||
"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"
|
||||||
},
|
},
|
||||||
"state": "Uncompleted"
|
"state": "Uncompleted"
|
||||||
}
|
}
|
||||||
|
@ -631,13 +635,6 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"state": "Uncompleted"
|
"state": "Uncompleted"
|
||||||
},
|
|
||||||
{
|
|
||||||
"action": {
|
|
||||||
"action": "start_systemd_unit",
|
|
||||||
"unit": "nix-daemon.socket"
|
|
||||||
},
|
|
||||||
"state": "Uncompleted"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"planner": {
|
"planner": {
|
||||||
|
@ -656,7 +653,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.11.1/nix-2.11.1-x86_64-linux.tar.xz",
|
"nix_package_url": "https://releases.nixos.org/nix/nix-2.12.0/nix-2.12.0-x86_64-linux.tar.xz",
|
||||||
"extra_conf": [],
|
"extra_conf": [],
|
||||||
"force": false
|
"force": false
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue