Skip to content

Commit

Permalink
install: configure and bootstrap synthetic.conf on darwin
Browse files Browse the repository at this point in the history
Starting macOS 10.15 /nix can't be creasted directly anymore due to the
readonly filesystem, but synthetic.conf was introduced to enable
creating mountpoints or symlinks for special usecases like package
managers.
  • Loading branch information
LnL7 committed May 21, 2020
1 parent 5d2d0a7 commit 0726ad5
Show file tree
Hide file tree
Showing 3 changed files with 177 additions and 37 deletions.
12 changes: 9 additions & 3 deletions release.nix
Original file line number Diff line number Diff line change
Expand Up @@ -177,10 +177,10 @@ let
}
''
cp ${installerClosureInfo}/registration $TMPDIR/reginfo
cp ${./scripts/create-darwin-volume.sh} $TMPDIR/create-darwin-volume.sh
substitute ${./scripts/install-nix-from-closure.sh} $TMPDIR/install \
--subst-var-by nix ${toplevel} \
--subst-var-by cacert ${cacert}
substitute ${./scripts/install-darwin-multi-user.sh} $TMPDIR/install-darwin-multi-user.sh \
--subst-var-by nix ${toplevel} \
--subst-var-by cacert ${cacert}
Expand All @@ -195,6 +195,7 @@ let
# SC1090: Don't worry about not being able to find
# $nix/etc/profile.d/nix.sh
shellcheck --exclude SC1090 $TMPDIR/install
shellcheck $TMPDIR/create-darwin-volume.sh
shellcheck $TMPDIR/install-darwin-multi-user.sh
shellcheck $TMPDIR/install-systemd-multi-user.sh
Expand All @@ -210,6 +211,7 @@ let
fi
chmod +x $TMPDIR/install
chmod +x $TMPDIR/create-darwin-volume.sh
chmod +x $TMPDIR/install-darwin-multi-user.sh
chmod +x $TMPDIR/install-systemd-multi-user.sh
chmod +x $TMPDIR/install-multi-user
Expand All @@ -222,11 +224,15 @@ let
--absolute-names \
--hard-dereference \
--transform "s,$TMPDIR/install,$dir/install," \
--transform "s,$TMPDIR/create-darwin-volume.sh,$dir/create-darwin-volume.sh," \
--transform "s,$TMPDIR/reginfo,$dir/.reginfo," \
--transform "s,$NIX_STORE,$dir/store,S" \
$TMPDIR/install $TMPDIR/install-darwin-multi-user.sh \
$TMPDIR/install \
$TMPDIR/create-darwin-volume.sh \
$TMPDIR/install-darwin-multi-user.sh \
$TMPDIR/install-systemd-multi-user.sh \
$TMPDIR/install-multi-user $TMPDIR/reginfo \
$TMPDIR/install-multi-user \
$TMPDIR/reginfo \
$(cat ${installerClosureInfo}/store-paths)
'');

Expand Down
107 changes: 107 additions & 0 deletions scripts/create-darwin-volume.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#!/bin/sh
set -e

root_disks() {
diskutil list -plist /
}

apfs_volumes_for() {
disk=$1
diskutil apfs list -plist "$disk"
}

disk_identifier() {
xpath "/plist/dict/key[text()='WholeDisks']/following-sibling::array[1]/string/text()" 2>/dev/null
}

volume_get() {
key=$1 i=$2
xpath "/plist/dict/array/dict/key[text()='Volumes']/following-sibling::array/dict[$i]/key[text()='$key']/following-sibling::string[1]/text()" 2> /dev/null
}

find_nix_volume() {
disk=$1
i=1
volumes=$(apfs_volumes_for "$disk")
while true; do
name=$(echo "$volumes" | volume_get "Name" "$i")
if [ -z "$name" ]; then
break
fi
case "$name" in
[Nn]ix*)
echo "$name"
break
;;
esac
i=$((i+1))
done
}

test_fstab() {
grep -q "/nix" /etc/fstab 2>/dev/null
}

test_synthetic_conf() {
grep -q "^nix" /etc/synthetic.conf 2>/dev/null
}

test_nix() {
test -d "/nix"
}

main() {
(
echo ""
echo " ------------------------------------------------------------------ "
echo " | This installer will create a volume for the nix store and |"
echo " | configure it to mount at /nix. Follow these steps to uninstall. |"
echo " ------------------------------------------------------------------ "
echo ""
echo " 1. Remove the entry from fstab using 'sudo vifs'"
echo " 2. Destroy the data volume using 'diskutil apfs deleteVolume'"
echo " 3. Delete /etc/synthetic.conf"
echo ""
) >&2

if [ -L "/nix" ]; then
echo "error: /nix is a symlink, please remove it or edit synthetic.conf (requires reboot)" >&2
echo " /nix -> $(readlink "/nix")" >&2
exit 2
fi

if ! test_synthetic_conf; then
echo "Configuring /etc/synthetic.conf..." >&2
echo nix | sudo tee /etc/synthetic.conf
/System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util -B
fi

if ! test_nix; then
echo "Creating mountpoint for /nix..." >&2
sudo mkdir /nix
fi

disk=$(root_disks | disk_identifier)
volume=$(find_nix_volume "$disk")
if [ -z "$volume" ]; then
echo "Creating a Nix Store volume..." >&2
sudo diskutil apfs addVolume "$disk" APFS 'Nix Store' -mountpoint /nix
volume="Nix Store"
else
echo "Using existing '$volume' volume" >&2
fi

if ! test_fstab; then
echo "Configuring /etc/fstab..." >&2
label=$(echo "$volume" | sed 's/ /\\040/g')
printf "\$a\nLABEL=%s /nix apfs rw\n.\nwq\n" "$label" | EDITOR=ed sudo vifs
fi

echo "The following options can be enabled to disable spotlight indexing" >&2
echo "of the volume, which might be desirable." >&2
echo "" >&2
echo " $ mdutil -i off /nix" >&2
echo "" >&2
}

main "$@"
95 changes: 61 additions & 34 deletions scripts/install-nix-from-closure.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,44 +40,62 @@ elif [ "$(uname -s)" = "Linux" ] && [ -e /run/systemd/system ]; then
fi

INSTALL_MODE=no-daemon

CREATE_DARWIN_VOLUME=0
# handle the command line flags
while [ "x${1:-}" != "x" ]; do
if [ "x${1:-}" = "x--no-daemon" ]; then
INSTALL_MODE=no-daemon
elif [ "x${1:-}" = "x--daemon" ]; then
INSTALL_MODE=daemon
elif [ "x${1:-}" = "x--no-channel-add" ]; then
NIX_INSTALLER_NO_CHANNEL_ADD=1
elif [ "x${1:-}" = "x--no-modify-profile" ]; then
NIX_INSTALLER_NO_MODIFY_PROFILE=1
elif [ "x${1:-}" != "x" ]; then
(
echo "Nix Installer [--daemon|--no-daemon] [--no-channel-add] [--no-modify-profile]"

echo "Choose installation method."
echo ""
echo " --daemon: Installs and configures a background daemon that manages the store,"
echo " providing multi-user support and better isolation for local builds."
echo " Both for security and reproducibility, this method is recommended if"
echo " supported on your platform."
echo " See https://nixos.org/nix/manual/#sect-multi-user-installation"
echo ""
echo " --no-daemon: Simple, single-user installation that does not require root and is"
echo " trivial to uninstall."
echo " (default)"
echo ""
echo " --no-channel-add: Don't add any channels. nixpkgs-unstable is installed by default."
echo ""
echo " --no-modify-profile: Skip channel installation. When not provided nixpkgs-unstable"
echo " is installed by default."
echo ""
) >&2
exit
fi
while [ $# -gt 0 ]; do
case $1 in
--daemon)
INSTALL_MODE=daemon;;
--no-daemon)
INSTALL_MODE=no-daemon;;
--no-channel-add)
NIX_INSTALLER_NO_CHANNEL_ADD=1;;
--no-modify-profile)
NIX_INSTALLER_NO_MODIFY_PROFILE=1;;
--create-volume)
CREATE_DARWIN_VOLUME=1;;
*)
(
echo "Nix Installer [--daemon|--no-daemon] [--no-channel-add] [--no-modify-profile]"

echo "Choose installation method."
echo ""
echo " --daemon: Installs and configures a background daemon that manages the store,"
echo " providing multi-user support and better isolation for local builds."
echo " Both for security and reproducibility, this method is recommended if"
echo " supported on your platform."
echo " See https://nixos.org/nix/manual/#sect-multi-user-installation"
echo ""
echo " --no-daemon: Simple, single-user installation that does not require root and is"
echo " trivial to uninstall."
echo " (default)"
echo ""
echo " --no-channel-add: Don't add any channels. nixpkgs-unstable is installed by default."
echo ""
echo " --no-modify-profile: Skip channel installation. When not provided nixpkgs-unstable"
echo " is installed by default."
echo ""
) >&2

if [ "$(uname -s)" = "Darwin" ]; then
(
echo " --create-volume: Create an APFS volume for the store and create the /nix"
echo " mountpoint for it using synthetic.conf."
echo " (required on macOS >=10.15)"
echo " See https://nixos.org/nix/manual/#sect-darwin-apfs-volume"
echo ""
) >&2
fi
exit;;
esac
shift
done

if [ "$(uname -s)" = "Darwin" ] && [ "$CREATE_DARWIN_VOLUME" = 1 ]; then
printf '\e[1;31mCreating volume and mountpoint /nix.\e[0m\n'
"$self/create-darwin-volume.sh"
fi

if [ "$INSTALL_MODE" = "daemon" ]; then
printf '\e[1;31mSwitching to the Daemon-based Installer\e[0m\n'
exec "$self/install-multi-user"
Expand All @@ -95,6 +113,15 @@ if ! [ -e $dest ]; then
echo "directory $dest does not exist; creating it by running '$cmd' using sudo" >&2
if ! sudo sh -c "$cmd"; then
echo "$0: please manually run '$cmd' as root to create $dest" >&2
if [ "$(uname -s)" = "Darwin" ]; then
(
echo ""
echo "Installing on macOS >=10.15 requires relocating the store to an apfs volume."
echo "Use --create-volume or run the preparation steps manually."
echo "See https://nixos.org/nix/manual/#sect-darwin-apfs-volume."
echo ""
) >&2
fi
exit 1
fi
fi
Expand Down

0 comments on commit 0726ad5

Please sign in to comment.