Hobbling along

This commit is contained in:
Ana Hobden 2022-10-24 16:16:18 -07:00
parent 86a518f2fe
commit 8924bf5cb7
14 changed files with 235 additions and 79 deletions

View file

@ -81,7 +81,7 @@ impl Actionable for ConfigureNixDaemonService {
const DARWIN_NIX_DAEMON_DEST: &str = const DARWIN_NIX_DAEMON_DEST: &str =
"/Library/LaunchDaemons/org.nixos.nix-daemon.plist"; "/Library/LaunchDaemons/org.nixos.nix-daemon.plist";
let src = Path::new("/nix/var/nix/profiles/default").join(DARWIN_NIX_DAEMON_DEST); let src = Path::new("/nix/var/nix/profiles/default/Library/LaunchDaemons/org.nixos.nix-daemon.plist");
tokio::fs::copy(src.clone(), DARWIN_NIX_DAEMON_DEST) tokio::fs::copy(src.clone(), DARWIN_NIX_DAEMON_DEST)
.await .await
.map_err(|e| { .map_err(|e| {

View file

@ -9,16 +9,18 @@ use crate::actions::{Action, ActionDescription, ActionState, Actionable};
pub struct CreateUser { pub struct CreateUser {
name: String, name: String,
uid: usize, uid: usize,
groupname: String,
gid: usize, gid: usize,
action_state: ActionState, action_state: ActionState,
} }
impl CreateUser { impl CreateUser {
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
pub fn plan(name: String, uid: usize, gid: usize) -> Self { pub fn plan(name: String, uid: usize, groupname: String, gid: usize) -> Self {
Self { Self {
name, name,
uid, uid,
groupname,
gid, gid,
action_state: ActionState::Uncompleted, action_state: ActionState::Uncompleted,
} }
@ -36,6 +38,7 @@ impl Actionable for CreateUser {
let Self { let Self {
name, name,
uid, uid,
groupname: _,
gid, gid,
action_state: _, action_state: _,
} = self; } = self;
@ -52,12 +55,14 @@ impl Actionable for CreateUser {
#[tracing::instrument(skip_all, fields( #[tracing::instrument(skip_all, fields(
user = self.name, user = self.name,
uid = self.uid, uid = self.uid,
groupname = self.groupname,
gid = self.gid, gid = self.gid,
))] ))]
async fn execute(&mut self) -> Result<(), Self::Error> { async fn execute(&mut self) -> Result<(), Self::Error> {
let Self { let Self {
name, name,
uid, uid,
groupname,
gid, gid,
action_state, action_state,
} = self; } = self;
@ -77,15 +82,79 @@ impl Actionable for CreateUser {
| OperatingSystem::Darwin => { | OperatingSystem::Darwin => {
execute_command(Command::new("/usr/bin/dscl").args([ execute_command(Command::new("/usr/bin/dscl").args([
".", ".",
"create", "-create",
&format!("/Users/{name}"), &format!("/Users/{name}"),
"UniqueId", ]))
.await
.map_err(Self::Error::Command)?;
execute_command(Command::new("/usr/bin/dscl").args([
".",
"-create",
&format!("/Users/{name}"),
"UniqueID",
&format!("{uid}"), &format!("{uid}"),
]))
.await
.map_err(Self::Error::Command)?;
execute_command(Command::new("/usr/bin/dscl").args([
".",
"-create",
&format!("/Users/{name}"),
"PrimaryGroupID", "PrimaryGroupID",
&format!("{gid}"), &format!("{gid}"),
])) ]))
.await .await
.map_err(Self::Error::Command)?; .map_err(Self::Error::Command)?;
execute_command(Command::new("/usr/bin/dscl").args([
".",
"-create",
&format!("/Users/{name}"),
"NFSHomeDirectory",
"/var/empty",
]))
.await
.map_err(Self::Error::Command)?;
execute_command(Command::new("/usr/bin/dscl").args([
".",
"-create",
&format!("/Users/{name}"),
"UserShell",
"/sbin/nologin",
]))
.await
.map_err(Self::Error::Command)?;
execute_command(
Command::new("/usr/bin/dscl")
.args([
".",
"-append",
&format!("/Groups/{groupname}"),
"GroupMembership",
])
.arg(&name),
)
.await
.map_err(Self::Error::Command)?;
execute_command(Command::new("/usr/bin/dscl").args([
".",
"-create",
&format!("/Users/{name}"),
"IsHidden",
"1",
]))
.await
.map_err(Self::Error::Command)?;
execute_command(
Command::new("/usr/sbin/dseditgroup")
.args(["-o", "edit"])
.arg("-a")
.arg(&name)
.arg("-t")
.arg(&name)
.arg(groupname),
)
.await
.map_err(Self::Error::Command)?;
}, },
_ => { _ => {
execute_command(Command::new("useradd").args([ execute_command(Command::new("useradd").args([
@ -124,6 +193,7 @@ impl Actionable for CreateUser {
let Self { let Self {
name, name,
uid, uid,
groupname: _,
gid, gid,
action_state: _, action_state: _,
} = self; } = self;
@ -146,6 +216,7 @@ impl Actionable for CreateUser {
let Self { let Self {
name, name,
uid: _, uid: _,
groupname: _,
gid: _, gid: _,
action_state, action_state,
} = self; } = self;
@ -163,7 +234,13 @@ impl Actionable for CreateUser {
patch: _, patch: _,
} }
| OperatingSystem::Darwin => { | OperatingSystem::Darwin => {
todo!() execute_command(Command::new("/usr/bin/dscl").args([
".",
"-delete",
&format!("/Users/{name}"),
]))
.await
.map_err(Self::Error::Command)?;
}, },
_ => { _ => {
execute_command(Command::new("userdel").args([&name.to_string()])) execute_command(Command::new("userdel").args([&name.to_string()]))

View file

@ -56,9 +56,13 @@ impl Actionable for BootstrapVolume {
) )
.await .await
.map_err(Self::Error::Command)?; .map_err(Self::Error::Command)?;
execute_command(Command::new("launchctl").args(["-k", "system/org.nixos.darwin-store"])) execute_command(Command::new("launchctl").args([
.await "kickstart",
.map_err(Self::Error::Command)?; "-k",
"system/org.nixos.darwin-store",
]))
.await
.map_err(Self::Error::Command)?;
tracing::trace!("Bootstrapped volume"); tracing::trace!("Bootstrapped volume");
*action_state = ActionState::Completed; *action_state = ActionState::Completed;

View file

@ -121,14 +121,9 @@ impl Actionable for CreateVolume {
} }
tracing::debug!("Deleting volume"); tracing::debug!("Deleting volume");
execute_command(Command::new("/usr/sbin/diskutil").args([ execute_command(Command::new("/usr/sbin/diskutil").args(["apfs", "deleteVolume", name]))
"apfs", .await
"deleteVolume", .map_err(Self::Error::Command)?;
&format!("{}", disk.display()),
name,
]))
.await
.map_err(Self::Error::Command)?;
tracing::trace!("Deleted volume"); tracing::trace!("Deleted volume");
*action_state = ActionState::Completed; *action_state = ActionState::Completed;

View file

@ -73,15 +73,6 @@ impl Actionable for SetupDefaultProfile {
return Err(Self::Error::NoNssCacert); // TODO(@hoverbear): Fix this error return Err(Self::Error::NoNssCacert); // TODO(@hoverbear): Fix this error
}; };
// Install `nix` itself into the store
execute_command(
Command::new(nix_pkg.join("bin/nix-env"))
.arg("-i")
.arg(&nix_pkg),
)
.await
.map_err(SetupDefaultProfileError::Command)?;
// Find an `nss-cacert` package, add it too. // Find an `nss-cacert` package, add it too.
let nss_ca_cert_pkg_glob = "/nix/store/*-nss-cacert-*"; let nss_ca_cert_pkg_glob = "/nix/store/*-nss-cacert-*";
let mut found_nss_ca_cert_pkg = None; let mut found_nss_ca_cert_pkg = None;
@ -101,11 +92,29 @@ impl Actionable for SetupDefaultProfile {
return Err(Self::Error::NoNssCacert); return Err(Self::Error::NoNssCacert);
}; };
// Install `nix` itself into the store
execute_command(
Command::new(nix_pkg.join("bin/nix-env"))
.arg("-i")
.arg(&nix_pkg)
.env("HOME", dirs::home_dir().ok_or(Self::Error::NoRootHome)?)
.env(
"NIX_SSL_CERT_FILE",
nss_ca_cert_pkg.join("etc/ssl/certs/ca-bundle.crt"),
), /* This is apparently load bearing... */
)
.await
.map_err(SetupDefaultProfileError::Command)?;
// Install `nss-cacert` into the store // Install `nss-cacert` into the store
execute_command( execute_command(
Command::new(nix_pkg.join("bin/nix-env")) Command::new(nix_pkg.join("bin/nix-env"))
.arg("-i") .arg("-i")
.arg(&nss_ca_cert_pkg), .arg(&nss_ca_cert_pkg)
.env(
"NIX_SSL_CERT_FILE",
nss_ca_cert_pkg.join("etc/ssl/certs/ca-bundle.crt"),
),
) )
.await .await
.map_err(SetupDefaultProfileError::Command)?; .map_err(SetupDefaultProfileError::Command)?;
@ -199,4 +208,6 @@ pub enum SetupDefaultProfileError {
#[serde(serialize_with = "crate::serialize_error_to_display")] #[serde(serialize_with = "crate::serialize_error_to_display")]
std::io::Error, std::io::Error,
), ),
#[error("No root home found to place channel configuration in")]
NoRootHome,
} }

View file

@ -32,6 +32,7 @@ impl CreateUsersAndGroup {
CreateUser::plan( CreateUser::plan(
format!("{}{count}", settings.nix_build_user_prefix), format!("{}{count}", settings.nix_build_user_prefix),
settings.nix_build_user_id_base + count, settings.nix_build_user_id_base + count,
settings.nix_build_group_name.clone(),
settings.nix_build_group_id, settings.nix_build_group_id,
) )
}) })
@ -108,35 +109,30 @@ impl Actionable for CreateUsersAndGroup {
// Create group // Create group
create_group.execute().await?; create_group.execute().await?;
// Create users // Mac is apparently not threadsafe here...
// TODO(@hoverbear): Abstract this, it will be common for create_user in create_users.iter_mut() {
let mut set = JoinSet::new(); // let mut create_user_clone = create_user.clone();
// let _abort_handle = set.spawn(async move {
let mut errors = Vec::default(); create_user.execute().await?;
// Result::<_, CreateUserError>::Ok((idx, create_user_clone))
for (idx, create_user) in create_users.iter().enumerate() { // });
let mut create_user_clone = create_user.clone();
let _abort_handle = set.spawn(async move {
create_user_clone.execute().await?;
Result::<_, CreateUserError>::Ok((idx, create_user_clone))
});
} }
while let Some(result) = set.join_next().await { // while let Some(result) = set.join_next().await {
match result { // match result {
Ok(Ok((idx, success))) => create_users[idx] = success, // Ok(Ok((idx, success))) => create_users[idx] = success,
Ok(Err(e)) => errors.push(e), // Ok(Err(e)) => errors.push(e),
Err(e) => return Err(e)?, // Err(e) => return Err(e)?,
}; // };
} // }
if !errors.is_empty() { // if !errors.is_empty() {
if errors.len() == 1 { // if errors.len() == 1 {
return Err(errors.into_iter().next().unwrap().into()); // return Err(errors.into_iter().next().unwrap().into());
} else { // } else {
return Err(CreateUsersAndGroupError::CreateUsers(errors)); // return Err(CreateUsersAndGroupError::CreateUsers(errors));
} // }
} // }
tracing::trace!("Created users and groups"); tracing::trace!("Created users and groups");
*action_state = ActionState::Completed; *action_state = ActionState::Completed;

View file

@ -1,5 +1,8 @@
use serde::Serialize; use serde::Serialize;
use std::path::{Path, PathBuf}; use std::{
path::{Path, PathBuf},
time::Duration,
};
use crate::actions::base::{ use crate::actions::base::{
darwin::{ darwin::{
@ -7,7 +10,7 @@ use crate::actions::base::{
CreateVolume, CreateVolumeError, EnableOwnership, EnableOwnershipError, EncryptVolume, CreateVolume, CreateVolumeError, EnableOwnership, EnableOwnershipError, EncryptVolume,
EncryptVolumeError, UnmountVolume, UnmountVolumeError, EncryptVolumeError, UnmountVolume, UnmountVolumeError,
}, },
CreateOrAppendFile, CreateOrAppendFileError, CreateFile, CreateFileError, CreateOrAppendFile, CreateOrAppendFileError,
}; };
use crate::actions::{base::darwin, Action, ActionDescription, ActionState, Actionable}; use crate::actions::{base::darwin, Action, ActionDescription, ActionState, Actionable};
@ -25,6 +28,7 @@ pub struct CreateApfsVolume {
create_volume: CreateVolume, create_volume: CreateVolume,
create_or_append_fstab: CreateOrAppendFile, create_or_append_fstab: CreateOrAppendFile,
encrypt_volume: Option<EncryptVolume>, encrypt_volume: Option<EncryptVolume>,
setup_volume_daemon: CreateFile,
bootstrap_volume: BootstrapVolume, bootstrap_volume: BootstrapVolume,
enable_ownership: EnableOwnership, enable_ownership: EnableOwnership,
action_state: ActionState, action_state: ActionState,
@ -39,9 +43,14 @@ impl CreateApfsVolume {
encrypt: Option<String>, encrypt: Option<String>,
) -> Result<Self, CreateApfsVolumeError> { ) -> Result<Self, CreateApfsVolumeError> {
let disk = disk.as_ref(); let disk = disk.as_ref();
let create_or_append_synthetic_conf = let create_or_append_synthetic_conf = CreateOrAppendFile::plan(
CreateOrAppendFile::plan("/etc/synthetic.conf", None, None, 0o0655, "nix".into()) "/etc/synthetic.conf",
.await?; None,
None,
0o0655,
"nix\n".into(), /* The newline is required otherwise it segfaults */
)
.await?;
let create_synthetic_objects = CreateSyntheticObjects::plan().await?; let create_synthetic_objects = CreateSyntheticObjects::plan().await?;
@ -64,6 +73,49 @@ impl CreateApfsVolume {
None None
}; };
let mount_command = if encrypt.is_some() {
vec![
"/bin/sh",
"-c",
"/usr/bin/security find-generic-password",
"-s",
"{name}",
"-w",
"|",
"/usr/sbin/diskutil",
"apfs",
"unlockVolume",
&name,
"-mountpoint",
"/nix",
"-stdinpassphrase",
]
} else {
vec!["/usr/sbin/diskutil", "mount", "-mountPoint", "/nix", &name]
};
// TODO(@hoverbear): Use plist lib we have in tree...
let mount_plist = format!(
"\
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n\
<plist version=\"1.0\">\n\
<dict>\n\
<key>RunAtLoad</key>\n\
<true/>\n\
<key>Label</key>\n\
<string>org.nixos.darwin-store</string>\n\
<key>ProgramArguments</key>\n\
<array>\n\
{}\
</array>\n\
</dict>\n\
</plist>\n\
\
", mount_command.iter().map(|v| format!("<string>{v}</string>\n")).collect::<Vec<_>>().join("\n")
);
let setup_volume_daemon =
CreateFile::plan(NIX_VOLUME_MOUNTD_DEST, None, None, None, mount_plist, false).await?;
let bootstrap_volume = BootstrapVolume::plan(NIX_VOLUME_MOUNTD_DEST).await?; let bootstrap_volume = BootstrapVolume::plan(NIX_VOLUME_MOUNTD_DEST).await?;
let enable_ownership = EnableOwnership::plan("/nix").await?; let enable_ownership = EnableOwnership::plan("/nix").await?;
@ -78,6 +130,7 @@ impl CreateApfsVolume {
create_volume, create_volume,
create_or_append_fstab, create_or_append_fstab,
encrypt_volume, encrypt_volume,
setup_volume_daemon,
bootstrap_volume, bootstrap_volume,
enable_ownership, enable_ownership,
action_state: ActionState::Uncompleted, action_state: ActionState::Uncompleted,
@ -121,6 +174,7 @@ impl Actionable for CreateApfsVolume {
create_volume, create_volume,
create_or_append_fstab, create_or_append_fstab,
encrypt_volume, encrypt_volume,
setup_volume_daemon,
bootstrap_volume, bootstrap_volume,
enable_ownership, enable_ownership,
action_state, action_state,
@ -139,7 +193,13 @@ impl Actionable for CreateApfsVolume {
if let Some(encrypt_volume) = encrypt_volume { if let Some(encrypt_volume) = encrypt_volume {
encrypt_volume.execute().await?; encrypt_volume.execute().await?;
} }
setup_volume_daemon.execute().await?;
bootstrap_volume.execute().await?; bootstrap_volume.execute().await?;
// TODO: Check wait
tokio::time::sleep(Duration::from_millis(5000)).await;
enable_ownership.execute().await?; enable_ownership.execute().await?;
tracing::trace!("Created APFS volume"); tracing::trace!("Created APFS volume");
@ -179,6 +239,7 @@ impl Actionable for CreateApfsVolume {
create_volume, create_volume,
create_or_append_fstab, create_or_append_fstab,
encrypt_volume, encrypt_volume,
setup_volume_daemon,
bootstrap_volume, bootstrap_volume,
enable_ownership, enable_ownership,
action_state, action_state,
@ -191,6 +252,7 @@ impl Actionable for CreateApfsVolume {
enable_ownership.revert().await?; enable_ownership.revert().await?;
bootstrap_volume.revert().await?; bootstrap_volume.revert().await?;
setup_volume_daemon.revert().await?;
if let Some(encrypt_volume) = encrypt_volume { if let Some(encrypt_volume) = encrypt_volume {
encrypt_volume.revert().await?; encrypt_volume.revert().await?;
} }
@ -217,6 +279,8 @@ impl From<CreateApfsVolume> for Action {
#[derive(Debug, thiserror::Error, Serialize)] #[derive(Debug, thiserror::Error, Serialize)]
pub enum CreateApfsVolumeError { pub enum CreateApfsVolumeError {
#[error(transparent)]
CreateFile(#[from] CreateFileError),
#[error(transparent)] #[error(transparent)]
DarwinBootstrapVolume(#[from] BootstrapVolumeError), DarwinBootstrapVolume(#[from] BootstrapVolumeError),
#[error(transparent)] #[error(transparent)]

View file

@ -26,7 +26,7 @@ impl PlaceChannelConfiguration {
let create_file = CreateFile::plan( let create_file = CreateFile::plan(
dirs::home_dir() dirs::home_dir()
.ok_or(PlaceChannelConfigurationError::NoRootHome)? .ok_or(PlaceChannelConfigurationError::NoRootHome)?
.join("/.nix-channels"), .join(".nix-channels"),
None, None,
None, None,
0o0664, 0o0664,

View file

@ -15,7 +15,6 @@ use super::{CreateNixTree, CreateNixTreeError, CreateUsersAndGroup, CreateUsersA
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)] #[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct ProvisionNix { pub struct ProvisionNix {
create_nix_dir: CreateDirectory,
fetch_nix: FetchNix, fetch_nix: FetchNix,
create_users_and_group: CreateUsersAndGroup, create_users_and_group: CreateUsersAndGroup,
create_nix_tree: CreateNixTree, create_nix_tree: CreateNixTree,
@ -26,8 +25,6 @@ pub struct ProvisionNix {
impl ProvisionNix { impl ProvisionNix {
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
pub async fn plan(settings: InstallSettings) -> Result<Self, ProvisionNixError> { pub async fn plan(settings: InstallSettings) -> Result<Self, ProvisionNixError> {
let create_nix_dir = CreateDirectory::plan("/nix", None, None, 0o0755, true).await?;
let fetch_nix = FetchNix::plan( let fetch_nix = FetchNix::plan(
settings.nix_package_url.clone(), settings.nix_package_url.clone(),
PathBuf::from("/nix/temp-install-dir"), PathBuf::from("/nix/temp-install-dir"),
@ -38,7 +35,6 @@ impl ProvisionNix {
let move_unpacked_nix = let move_unpacked_nix =
MoveUnpackedNix::plan(PathBuf::from("/nix/temp-install-dir")).await?; MoveUnpackedNix::plan(PathBuf::from("/nix/temp-install-dir")).await?;
Ok(Self { Ok(Self {
create_nix_dir,
fetch_nix, fetch_nix,
create_users_and_group, create_users_and_group,
create_nix_tree, create_nix_tree,
@ -53,7 +49,6 @@ impl Actionable for ProvisionNix {
type Error = ProvisionNixError; type Error = ProvisionNixError;
fn describe_execute(&self) -> Vec<ActionDescription> { fn describe_execute(&self) -> Vec<ActionDescription> {
let Self { let Self {
create_nix_dir,
fetch_nix, fetch_nix,
create_users_and_group, create_users_and_group,
create_nix_tree, create_nix_tree,
@ -64,7 +59,6 @@ impl Actionable for ProvisionNix {
vec![] vec![]
} else { } else {
let mut buf = Vec::default(); let mut buf = Vec::default();
buf.append(&mut create_nix_dir.describe_execute());
buf.append(&mut fetch_nix.describe_execute()); buf.append(&mut fetch_nix.describe_execute());
buf.append(&mut create_users_and_group.describe_execute()); buf.append(&mut create_users_and_group.describe_execute());
buf.append(&mut create_nix_tree.describe_execute()); buf.append(&mut create_nix_tree.describe_execute());
@ -77,7 +71,6 @@ impl Actionable for ProvisionNix {
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
async fn execute(&mut self) -> Result<(), Self::Error> { async fn execute(&mut self) -> Result<(), Self::Error> {
let Self { let Self {
create_nix_dir,
fetch_nix, fetch_nix,
create_nix_tree, create_nix_tree,
create_users_and_group, create_users_and_group,
@ -91,8 +84,6 @@ impl Actionable for ProvisionNix {
*action_state = ActionState::Progress; *action_state = ActionState::Progress;
tracing::debug!("Provisioning Nix"); tracing::debug!("Provisioning Nix");
create_nix_dir.execute().await?;
// We fetch nix while doing the rest, then move it over. // We fetch nix while doing the rest, then move it over.
let mut fetch_nix_clone = fetch_nix.clone(); let mut fetch_nix_clone = fetch_nix.clone();
let fetch_nix_handle = tokio::task::spawn(async { let fetch_nix_handle = tokio::task::spawn(async {
@ -116,7 +107,6 @@ impl Actionable for ProvisionNix {
fn describe_revert(&self) -> Vec<ActionDescription> { fn describe_revert(&self) -> Vec<ActionDescription> {
let Self { let Self {
create_nix_dir,
fetch_nix, fetch_nix,
create_users_and_group, create_users_and_group,
create_nix_tree, create_nix_tree,
@ -131,7 +121,6 @@ impl Actionable for ProvisionNix {
buf.append(&mut create_nix_tree.describe_revert()); buf.append(&mut create_nix_tree.describe_revert());
buf.append(&mut create_users_and_group.describe_revert()); buf.append(&mut create_users_and_group.describe_revert());
buf.append(&mut fetch_nix.describe_revert()); buf.append(&mut fetch_nix.describe_revert());
buf.append(&mut create_nix_dir.describe_revert());
buf buf
} }
} }
@ -139,7 +128,6 @@ impl Actionable for ProvisionNix {
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
async fn revert(&mut self) -> Result<(), Self::Error> { async fn revert(&mut self) -> Result<(), Self::Error> {
let Self { let Self {
create_nix_dir,
fetch_nix, fetch_nix,
create_nix_tree, create_nix_tree,
create_users_and_group, create_users_and_group,
@ -172,8 +160,6 @@ impl Actionable for ProvisionNix {
*fetch_nix = fetch_nix_handle.await.map_err(ProvisionNixError::from)??; *fetch_nix = fetch_nix_handle.await.map_err(ProvisionNixError::from)??;
move_unpacked_nix.revert().await?; move_unpacked_nix.revert().await?;
create_nix_dir.revert().await?;
tracing::trace!("Unprovisioned Nix"); tracing::trace!("Unprovisioned Nix");
*action_state = ActionState::Uncompleted; *action_state = ActionState::Uncompleted;
Ok(()) Ok(())

View file

@ -28,7 +28,10 @@ async fn execute_command(command: &mut Command) -> Result<Output, std::io::Error
true => Ok(output), true => Ok(output),
false => Err(std::io::Error::new( false => Err(std::io::Error::new(
std::io::ErrorKind::Other, std::io::ErrorKind::Other,
format!("Command `{command_str}` failed status"), format!(
"Command `{command_str}` failed status, stderr:\n{}\n",
String::from_utf8(output.stderr).unwrap_or_else(|_e| String::from("<Non-UTF-8>"))
),
)), )),
} }
} }

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
actions::{ actions::{
base::StartSystemdUnit, base::{CreateDirectory, StartSystemdUnit},
meta::{ConfigureNix, ProvisionNix}, meta::{ConfigureNix, ProvisionNix},
Action, ActionError, Action, ActionError,
}, },
@ -21,6 +21,10 @@ impl Plannable for LinuxMultiUser {
planner: Self.into(), planner: Self.into(),
settings: settings.clone(), settings: settings.clone(),
actions: vec![ actions: vec![
CreateDirectory::plan("/nix", None, None, 0o0755, true)
.await
.map(Action::from)
.map_err(ActionError::from)?,
ProvisionNix::plan(settings.clone()) ProvisionNix::plan(settings.clone())
.await .await
.map(Action::from) .map(Action::from)

View file

@ -20,8 +20,10 @@ impl Planner {
match (Architecture::host(), OperatingSystem::host()) { match (Architecture::host(), OperatingSystem::host()) {
(Architecture::X86_64, OperatingSystem::Linux) => Ok(Self::LinuxMultiUser), (Architecture::X86_64, OperatingSystem::Linux) => Ok(Self::LinuxMultiUser),
(Architecture::Aarch64(_), OperatingSystem::Linux) => Ok(Self::LinuxMultiUser), (Architecture::Aarch64(_), OperatingSystem::Linux) => Ok(Self::LinuxMultiUser),
(Architecture::X86_64, OperatingSystem::MacOSX { .. }) => Ok(Self::DarwinMultiUser), (Architecture::X86_64, OperatingSystem::MacOSX { .. })
(Architecture::Aarch64(_), OperatingSystem::MacOSX { .. }) => Ok(Self::DarwinMultiUser), | (Architecture::X86_64, OperatingSystem::Darwin) => Ok(Self::DarwinMultiUser),
(Architecture::Aarch64(_), OperatingSystem::MacOSX { .. })
| (Architecture::Aarch64(_), OperatingSystem::Darwin) => Ok(Self::DarwinMultiUser),
_ => Err(PlannerError::UnsupportedArchitecture(target_lexicon::HOST)), _ => Err(PlannerError::UnsupportedArchitecture(target_lexicon::HOST)),
} }
} }

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
actions::{ actions::{
base::StartSystemdUnit, base::{CreateDirectory, StartSystemdUnit},
meta::{CreateSystemdSysext, ProvisionNix}, meta::{CreateSystemdSysext, ProvisionNix},
Action, ActionError, Action, ActionError,
}, },
@ -27,6 +27,10 @@ impl Plannable for SteamDeck {
.await .await
.map(Action::from) .map(Action::from)
.map_err(ActionError::from)?, .map_err(ActionError::from)?,
CreateDirectory::plan("/nix", None, None, 0o0755, true)
.await
.map(Action::from)
.map_err(ActionError::from)?,
ProvisionNix::plan(settings.clone()) ProvisionNix::plan(settings.clone())
.await .await
.map(Action::from) .map(Action::from)

View file

@ -22,22 +22,32 @@ pub struct InstallSettings {
impl InstallSettings { impl InstallSettings {
pub fn default() -> Result<Self, InstallSettingsError> { pub fn default() -> Result<Self, InstallSettingsError> {
let url; let url;
let nix_build_user_prefix;
let nix_build_user_id_base;
use target_lexicon::{Architecture, OperatingSystem}; use target_lexicon::{Architecture, OperatingSystem};
match (Architecture::host(), OperatingSystem::host()) { match (Architecture::host(), OperatingSystem::host()) {
(Architecture::X86_64, OperatingSystem::Linux) => { (Architecture::X86_64, OperatingSystem::Linux) => {
url = "https://releases.nixos.org/nix/nix-2.11.0/nix-2.11.0-x86_64-linux.tar.xz"; url = "https://releases.nixos.org/nix/nix-2.11.0/nix-2.11.0-x86_64-linux.tar.xz";
nix_build_user_prefix = "nixbld";
nix_build_user_id_base = 3000;
}, },
(Architecture::Aarch64(_), OperatingSystem::Linux) => { (Architecture::Aarch64(_), OperatingSystem::Linux) => {
url = "https://releases.nixos.org/nix/nix-2.11.0/nix-2.11.0-aarch64-linux.tar.xz"; url = "https://releases.nixos.org/nix/nix-2.11.0/nix-2.11.0-aarch64-linux.tar.xz";
nix_build_user_prefix = "nixbld";
nix_build_user_id_base = 3000;
}, },
(Architecture::X86_64, OperatingSystem::MacOSX { .. }) (Architecture::X86_64, OperatingSystem::MacOSX { .. })
| (Architecture::X86_64, OperatingSystem::Darwin) => { | (Architecture::X86_64, OperatingSystem::Darwin) => {
url = "https://releases.nixos.org/nix/nix-2.11.0/nix-2.11.0-x86_64-darwin.tar.xz"; url = "https://releases.nixos.org/nix/nix-2.11.0/nix-2.11.0-x86_64-darwin.tar.xz";
nix_build_user_prefix = "_nixbld";
nix_build_user_id_base = 300;
}, },
(Architecture::Aarch64(_), OperatingSystem::MacOSX { .. }) (Architecture::Aarch64(_), OperatingSystem::MacOSX { .. })
| (Architecture::Aarch64(_), OperatingSystem::Darwin) => { | (Architecture::Aarch64(_), OperatingSystem::Darwin) => {
url = "https://releases.nixos.org/nix/nix-2.11.0/nix-2.11.0-aarch64-darwin.tar.xz"; url = "https://releases.nixos.org/nix/nix-2.11.0/nix-2.11.0-aarch64-darwin.tar.xz";
nix_build_user_prefix = "_nixbld";
nix_build_user_id_base = 300;
}, },
_ => { _ => {
return Err(InstallSettingsError::UnsupportedArchitecture( return Err(InstallSettingsError::UnsupportedArchitecture(
@ -53,8 +63,8 @@ impl InstallSettings {
modify_profile: Default::default(), modify_profile: Default::default(),
nix_build_group_name: String::from("nixbld"), nix_build_group_name: String::from("nixbld"),
nix_build_group_id: 3000, nix_build_group_id: 3000,
nix_build_user_prefix: String::from("nixbld"), nix_build_user_prefix: nix_build_user_prefix.to_string(),
nix_build_user_id_base: 3001, nix_build_user_id_base,
nix_package_url: url nix_package_url: url
.parse() .parse()
.expect("Could not parse default Nix archive url, please report this issue"), .expect("Could not parse default Nix archive url, please report this issue"),