Curing existing /nix (#310)

* Curing existing /nix

* Fixup macs

* Suggest an uninstall command if the binary is not present

* Fixup some nits

* Skip a not great suggestion

* Suggest a nice url
This commit is contained in:
Ana Hobden 2023-03-08 10:43:57 -08:00 committed by GitHub
parent b7d7afd02e
commit 85abfc3cb5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 246 additions and 119 deletions

View file

@ -78,7 +78,7 @@ impl CreateDirectory {
} }
tracing::debug!("Creating directory `{}` already complete", path.display(),); tracing::debug!("Creating directory `{}` already complete", path.display(),);
ActionState::Skipped ActionState::Completed
} else { } else {
ActionState::Uncompleted ActionState::Uncompleted
}; };

View file

@ -9,6 +9,7 @@ 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;
pub(crate) mod remove_directory;
pub(crate) mod setup_default_profile; pub(crate) mod setup_default_profile;
pub use add_user_to_group::AddUserToGroup; pub use add_user_to_group::AddUserToGroup;
@ -20,4 +21,5 @@ 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};
pub use remove_directory::RemoveDirectory;
pub use setup_default_profile::{SetupDefaultProfile, SetupDefaultProfileError}; pub use setup_default_profile::{SetupDefaultProfile, SetupDefaultProfileError};

View file

@ -11,14 +11,14 @@ Move an unpacked Nix at `src` to `/nix`
*/ */
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)] #[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct MoveUnpackedNix { pub struct MoveUnpackedNix {
src: PathBuf, unpacked_path: PathBuf,
} }
impl MoveUnpackedNix { impl MoveUnpackedNix {
#[tracing::instrument(level = "debug", skip_all)] #[tracing::instrument(level = "debug", skip_all)]
pub async fn plan(src: PathBuf) -> Result<StatefulAction<Self>, ActionError> { pub async fn plan(unpacked_path: PathBuf) -> Result<StatefulAction<Self>, ActionError> {
// Note: Do NOT try to check for the src/dest since the installer creates those // Note: Do NOT try to check for the src/dest since the installer creates those
Ok(Self { src }.into()) Ok(Self { unpacked_path }.into())
} }
} }
@ -36,7 +36,7 @@ impl Action for MoveUnpackedNix {
span!( span!(
tracing::Level::DEBUG, tracing::Level::DEBUG,
"mount_unpacked_nix", "mount_unpacked_nix",
src = tracing::field::display(self.src.display()), src = tracing::field::display(self.unpacked_path.display()),
dest = DEST, dest = DEST,
) )
} }
@ -46,44 +46,56 @@ impl Action for MoveUnpackedNix {
format!("Move the downloaded Nix into `/nix`"), format!("Move the downloaded Nix into `/nix`"),
vec![format!( vec![format!(
"Nix is being downloaded to `{}` and should be in `/nix`", "Nix is being downloaded to `{}` and should be in `/nix`",
self.src.display(), self.unpacked_path.display(),
)], )],
)] )]
} }
#[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 { src } = self; let Self { unpacked_path } = self;
// TODO(@Hoverbear): I would like to make this less awful // This is the `nix-$VERSION` folder which unpacks from the tarball, not a nix derivation
let found_nix_paths = glob::glob(&format!("{}/nix-*", src.display())) let found_nix_paths = glob::glob(&format!("{}/nix-*", unpacked_path.display()))
.map_err(|e| ActionError::Custom(Box::new(e)))? .map_err(|e| ActionError::Custom(Box::new(e)))?
.collect::<Result<Vec<_>, _>>() .collect::<Result<Vec<_>, _>>()
.map_err(|e| ActionError::Custom(Box::new(e)))?; .map_err(|e| ActionError::Custom(Box::new(e)))?;
assert_eq!( if found_nix_paths.len() != 1 {
found_nix_paths.len(), return Err(ActionError::MalformedBinaryTarball);
1, }
"Did not expect to find multiple nix paths, please report this"
);
let found_nix_path = found_nix_paths.into_iter().next().unwrap(); let found_nix_path = found_nix_paths.into_iter().next().unwrap();
let src_store = found_nix_path.join("store"); let src_store = found_nix_path.join("store");
let dest = Path::new(DEST).join("store"); let mut src_store_listing = tokio::fs::read_dir(src_store.clone())
tracing::trace!(src = %src_store.display(), dest = %dest.display(), "Renaming");
tokio::fs::rename(&src_store, &dest)
.await .await
.map_err(|e| ActionError::Rename(src_store.clone(), dest.to_owned(), e))?; .map_err(|e| ActionError::ReadDir(src_store.clone(), e))?;
let dest_store = Path::new(DEST).join("store");
let src_reginfo = found_nix_path.join(".reginfo"); if dest_store.exists() {
if !dest_store.is_dir() {
// Move_unpacked_nix expects it here return Err(ActionError::PathWasNotDirectory(dest_store.clone()))?;
let dest_reginfo = Path::new(DEST).join(".reginfo"); }
tokio::fs::rename(&src_reginfo, &dest_reginfo) } else {
tokio::fs::create_dir(&dest_store)
.await .await
.map_err(|e| ActionError::Rename(src_reginfo.clone(), dest_reginfo.to_owned(), e))?; .map_err(|e| ActionError::CreateDirectory(dest_store.clone(), e))?;
}
tokio::fs::remove_dir_all(&src) while let Some(entry) = src_store_listing
.next_entry()
.await .await
.map_err(|e| ActionError::Remove(src.clone(), e))?; .map_err(|e| ActionError::ReadDir(src_store.clone(), e))?
{
let entry_dest = dest_store.join(entry.file_name());
if entry_dest.exists() {
tracing::trace!(src = %entry.path().display(), dest = %entry_dest.display(), "Skipping, already exists");
} else {
tracing::trace!(src = %entry.path().display(), dest = %entry_dest.display(), "Renaming");
tokio::fs::rename(&entry.path(), &entry_dest)
.await
.map_err(|e| {
ActionError::Rename(entry.path().clone(), entry_dest.to_owned(), e)
})?;
}
}
Ok(()) Ok(())
} }

View file

@ -0,0 +1,76 @@
use std::path::{Path, PathBuf};
use tokio::fs::remove_dir_all;
use tracing::{span, Span};
use crate::action::{Action, ActionDescription, ActionState};
use crate::action::{ActionError, StatefulAction};
/** Remove a directory, does nothing on revert.
*/
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct RemoveDirectory {
path: PathBuf,
}
impl RemoveDirectory {
#[tracing::instrument(level = "debug", skip_all)]
pub async fn plan(path: impl AsRef<Path>) -> Result<StatefulAction<Self>, ActionError> {
let path = path.as_ref().to_path_buf();
Ok(StatefulAction {
action: Self {
path: path.to_path_buf(),
},
state: ActionState::Uncompleted,
})
}
}
#[async_trait::async_trait]
#[typetag::serde(name = "remove_directory")]
impl Action for RemoveDirectory {
fn action_tag() -> crate::action::ActionTag {
crate::action::ActionTag("remove_directory")
}
fn tracing_synopsis(&self) -> String {
format!("Remove directory `{}`", self.path.display())
}
fn tracing_span(&self) -> Span {
span!(
tracing::Level::DEBUG,
"remove_directory",
path = tracing::field::display(self.path.display()),
)
}
fn execute_description(&self) -> Vec<ActionDescription> {
vec![ActionDescription::new(self.tracing_synopsis(), vec![])]
}
#[tracing::instrument(level = "debug", skip_all)]
async fn execute(&mut self) -> Result<(), ActionError> {
if self.path.exists() {
if !self.path.is_dir() {
return Err(ActionError::PathWasNotDirectory(self.path.clone()));
}
remove_dir_all(&self.path)
.await
.map_err(|e| ActionError::Remove(self.path.clone(), e))?;
} else {
tracing::debug!("Directory `{}` not present, skipping", self.path.display(),);
};
Ok(())
}
fn revert_description(&self) -> Vec<ActionDescription> {
vec![]
}
#[tracing::instrument(level = "debug", skip_all)]
async fn revert(&mut self) -> Result<(), ActionError> {
Ok(())
}
}

View file

@ -1,4 +1,4 @@
use std::path::{Path, PathBuf}; use std::path::PathBuf;
use crate::{ use crate::{
action::{ActionError, ActionTag, StatefulAction}, action::{ActionError, ActionTag, StatefulAction},
@ -16,12 +16,14 @@ use crate::action::{Action, ActionDescription};
Setup the default Nix profile with `nss-cacert` and `nix` itself. Setup the default Nix profile with `nss-cacert` and `nix` itself.
*/ */
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)] #[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct SetupDefaultProfile {} pub struct SetupDefaultProfile {
unpacked_path: PathBuf,
}
impl SetupDefaultProfile { impl SetupDefaultProfile {
#[tracing::instrument(level = "debug", skip_all)] #[tracing::instrument(level = "debug", skip_all)]
pub async fn plan() -> Result<StatefulAction<Self>, ActionError> { pub async fn plan(unpacked_path: PathBuf) -> Result<StatefulAction<Self>, ActionError> {
Ok(Self {}.into()) Ok(Self { unpacked_path }.into())
} }
} }
@ -91,9 +93,15 @@ impl Action for SetupDefaultProfile {
))); )));
}; };
{ let found_nix_paths = glob::glob(&format!("{}/nix-*", self.unpacked_path.display()))
let reginfo_path = .map_err(|e| ActionError::Custom(Box::new(e)))?
Path::new(crate::action::base::move_unpacked_nix::DEST).join(".reginfo"); .collect::<Result<Vec<_>, _>>()
.map_err(|e| ActionError::Custom(Box::new(e)))?;
if found_nix_paths.len() != 1 {
return Err(ActionError::MalformedBinaryTarball);
}
let found_nix_path = found_nix_paths.into_iter().next().unwrap();
let reginfo_path = PathBuf::from(found_nix_path).join(".reginfo");
let reginfo = tokio::fs::read(&reginfo_path) let reginfo = tokio::fs::read(&reginfo_path)
.await .await
.map_err(|e| ActionError::Read(reginfo_path.to_path_buf(), e))?; .map_err(|e| ActionError::Read(reginfo_path.to_path_buf(), e))?;
@ -140,7 +148,6 @@ impl Action for SetupDefaultProfile {
if !output.status.success() { if !output.status.success() {
return Err(ActionError::command_output(&load_db_command, output)); return Err(ActionError::command_output(&load_db_command, output));
}; };
}
// Install `nix` itself into the store // Install `nix` itself into the store
execute_command( execute_command(

View file

@ -1,4 +1,4 @@
use std::path::PathBuf; use std::path::{Path, PathBuf};
use tokio::process::Command; use tokio::process::Command;
use tracing::{span, Span}; use tracing::{span, Span};
@ -138,6 +138,7 @@ impl Action for ConfigureInitService {
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
InitSystem::Systemd => { InitSystem::Systemd => {
tracing::trace!(src = TMPFILES_SRC, dest = TMPFILES_DEST, "Symlinking"); tracing::trace!(src = TMPFILES_SRC, dest = TMPFILES_DEST, "Symlinking");
if !Path::new(TMPFILES_DEST).exists() {
tokio::fs::symlink(TMPFILES_SRC, TMPFILES_DEST) tokio::fs::symlink(TMPFILES_SRC, TMPFILES_DEST)
.await .await
.map_err(|e| { .map_err(|e| {
@ -147,6 +148,7 @@ impl Action for ConfigureInitService {
e, e,
) )
})?; })?;
}
execute_command( execute_command(
Command::new("systemd-tmpfiles") Command::new("systemd-tmpfiles")

View file

@ -1,10 +1,12 @@
use std::path::PathBuf;
use crate::{ use crate::{
action::{ action::{
base::SetupDefaultProfile, base::SetupDefaultProfile,
common::{ConfigureShellProfile, PlaceNixConfiguration}, common::{ConfigureShellProfile, PlaceNixConfiguration},
Action, ActionDescription, ActionError, ActionTag, StatefulAction, Action, ActionDescription, ActionError, ActionTag, StatefulAction,
}, },
settings::CommonSettings, settings::{CommonSettings, SCRATCH_DIR},
}; };
use tracing::{span, Instrument, Span}; use tracing::{span, Instrument, Span};
@ -22,7 +24,7 @@ pub struct ConfigureNix {
impl ConfigureNix { impl ConfigureNix {
#[tracing::instrument(level = "debug", skip_all)] #[tracing::instrument(level = "debug", skip_all)]
pub async fn plan(settings: &CommonSettings) -> Result<StatefulAction<Self>, ActionError> { pub async fn plan(settings: &CommonSettings) -> Result<StatefulAction<Self>, ActionError> {
let setup_default_profile = SetupDefaultProfile::plan() let setup_default_profile = SetupDefaultProfile::plan(PathBuf::from(SCRATCH_DIR))
.await .await
.map_err(|e| ActionError::Child(SetupDefaultProfile::action_tag(), Box::new(e)))?; .map_err(|e| ActionError::Child(SetupDefaultProfile::action_tag(), Box::new(e)))?;

View file

@ -6,7 +6,7 @@ use crate::{
base::{FetchAndUnpackNix, MoveUnpackedNix}, base::{FetchAndUnpackNix, MoveUnpackedNix},
Action, ActionDescription, ActionError, ActionTag, StatefulAction, Action, ActionDescription, ActionError, ActionTag, StatefulAction,
}, },
settings::CommonSettings, settings::{CommonSettings, SCRATCH_DIR},
}; };
use std::path::PathBuf; use std::path::PathBuf;
@ -24,10 +24,8 @@ pub struct ProvisionNix {
impl ProvisionNix { impl ProvisionNix {
#[tracing::instrument(level = "debug", skip_all)] #[tracing::instrument(level = "debug", skip_all)]
pub async fn plan(settings: &CommonSettings) -> Result<StatefulAction<Self>, ActionError> { pub async fn plan(settings: &CommonSettings) -> Result<StatefulAction<Self>, ActionError> {
let fetch_nix = FetchAndUnpackNix::plan( let fetch_nix =
settings.nix_package_url.clone(), FetchAndUnpackNix::plan(settings.nix_package_url.clone(), PathBuf::from(SCRATCH_DIR))
PathBuf::from("/nix/temp-install-dir"),
)
.await?; .await?;
let create_users_and_group = CreateUsersAndGroups::plan(settings.clone()) let create_users_and_group = CreateUsersAndGroups::plan(settings.clone())
.await .await
@ -35,7 +33,7 @@ impl ProvisionNix {
let create_nix_tree = CreateNixTree::plan() let create_nix_tree = CreateNixTree::plan()
.await .await
.map_err(|e| ActionError::Child(CreateNixTree::action_tag(), Box::new(e)))?; .map_err(|e| ActionError::Child(CreateNixTree::action_tag(), Box::new(e)))?;
let move_unpacked_nix = MoveUnpackedNix::plan(PathBuf::from("/nix/temp-install-dir")) let move_unpacked_nix = MoveUnpackedNix::plan(PathBuf::from(SCRATCH_DIR))
.await .await
.map_err(|e| ActionError::Child(MoveUnpackedNix::action_tag(), Box::new(e)))?; .map_err(|e| ActionError::Child(MoveUnpackedNix::action_tag(), Box::new(e)))?;
Ok(Self { Ok(Self {

View file

@ -311,8 +311,10 @@ pub enum ActionError {
existing_mode = .1 & 0o777, existing_mode = .1 & 0o777,
planned_mode = .2 & 0o777)] planned_mode = .2 & 0o777)]
PathModeMismatch(std::path::PathBuf, u32, u32), PathModeMismatch(std::path::PathBuf, u32, u32),
#[error("`{0}` was not a file")] #[error("Path `{0}` exists, but is not a file, consider removing it with `rm {0}`")]
PathWasNotFile(std::path::PathBuf), PathWasNotFile(std::path::PathBuf),
#[error("Path `{0}` exists, but is not a directory, consider removing it with `rm {0}`")]
PathWasNotDirectory(std::path::PathBuf),
#[error("Getting metadata for {0}`")] #[error("Getting metadata for {0}`")]
GettingMetadata(std::path::PathBuf, #[source] std::io::Error), GettingMetadata(std::path::PathBuf, #[source] std::io::Error),
#[error("Creating directory `{0}`")] #[error("Creating directory `{0}`")]
@ -341,6 +343,8 @@ pub enum ActionError {
), ),
#[error("Read path `{0}`")] #[error("Read path `{0}`")]
Read(std::path::PathBuf, #[source] std::io::Error), Read(std::path::PathBuf, #[source] std::io::Error),
#[error("Reading directory `{0}`")]
ReadDir(std::path::PathBuf, #[source] std::io::Error),
#[error("Open path `{0}`")] #[error("Open path `{0}`")]
Open(std::path::PathBuf, #[source] std::io::Error), Open(std::path::PathBuf, #[source] std::io::Error),
#[error("Write path `{0}`")] #[error("Write path `{0}`")]
@ -410,6 +414,8 @@ pub enum ActionError {
/// A MacOS (Darwin) plist related error /// A MacOS (Darwin) plist related error
#[error(transparent)] #[error(transparent)]
Plist(#[from] plist::Error), Plist(#[from] plist::Error),
#[error("Unexpected binary tarball contents found, the build result from `https://releases.nixos.org/?prefix=nix/` or `nix build nix#hydraJobs.binaryTarball.$SYSTEM` is expected")]
MalformedBinaryTarball,
} }
impl ActionError { impl ActionError {

View file

@ -71,6 +71,7 @@ impl CommandExecute for Install {
let existing_receipt: Option<InstallPlan> = match Path::new(RECEIPT_LOCATION).exists() { let existing_receipt: Option<InstallPlan> = match Path::new(RECEIPT_LOCATION).exists() {
true => { true => {
tracing::trace!("Reading existing receipt");
let install_plan_string = tokio::fs::read_to_string(&RECEIPT_LOCATION) let install_plan_string = tokio::fs::read_to_string(&RECEIPT_LOCATION)
.await .await
.wrap_err("Reading plan")?; .wrap_err("Reading plan")?;
@ -79,6 +80,11 @@ impl CommandExecute for Install {
false => None, false => None,
}; };
let uninstall_command = match Path::new("/nix/nix-installer").exists() {
true => "/nix/nix-installer uninstall".into(),
false => format!("curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix/tag/v{} | sh -s -- uninstall", env!("CARGO_PKG_VERSION")),
};
let mut install_plan = match (planner, plan) { let mut install_plan = match (planner, plan) {
(Some(planner), None) => { (Some(planner), None) => {
let chosen_planner: Box<dyn Planner> = planner.clone().boxed(); let chosen_planner: Box<dyn Planner> = planner.clone().boxed();
@ -86,18 +92,15 @@ impl CommandExecute for Install {
match existing_receipt { match existing_receipt {
Some(existing_receipt) => { Some(existing_receipt) => {
if existing_receipt.planner.typetag_name() != chosen_planner.typetag_name() { if existing_receipt.planner.typetag_name() != chosen_planner.typetag_name() {
eprintln!("{}", format!("Found existing plan in `{RECEIPT_LOCATION}` which used a different planner, try uninstalling the existing install").red()); eprintln!("{}", format!("Found existing plan in `{RECEIPT_LOCATION}` which used a different planner, try uninstalling the existing install with `{uninstall_command}`").red());
return Ok(ExitCode::FAILURE) return Ok(ExitCode::FAILURE)
} }
if existing_receipt.planner.settings().map_err(|e| eyre!(e))? != chosen_planner.settings().map_err(|e| eyre!(e))? { if existing_receipt.planner.settings().map_err(|e| eyre!(e))? != chosen_planner.settings().map_err(|e| eyre!(e))? {
eprintln!("{}", format!("Found existing plan in `{RECEIPT_LOCATION}` which used different planner settings, try uninstalling the existing install").red()); eprintln!("{}", format!("Found existing plan in `{RECEIPT_LOCATION}` which used different planner settings, try uninstalling the existing install with `{uninstall_command}`").red());
return Ok(ExitCode::FAILURE) return Ok(ExitCode::FAILURE)
} }
if existing_receipt.actions.iter().all(|v| v.state == ActionState::Completed) { eprintln!("{}", format!("Found existing plan in `{RECEIPT_LOCATION}`, with the same settings, already completed, try uninstalling (`{uninstall_command}`) and reinstalling if Nix isn't working").red());
eprintln!("{}", format!("Found existing plan in `{RECEIPT_LOCATION}`, with the same settings, already completed, try uninstalling and reinstalling if Nix isn't working").red());
return Ok(ExitCode::FAILURE) return Ok(ExitCode::FAILURE)
}
existing_receipt
} , } ,
None => { None => {
planner.plan().await.map_err(|e| eyre!(e))? planner.plan().await.map_err(|e| eyre!(e))?
@ -114,18 +117,19 @@ impl CommandExecute for Install {
let builtin_planner = BuiltinPlanner::from_common_settings(settings) let builtin_planner = BuiltinPlanner::from_common_settings(settings)
.await .await
.map_err(|e| eyre::eyre!(e))?; .map_err(|e| eyre::eyre!(e))?;
match existing_receipt { match existing_receipt {
Some(existing_receipt) => { Some(existing_receipt) => {
if existing_receipt.planner.typetag_name() != builtin_planner.typetag_name() { if existing_receipt.planner.typetag_name() != builtin_planner.typetag_name() {
eprintln!("{}", format!("Found existing plan in `{RECEIPT_LOCATION}` which used a different planner, try uninstalling the existing install").red()); eprintln!("{}", format!("Found existing plan in `{RECEIPT_LOCATION}` which used a different planner, try uninstalling the existing install with `{uninstall_command}`").red());
return Ok(ExitCode::FAILURE) return Ok(ExitCode::FAILURE)
} }
if existing_receipt.planner.settings().map_err(|e| eyre!(e))? != builtin_planner.settings().map_err(|e| eyre!(e))? { if existing_receipt.planner.settings().map_err(|e| eyre!(e))? != builtin_planner.settings().map_err(|e| eyre!(e))? {
eprintln!("{}", format!("Found existing plan in `{RECEIPT_LOCATION}` which used different planner settings, try uninstalling the existing install").red()); eprintln!("{}", format!("Found existing plan in `{RECEIPT_LOCATION}` which used different planner settings, try uninstalling the existing install with `{uninstall_command}`").red());
return Ok(ExitCode::FAILURE) return Ok(ExitCode::FAILURE)
} }
if existing_receipt.actions.iter().all(|v| v.state == ActionState::Completed) { if existing_receipt.actions.iter().all(|v| v.state == ActionState::Completed) {
eprintln!("{}", format!("Found existing plan in `{RECEIPT_LOCATION}`, with the same settings, already completed, try uninstalling and reinstalling if Nix isn't working").red()); eprintln!("{}", format!("Found existing plan in `{RECEIPT_LOCATION}`, with the same settings, already completed, try uninstalling (`{uninstall_command}`) and reinstalling if Nix isn't working").red());
return Ok(ExitCode::FAILURE) return Ok(ExitCode::FAILURE)
} }
existing_receipt existing_receipt

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
action::{ action::{
base::CreateDirectory, base::{CreateDirectory, RemoveDirectory},
common::{ConfigureInitService, ConfigureNix, ProvisionNix}, common::{ConfigureInitService, ConfigureNix, ProvisionNix},
StatefulAction, StatefulAction,
}, },
@ -88,6 +88,10 @@ impl Planner for Linux {
.await .await
.map_err(PlannerError::Action)? .map_err(PlannerError::Action)?
.boxed(), .boxed(),
RemoveDirectory::plan(crate::settings::SCRATCH_DIR)
.await
.map_err(PlannerError::Action)?
.boxed(),
]) ])
} }

View file

@ -6,6 +6,7 @@ use tokio::process::Command;
use crate::{ use crate::{
action::{ action::{
base::RemoveDirectory,
common::{ConfigureInitService, ConfigureNix, ProvisionNix}, common::{ConfigureInitService, ConfigureNix, ProvisionNix},
macos::CreateNixVolume, macos::CreateNixVolume,
StatefulAction, StatefulAction,
@ -145,6 +146,10 @@ impl Planner for Macos {
.await .await
.map_err(PlannerError::Action)? .map_err(PlannerError::Action)?
.boxed(), .boxed(),
RemoveDirectory::plan(crate::settings::SCRATCH_DIR)
.await
.map_err(PlannerError::Action)?
.boxed(),
]) ])
} }

View file

@ -63,7 +63,7 @@ use std::{collections::HashMap, path::PathBuf};
use crate::{ use crate::{
action::{ action::{
base::{CreateDirectory, CreateFile}, base::{CreateDirectory, CreateFile, RemoveDirectory},
common::{ConfigureInitService, ConfigureNix, ProvisionNix}, common::{ConfigureInitService, ConfigureNix, ProvisionNix},
linux::StartSystemdUnit, linux::StartSystemdUnit,
Action, StatefulAction, Action, StatefulAction,
@ -234,6 +234,10 @@ impl Planner for SteamDeck {
.await .await
.map_err(PlannerError::Action)? .map_err(PlannerError::Action)?
.boxed(), .boxed(),
RemoveDirectory::plan(crate::settings::SCRATCH_DIR)
.await
.map_err(PlannerError::Action)?
.boxed(),
]) ])
} }

View file

@ -6,6 +6,8 @@ use std::collections::HashMap;
use clap::ArgAction; use clap::ArgAction;
use url::Url; use url::Url;
pub const SCRATCH_DIR: &str = "/nix/temp-install-dir";
/// Default [`nix_package_url`](CommonSettings::nix_package_url) for Linux x86_64 /// Default [`nix_package_url`](CommonSettings::nix_package_url) for Linux x86_64
pub const NIX_X64_64_LINUX_URL: &str = pub const NIX_X64_64_LINUX_URL: &str =
"https://releases.nixos.org/nix/nix-2.13.3/nix-2.13.3-x86_64-linux.tar.xz"; "https://releases.nixos.org/nix/nix-2.13.3/nix-2.13.3-x86_64-linux.tar.xz";

View file

@ -758,7 +758,7 @@
}, },
"move_unpacked_nix": { "move_unpacked_nix": {
"action": { "action": {
"src": "/nix/temp-install-dir" "unpacked_path": "/nix/temp-install-dir"
}, },
"state": "Uncompleted" "state": "Uncompleted"
} }
@ -775,7 +775,8 @@
"nixpkgs", "nixpkgs",
"https://nixos.org/channels/nixpkgs-unstable" "https://nixos.org/channels/nixpkgs-unstable"
] ]
] ],
"unpacked_path": "/nix/temp-install-dir"
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },

View file

@ -802,7 +802,7 @@
}, },
"move_unpacked_nix": { "move_unpacked_nix": {
"action": { "action": {
"src": "/nix/temp-install-dir" "unpacked_path": "/nix/temp-install-dir"
}, },
"state": "Uncompleted" "state": "Uncompleted"
} }
@ -819,7 +819,8 @@
"nixpkgs", "nixpkgs",
"https://nixos.org/channels/nixpkgs-unstable" "https://nixos.org/channels/nixpkgs-unstable"
] ]
] ],
"unpacked_path": "/nix/temp-install-dir"
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },

View file

@ -823,7 +823,7 @@
}, },
"move_unpacked_nix": { "move_unpacked_nix": {
"action": { "action": {
"src": "/nix/temp-install-dir" "unpacked_path": "/nix/temp-install-dir"
}, },
"state": "Uncompleted" "state": "Uncompleted"
} }
@ -840,7 +840,8 @@
"nixpkgs", "nixpkgs",
"https://nixos.org/channels/nixpkgs-unstable" "https://nixos.org/channels/nixpkgs-unstable"
] ]
] ],
"unpacked_path": "/nix/temp-install-dir"
}, },
"state": "Uncompleted" "state": "Uncompleted"
}, },