Skip to content

Commit 2e04848

Browse files
cole-hcolemickens
andauthored
Add split-receipt command that splits receipt into phase 1 and 2 uninstallation flows (#1278)
* fixup: align ActionTag with serde and typetag tags * Bump to 0.28.0, since receipt format changed due to misaligned serde / typetag tags * fixup: make it possible to write receipts for anything serializable * Leave TODO about existing macos volume services being different * Remove determinate/upstream init service if it still exists * Check that the GID of an existing /nix/store is the same GID as we're going to create / use * fixup: make some fields pub(crate) for the upcoming split-receipt command * fixup: reorganize imports * Add `split-receipt` command that splits receipt into phase 1 and 2 uninstallation flows * Remove phase 1 and 2 uninstall receipts if they exist upon a successful install * Move split_receipt module into its own file * fixup: cargo clippy * fixup: extract "check existing nix store gid" into own function * fixup: define roundtrip_to_extract_type outside of other function * fixup: don't fail profile deserialization if UnknownProfileItem is missing fields plist::Value does not implement Eq, so we need to wrap it in something that does, I think, probably * fixup: put uninstall phase1 command on new line * Update fixtures * fixup: split_receipt: split match expression to separate let * fixup: roundtrip_to_exact_type: use type_name instead of manually passing action_tag --------- Co-authored-by: Cole Mickens <[email protected]>
1 parent d85fb91 commit 2e04848

File tree

22 files changed

+3200
-394
lines changed

22 files changed

+3200
-394
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "nix-installer"
33
description = "The Determinate Nix Installer"
4-
version = "0.27.1"
4+
version = "0.28.0"
55
edition = "2021"
66
resolver = "2"
77
license = "LGPL-2.1"

src/action/base/create_directory.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ If `force_prune_on_revert` is set, the folder will always be deleted on
2020
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
2121
#[serde(tag = "action_name", rename = "create_directory")]
2222
pub struct CreateDirectory {
23-
path: PathBuf,
23+
pub(crate) path: PathBuf,
2424
user: Option<String>,
2525
group: Option<String>,
2626
mode: Option<u32>,

src/action/common/configure_determinate_nixd_init_service/mod.rs

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ use crate::settings::InitSystem;
1414
const LINUX_NIXD_DAEMON_DEST: &str = "/etc/systemd/system/nix-daemon.service";
1515

1616
// Darwin
17-
const DARWIN_NIXD_DAEMON_DEST: &str = "/Library/LaunchDaemons/systems.determinate.nix-daemon.plist";
17+
pub(crate) const DARWIN_NIXD_DAEMON_DEST: &str =
18+
"/Library/LaunchDaemons/systems.determinate.nix-daemon.plist";
1819
const DARWIN_NIXD_SERVICE_NAME: &str = "systems.determinate.nix-daemon";
1920

2021
/**
@@ -37,7 +38,31 @@ impl ConfigureDeterminateNixdInitService {
3738
start_daemon: bool,
3839
) -> Result<StatefulAction<Self>, ActionError> {
3940
let service_dest: Option<PathBuf> = match init {
40-
InitSystem::Launchd => Some(DARWIN_NIXD_DAEMON_DEST.into()),
41+
InitSystem::Launchd => {
42+
// NOTE(cole-h): if the upstream daemon exists and we're installing determinate-
43+
// nixd, we need to remove the old daemon unit -- we used to have a bug[1] where
44+
// these service files wouldn't get removed, so we can't rely on them not being
45+
// there after phase 1 of the uninstall
46+
// [1]: https://github.com/DeterminateSystems/nix-installer/pull/1266
47+
if std::path::Path::new(
48+
super::configure_upstream_init_service::DARWIN_NIX_DAEMON_DEST,
49+
)
50+
.exists()
51+
{
52+
tokio::fs::remove_file(
53+
super::configure_upstream_init_service::DARWIN_NIX_DAEMON_DEST,
54+
)
55+
.await
56+
.map_err(|e| {
57+
Self::error(ActionErrorKind::Remove(
58+
super::configure_upstream_init_service::DARWIN_NIX_DAEMON_DEST.into(),
59+
e,
60+
))
61+
})?;
62+
}
63+
64+
Some(DARWIN_NIXD_DAEMON_DEST.into())
65+
},
4166
InitSystem::Systemd => Some(LINUX_NIXD_DAEMON_DEST.into()),
4267
InitSystem::None => None,
4368
};

src/action/common/configure_upstream_init_service.rs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::path::PathBuf;
22

33
use tracing::{span, Span};
44

5-
use crate::action::{ActionError, ActionTag, StatefulAction};
5+
use crate::action::{ActionError, ActionErrorKind, ActionTag, StatefulAction};
66

77
use crate::action::common::configure_init_service::{SocketFile, UnitSrc};
88
use crate::action::{common::ConfigureInitService, Action, ActionDescription};
@@ -15,7 +15,7 @@ const SERVICE_DEST: &str = "/etc/systemd/system/nix-daemon.service";
1515
// Darwin
1616
const DARWIN_NIX_DAEMON_SOURCE: &str =
1717
"/nix/var/nix/profiles/default/Library/LaunchDaemons/org.nixos.nix-daemon.plist";
18-
const DARWIN_NIX_DAEMON_DEST: &str = "/Library/LaunchDaemons/org.nixos.nix-daemon.plist";
18+
pub(crate) const DARWIN_NIX_DAEMON_DEST: &str = "/Library/LaunchDaemons/org.nixos.nix-daemon.plist";
1919
const DARWIN_LAUNCHD_SERVICE_NAME: &str = "org.nixos.nix-daemon";
2020

2121
/**
@@ -39,7 +39,32 @@ impl ConfigureUpstreamInitService {
3939
InitSystem::None => None,
4040
};
4141
let service_dest: Option<PathBuf> = match init {
42-
InitSystem::Launchd => Some(DARWIN_NIX_DAEMON_DEST.into()),
42+
InitSystem::Launchd => {
43+
// NOTE(cole-h): if the determinate daemon exists and we're installing the upstream
44+
// daemon, we need to remove the old daemon unit -- we used to have a bug[1] where
45+
// these service files wouldn't get removed, so we can't rely on them not being
46+
// there after phase 1 of the uninstall
47+
// [1]: https://github.com/DeterminateSystems/nix-installer/pull/1266
48+
if std::path::Path::new(
49+
super::configure_determinate_nixd_init_service::DARWIN_NIXD_DAEMON_DEST,
50+
)
51+
.exists()
52+
{
53+
tokio::fs::remove_file(
54+
super::configure_determinate_nixd_init_service::DARWIN_NIXD_DAEMON_DEST,
55+
)
56+
.await
57+
.map_err(|e| {
58+
Self::error(ActionErrorKind::Remove(
59+
super::configure_determinate_nixd_init_service::DARWIN_NIXD_DAEMON_DEST
60+
.into(),
61+
e,
62+
))
63+
})?;
64+
}
65+
66+
Some(DARWIN_NIX_DAEMON_DEST.into())
67+
},
4368
InitSystem::Systemd => Some(SERVICE_DEST.into()),
4469
InitSystem::None => None,
4570
};

src/action/common/provision_nix.rs

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,31 @@ use crate::{
88
},
99
settings::{CommonSettings, SCRATCH_DIR},
1010
};
11+
use std::os::unix::fs::MetadataExt as _;
1112
use std::path::PathBuf;
1213

14+
pub(crate) const NIX_STORE_LOCATION: &str = "/nix/store";
15+
1316
/**
1417
Place Nix and it's requirements onto the target
1518
*/
1619
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
1720
#[serde(tag = "action_name", rename = "provision_nix")]
1821
pub struct ProvisionNix {
19-
fetch_nix: StatefulAction<FetchAndUnpackNix>,
20-
create_nix_tree: StatefulAction<CreateNixTree>,
21-
move_unpacked_nix: StatefulAction<MoveUnpackedNix>,
22+
pub(crate) fetch_nix: StatefulAction<FetchAndUnpackNix>,
23+
pub(crate) create_nix_tree: StatefulAction<CreateNixTree>,
24+
pub(crate) move_unpacked_nix: StatefulAction<MoveUnpackedNix>,
2225
}
2326

2427
impl ProvisionNix {
2528
#[tracing::instrument(level = "debug", skip_all)]
2629
pub async fn plan(settings: &CommonSettings) -> Result<StatefulAction<Self>, ActionError> {
30+
if std::path::Path::new(NIX_STORE_LOCATION).exists() {
31+
check_existing_nix_store_gid_matches(settings.nix_build_group_id)
32+
.await
33+
.map_err(Self::error)?;
34+
}
35+
2736
let fetch_nix = FetchAndUnpackNix::plan(
2837
settings.nix_package_url.clone(),
2938
PathBuf::from(SCRATCH_DIR),
@@ -144,3 +153,24 @@ impl Action for ProvisionNix {
144153
}
145154
}
146155
}
156+
157+
/// If there is an existing /nix/store directory, ensure that the group ID we're going to use for
158+
/// the nix build group matches the group that owns /nix/store to prevent weird mismatched-ownership
159+
/// issues.
160+
async fn check_existing_nix_store_gid_matches(
161+
desired_nix_build_group_id: u32,
162+
) -> Result<(), ActionErrorKind> {
163+
let previous_store_metadata = tokio::fs::metadata(NIX_STORE_LOCATION)
164+
.await
165+
.map_err(|e| ActionErrorKind::GettingMetadata(NIX_STORE_LOCATION.into(), e))?;
166+
let previous_store_group_id = previous_store_metadata.gid();
167+
if previous_store_group_id != desired_nix_build_group_id {
168+
return Err(ActionErrorKind::PathGroupMismatch(
169+
NIX_STORE_LOCATION.into(),
170+
previous_store_group_id,
171+
desired_nix_build_group_id,
172+
));
173+
}
174+
175+
Ok(())
176+
}

src/action/macos/create_apfs_volume.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::action::{Action, ActionDescription};
1111
use crate::os::darwin::{DiskUtilApfsListOutput, DiskUtilInfoOutput};
1212

1313
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
14-
#[serde(tag = "action_name", rename = "create_volume")]
14+
#[serde(tag = "action_name", rename = "create_apfs_volume")]
1515
pub struct CreateApfsVolume {
1616
disk: PathBuf,
1717
name: String,
@@ -53,7 +53,7 @@ impl CreateApfsVolume {
5353
}
5454

5555
#[async_trait::async_trait]
56-
#[typetag::serde(name = "create_volume")]
56+
#[typetag::serde(name = "create_apfs_volume")]
5757
impl Action for CreateApfsVolume {
5858
fn action_tag() -> ActionTag {
5959
ActionTag("create_apfs_volume")

src/action/macos/create_determinate_nix_volume.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ pub struct CreateDeterminateNixVolume {
3535
create_directory: StatefulAction<CreateDirectory>,
3636
create_or_append_synthetic_conf: StatefulAction<CreateOrInsertIntoFile>,
3737
create_synthetic_objects: StatefulAction<CreateSyntheticObjects>,
38-
unmount_volume: StatefulAction<UnmountApfsVolume>,
39-
create_volume: StatefulAction<CreateApfsVolume>,
38+
pub(crate) unmount_volume: StatefulAction<UnmountApfsVolume>,
39+
pub(crate) create_volume: StatefulAction<CreateApfsVolume>,
4040
create_fstab_entry: StatefulAction<CreateFstabEntry>,
41-
encrypt_volume: StatefulAction<EncryptApfsVolume>,
41+
pub(crate) encrypt_volume: StatefulAction<EncryptApfsVolume>,
4242
setup_volume_daemon: StatefulAction<CreateDeterminateVolumeService>,
4343
bootstrap_volume: StatefulAction<BootstrapLaunchctlService>,
4444
kickstart_launchctl_service: StatefulAction<KickstartLaunchctlService>,

src/action/macos/create_nix_volume.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,18 @@ pub const NIX_VOLUME_MOUNTD_DEST: &str = "/Library/LaunchDaemons/org.nixos.darwi
2222

2323
/// Create an APFS volume
2424
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
25-
#[serde(tag = "action_name", rename = "create_apfs_volume")]
25+
#[serde(tag = "action_name", rename = "create_nix_volume")]
2626
pub struct CreateNixVolume {
2727
disk: PathBuf,
2828
name: String,
2929
case_sensitive: bool,
3030
encrypt: bool,
3131
create_or_append_synthetic_conf: StatefulAction<CreateOrInsertIntoFile>,
3232
create_synthetic_objects: StatefulAction<CreateSyntheticObjects>,
33-
unmount_volume: StatefulAction<UnmountApfsVolume>,
34-
create_volume: StatefulAction<CreateApfsVolume>,
33+
pub(crate) unmount_volume: StatefulAction<UnmountApfsVolume>,
34+
pub(crate) create_volume: StatefulAction<CreateApfsVolume>,
3535
create_fstab_entry: StatefulAction<CreateFstabEntry>,
36-
encrypt_volume: Option<StatefulAction<EncryptApfsVolume>>,
36+
pub(crate) encrypt_volume: Option<StatefulAction<EncryptApfsVolume>>,
3737
setup_volume_daemon: StatefulAction<CreateVolumeService>,
3838
bootstrap_volume: StatefulAction<BootstrapLaunchctlService>,
3939
kickstart_launchctl_service: StatefulAction<KickstartLaunchctlService>,
@@ -121,7 +121,7 @@ impl CreateNixVolume {
121121
}
122122

123123
#[async_trait::async_trait]
124-
#[typetag::serde(name = "create_apfs_volume")]
124+
#[typetag::serde(name = "create_nix_volume")]
125125
impl Action for CreateNixVolume {
126126
fn action_tag() -> ActionTag {
127127
ActionTag("create_nix_volume")
@@ -138,7 +138,7 @@ impl Action for CreateNixVolume {
138138
fn tracing_span(&self) -> Span {
139139
span!(
140140
tracing::Level::DEBUG,
141-
"create_apfs_volume",
141+
"create_nix_volume",
142142
disk = tracing::field::display(self.disk.display()),
143143
name = self.name
144144
)

src/action/macos/create_volume_service.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ impl CreateVolumeService {
103103
?expected_plist,
104104
"Parsed plists not equal"
105105
);
106+
// TODO(cole-h): should this really be an error? we could just replace the contents.......
107+
// maybe it's possible to have duplicate volume names...?
106108
return Err(Self::error(CreateVolumeServiceError::DifferentPlist {
107109
expected: expected_plist,
108110
discovered: discovered_plist,

0 commit comments

Comments
 (0)