mirror of
https://github.com/cachix/install-nix-action.git
synced 2024-11-24 01:18:05 +00:00
commit
f57eb6b95e
3 changed files with 141 additions and 30 deletions
102
lib/create-darwin-volume.sh
Executable file
102
lib/create-darwin-volume.sh
Executable file
|
@ -0,0 +1,102 @@
|
|||
#!/usr/bin/env bash
|
||||
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
|
||||
sudo defaults write /Library/Preferences/SystemConfiguration/autodiskmount AutomountDisksWithoutUserLogin -bool true
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
32
lib/main.js
32
lib/main.js
|
@ -19,7 +19,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||
const core = __importStar(require("@actions/core"));
|
||||
const exec = __importStar(require("@actions/exec"));
|
||||
const tc = __importStar(require("@actions/tool-cache"));
|
||||
const child_process_1 = require("child_process");
|
||||
const os_1 = require("os");
|
||||
const process_1 = require("process");
|
||||
const net_1 = require("net");
|
||||
function nixConf() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
// Workaround a segfault: https://github.com/NixOS/nix/issues/2733
|
||||
|
@ -35,22 +38,14 @@ function run() {
|
|||
return __awaiter(this, void 0, void 0, function* () {
|
||||
try {
|
||||
const PATH = process.env.PATH;
|
||||
const INSTALL_PATH = '/opt/nix';
|
||||
yield nixConf();
|
||||
// Catalina workaround https://github.com/NixOS/nix/issues/2925
|
||||
if (os_1.type() == "Darwin") {
|
||||
yield exec.exec("sudo", ["sh", "-c", `echo \"nix\t${INSTALL_PATH}\" >> /etc/synthetic.conf`]);
|
||||
yield exec.exec("sudo", ["sh", "-c", `mkdir -m 0755 ${INSTALL_PATH} && chown runner ${INSTALL_PATH}`]);
|
||||
yield exec.exec("/System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util", ["-B"]);
|
||||
// Needed for sudo to pass NIX_IGNORE_SYMLINK_STORE
|
||||
yield exec.exec("sudo", ["sh", "-c", "echo 'Defaults env_keep += NIX_IGNORE_SYMLINK_STORE' >> /etc/sudoers"]);
|
||||
core.exportVariable('NIX_IGNORE_SYMLINK_STORE', "1");
|
||||
// Needed for nix-daemon installation
|
||||
yield exec.exec("sudo", ["launchctl", "setenv", "NIX_IGNORE_SYMLINK_STORE", "1"]);
|
||||
child_process_1.execFileSync(`${__dirname}/create-darwin-volume.sh`, { stdio: 'inherit' });
|
||||
}
|
||||
// Needed due to multi-user being too defensive
|
||||
core.exportVariable('ALLOW_PREEXISTING_INSTALLATION', "1");
|
||||
// TODO: retry due to all the things that go wrong
|
||||
// TODO: retry due to all the things that can go wrong
|
||||
const nixInstall = yield tc.downloadTool('https://nixos.org/nix/install');
|
||||
yield exec.exec("sh", [nixInstall, "--daemon"]);
|
||||
// write nix.conf again as installation overwrites it, reload the daemon to pick up changes
|
||||
|
@ -63,9 +58,7 @@ function run() {
|
|||
// macOS needs certificates hints
|
||||
core.exportVariable('NIX_SSL_CERT_FILE', '/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt');
|
||||
// TODO: nc doesn't work correctly on macOS :(
|
||||
//await exec.exec("sh", ["-c", "while ! nc -zU /nix/var/nix/daemon-socket/socket; do sleep 0.5; done"]);
|
||||
// macOS needs time to reload the daemon :(
|
||||
yield exec.exec("sleep", ["10"]);
|
||||
yield awaitSocket();
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
|
@ -74,4 +67,17 @@ function run() {
|
|||
}
|
||||
});
|
||||
}
|
||||
function awaitSocket() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const daemonSocket = net_1.createConnection({ path: '/nix/var/nix/daemon-socket/socket' });
|
||||
daemonSocket.on('error', () => __awaiter(this, void 0, void 0, function* () {
|
||||
console.log('Waiting for daemon socket to be available, reconnecting...');
|
||||
yield new Promise(resolve => setTimeout(resolve, 500));
|
||||
yield awaitSocket();
|
||||
}));
|
||||
daemonSocket.on('connect', () => {
|
||||
process_1.exit(0);
|
||||
});
|
||||
});
|
||||
}
|
||||
run();
|
||||
|
|
37
src/main.ts
37
src/main.ts
|
@ -1,7 +1,10 @@
|
|||
import * as core from '@actions/core';
|
||||
import * as exec from '@actions/exec';
|
||||
import * as tc from '@actions/tool-cache';
|
||||
import {execFileSync} from 'child_process';
|
||||
import {type} from 'os';
|
||||
import {exit} from 'process';
|
||||
import {createConnection} from 'net';
|
||||
|
||||
async function nixConf() {
|
||||
// Workaround a segfault: https://github.com/NixOS/nix/issues/2733
|
||||
|
@ -17,28 +20,19 @@ async function nixConf() {
|
|||
|
||||
async function run() {
|
||||
try {
|
||||
const PATH = process.env.PATH;
|
||||
const INSTALL_PATH = '/opt/nix';
|
||||
const PATH = process.env.PATH;
|
||||
|
||||
await nixConf();
|
||||
|
||||
// Catalina workaround https://github.com/NixOS/nix/issues/2925
|
||||
if (type() == "Darwin") {
|
||||
await exec.exec("sudo", ["sh", "-c", `echo \"nix\t${INSTALL_PATH}\" >> /etc/synthetic.conf`]);
|
||||
await exec.exec("sudo", ["sh", "-c", `mkdir -m 0755 ${INSTALL_PATH} && chown runner ${INSTALL_PATH}`]);
|
||||
await exec.exec("/System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util", ["-B"]);
|
||||
|
||||
// Needed for sudo to pass NIX_IGNORE_SYMLINK_STORE
|
||||
await exec.exec("sudo", ["sh", "-c", "echo 'Defaults env_keep += NIX_IGNORE_SYMLINK_STORE' >> /etc/sudoers"]);
|
||||
core.exportVariable('NIX_IGNORE_SYMLINK_STORE', "1");
|
||||
// Needed for nix-daemon installation
|
||||
await exec.exec("sudo", ["launchctl", "setenv", "NIX_IGNORE_SYMLINK_STORE", "1"]);
|
||||
execFileSync(`${__dirname}/create-darwin-volume.sh`, { stdio: 'inherit' });
|
||||
}
|
||||
|
||||
// Needed due to multi-user being too defensive
|
||||
core.exportVariable('ALLOW_PREEXISTING_INSTALLATION', "1");
|
||||
|
||||
// TODO: retry due to all the things that go wrong
|
||||
// TODO: retry due to all the things that can go wrong
|
||||
const nixInstall = await tc.downloadTool('https://nixos.org/nix/install');
|
||||
await exec.exec("sh", [nixInstall, "--daemon"]);
|
||||
|
||||
|
@ -54,15 +48,24 @@ async function run() {
|
|||
core.exportVariable('NIX_SSL_CERT_FILE', '/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt');
|
||||
|
||||
// TODO: nc doesn't work correctly on macOS :(
|
||||
//await exec.exec("sh", ["-c", "while ! nc -zU /nix/var/nix/daemon-socket/socket; do sleep 0.5; done"]);
|
||||
// macOS needs time to reload the daemon :(
|
||||
await exec.exec("sleep", ["10"]);
|
||||
await awaitSocket();
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
core.setFailed(`Action failed with error: ${error}`);
|
||||
throw(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function awaitSocket() {
|
||||
const daemonSocket = createConnection({ path: '/nix/var/nix/daemon-socket/socket' });
|
||||
daemonSocket.on('error', async () => {
|
||||
console.log('Waiting for daemon socket to be available, reconnecting...');
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
await awaitSocket();
|
||||
});
|
||||
daemonSocket.on('connect', () => {
|
||||
exit(0);
|
||||
});
|
||||
}
|
||||
|
||||
run();
|
||||
|
|
Loading…
Reference in a new issue