diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..1de5659 --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +target \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f96e224..d539178 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Install Nix - uses: DeterminateSystems/nix-installer-action@main + uses: DeterminateSystems/nix-installer-action@start-daemon-and-init with: github-token: ${{ secrets.GITHUB_TOKEN }} - name: Cache lint store (x86_64-linux) @@ -36,7 +36,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Install Nix - uses: DeterminateSystems/nix-installer-action@main + uses: DeterminateSystems/nix-installer-action@start-daemon-and-init with: github-token: ${{ secrets.GITHUB_TOKEN }} - name: Cache build store (x86_64-linux) @@ -67,7 +67,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Install Nix - uses: DeterminateSystems/nix-installer-action@main + uses: DeterminateSystems/nix-installer-action@start-daemon-and-init with: github-token: ${{ secrets.GITHUB_TOKEN }} - name: Cache build store (x86_64-linux) @@ -100,7 +100,7 @@ jobs: cp nix-installer.sh install-root/nix-installer.sh mv nix-installer install-root/nix-installer-x86_64-linux - name: Initial install - uses: DeterminateSystems/nix-installer-action@main + uses: DeterminateSystems/nix-installer-action@start-daemon-and-init with: local-root: install-root/ logger: pretty @@ -129,7 +129,7 @@ jobs: exit 1 fi - name: Repeated install - uses: DeterminateSystems/nix-installer-action@main + uses: DeterminateSystems/nix-installer-action@start-daemon-and-init with: local-root: install-root/ logger: pretty @@ -184,6 +184,113 @@ jobs: exit 1 fi + run-x86_64-linux-no-init: + name: Run x86_64 Linux (No init) + runs-on: ubuntu-22.04 + needs: [build-x86_64-linux, lints] + steps: + - uses: actions/checkout@v3 + - run: sudo apt install fish zsh + - uses: actions/download-artifact@v3 + with: + name: nix-installer-x86_64-linux + - name: Move & set executable + run: | + chmod +x ./nix-installer + mkdir install-root + cp nix-installer.sh install-root/nix-installer.sh + mv nix-installer install-root/nix-installer-x86_64-linux + - name: Initial install + uses: DeterminateSystems/nix-installer-action@start-daemon-and-init + with: + init: none + planner: linux-multi + local-root: install-root/ + logger: pretty + log-directives: nix_installer=trace + backtrace: full + github-token: ${{ secrets.GITHUB_TOKEN }} + - name: Ensure daemon was not configured with init + run: | + if systemctl is-active nix-daemon.socket; then + echo "nix-daemon.socket was running" + exit 1 + fi + if systemctl is-active nix-daemon.service; then + echo "nix-daemon.service was running" + exit 1 + fi + - name: Initial uninstall (without a `nix run` first) + run: sudo -E /nix/nix-installer uninstall + env: + NIX_INSTALLER_NO_CONFIRM: true + NIX_INSTALLER_LOGGER: pretty + NIX_INSTALLER_LOG_DIRECTIVES: nix_installer=trace + RUST_BACKTRACE: full + - name: Ensure `nix` is removed + run: | + if [ -e /nix ]; then + echo "/nix exists" + exit 1 + fi + - name: Repeated install + uses: DeterminateSystems/nix-installer-action@start-daemon-and-init + with: + init: none + planner: linux-multi + local-root: install-root/ + logger: pretty + log-directives: nix_installer=trace + backtrace: full + github-token: ${{ secrets.GITHUB_TOKEN }} + - name: echo $PATH + run: echo $PATH + - name: Test `nix` with `$GITHUB_PATH` + if: success() || failure() + run: | + sudo -i nix run nixpkgs#fortune + sudo -i nix profile install nixpkgs#fortune + fortune + sudo -i nix store gc + sudo -i nix run nixpkgs#fortune + - name: Test bash + run: sudo -i nix-instantiate -E 'builtins.currentTime' --eval + if: success() || failure() + shell: bash --login {0} + - name: Test sh + run: sudo -i nix-instantiate -E 'builtins.currentTime' --eval + if: success() || failure() + shell: sh -l {0} + - name: Test zsh + run: sudo -i nix-instantiate -E 'builtins.currentTime' --eval + if: success() || failure() + shell: zsh --login --interactive {0} + - name: Test fish + run: sudo -i nix-instantiate -E 'builtins.currentTime' --eval + if: success() || failure() + shell: fish --login {0} + - name: Repeated uninstall + run: sudo -E /nix/nix-installer uninstall + env: + NIX_INSTALLER_NO_CONFIRM: true + NIX_INSTALLER_LOGGER: pretty + NIX_INSTALLER_LOG_DIRECTIVES: nix_installer=trace + RUST_BACKTRACE: full + - name: Ensure `nix` is removed + run: | + if systemctl is-active nix-daemon.socket; then + echo "nix-daemon.socket was running" + exit 1 + fi + if systemctl is-active nix-daemon.service; then + echo "nix-daemon.service was running" + exit 1 + fi + if [ -e /nix ]; then + echo "/nix exists" + exit 1 + fi + run-steam-deck: name: Run Steam Deck (mock) runs-on: ubuntu-22.04 @@ -207,7 +314,7 @@ jobs: sudo chmod +x /bin/steamos-readonly sudo useradd -m deck - name: Initial install - uses: DeterminateSystems/nix-installer-action@main + uses: DeterminateSystems/nix-installer-action@start-daemon-and-init with: local-root: install-root/ logger: pretty @@ -242,7 +349,7 @@ jobs: exit 1 fi - name: Repeated install - uses: DeterminateSystems/nix-installer-action@main + uses: DeterminateSystems/nix-installer-action@start-daemon-and-init with: local-root: install-root/ logger: pretty @@ -309,7 +416,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Install Nix - uses: DeterminateSystems/nix-installer-action@main + uses: DeterminateSystems/nix-installer-action@start-daemon-and-init with: github-token: ${{ secrets.GITHUB_TOKEN }} # Runs clippy as part of the preBuild. @@ -339,7 +446,7 @@ jobs: cp nix-installer.sh install-root/nix-installer.sh mv nix-installer install-root/nix-installer-x86_64-darwin - name: Initial install - uses: DeterminateSystems/nix-installer-action@main + uses: DeterminateSystems/nix-installer-action@start-daemon-and-init with: local-root: install-root/ logger: pretty @@ -356,7 +463,7 @@ jobs: NIX_INSTALLER_LOG_DIRECTIVES: nix_installer=trace RUST_BACKTRACE: full - name: Repeated install - uses: DeterminateSystems/nix-installer-action@main + uses: DeterminateSystems/nix-installer-action@start-daemon-and-init with: local-root: install-root/ logger: pretty @@ -397,4 +504,3 @@ jobs: NIX_INSTALLER_LOGGER: pretty NIX_INSTALLER_LOG_DIRECTIVES: nix_installer=trace RUST_BACKTRACE: full - \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1807179..c23d7a4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -156,7 +156,7 @@ It's perfectly fine if they are manual or labor intensive, as these should be a ## `qemu` VM tests -In `nix/tests/vm-test` there exists some Nix derivations which we expose in the flake via `hydraJobs`. +For x86_64 Linux we have some additional QEMU based tests. In `nix/tests/vm-test` there exists some Nix derivations which we expose in the flake via `hydraJobs`. These should be visible in `nix flake show`: @@ -190,13 +190,13 @@ git+file:///home/ana/git/determinatesystems/nix-installer To run all of the currently supported tests: ```bash -nix build .#hydraJobs.vm-test.all.x86_64-linux.install-default -L +nix build .#hydraJobs.vm-test.all.x86_64-linux.all -L ``` To run a specific distribution listed in the `nix flake show` output: ```bash -nix build .#hydraJobs.vm-test.rhel-v7.x86_64-linux.install-default -L +nix build .#hydraJobs.vm-test.rhel-v7.x86_64-linux.all -L ``` For PR review, you can also test arbitrary branches or checkouts like so: @@ -238,6 +238,120 @@ installer-test-rhel-v7-install-default> Formatting './disk.qcow2', fmt=qcow2 clu +## Container tests + + +For x86_64 Linux we have some additional container tests. In `nix/tests/container-test` there exists some Nix derivations which we expose in the flake via `hydraJobs`. + +These should be visible in `nix flake show`: + +``` +❯ nix flake show +warning: Git tree '/home/ana/git/determinatesystems/nix-installer' is dirty +git+file:///home/ana/git/determinatesystems/nix-installer +# ... +├───hydraJobs +│ ├───container-test +│ │ ├───all +│ │ │ └───x86_64-linux +│ │ │ ├───all: derivation 'all' +│ │ │ ├───docker: derivation 'all' +│ │ │ └───podman: derivation 'all' +│ │ ├───ubuntu-v18_04 +│ │ │ └───x86_64-linux +│ │ │ ├───all: derivation 'all' +│ │ │ ├───docker: derivation 'vm-test-run-container-test-ubuntu-v18_04' +│ │ │ └───podman: derivation 'vm-test-run-container-test-ubuntu-v18_04' +│ │ ├───ubuntu-v20_04 +│ │ │ └───x86_64-linux +│ │ │ ├───all: derivation 'all' +│ │ │ ├───docker: derivation 'vm-test-run-container-test-ubuntu-v20_04' +│ │ │ └───podman: derivation 'vm-test-run-container-test-ubuntu-v20_04' +│ │ └───ubuntu-v22_04 +│ │ └───x86_64-linux +│ │ ├───all: derivation 'all' +│ │ ├───docker: derivation 'vm-test-run-container-test-ubuntu-v22_04' +│ │ └───podman: derivation 'vm-test-run-container-test-ubuntu-v22_04' +``` + +To run all of the currently supported tests: + +```bash +nix build .#hydraJobs.container-test.all.x86_64-linux.all -L +``` + +To run a specific distribution listed in the `nix flake show` output: + +```bash +nix build .#hydraJobs.container-test.ubuntu-v22_04.x86_64-linux.docker -L +``` + +For PR review, you can also test arbitrary branches or checkouts like so: + +```bash +nix build github:determinatesystems/nix-installer/${BRANCH}#hydraJobs.container-test.ubuntu-v22_04.x86_64-linux.podman -L +``` + +
+ Adding a distro? + +Notice how `ubuntu-v20_02` has a `v20`, not just `20`? That's so the test output shows correctly, as Nix will interpret the first `-\d` (eg `-20`, `-123213`) as a version, and not show it in the output. + +Using `v20` instead turns: + +``` +# ... +vm-test-run-container-test-ubuntu> machine # [ 23.385182] dhcpcd[670]: vethae56f366: deleting address fe80::c036:c8ff:fe04:5832 +vm-test-run-container-test-ubuntu> machine # this derivation will be built: +vm-test-run-container-test-ubuntu> machine # /nix/store/9qb0l9n1gsmcyynfmndnq3qpmlvq8rln-foo.drv +vm-test-run-container-test-ubuntu> machine # [ 23.424605] dhcpcd[670]: vethae56f366: removing interface +vm-test-run-container-test-ubuntu> machine # building '/nix/store/9qb0l9n1gsmcyynfmndnq3qpmlvq8rln-foo.drv'... +vm-test-run-container-test-ubuntu> machine # [ 23.371066] systemd[1]: crun-buildah-buildah1810857047.scope: Deactivated successfully. +# ... +``` + +Into this: + +``` +# ... +vm-test-run-container-test-ubuntu-v18_04> machine # [ 23.385182] dhcpcd[670]: vethae56f366: deleting address fe80::c036:c8ff:fe04:5832 +vm-test-run-container-test-ubuntu-v20_04> machine # this derivation will be built: +vm-test-run-container-test-ubuntu-v20_04> machine # /nix/store/9qb0l9n1gsmcyynfmndnq3qpmlvq8rln-foo.drv +vm-test-run-container-test-ubuntu-v18_04> machine # [ 23.424605] dhcpcd[670]: vethae56f366: removing interface +vm-test-run-container-test-ubuntu-v20_04> machine # building '/nix/store/9qb0l9n1gsmcyynfmndnq3qpmlvq8rln-foo.drv'... +vm-test-run-container-test-ubuntu-v20_04> machine # [ 23.371066] systemd[1]: crun-buildah-buildah1810857047.scope: Deactivated successfully. +# ... +``` + +
+ +## WSL tests + +On a Windows Machine with WSL2 enabled (and updated to [support systemd](https://ubuntu.com/blog/ubuntu-wsl-enable-systemd)) you can test using WSL the scripts in `tests/windows`: + +```powershell +.\tests\windows\test-wsl.ps1 +.\tests\windows\test-wsl.ps1 -Systemd +``` + +If something breaks you may need to unregister the test WSL instance. First, look for the distro prefixed with `nix-installer-test`: + +```powershell +$ wsl --list +Windows Subsystem for Linux Distributions: +Ubuntu (Default) +nix-installer-test-ubuntu-jammy +``` + +Then delete it: + +```powershell +wsl --unregister nix-installer-test-ubuntu-jammy +``` + +You can also remove your `$HOME/nix-installer-wsl-tests-temp` folder whenever you wish. + + ## Testing the `action.yml` The `action.yml` is used directly in the CI process, so it is automatically tested for most changes. diff --git a/README.md b/README.md index 04754b5..2c4cc0d 100644 --- a/README.md +++ b/README.md @@ -16,12 +16,11 @@ curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix Current and planned support: -* [x] Multi-user Linux (aarch64 and x86_64) with systemd init, no SELinux -* [x] Multi-user MacOS (aarch64 and x86_64) - + Note: User deletion is currently unimplemented, you need to use a user with a secure token and `dscl . -delete /Users/_nixbuild*` where `*` is each user number. -* [x] Valve Steam Deck -* [ ] Multi-user Linux (aarch64 and x86_64) with systemd init & SELinux -* [ ] Single-user Linux (aarch64 and x86_64) +* [x] Multi-user Linux (aarch64 and x86_64) with systemd integration, no SELinux +* [x] Root-only Linux (aarch64 and x86_64) with no init integration, no SELinux +* [x] Multi-user MacOS (aarch64 and x86_64) with launchd integration +* [x] SteamOS on the Valve Steam Deck +* [ ] Multi-user Linux (aarch64 and x86_64) with systemd integration & SELinux * [ ] Others... ## Installation Differences @@ -95,16 +94,16 @@ Usage: nix-installer install linux-multi [OPTIONS] Options: # ... - --nix-build-user-count - Number of build users to create + --nix-build-group-name + The Nix build group name - [env: NIX_INSTALLER_NIX_BUILD_USER_COUNT=] - [default: 32] + [env: NIX_INSTALLER_NIX_BUILD_GROUP_NAME=] + [default: nixbld] - --nix-build-user-id-base - The Nix build user base UID (ascending) + --nix-build-group-id + The Nix build group GID - [env: NIX_INSTALLER_NIX_BUILD_USER_ID_BASE=] + [env: NIX_INSTALLER_NIX_BUILD_GROUP_ID=] [default: 3000] # ... ``` @@ -112,9 +111,9 @@ Options: Planners can be configured via environment variable or command arguments: ```bash -$ curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | NIX_BUILD_USER_COUNT=4 sh -s -- install linux-multi --nix-build-user-id-base 4000 +$ curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | NIX_BUILD_GROUP_NAME=nixbuilder sh -s -- install linux-multi --nix-build-group-id 4000 # Or... -$ NIX_BUILD_USER_COUNT=4 ./nix-installer install linux-multi --nix-build-user-id-base 4000 +$ NIX_BUILD_GROUP_NAME=nixbuilder ./nix-installer install linux-multi --nix-build-group-id 4000 ``` @@ -145,28 +144,102 @@ jobs: - uses: actions/checkout@v3 - name: Install Nix uses: DeterminateSystems/nix-installer-action@main - with: - # Allow the installed Nix to make authenticated Github requests. - # If you skip this, you will likely get rate limited. - github-token: ${{ secrets.GITHUB_TOKEN }} - name: Run `nix build` run: nix build . ``` +## In a container -## Building +In Docker/Podman containers or WSL instances where an init (like `systemd`) is not present, pass `--init none`. + +> When `--init none` is used, only `root` or sudoers can run Nix: +> +> ```bash +> sudo -i nix run nixpkgs#hello +> ``` + +For Docker containers (without an init): + +```dockerfile +# Dockerfile +FROM ubuntu:latest +RUN apt update -y +RUN apt install curl -y +COPY nix-installer /nix-installer +RUN /nix-installer install linux-multi --init none --no-confirm +ENV PATH="${PATH}:/nix/var/nix/profiles/default/bin" +RUN nix run nixpkgs#hello +``` + +Podman containers require `sandbox = false` in your `Nix.conf`. + +For podman containers without an init: + +```dockerfile +# Dockerfile +FROM ubuntu:latest +RUN apt update -y +RUN apt install curl -y +COPY nix-installer /nix-installer +RUN /nix-installer install linux-multi --extra-conf "sandbox = false" --init none --no-confirm +ENV PATH="${PATH}:/nix/var/nix/profiles/default/bin" +RUN nix run nixpkgs#hello +``` + +For Podman containers with an init: + +```dockerfile +# Dockerfile +FROM ubuntu:latest +RUN apt update -y +RUN apt install curl systemd -y +COPY nix-installer /nix-installer +RUN /nix-installer install linux-multi --extra-conf "sandbox = false" --no-start-daemon --no-confirm +ENV PATH="${PATH}:/nix/var/nix/profiles/default/bin" +RUN nix run nixpkgs#hello +CMD [ "/usr/sbin/init" ] +``` + +## In WSL + +If [systemd is enabled](https://ubuntu.com/blog/ubuntu-wsl-enable-systemd) it's possible to install Nix as normal using the command at the top of this document: + +```bash +curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install +``` + +If systemd is not enabled, pass `--init none` at the end of the command: + +> When `--init none` is used, only `root` or sudoers can run Nix: +> +> ```bash +> sudo -i nix run nixpkgs#hello +> ``` + + +```bash +curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install --init none +``` + +## Building a binary Since you'll be using `nix-installer` to install Nix on systems without Nix, the default build is a static binary. -Build a portable binary on a system with Nix: +Build a portable Linux binary on a system with Nix: ```bash nix build -L github:determinatesystems/nix-installer#nix-installer-static ``` +On Mac: + +```bash +nix build -L github:determinatesystems/nix-installer#nix-installer +``` + Then copy the `result/bin/nix-installer` to the machine you wish to run it on. -You can also add `nix-installer` to your system without having Nix: +You can also add `nix-installer` to a system without Nix via `cargo`: ```bash RUSTFLAGS="--cfg tokio_unstable" cargo install nix-installer @@ -188,7 +261,7 @@ cargo add nix-installer > **Building a CLI?** Check out the `cli` feature flag for `clap` integration. -You'll also need to edit your `.cargo/config.toml` to use `tokio_unstable`: +You'll also need to edit your `.cargo/config.toml` to use `tokio_unstable` as we utilize [Tokio's process groups](https://docs.rs/tokio/1.24.1/tokio/process/struct.Command.html#method.process_group), which wrap stable `std` APIs, but are unstable due to it requiring an MSRV bump: ```toml # .cargo/config.toml @@ -208,3 +281,5 @@ Documentation is also available via `nix` build: nix build github:DeterminateSystems/nix-installer#nix-installer.doc firefox result-doc/nix-installer/index.html ``` + + diff --git a/flake.nix b/flake.nix index 4942b8e..14145fd 100644 --- a/flake.nix +++ b/flake.nix @@ -182,6 +182,10 @@ inherit forSystem; inherit (nix.hydraJobs) binaryTarball; }; + container-test = import ./nix/tests/container-test { + inherit forSystem; + inherit (nix.hydraJobs) binaryTarball; + }; }; }; } diff --git a/nix/check.nix b/nix/check.nix index e2a7255..5a45b57 100644 --- a/nix/check.nix +++ b/nix/check.nix @@ -18,8 +18,8 @@ in runtimeInputs = with pkgs; [ git codespell ]; text = '' codespell \ - --ignore-words-list ba,sur,crate,pullrequest,pullrequests,ser \ - --skip target \ + --ignore-words-list ba,sur,crate,pullrequest,pullrequests,ser,distroname \ + --skip target,.git \ . ''; }); diff --git a/nix/tests/container-test/default.nix b/nix/tests/container-test/default.nix new file mode 100644 index 0000000..ba66ab5 --- /dev/null +++ b/nix/tests/container-test/default.nix @@ -0,0 +1,100 @@ +# Largely derived from https://github.com/NixOS/nix/blob/14f7dae3e4eb0c34192d0077383a7f2a2d630129/tests/installer/default.nix +{ forSystem, binaryTarball }: + +let + images = { + + # Found via https://hub.docker.com/_/ubuntu/ under "How is the rootfs build?" + # Jammy + "ubuntu-v22_04" = { + tarball = import { + url = "https://launchpad.net/~cloud-images-release-managers/+livefs/ubuntu/jammy/ubuntu-oci/+build/408115/+files/livecd.ubuntu-oci.rootfs.tar.gz"; + hash = "sha256-BirwSM4c+ZV1upU0yV3qa+BW9AvpBUxvZuPTeI9mA8M="; + }; + tester = ./default/Dockerfile; + system = "x86_64-linux"; + }; + + # focal + "ubuntu-v20_04" = { + tarball = import { + url = "https://launchpad.net/~cloud-images-release-managers/+livefs/ubuntu/focal/ubuntu-oci/+build/408120/+files/livecd.ubuntu-oci.rootfs.tar.gz"; + hash = "sha256-iTJR+DeC5lT4PMqT/xFAFwmlC/qvslDFccDrVFLt/a8="; + }; + tester = ./default/Dockerfile; + system = "x86_64-linux"; + }; + + # bionic + "ubuntu-v18_04" = { + tarball = import { + url = "https://launchpad.net/~cloud-images-release-managers/+livefs/ubuntu/bionic/ubuntu-oci/+build/408103/+files/livecd.ubuntu-oci.rootfs.tar.gz"; + hash = "sha256-gi48yl5laoKLoVCDIORsseOM6DI58FNpAjSVe7OOs7I="; + }; + tester = ./default/Dockerfile; + system = "x86_64-linux"; + }; + + }; + + makeTest = containerTool: imageName: + let image = images.${imageName}; in + with (forSystem image.system ({ system, pkgs, lib, ... }: pkgs)); + testers.nixosTest + { + name = "container-test-${imageName}"; + nodes = { + machine = + { config, pkgs, ... }: { + virtualisation.${containerTool}.enable = true; + }; + }; + testScript = '' + machine.start() + machine.copy_from_host("${image.tarball}", "/image") + machine.succeed("mkdir -p /test") + machine.copy_from_host("${image.tester}", "/test/Dockerfile") + machine.copy_from_host("${nix-installer-static}", "/test/nix-installer") + machine.copy_from_host("${binaryTarball.${system}}", "/test/binary-tarball") + machine.succeed("${containerTool} import /image default") + machine.succeed("${containerTool} build -t test /test") + ''; + }; + + container-tests = builtins.mapAttrs + (imageName: image: (with (forSystem "x86_64-linux" ({ system, pkgs, ... }: pkgs)); { + ${image.system} = rec { + docker = makeTest "docker" imageName; + podman = makeTest "podman" imageName; + all = pkgs.releaseTools.aggregate { + name = "all"; + constituents = [ + docker + podman + ]; + }; + }; + })) + images; + +in +container-tests // { + all."x86_64-linux" = rec { + all = (with (forSystem "x86_64-linux" ({ system, pkgs, ... }: pkgs)); pkgs.releaseTools.aggregate { + name = "all"; + constituents = [ + docker + podman + ]; + }); + docker = (with (forSystem "x86_64-linux" ({ system, pkgs, ... }: pkgs)); pkgs.releaseTools.aggregate { + name = "all"; + constituents = pkgs.lib.mapAttrsToList (name: value: value."x86_64-linux".docker) container-tests; + }); + podman = (with (forSystem "x86_64-linux" ({ system, pkgs, ... }: pkgs)); pkgs.releaseTools.aggregate { + name = "all"; + constituents = pkgs.lib.mapAttrsToList (name: value: value."x86_64-linux".podman) container-tests; + }); + }; +} + diff --git a/nix/tests/container-test/default/Dockerfile b/nix/tests/container-test/default/Dockerfile new file mode 100644 index 0000000..eac0f65 --- /dev/null +++ b/nix/tests/container-test/default/Dockerfile @@ -0,0 +1,8 @@ +FROM default +COPY nix-installer /nix-installer +RUN chmod +x /nix-installer +COPY binary-tarball /binary-tarball +RUN mv /binary-tarball/nix-*.tar.xz nix.tar.xz +RUN /nix-installer/bin/nix-installer install linux-multi --nix-package-url file:///nix.tar.xz --init none --extra-conf "sandbox = false" --channel --no-confirm -vvv +ENV PATH="${PATH}:/nix/var/nix/profiles/default/bin" +RUN nix-build --no-substitute -E 'derivation { name = "foo"; system = "x86_64-linux"; builder = "/bin/sh"; args = ["-c" "echo foobar > $out"]; }' \ No newline at end of file diff --git a/nix/tests/vm-test/default.nix b/nix/tests/vm-test/default.nix index fb18048..9ead800 100644 --- a/nix/tests/vm-test/default.nix +++ b/nix/tests/vm-test/default.nix @@ -5,10 +5,61 @@ let installScripts = { install-default = { - script = '' + install = '' NIX_PATH=$(readlink -f nix.tar.xz) RUST_BACKTRACE="full" ./nix-installer install --logger pretty --log-directive nix_installer=trace --channel --nix-package-url "file://$NIX_PATH" --no-confirm ''; + check = '' + set -ex + + nix-env --version + nix --extra-experimental-features nix-command store ping + + out=$(nix-build --no-substitute -E 'derivation { name = "foo"; system = "x86_64-linux"; builder = "/bin/sh"; args = ["-c" "echo foobar > $out"]; }') + [[ $(cat $out) = foobar ]] + ''; + }; + install-no-start-daemon = { + install = '' + NIX_PATH=$(readlink -f nix.tar.xz) + RUST_BACKTRACE="full" ./nix-installer install linux-multi --no-start-daemon --logger pretty --log-directive nix_installer=trace --channel --nix-package-url "file://$NIX_PATH" --no-confirm + ''; + check = '' + set -ex + + if systemctl is-active nix-daemon.socket; then + echo "nix-daemon.socket was running, should not be" + exit 1 + fi + if systemctl is-active nix-daemon.service; then + echo "nix-daemon.service was running, should not be" + exit 1 + fi + + sudo systemctl start nix-daemon.socket + + nix-env --version + nix --extra-experimental-features nix-command store ping + + out=$(nix-build --no-substitute -E 'derivation { name = "foo"; system = "x86_64-linux"; builder = "/bin/sh"; args = ["-c" "echo foobar > $out"]; }') + [[ $(cat $out) = foobar ]] + ''; + }; + install-daemonless = { + install = '' + NIX_PATH=$(readlink -f nix.tar.xz) + RUST_BACKTRACE="full" ./nix-installer install linux-multi --init none --logger pretty --log-directive nix_installer=trace --channel --nix-package-url "file://$NIX_PATH" --no-confirm + ''; + check = '' + set -ex + + sudo -i nix-env --version + sudo -i nix --extra-experimental-features nix-command store ping + + echo 'derivation { name = "foo"; system = "x86_64-linux"; builder = "/bin/sh"; args = ["-c" "echo foobar > $out"]; }' | sudo tee -a /drv + out=$(sudo -i nix-build --no-substitute /drv) + [[ $(cat $out) = foobar ]] + ''; }; }; @@ -114,7 +165,8 @@ let buildInputs = [ qemu_kvm openssh ]; image = image.image; postBoot = image.postBoot or ""; - installScript = installScripts.${testName}.script; + installScript = installScripts.${testName}.install; + checkScript = installScripts.${testName}.check; installer = nix-installer-static; binaryTarball = binaryTarball.${system}; } @@ -182,15 +234,7 @@ let $ssh "set -eux; $installScript" echo "Testing Nix installation..." - $ssh < \$out"]; }') - [[ \$(cat \$out) = foobar ]] - EOF + $ssh "set -eux; $checkScript" echo "Done!" touch $out @@ -198,20 +242,47 @@ let vm-tests = builtins.mapAttrs (imageName: image: - { - ${image.system} = builtins.mapAttrs + rec { + ${image.system} = (builtins.mapAttrs (testName: test: makeTest imageName testName ) - installScripts; + installScripts) // { + all = (with (forSystem "x86_64-linux" ({ system, pkgs, ... }: pkgs)); pkgs.releaseTools.aggregate { + name = "all"; + constituents = ( + pkgs.lib.mapAttrsToList + (testName: test: + makeTest imageName testName + ) + installScripts + ); + }); + }; } ) images; in -vm-tests // { +vm-tests // rec { all."x86_64-linux".install-default = (with (forSystem "x86_64-linux" ({ system, pkgs, ... }: pkgs)); pkgs.releaseTools.aggregate { name = "all"; constituents = pkgs.lib.mapAttrsToList (name: value: value."x86_64-linux".install-default) vm-tests; }); + all."x86_64-linux".install-no-start-daemon = (with (forSystem "x86_64-linux" ({ system, pkgs, ... }: pkgs)); pkgs.releaseTools.aggregate { + name = "all"; + constituents = pkgs.lib.mapAttrsToList (name: value: value."x86_64-linux".install-default) vm-tests; + }); + all."x86_64-linux".install-daemonless = (with (forSystem "x86_64-linux" ({ system, pkgs, ... }: pkgs)); pkgs.releaseTools.aggregate { + name = "all"; + constituents = pkgs.lib.mapAttrsToList (name: value: value."x86_64-linux".install-daemonless) vm-tests; + }); + all."x86_64-linux".all = (with (forSystem "x86_64-linux" ({ system, pkgs, ... }: pkgs)); pkgs.releaseTools.aggregate { + name = "all"; + constituents = [ + all."x86_64-linux".install-default + all."x86_64-linux".install-no-start-daemon + all."x86_64-linux".install-daemonless + ]; + }); } diff --git a/src/action/base/setup_default_profile.rs b/src/action/base/setup_default_profile.rs index 7a77864..ac5cbe6 100644 --- a/src/action/base/setup_default_profile.rs +++ b/src/action/base/setup_default_profile.rs @@ -2,7 +2,7 @@ use std::path::{Path, PathBuf}; use crate::{ action::{ActionError, StatefulAction}, - execute_command, set_env, + execute_command, set_env, ChannelValue, }; use glob::glob; @@ -17,12 +17,12 @@ Setup the default Nix profile with `nss-cacert` and `nix` itself. */ #[derive(Debug, serde::Deserialize, serde::Serialize, Clone)] pub struct SetupDefaultProfile { - channels: Vec, + channels: Vec, } impl SetupDefaultProfile { #[tracing::instrument(level = "debug", skip_all)] - pub async fn plan(channels: Vec) -> Result, ActionError> { + pub async fn plan(channels: Vec) -> Result, ActionError> { Ok(Self { channels }.into()) } } @@ -38,7 +38,12 @@ impl Action for SetupDefaultProfile { span!( tracing::Level::DEBUG, "setup_default_profile", - channels = self.channels.join(","), + channels = self + .channels + .iter() + .map(|ChannelValue(channel, url)| format!("{channel}={url}")) + .collect::>() + .join(","), ) } @@ -206,7 +211,7 @@ impl Action for SetupDefaultProfile { command.process_group(0); command.arg("--update"); for channel in channels { - command.arg(channel); + command.arg(channel.0.clone()); } command.env( "NIX_SSL_CERT_FILE", diff --git a/src/action/common/configure_nix_daemon_service.rs b/src/action/common/configure_init_service.rs similarity index 62% rename from src/action/common/configure_nix_daemon_service.rs rename to src/action/common/configure_init_service.rs index e76c8e5..ddd6fce 100644 --- a/src/action/common/configure_nix_daemon_service.rs +++ b/src/action/common/configure_init_service.rs @@ -1,7 +1,5 @@ -use std::path::{Path, PathBuf}; +use std::path::PathBuf; -use target_lexicon::OperatingSystem; -use tokio::fs::remove_file; use tokio::process::Command; use tracing::{span, Span}; @@ -9,48 +7,54 @@ use crate::action::{ActionError, StatefulAction}; use crate::execute_command; use crate::action::{Action, ActionDescription}; +use crate::settings::InitSystem; +#[cfg(target_os = "linux")] const SERVICE_SRC: &str = "/nix/var/nix/profiles/default/lib/systemd/system/nix-daemon.service"; +#[cfg(target_os = "linux")] const SOCKET_SRC: &str = "/nix/var/nix/profiles/default/lib/systemd/system/nix-daemon.socket"; +#[cfg(target_os = "linux")] const TMPFILES_SRC: &str = "/nix/var/nix/profiles/default/lib/tmpfiles.d/nix-daemon.conf"; +#[cfg(target_os = "linux")] const TMPFILES_DEST: &str = "/etc/tmpfiles.d/nix-daemon.conf"; +#[cfg(target_os = "macos")] const DARWIN_NIX_DAEMON_DEST: &str = "/Library/LaunchDaemons/org.nixos.nix-daemon.plist"; +#[cfg(target_os = "macos")] const DARWIN_NIX_DAEMON_SOURCE: &str = "/nix/var/nix/profiles/default/Library/LaunchDaemons/org.nixos.nix-daemon.plist"; /** -Run systemd utilities to configure the Nix daemon +Configure the init to run the Nix daemon */ #[derive(Debug, serde::Deserialize, serde::Serialize, Clone)] -pub struct ConfigureNixDaemonService {} +pub struct ConfigureInitService { + init: InitSystem, + start_daemon: bool, +} -impl ConfigureNixDaemonService { +impl ConfigureInitService { #[tracing::instrument(level = "debug", skip_all)] - pub async fn plan() -> Result, ActionError> { - match OperatingSystem::host() { - OperatingSystem::MacOSX { - major: _, - minor: _, - patch: _, - } - | OperatingSystem::Darwin => (), - _ => { - if !Path::new("/run/systemd/system").exists() { - return Err(ActionError::Custom(Box::new( - ConfigureNixDaemonServiceError::InitNotSupported, - ))); - } - }, - }; - - Ok(Self {}.into()) + pub async fn plan( + init: InitSystem, + start_daemon: bool, + ) -> Result, ActionError> { + Ok(Self { init, start_daemon }.into()) } } #[async_trait::async_trait] #[typetag::serde(name = "configure_nix_daemon")] -impl Action for ConfigureNixDaemonService { +impl Action for ConfigureInitService { fn tracing_synopsis(&self) -> String { - "Configure Nix daemon related settings with systemd".to_string() + match self.init { + #[cfg(target_os = "linux")] + InitSystem::Systemd => "Configure Nix daemon related settings with systemd".to_string(), + #[cfg(target_os = "macos")] + InitSystem::Launchd => { + "Configure Nix daemon related settings with launchctl".to_string() + }, + #[cfg(not(target_os = "macos"))] + InitSystem::None => "Leave the Nix daemon unconfigured".to_string(), + } } fn tracing_span(&self) -> Span { @@ -58,44 +62,45 @@ impl Action for ConfigureNixDaemonService { } fn execute_description(&self) -> Vec { - match OperatingSystem::host() { - OperatingSystem::MacOSX { - major: _, - minor: _, - patch: _, - } - | OperatingSystem::Darwin => vec![ActionDescription::new( - self.tracing_synopsis(), - vec![ - format!("Copy `{DARWIN_NIX_DAEMON_SOURCE}` to `DARWIN_NIX_DAEMON_DEST`"), - format!("Run `launchctl load {DARWIN_NIX_DAEMON_DEST}`"), - ], - )], - _ => vec![ActionDescription::new( - self.tracing_synopsis(), - vec![ + let mut vec = Vec::new(); + match self.init { + #[cfg(target_os = "linux")] + InitSystem::Systemd => { + let mut explanation = vec![ "Run `systemd-tempfiles --create --prefix=/nix/var/nix`".to_string(), format!("Run `systemctl link {SERVICE_SRC}`"), format!("Run `systemctl link {SOCKET_SRC}`"), "Run `systemctl daemon-reload`".to_string(), - format!("Run `systemctl enable --now {SOCKET_SRC}`"), - ], - )], + ]; + if self.start_daemon { + explanation.push(format!("Run `systemctl enable --now {SOCKET_SRC}`")); + } + vec.push(ActionDescription::new(self.tracing_synopsis(), explanation)) + }, + #[cfg(target_os = "macos")] + InitSystem::Launchd => { + let mut explanation = vec![format!( + "Copy `{DARWIN_NIX_DAEMON_SOURCE}` to `DARWIN_NIX_DAEMON_DEST`" + )]; + if self.start_daemon { + explanation.push(format!("Run `launchctl load {DARWIN_NIX_DAEMON_DEST}`")); + } + vec.push(ActionDescription::new(self.tracing_synopsis(), explanation)) + }, + #[cfg(not(target_os = "macos"))] + InitSystem::None => (), } + vec } #[tracing::instrument(level = "debug", skip_all)] async fn execute(&mut self) -> Result<(), ActionError> { - let Self {} = self; + let Self { init, start_daemon } = self; - match OperatingSystem::host() { - OperatingSystem::MacOSX { - major: _, - minor: _, - patch: _, - } - | OperatingSystem::Darwin => { - let src = Path::new(DARWIN_NIX_DAEMON_SOURCE); + match init { + #[cfg(target_os = "macos")] + InitSystem::Launchd => { + let src = std::path::Path::new(DARWIN_NIX_DAEMON_SOURCE); tokio::fs::copy(src.clone(), DARWIN_NIX_DAEMON_DEST) .await .map_err(|e| { @@ -115,8 +120,22 @@ impl Action for ConfigureNixDaemonService { ) .await .map_err(ActionError::Command)?; + + if *start_daemon { + execute_command( + Command::new("launchctl") + .process_group(0) + .arg("kickstart") + .arg("-k") + .arg("system/org.nixos.nix-daemon") + .stdin(std::process::Stdio::null()), + ) + .await + .map_err(ActionError::Command)?; + } }, - _ => { + #[cfg(target_os = "linux")] + InitSystem::Systemd => { tracing::trace!(src = TMPFILES_SRC, dest = TMPFILES_DEST, "Symlinking"); tokio::fs::symlink(TMPFILES_SRC, TMPFILES_DEST) .await @@ -158,24 +177,30 @@ impl Action for ConfigureNixDaemonService { .await .map_err(ActionError::Command)?; - execute_command( - Command::new("systemctl") - .process_group(0) - .arg("daemon-reload") - .stdin(std::process::Stdio::null()), - ) - .await - .map_err(ActionError::Command)?; + if *start_daemon { + execute_command( + Command::new("systemctl") + .process_group(0) + .arg("daemon-reload") + .stdin(std::process::Stdio::null()), + ) + .await + .map_err(ActionError::Command)?; - execute_command( - Command::new("systemctl") - .process_group(0) - .arg("enable") - .arg("--now") - .arg(SOCKET_SRC), - ) - .await - .map_err(ActionError::Command)?; + execute_command( + Command::new("systemctl") + .process_group(0) + .arg("enable") + .arg("--now") + .arg(SOCKET_SRC), + ) + .await + .map_err(ActionError::Command)?; + } + }, + #[cfg(not(target_os = "macos"))] + InitSystem::None => { + // Nothing here, no init system }, }; @@ -183,37 +208,36 @@ impl Action for ConfigureNixDaemonService { } fn revert_description(&self) -> Vec { - match OperatingSystem::host() { - OperatingSystem::MacOSX { - major: _, - minor: _, - patch: _, - } - | OperatingSystem::Darwin => vec![ActionDescription::new( - "Unconfigure Nix daemon related settings with launchd".to_string(), - vec!["Run `launchctl unload {DARWIN_NIX_DAEMON_DEST}`".to_string()], - )], - _ => vec![ActionDescription::new( - "Unconfigure Nix daemon related settings with systemd".to_string(), - vec![ - "Run `systemctl disable {SOCKET_SRC}`".to_string(), - "Run `systemctl disable {SERVICE_SRC}`".to_string(), - "Run `systemd-tempfiles --remove --prefix=/nix/var/nix`".to_string(), - "Run `systemctl daemon-reload`".to_string(), - ], - )], + match self.init { + #[cfg(target_os = "linux")] + InitSystem::Systemd => { + vec![ActionDescription::new( + "Unconfigure Nix daemon related settings with systemd".to_string(), + vec![ + "Run `systemctl disable {SOCKET_SRC}`".to_string(), + "Run `systemctl disable {SERVICE_SRC}`".to_string(), + "Run `systemd-tempfiles --remove --prefix=/nix/var/nix`".to_string(), + "Run `systemctl daemon-reload`".to_string(), + ], + )] + }, + #[cfg(target_os = "macos")] + InitSystem::Launchd => { + vec![ActionDescription::new( + "Unconfigure Nix daemon related settings with launchctl".to_string(), + vec!["Run `launchctl unload {DARWIN_NIX_DAEMON_DEST}`".to_string()], + )] + }, + #[cfg(not(target_os = "macos"))] + InitSystem::None => Vec::new(), } } #[tracing::instrument(level = "debug", skip_all)] async fn revert(&mut self) -> Result<(), ActionError> { - match OperatingSystem::host() { - OperatingSystem::MacOSX { - major: _, - minor: _, - patch: _, - } - | OperatingSystem::Darwin => { + match self.init { + #[cfg(target_os = "macos")] + InitSystem::Launchd => { execute_command( Command::new("launchctl") .process_group(0) @@ -223,7 +247,8 @@ impl Action for ConfigureNixDaemonService { .await .map_err(ActionError::Command)?; }, - _ => { + #[cfg(target_os = "linux")] + InitSystem::Systemd => { // We separate stop and disable (instead of using `--now`) to avoid cases where the service isn't started, but is enabled. let socket_is_active = is_active("nix-daemon.socket").await?; @@ -285,7 +310,7 @@ impl Action for ConfigureNixDaemonService { .await .map_err(ActionError::Command)?; - remove_file(TMPFILES_DEST) + tokio::fs::remove_file(TMPFILES_DEST) .await .map_err(|e| ActionError::Remove(PathBuf::from(TMPFILES_DEST), e))?; @@ -298,6 +323,10 @@ impl Action for ConfigureNixDaemonService { .await .map_err(ActionError::Command)?; }, + #[cfg(not(target_os = "macos"))] + InitSystem::None => { + // Nothing here, no init + }, }; Ok(()) @@ -310,6 +339,7 @@ pub enum ConfigureNixDaemonServiceError { InitNotSupported, } +#[cfg(target_os = "linux")] async fn is_active(unit: &str) -> Result { let output = Command::new("systemctl") .arg("is-active") @@ -326,6 +356,7 @@ async fn is_active(unit: &str) -> Result { } } +#[cfg(target_os = "linux")] async fn is_enabled(unit: &str) -> Result { let output = Command::new("systemctl") .arg("is-enabled") diff --git a/src/action/common/configure_nix.rs b/src/action/common/configure_nix.rs index fa10bf8..b7a6118 100644 --- a/src/action/common/configure_nix.rs +++ b/src/action/common/configure_nix.rs @@ -1,17 +1,12 @@ use crate::{ action::{ base::SetupDefaultProfile, - common::{ - ConfigureNixDaemonService, ConfigureShellProfile, PlaceChannelConfiguration, - PlaceNixConfiguration, - }, + common::{ConfigureShellProfile, PlaceChannelConfiguration, PlaceNixConfiguration}, Action, ActionDescription, ActionError, StatefulAction, }, - channel_value::ChannelValue, settings::CommonSettings, }; -use reqwest::Url; use tracing::{span, Instrument, Span}; /** @@ -23,20 +18,12 @@ pub struct ConfigureNix { configure_shell_profile: Option>, place_channel_configuration: StatefulAction, place_nix_configuration: StatefulAction, - configure_nix_daemon_service: StatefulAction, } impl ConfigureNix { #[tracing::instrument(level = "debug", skip_all)] pub async fn plan(settings: &CommonSettings) -> Result, ActionError> { - let channels: Vec<(String, Url)> = settings - .channels - .iter() - .map(|ChannelValue(channel, url)| (channel.to_string(), url.clone())) - .collect(); - - let setup_default_profile = - SetupDefaultProfile::plan(channels.iter().map(|(v, _k)| v.clone()).collect()).await?; + let setup_default_profile = SetupDefaultProfile::plan(settings.channels.clone()).await?; let configure_shell_profile = if settings.modify_profile { Some(ConfigureShellProfile::plan().await?) @@ -44,20 +31,18 @@ impl ConfigureNix { None }; let place_channel_configuration = - PlaceChannelConfiguration::plan(channels, settings.force).await?; + PlaceChannelConfiguration::plan(settings.channels.clone(), settings.force).await?; let place_nix_configuration = PlaceNixConfiguration::plan( settings.nix_build_group_name.clone(), settings.extra_conf.clone(), settings.force, ) .await?; - let configure_nix_daemon_service = ConfigureNixDaemonService::plan().await?; Ok(Self { place_channel_configuration, place_nix_configuration, setup_default_profile, - configure_nix_daemon_service, configure_shell_profile, } .into()) @@ -78,14 +63,12 @@ impl Action for ConfigureNix { fn execute_description(&self) -> Vec { let Self { setup_default_profile, - configure_nix_daemon_service, place_nix_configuration, place_channel_configuration, configure_shell_profile, } = &self; let mut buf = setup_default_profile.describe_execute(); - buf.append(&mut configure_nix_daemon_service.describe_execute()); buf.append(&mut place_nix_configuration.describe_execute()); buf.append(&mut place_channel_configuration.describe_execute()); if let Some(configure_shell_profile) = configure_shell_profile { @@ -98,7 +81,6 @@ impl Action for ConfigureNix { async fn execute(&mut self) -> Result<(), ActionError> { let Self { setup_default_profile, - configure_nix_daemon_service, place_nix_configuration, place_channel_configuration, configure_shell_profile, @@ -168,7 +150,6 @@ impl Action for ConfigureNix { }, )?; }; - configure_nix_daemon_service.try_execute().await?; Ok(()) } @@ -176,7 +157,6 @@ impl Action for ConfigureNix { fn revert_description(&self) -> Vec { let Self { setup_default_profile, - configure_nix_daemon_service, place_nix_configuration, place_channel_configuration, configure_shell_profile, @@ -188,7 +168,6 @@ impl Action for ConfigureNix { } buf.append(&mut place_channel_configuration.describe_revert()); buf.append(&mut place_nix_configuration.describe_revert()); - buf.append(&mut configure_nix_daemon_service.describe_revert()); buf.append(&mut setup_default_profile.describe_revert()); buf @@ -198,13 +177,11 @@ impl Action for ConfigureNix { async fn revert(&mut self) -> Result<(), ActionError> { let Self { setup_default_profile, - configure_nix_daemon_service, place_nix_configuration, place_channel_configuration, configure_shell_profile, } = self; - configure_nix_daemon_service.try_revert().await?; if let Some(configure_shell_profile) = configure_shell_profile { configure_shell_profile.try_revert().await?; } diff --git a/src/action/common/mod.rs b/src/action/common/mod.rs index 48dd904..ae7c566 100644 --- a/src/action/common/mod.rs +++ b/src/action/common/mod.rs @@ -1,7 +1,7 @@ //! [`Action`](crate::action::Action)s which only call other base plugins +pub(crate) mod configure_init_service; pub(crate) mod configure_nix; -pub(crate) mod configure_nix_daemon_service; pub(crate) mod configure_shell_profile; pub(crate) mod create_nix_tree; pub(crate) mod create_users_and_groups; @@ -9,8 +9,8 @@ pub(crate) mod place_channel_configuration; pub(crate) mod place_nix_configuration; pub(crate) mod provision_nix; +pub use configure_init_service::{ConfigureInitService, ConfigureNixDaemonServiceError}; pub use configure_nix::ConfigureNix; -pub use configure_nix_daemon_service::{ConfigureNixDaemonService, ConfigureNixDaemonServiceError}; pub use configure_shell_profile::ConfigureShellProfile; pub use create_nix_tree::CreateNixTree; pub use create_users_and_groups::CreateUsersAndGroups; diff --git a/src/action/common/place_channel_configuration.rs b/src/action/common/place_channel_configuration.rs index c8baba1..5805f1c 100644 --- a/src/action/common/place_channel_configuration.rs +++ b/src/action/common/place_channel_configuration.rs @@ -1,7 +1,7 @@ use crate::action::base::CreateFile; use crate::action::ActionError; use crate::action::{Action, ActionDescription, StatefulAction}; -use reqwest::Url; +use crate::ChannelValue; use tracing::{span, Span}; /** @@ -9,19 +9,19 @@ Place a channel configuration containing `channels` to the `$ROOT_HOME/.nix-chan */ #[derive(Debug, serde::Deserialize, serde::Serialize, Clone)] pub struct PlaceChannelConfiguration { - channels: Vec<(String, Url)>, + channels: Vec, create_file: StatefulAction, } impl PlaceChannelConfiguration { #[tracing::instrument(level = "debug", skip_all)] pub async fn plan( - channels: Vec<(String, Url)>, + channels: Vec, force: bool, ) -> Result, ActionError> { let buf = channels .iter() - .map(|(name, url)| format!("{} {}", url, name)) + .map(|ChannelValue(name, url)| format!("{} {}", url, name)) .collect::>() .join("\n"); let create_file = CreateFile::plan( @@ -62,7 +62,7 @@ impl Action for PlaceChannelConfiguration { channels = self .channels .iter() - .map(|(c, u)| format!("{c}={u}")) + .map(|ChannelValue(c, u)| format!("{c}={u}")) .collect::>() .join(", "), ) diff --git a/src/action/darwin/create_fstab_entry.rs b/src/action/darwin/create_fstab_entry.rs index 240c5b1..e0980ab 100644 --- a/src/action/darwin/create_fstab_entry.rs +++ b/src/action/darwin/create_fstab_entry.rs @@ -1,19 +1,13 @@ -use nix::unistd::{chown, Group, User}; use uuid::Uuid; use crate::{ action::{Action, ActionDescription, ActionError, StatefulAction}, execute_command, }; -use rand::Rng; use serde::Deserialize; -use std::{ - io::SeekFrom, - path::{Path, PathBuf}, - str::FromStr, -}; +use std::{io::SeekFrom, path::Path}; use tokio::{ - fs::{remove_file, OpenOptions}, + fs::OpenOptions, io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt}, process::Command, }; diff --git a/src/action/darwin/kickstart_launchctl_service.rs b/src/action/darwin/kickstart_launchctl_service.rs deleted file mode 100644 index 852d8d5..0000000 --- a/src/action/darwin/kickstart_launchctl_service.rs +++ /dev/null @@ -1,71 +0,0 @@ -use tokio::process::Command; -use tracing::{span, Span}; - -use crate::action::{ActionError, StatefulAction}; -use crate::execute_command; - -use crate::action::{Action, ActionDescription}; - -/** -Kickstart a `launchctl` service - */ -#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)] -pub struct KickstartLaunchctlService { - unit: String, -} - -impl KickstartLaunchctlService { - #[tracing::instrument(level = "debug", skip_all)] - pub async fn plan(unit: String) -> Result, ActionError> { - Ok(Self { unit }.into()) - } -} - -#[async_trait::async_trait] -#[typetag::serde(name = "kickstart_launchctl_service")] -impl Action for KickstartLaunchctlService { - fn tracing_synopsis(&self) -> String { - let Self { unit, .. } = self; - format!("Kickstart the launchctl unit `{unit}`") - } - - fn tracing_span(&self) -> Span { - span!( - tracing::Level::DEBUG, - "kickstart_launchctl_service", - unit = %self.unit, - ) - } - - fn execute_description(&self) -> Vec { - vec![ActionDescription::new(self.tracing_synopsis(), vec![])] - } - - #[tracing::instrument(level = "debug", skip_all)] - async fn execute(&mut self) -> Result<(), ActionError> { - let Self { unit } = self; - - execute_command( - Command::new("launchctl") - .process_group(0) - .arg("kickstart") - .arg("-k") - .arg(unit) - .stdin(std::process::Stdio::null()), - ) - .await - .map_err(ActionError::Command)?; - - Ok(()) - } - - fn revert_description(&self) -> Vec { - vec![] - } - - #[tracing::instrument(level = "debug", skip_all)] - async fn revert(&mut self) -> Result<(), ActionError> { - // noop - Ok(()) - } -} diff --git a/src/action/darwin/mod.rs b/src/action/darwin/mod.rs index add755a..e0335f5 100644 --- a/src/action/darwin/mod.rs +++ b/src/action/darwin/mod.rs @@ -8,7 +8,6 @@ pub(crate) mod create_nix_volume; pub(crate) mod create_synthetic_objects; pub(crate) mod enable_ownership; pub(crate) mod encrypt_apfs_volume; -pub(crate) mod kickstart_launchctl_service; pub(crate) mod unmount_apfs_volume; pub use bootstrap_apfs_volume::{BootstrapApfsVolume, BootstrapVolumeError}; @@ -17,5 +16,4 @@ pub use create_nix_volume::{CreateNixVolume, NIX_VOLUME_MOUNTD_DEST}; pub use create_synthetic_objects::{CreateSyntheticObjects, CreateSyntheticObjectsError}; pub use enable_ownership::{EnableOwnership, EnableOwnershipError}; pub use encrypt_apfs_volume::EncryptApfsVolume; -pub use kickstart_launchctl_service::KickstartLaunchctlService; pub use unmount_apfs_volume::UnmountApfsVolume; diff --git a/src/action/mod.rs b/src/action/mod.rs index 1c1de5a..a05e8d3 100644 --- a/src/action/mod.rs +++ b/src/action/mod.rs @@ -32,7 +32,7 @@ action.try_revert().await.unwrap(); ``` A general guidance for what determines how fine-grained an [`Action`] should be is the unit of -reversion. The [`ConfigureNixDaemonService`](common::ConfigureNixDaemonService) action is a good +reversion. The [`ConfigureInitService`](common::ConfigureInitService) action is a good example of this, it takes several steps, such as running `systemd-tmpfiles`, and calling `systemctl link` on some systemd units. @@ -49,7 +49,7 @@ use tracing::{Span, span}; use nix_installer::{ InstallPlan, settings::{CommonSettings, InstallSettingsError}, - planner::{Planner, PlannerError, linux::SteamDeck}, + planner::{Planner, PlannerError}, action::{Action, ActionError, StatefulAction, ActionDescription}, }; @@ -112,7 +112,7 @@ pub struct MyPlanner { impl Planner for MyPlanner { async fn default() -> Result { Ok(Self { - common: CommonSettings::default()?, + common: CommonSettings::default().await?, }) } diff --git a/src/lib.rs b/src/lib.rs index 5b80bde..1a67cca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,14 +34,17 @@ match plan.install(None).await { # } ``` -Sometimes choosing a specific plan is desired: +Sometimes choosing a specific planner is desired: ```rust,no_run use std::error::Error; -use nix_installer::{InstallPlan, planner::{Planner, linux::SteamDeck}}; +use nix_installer::{InstallPlan, planner::Planner}; # async fn chosen_planner_install() -> color_eyre::Result<()> { -let planner = SteamDeck::default().await?; +#[cfg(target_os = "linux")] +let planner = nix_installer::planner::linux::SteamDeck::default().await?; +#[cfg(target_os = "macos")] +let planner = nix_installer::planner::darwin::DarwinMulti::default().await?; // Or call `crate::planner::BuiltinPlanner::default()` // Match on the result to customize. diff --git a/src/planner/darwin/multi.rs b/src/planner/darwin/multi.rs index 7abacad..2e01539 100644 --- a/src/planner/darwin/multi.rs +++ b/src/planner/darwin/multi.rs @@ -6,15 +6,15 @@ use tokio::process::Command; use crate::{ action::{ - common::{ConfigureNix, ProvisionNix}, - darwin::{CreateNixVolume, KickstartLaunchctlService}, + common::{ConfigureInitService, ConfigureNix, ProvisionNix}, + darwin::CreateNixVolume, StatefulAction, }, execute_command, os::darwin::DiskUtilOutput, planner::{Planner, PlannerError}, - settings::CommonSettings, settings::InstallSettingsError, + settings::{CommonSettings, InitSystem}, Action, BuiltinPlanner, }; @@ -24,6 +24,7 @@ use crate::{ pub struct DarwinMulti { #[cfg_attr(feature = "cli", clap(flatten))] pub settings: CommonSettings, + /// Force encryption on the volume #[cfg_attr( feature = "cli", @@ -76,7 +77,7 @@ async fn default_root_disk() -> Result { impl Planner for DarwinMulti { async fn default() -> Result { Ok(Self { - settings: CommonSettings::default()?, + settings: CommonSettings::default().await?, root_disk: Some(default_root_disk().await?), case_sensitive: false, encrypt: None, @@ -140,7 +141,7 @@ impl Planner for DarwinMulti { .await .map_err(PlannerError::Action)? .boxed(), - KickstartLaunchctlService::plan("system/org.nixos.nix-daemon".into()) + ConfigureInitService::plan(InitSystem::Launchd, true) .await .map_err(PlannerError::Action)? .boxed(), diff --git a/src/planner/linux/multi.rs b/src/planner/linux/multi.rs index df84424..9b82d9a 100644 --- a/src/planner/linux/multi.rs +++ b/src/planner/linux/multi.rs @@ -1,12 +1,12 @@ use crate::{ action::{ base::CreateDirectory, - common::{ConfigureNix, ProvisionNix}, + common::{ConfigureInitService, ConfigureNix, ProvisionNix}, StatefulAction, }, planner::{Planner, PlannerError}, settings::CommonSettings, - settings::InstallSettingsError, + settings::{InitSettings, InstallSettingsError}, Action, BuiltinPlanner, }; use std::{collections::HashMap, path::Path}; @@ -18,6 +18,8 @@ use tokio::process::Command; pub struct LinuxMulti { #[cfg_attr(feature = "cli", clap(flatten))] pub settings: CommonSettings, + #[cfg_attr(feature = "cli", clap(flatten))] + pub init: InitSettings, } #[async_trait::async_trait] @@ -25,7 +27,8 @@ pub struct LinuxMulti { impl Planner for LinuxMulti { async fn default() -> Result { Ok(Self { - settings: CommonSettings::default()?, + settings: CommonSettings::default().await?, + init: InitSettings::default().await?, }) } @@ -77,14 +80,19 @@ impl Planner for LinuxMulti { .await .map_err(PlannerError::Action)? .boxed(), + ConfigureInitService::plan(self.init.init, self.init.start_daemon) + .await + .map_err(PlannerError::Action)? + .boxed(), ]) } fn settings(&self) -> Result, InstallSettingsError> { - let Self { settings } = self; + let Self { settings, init } = self; let mut map = HashMap::default(); map.extend(settings.settings()?.into_iter()); + map.extend(init.settings()?.into_iter()); Ok(map) } diff --git a/src/planner/linux/steam_deck.rs b/src/planner/linux/steam_deck.rs index b34f635..170ddff 100644 --- a/src/planner/linux/steam_deck.rs +++ b/src/planner/linux/steam_deck.rs @@ -64,12 +64,12 @@ use std::{collections::HashMap, path::PathBuf}; use crate::{ action::{ base::{CreateDirectory, CreateFile}, - common::{ConfigureNix, ProvisionNix}, + common::{ConfigureInitService, ConfigureNix, ProvisionNix}, linux::StartSystemdUnit, Action, StatefulAction, }, planner::{Planner, PlannerError}, - settings::{CommonSettings, InstallSettingsError}, + settings::{CommonSettings, InitSystem, InstallSettingsError}, BuiltinPlanner, }; @@ -95,7 +95,7 @@ impl Planner for SteamDeck { async fn default() -> Result { Ok(Self { persistence: PathBuf::from("/home/nix"), - settings: CommonSettings::default()?, + settings: CommonSettings::default().await?, }) } @@ -225,6 +225,11 @@ impl Planner for SteamDeck { .await .map_err(PlannerError::Action)? .boxed(), + // Init is required for the steam-deck archetype to make the `/nix` mount + ConfigureInitService::plan(InitSystem::Systemd, true) + .await + .map_err(PlannerError::Action)? + .boxed(), ]) } diff --git a/src/planner/mod.rs b/src/planner/mod.rs index c394997..3c73b8d 100644 --- a/src/planner/mod.rs +++ b/src/planner/mod.rs @@ -1,7 +1,6 @@ /*! [`BuiltinPlanner`]s and traits to create new types which can be used to plan out an [`InstallPlan`] -It's a [`Planner`]s job to construct (if possible) a valid [`InstallPlan`] for the host. Some planners, -like [`LinuxMulti`](linux::LinuxMulti), are operating system specific. Others, like [`SteamDeck`](linux::SteamDeck), are device specific. +It's a [`Planner`]s job to construct (if possible) a valid [`InstallPlan`] for the host. Some planners are operating system specific, others are device specific. [`Planner`]s contain their planner specific settings, typically alongside a [`CommonSettings`][crate::settings::CommonSettings]. @@ -16,8 +15,8 @@ use std::{error::Error, collections::HashMap}; use nix_installer::{ InstallPlan, settings::{CommonSettings, InstallSettingsError}, - planner::{Planner, PlannerError, linux::SteamDeck}, - action::{Action, StatefulAction, linux::StartSystemdUnit}, + planner::{Planner, PlannerError}, + action::{Action, StatefulAction, base::CreateFile}, }; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] @@ -31,7 +30,7 @@ pub struct MyPlanner { impl Planner for MyPlanner { async fn default() -> Result { Ok(Self { - common: CommonSettings::default()?, + common: CommonSettings::default().await?, }) } @@ -39,7 +38,7 @@ impl Planner for MyPlanner { Ok(vec![ // ... - StartSystemdUnit::plan("nix-daemon.socket") + CreateFile::plan("/example", None, None, None, "Example".to_string(), false) .await .map_err(PlannerError::Action)?.boxed(), ]) @@ -74,7 +73,9 @@ match plan.install(None).await { ``` */ +#[cfg(target_os = "macos")] pub mod darwin; +#[cfg(target_os = "linux")] pub mod linux; use std::{collections::HashMap, string::FromUtf8Error}; @@ -113,11 +114,14 @@ dyn_clone::clone_trait_object!(Planner); #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "cli", derive(clap::Subcommand))] pub enum BuiltinPlanner { + #[cfg(target_os = "linux")] /// A standard Linux multi-user install LinuxMulti(linux::LinuxMulti), /// A standard MacOS (Darwin) multi-user install + #[cfg(target_os = "macos")] DarwinMulti(darwin::DarwinMulti), /// A specialized install suitable for the Valve Steam Deck console + #[cfg(target_os = "linux")] SteamDeck(linux::SteamDeck), } @@ -126,16 +130,20 @@ impl BuiltinPlanner { pub async fn default() -> Result { use target_lexicon::{Architecture, OperatingSystem}; match (Architecture::host(), OperatingSystem::host()) { + #[cfg(target_os = "linux")] (Architecture::X86_64, OperatingSystem::Linux) => { Ok(Self::LinuxMulti(linux::LinuxMulti::default().await?)) }, + #[cfg(target_os = "linux")] (Architecture::Aarch64(_), OperatingSystem::Linux) => { Ok(Self::LinuxMulti(linux::LinuxMulti::default().await?)) }, + #[cfg(target_os = "macos")] (Architecture::X86_64, OperatingSystem::MacOSX { .. }) | (Architecture::X86_64, OperatingSystem::Darwin) => { Ok(Self::DarwinMulti(darwin::DarwinMulti::default().await?)) }, + #[cfg(target_os = "macos")] (Architecture::Aarch64(_), OperatingSystem::MacOSX { .. }) | (Architecture::Aarch64(_), OperatingSystem::Darwin) => { Ok(Self::DarwinMulti(darwin::DarwinMulti::default().await?)) @@ -147,41 +155,56 @@ impl BuiltinPlanner { pub async fn from_common_settings(settings: CommonSettings) -> Result { let mut built = Self::default().await?; match &mut built { + #[cfg(target_os = "linux")] BuiltinPlanner::LinuxMulti(inner) => inner.settings = settings, - BuiltinPlanner::DarwinMulti(inner) => inner.settings = settings, + #[cfg(target_os = "linux")] BuiltinPlanner::SteamDeck(inner) => inner.settings = settings, + #[cfg(target_os = "macos")] + BuiltinPlanner::DarwinMulti(inner) => inner.settings = settings, } Ok(built) } pub async fn plan(self) -> Result { match self { + #[cfg(target_os = "linux")] BuiltinPlanner::LinuxMulti(planner) => InstallPlan::plan(planner).await, - BuiltinPlanner::DarwinMulti(planner) => InstallPlan::plan(planner).await, + #[cfg(target_os = "linux")] BuiltinPlanner::SteamDeck(planner) => InstallPlan::plan(planner).await, + #[cfg(target_os = "macos")] + BuiltinPlanner::DarwinMulti(planner) => InstallPlan::plan(planner).await, } } pub fn boxed(self) -> Box { match self { + #[cfg(target_os = "linux")] BuiltinPlanner::LinuxMulti(i) => i.boxed(), - BuiltinPlanner::DarwinMulti(i) => i.boxed(), + #[cfg(target_os = "linux")] BuiltinPlanner::SteamDeck(i) => i.boxed(), + #[cfg(target_os = "macos")] + BuiltinPlanner::DarwinMulti(i) => i.boxed(), } } pub fn typetag_name(&self) -> &'static str { match self { + #[cfg(target_os = "linux")] BuiltinPlanner::LinuxMulti(i) => i.typetag_name(), - BuiltinPlanner::DarwinMulti(i) => i.typetag_name(), + #[cfg(target_os = "linux")] BuiltinPlanner::SteamDeck(i) => i.typetag_name(), + #[cfg(target_os = "macos")] + BuiltinPlanner::DarwinMulti(i) => i.typetag_name(), } } pub fn settings(&self) -> Result, InstallSettingsError> { match self { + #[cfg(target_os = "linux")] BuiltinPlanner::LinuxMulti(i) => i.settings(), - BuiltinPlanner::DarwinMulti(i) => i.settings(), + #[cfg(target_os = "linux")] BuiltinPlanner::SteamDeck(i) => i.settings(), + #[cfg(target_os = "macos")] + BuiltinPlanner::DarwinMulti(i) => i.settings(), } } } diff --git a/src/settings.rs b/src/settings.rs index 0063884..3cf367b 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -21,6 +21,30 @@ pub const NIX_X64_64_DARWIN_URL: &str = pub const NIX_AARCH64_DARWIN_URL: &str = "https://releases.nixos.org/nix/nix-2.12.0/nix-2.12.0-aarch64-darwin.tar.xz"; +#[derive(Debug, serde::Deserialize, serde::Serialize, Clone, Copy)] +#[cfg_attr(feature = "cli", derive(clap::ValueEnum))] +pub enum InitSystem { + #[cfg(not(target_os = "macos"))] + None, + #[cfg(target_os = "linux")] + Systemd, + #[cfg(target_os = "macos")] + Launchd, +} + +impl std::fmt::Display for InitSystem { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + #[cfg(not(target_os = "macos"))] + InitSystem::None => write!(f, "none"), + #[cfg(target_os = "linux")] + InitSystem::Systemd => write!(f, "systemd"), + #[cfg(target_os = "macos")] + InitSystem::Launchd => write!(f, "launchd"), + } + } +} + /** Common settings used by all [`BuiltinPlanner`](crate::planner::BuiltinPlanner)s Settings which only apply to certain [`Planner`](crate::planner::Planner)s should be located in the planner. @@ -173,29 +197,33 @@ pub struct CommonSettings { impl CommonSettings { /// The default settings for the given Architecture & Operating System - pub fn default() -> Result { + pub async fn default() -> Result { let url; let nix_build_user_prefix; let nix_build_user_id_base; use target_lexicon::{Architecture, OperatingSystem}; match (Architecture::host(), OperatingSystem::host()) { + #[cfg(target_os = "linux")] (Architecture::X86_64, OperatingSystem::Linux) => { url = NIX_X64_64_LINUX_URL; nix_build_user_prefix = "nixbld"; nix_build_user_id_base = 3000; }, + #[cfg(target_os = "linux")] (Architecture::Aarch64(_), OperatingSystem::Linux) => { url = NIX_AARCH64_LINUX_URL; nix_build_user_prefix = "nixbld"; nix_build_user_id_base = 3000; }, + #[cfg(target_os = "macos")] (Architecture::X86_64, OperatingSystem::MacOSX { .. }) | (Architecture::X86_64, OperatingSystem::Darwin) => { url = NIX_X64_64_DARWIN_URL; nix_build_user_prefix = "_nixbld"; nix_build_user_id_base = 300; }, + #[cfg(target_os = "macos")] (Architecture::Aarch64(_), OperatingSystem::MacOSX { .. }) | (Architecture::Aarch64(_), OperatingSystem::Darwin) => { url = NIX_AARCH64_DARWIN_URL; @@ -286,6 +314,34 @@ impl CommonSettings { Ok(map) } } +#[cfg(target_os = "linux")] +async fn linux_detect_init() -> (InitSystem, bool) { + use std::process::Stdio; + + let mut detected = InitSystem::None; + let mut started = false; + if std::path::Path::new("/run/systemd/system").exists() { + detected = InitSystem::Systemd; + started = if tokio::process::Command::new("systemctl") + .arg("status") + .stdin(Stdio::null()) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .status() + .await + .ok() + .map(|exit| exit.success()) + .unwrap_or(false) + { + true + } else { + false + } + } + + // TODO: Other inits + (detected, started) +} // Builder Pattern impl CommonSettings { @@ -349,6 +405,96 @@ impl CommonSettings { } } +#[serde_with::serde_as] +#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)] +#[cfg_attr(feature = "cli", derive(clap::Parser))] +pub struct InitSettings { + /// Which init system to configure (if `--init none` Nix will be root-only) + #[cfg_attr(feature = "cli", clap(value_parser, long, env = "NIX_INSTALLER_INIT",))] + #[cfg_attr( + all(target_os = "macos", feature = "cli"), + clap(default_value_t = InitSystem::Launchd) + )] + #[cfg_attr( + all(target_os = "linux", feature = "cli"), + clap(default_value_t = InitSystem::Systemd) + )] + pub(crate) init: InitSystem, + + /// Start the daemon (if not `--init none`) + #[cfg_attr( + feature = "cli", + clap( + value_parser, + long, + action(ArgAction::SetFalse), + env = "NIX_INSTALLER_START_DAEMON", + default_value_t = true, + long = "no-start-daemon" + ) + )] + pub(crate) start_daemon: bool, +} + +impl InitSettings { + /// The default settings for the given Architecture & Operating System + pub async fn default() -> Result { + let init; + let start_daemon; + + use target_lexicon::{Architecture, OperatingSystem}; + match (Architecture::host(), OperatingSystem::host()) { + #[cfg(target_os = "linux")] + (Architecture::X86_64, OperatingSystem::Linux) => { + (init, start_daemon) = linux_detect_init().await; + }, + #[cfg(target_os = "linux")] + (Architecture::Aarch64(_), OperatingSystem::Linux) => { + (init, start_daemon) = linux_detect_init().await; + }, + #[cfg(target_os = "macos")] + (Architecture::X86_64, OperatingSystem::MacOSX { .. }) + | (Architecture::X86_64, OperatingSystem::Darwin) => { + (init, start_daemon) = (InitSystem::Launchd, true); + }, + #[cfg(target_os = "macos")] + (Architecture::Aarch64(_), OperatingSystem::MacOSX { .. }) + | (Architecture::Aarch64(_), OperatingSystem::Darwin) => { + (init, start_daemon) = (InitSystem::Launchd, true); + }, + _ => { + return Err(InstallSettingsError::UnsupportedArchitecture( + target_lexicon::HOST, + )) + }, + }; + + Ok(Self { init, start_daemon }) + } + + /// A listing of the settings, suitable for [`Planner::settings`](crate::planner::Planner::settings) + pub fn settings(&self) -> Result, InstallSettingsError> { + let Self { init, start_daemon } = self; + let mut map = HashMap::default(); + + map.insert("init".into(), serde_json::to_value(init)?); + map.insert("start_daemon".into(), serde_json::to_value(start_daemon)?); + Ok(map) + } + + /// Which init system to configure + pub fn init(&mut self, init: InitSystem) -> &mut Self { + self.init = init; + self + } + + /// Start the daemon (if one is configured) + pub fn start_daemon(&mut self, toggle: bool) -> &mut Self { + self.start_daemon = toggle; + self + } +} + /// An error originating from a [`Planner::settings`](crate::planner::Planner::settings) #[derive(thiserror::Error, Debug)] pub enum InstallSettingsError { @@ -369,4 +515,6 @@ pub enum InstallSettingsError { #[from] serde_json::Error, ), + #[error("No supported init system found")] + InitNotSupported, } diff --git a/tests/fixtures/darwin/darwin-multi.json b/tests/fixtures/darwin/darwin-multi.json index fcd7ae7..f263f50 100644 --- a/tests/fixtures/darwin/darwin-multi.json +++ b/tests/fixtures/darwin/darwin-multi.json @@ -546,7 +546,10 @@ "setup_default_profile": { "action": { "channels": [ - "nixpkgs" + [ + "nixpkgs", + "https://nixos.org/channels/nixpkgs-unstable" + ] ] }, "state": "Uncompleted" @@ -632,25 +635,22 @@ "user": null, "group": null, "mode": 436, - "buf": "\n\nbuild-users-group = nixbld\n\nexperimental-features = nix-command flakes\n\nauto-optimise-store = true\n", + "buf": "# Generated by https://github.com/DeterminateSystems/nix-installer, version 0.1.0-unreleased.\n\n\n\nbuild-users-group = nixbld\n\nexperimental-features = nix-command flakes\n\nauto-optimise-store = true\n\nbash-prompt-prefix = (nix:$name)\\040\n", "force": false }, "state": "Uncompleted" } }, "state": "Uncompleted" - }, - "configure_nix_daemon_service": { - "action": {}, - "state": "Uncompleted" } }, "state": "Uncompleted" }, { "action": { - "action": "kickstart_launchctl_service", - "unit": "system/org.nixos.nix-daemon" + "action": "configure_nix_daemon", + "init": "Launchd", + "start_daemon": true }, "state": "Uncompleted" } diff --git a/tests/fixtures/linux/linux-multi.json b/tests/fixtures/linux/linux-multi.json index 6042d0f..4b049b2 100644 --- a/tests/fixtures/linux/linux-multi.json +++ b/tests/fixtures/linux/linux-multi.json @@ -1,617 +1,628 @@ { - "version": "0.1.0-unreleased", - "actions": [ - { - "action": { - "action": "create_directory", - "path": "/nix", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": true - }, - "state": "Skipped" - }, - { - "action": { - "action": "provision_nix", - "fetch_nix": { - "action": { - "url": "https://releases.nixos.org/nix/nix-2.12.0/nix-2.12.0-x86_64-linux.tar.xz", - "dest": "/nix/temp-install-dir" - }, - "state": "Uncompleted" + "version": "0.1.0-unreleased", + "actions": [ + { + "action": { + "action": "create_directory", + "path": "/nix", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": true }, - "create_users_and_group": { - "action": { - "nix_build_user_count": 32, - "nix_build_group_name": "nixbld", - "nix_build_group_id": 3000, - "nix_build_user_prefix": "nixbld", - "nix_build_user_id_base": 3000, - "create_group": { - "action": { - "name": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" + "state": "Uncompleted" + }, + { + "action": { + "action": "provision_nix", + "fetch_nix": { + "action": { + "url": "https://releases.nixos.org/nix/nix-2.12.0/nix-2.12.0-x86_64-linux.tar.xz", + "dest": "/nix/temp-install-dir" }, - "create_users": [ - { - "action": { - "name": "nixbld0", - "uid": 3000, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld1", - "uid": 3001, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld2", - "uid": 3002, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld3", - "uid": 3003, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld4", - "uid": 3004, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld5", - "uid": 3005, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld6", - "uid": 3006, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld7", - "uid": 3007, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld8", - "uid": 3008, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld9", - "uid": 3009, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld10", - "uid": 3010, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld11", - "uid": 3011, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld12", - "uid": 3012, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld13", - "uid": 3013, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld14", - "uid": 3014, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld15", - "uid": 3015, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld16", - "uid": 3016, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld17", - "uid": 3017, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld18", - "uid": 3018, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld19", - "uid": 3019, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld20", - "uid": 3020, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld21", - "uid": 3021, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld22", - "uid": 3022, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld23", - "uid": 3023, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld24", - "uid": 3024, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld25", - "uid": 3025, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld26", - "uid": 3026, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld27", - "uid": 3027, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld28", - "uid": 3028, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld29", - "uid": 3029, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld30", - "uid": 3030, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld31", - "uid": 3031, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - } - ] + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - "create_nix_tree": { - "action": { - "create_directories": [ - { + "create_users_and_group": { + "action": { + "nix_build_user_count": 32, + "nix_build_group_name": "nixbld", + "nix_build_group_id": 3000, + "nix_build_user_prefix": "nixbld", + "nix_build_user_id_base": 3000, + "create_group": { "action": { - "path": "/nix/var", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": false + "name": "nixbld", + "gid": 3000 }, "state": "Uncompleted" }, - { - "action": { - "path": "/nix/var/log", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": false + "create_users": [ + { + "action": { + "name": "nixbld0", + "uid": 3000, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - { - "action": { - "path": "/nix/var/log/nix", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": false + { + "action": { + "name": "nixbld1", + "uid": 3001, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - { - "action": { - "path": "/nix/var/log/nix/drvs", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": false + { + "action": { + "name": "nixbld2", + "uid": 3002, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - { - "action": { - "path": "/nix/var/nix", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": false + { + "action": { + "name": "nixbld3", + "uid": 3003, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - { - "action": { - "path": "/nix/var/nix/db", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": false + { + "action": { + "name": "nixbld4", + "uid": 3004, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - { - "action": { - "path": "/nix/var/nix/gcroots", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": false + { + "action": { + "name": "nixbld5", + "uid": 3005, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - { - "action": { - "path": "/nix/var/nix/gcroots/per-user", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": false + { + "action": { + "name": "nixbld6", + "uid": 3006, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - { - "action": { - "path": "/nix/var/nix/profiles", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": false + { + "action": { + "name": "nixbld7", + "uid": 3007, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - { - "action": { - "path": "/nix/var/nix/profiles/per-user", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": false + { + "action": { + "name": "nixbld8", + "uid": 3008, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - { - "action": { - "path": "/nix/var/nix/temproots", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": false + { + "action": { + "name": "nixbld9", + "uid": 3009, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - { - "action": { - "path": "/nix/var/nix/userpool", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": false + { + "action": { + "name": "nixbld10", + "uid": 3010, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - { - "action": { - "path": "/nix/var/nix/daemon-socket", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": false + { + "action": { + "name": "nixbld11", + "uid": 3011, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - } - ] - }, - "state": "Uncompleted" - }, - "move_unpacked_nix": { - "action": { - "src": "/nix/temp-install-dir" - }, - "state": "Uncompleted" - } - }, - "state": "Uncompleted" - }, - { - "action": { - "action": "configure_nix", - "setup_default_profile": { - "action": { - "channels": [ - "nixpkgs" - ] - }, - "state": "Uncompleted" - }, - "configure_shell_profile": { - "action": { - "create_directories": [], - "create_or_insert_into_files": [ - { - "action": { - "path": "/etc/bashrc", - "user": null, - "group": null, - "mode": 493, - "buf": "\n# Nix\nif [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then\n . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'\nfi\n# End Nix\n\n \n", - "position": "Beginning" + { + "action": { + "name": "nixbld12", + "uid": 3012, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - { - "action": { - "path": "/etc/profile.d/nix.sh", - "user": null, - "group": null, - "mode": 493, - "buf": "\n# Nix\nif [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then\n . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'\nfi\n# End Nix\n\n \n", - "position": "Beginning" + { + "action": { + "name": "nixbld13", + "uid": 3013, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - { - "action": { - "path": "/etc/zshenv", - "user": null, - "group": null, - "mode": 493, - "buf": "\n# Nix\nif [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then\n . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'\nfi\n# End Nix\n\n \n", - "position": "Beginning" + { + "action": { + "name": "nixbld14", + "uid": 3014, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - { - "action": { - "path": "/etc/bash.bashrc", - "user": null, - "group": null, - "mode": 493, - "buf": "\n# Nix\nif [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then\n . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'\nfi\n# End Nix\n\n \n", - "position": "Beginning" + { + "action": { + "name": "nixbld15", + "uid": 3015, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - } - ] - }, - "state": "Uncompleted" - }, - "place_channel_configuration": { - "action": { - "channels": [ - [ - "nixpkgs", - "https://nixos.org/channels/nixpkgs-unstable" + { + "action": { + "name": "nixbld16", + "uid": 3016, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld17", + "uid": 3017, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld18", + "uid": 3018, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld19", + "uid": 3019, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld20", + "uid": 3020, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld21", + "uid": 3021, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld22", + "uid": 3022, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld23", + "uid": 3023, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld24", + "uid": 3024, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld25", + "uid": 3025, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld26", + "uid": 3026, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld27", + "uid": 3027, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld28", + "uid": 3028, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld29", + "uid": 3029, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld30", + "uid": 3030, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld31", + "uid": 3031, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + } ] - ], - "create_file": { - "action": { - "path": "/root/.nix-channels", - "user": null, - "group": null, - "mode": 436, - "buf": "https://nixos.org/channels/nixpkgs-unstable nixpkgs", - "force": false - }, - "state": "Uncompleted" - } - }, - "state": "Uncompleted" - }, - "place_nix_configuration": { - "action": { - "create_directory": { - "action": { - "path": "/etc/nix", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": false - }, - "state": "Uncompleted" }, - "create_file": { - "action": { - "path": "/etc/nix/nix.conf", - "user": null, - "group": null, - "mode": 436, - "buf": "\n\nbuild-users-group = nixbld\n\nexperimental-features = nix-command flakes\n\nauto-optimise-store = true\n", - "force": false - }, - "state": "Uncompleted" - } + "state": "Uncompleted" }, - "state": "Uncompleted" + "create_nix_tree": { + "action": { + "create_directories": [ + { + "action": { + "path": "/nix/var", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": false + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/nix/var/log", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": false + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/nix/var/log/nix", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": false + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/nix/var/log/nix/drvs", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": false + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/nix/var/nix", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": false + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/nix/var/nix/db", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": false + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/nix/var/nix/gcroots", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": false + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/nix/var/nix/gcroots/per-user", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": false + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/nix/var/nix/profiles", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": false + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/nix/var/nix/profiles/per-user", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": false + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/nix/var/nix/temproots", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": false + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/nix/var/nix/userpool", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": false + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/nix/var/nix/daemon-socket", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": false + }, + "state": "Uncompleted" + } + ] + }, + "state": "Uncompleted" + }, + "move_unpacked_nix": { + "action": { + "src": "/nix/temp-install-dir" + }, + "state": "Uncompleted" + } }, - "configure_nix_daemon_service": { - "action": {}, - "state": "Uncompleted" - } + "state": "Uncompleted" }, - "state": "Uncompleted" + { + "action": { + "action": "configure_nix", + "setup_default_profile": { + "action": { + "channels": [ + [ + "nixpkgs", + "https://nixos.org/channels/nixpkgs-unstable" + ] + ] + }, + "state": "Uncompleted" + }, + "configure_shell_profile": { + "action": { + "create_directories": [], + "create_or_insert_into_files": [ + { + "action": { + "path": "/etc/bashrc", + "user": null, + "group": null, + "mode": 493, + "buf": "\n# Nix\nif [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then\n . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'\nfi\n# End Nix\n\n \n", + "position": "Beginning" + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/etc/profile.d/nix.sh", + "user": null, + "group": null, + "mode": 493, + "buf": "\n# Nix\nif [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then\n . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'\nfi\n# End Nix\n\n \n", + "position": "Beginning" + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/etc/zshenv", + "user": null, + "group": null, + "mode": 493, + "buf": "\n# Nix\nif [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then\n . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'\nfi\n# End Nix\n\n \n", + "position": "Beginning" + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/etc/bash.bashrc", + "user": null, + "group": null, + "mode": 493, + "buf": "\n# Nix\nif [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then\n . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'\nfi\n# End Nix\n\n \n", + "position": "Beginning" + }, + "state": "Uncompleted" + } + ] + }, + "state": "Uncompleted" + }, + "place_channel_configuration": { + "action": { + "channels": [ + [ + "nixpkgs", + "https://nixos.org/channels/nixpkgs-unstable" + ] + ], + "create_file": { + "action": { + "path": "/home/ana/.nix-channels", + "user": null, + "group": null, + "mode": 436, + "buf": "https://nixos.org/channels/nixpkgs-unstable nixpkgs", + "force": false + }, + "state": "Uncompleted" + } + }, + "state": "Uncompleted" + }, + "place_nix_configuration": { + "action": { + "create_directory": { + "action": { + "path": "/etc/nix", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": false + }, + "state": "Uncompleted" + }, + "create_file": { + "action": { + "path": "/etc/nix/nix.conf", + "user": null, + "group": null, + "mode": 436, + "buf": "# Generated by https://github.com/DeterminateSystems/nix-installer, version 0.1.0-unreleased.\n\n\n\nbuild-users-group = nixbld\n\nexperimental-features = nix-command flakes\n\nauto-optimise-store = true\n\nbash-prompt-prefix = (nix:$name)\\040\n", + "force": false + }, + "state": "Uncompleted" + } + }, + "state": "Uncompleted" + } + }, + "state": "Uncompleted" + }, + { + "action": { + "action": "configure_nix_daemon", + "init": "Systemd", + "start_daemon": true + }, + "state": "Uncompleted" + } + ], + "planner": { + "planner": "linux-multi", + "settings": { + "channels": [ + [ + "nixpkgs", + "https://nixos.org/channels/nixpkgs-unstable" + ] + ], + "modify_profile": true, + "nix_build_user_count": 32, + "nix_build_group_name": "nixbld", + "nix_build_group_id": 3000, + "nix_build_user_prefix": "nixbld", + "nix_build_user_id_base": 3000, + "nix_package_url": "https://releases.nixos.org/nix/nix-2.12.0/nix-2.12.0-x86_64-linux.tar.xz", + "extra_conf": [], + "force": false + }, + "init": { + "init": "Systemd", + "start_daemon": true + } } - ], - "planner": { - "planner": "linux-multi", - "settings": { - "channels": [ - [ - "nixpkgs", - "https://nixos.org/channels/nixpkgs-unstable" - ] - ], - "modify_profile": true, - "nix_build_user_count": 32, - "nix_build_group_name": "nixbld", - "nix_build_group_id": 3000, - "nix_build_user_prefix": "nixbld", - "nix_build_user_id_base": 3000, - "nix_package_url": "https://releases.nixos.org/nix/nix-2.12.0/nix-2.12.0-x86_64-linux.tar.xz", - "extra_conf": [], - "force": false - } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/tests/fixtures/linux/steam-deck.json b/tests/fixtures/linux/steam-deck.json index e86ad0e..172e5d0 100644 --- a/tests/fixtures/linux/steam-deck.json +++ b/tests/fixtures/linux/steam-deck.json @@ -1,661 +1,668 @@ { - "version": "0.1.0-unreleased", - "actions": [ - { - "action": { - "action": "create_directory", - "path": "/home/nix", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": true - }, - "state": "Uncompleted" - }, - { - "action": { - "action": "create_file", - "path": "/etc/systemd/system/nix-directory.service", - "user": null, - "group": null, - "mode": 420, - "buf": "[Unit]\nDescription=Create a `/nix` directory to be used for bind mounting\nPropagatesStopTo=nix-daemon.service\nPropagatesStopTo=nix.mount\nDefaultDependencies=no\nAfter=grub-recordfail.service\nAfter=steamos-finish-oobe-migration.service\n\n[Service]\nType=oneshot\nExecStart=steamos-readonly disable\nExecStart=mkdir -vp /nix\nExecStart=chmod -v 0755 /nix\nExecStart=chown -v root /nix\nExecStart=chgrp -v root /nix\nExecStart=steamos-readonly enable\nExecStop=steamos-readonly disable\nExecStop=rmdir /nix\nExecStop=steamos-readonly enable\nRemainAfterExit=true\n", - "force": false - }, - "state": "Uncompleted" - }, - { - "action": { - "action": "create_file", - "path": "/etc/systemd/system/nix.mount", - "user": null, - "group": null, - "mode": 420, - "buf": "[Unit]\nDescription=Mount `/home/nix` on `/nix`\nPropagatesStopTo=nix-daemon.service\nPropagatesStopTo=nix-directory.service\nAfter=nix-directory.service\nRequires=nix-directory.service\nConditionPathIsDirectory=/nix\nDefaultDependencies=no\n\n[Mount]\nWhat=/home/nix\nWhere=/nix\nType=none\nDirectoryMode=0755\nOptions=bind\n", - "force": false - }, - "state": "Uncompleted" - }, - { - "action": { - "action": "create_file", - "path": "/etc/systemd/system/ensure-symlinked-units-resolve.service", - "user": null, - "group": null, - "mode": 420, - "buf": "[Unit]\nDescription=Ensure Nix related units which are symlinked resolve\nAfter=nix.mount\nRequires=nix-directory.service\nRequires=nix.mount\nPropagatesStopTo=nix-directory.service\nPropagatesStopTo=nix.mount\nDefaultDependencies=no\n\n[Service]\nType=oneshot\nRemainAfterExit=yes\nExecStart=/usr/bin/systemctl daemon-reload\nExecStart=/usr/bin/systemctl restart --no-block sockets.target timers.target multi-user.target\n\n[Install]\nWantedBy=sysinit.target\n", - "force": false - }, - "state": "Uncompleted" - }, - { - "action": { - "action": "start_systemd_unit", - "unit": "ensure-symlinked-units-resolve.service" - }, - "state": "Uncompleted" - }, - { - "action": { - "action": "provision_nix", - "fetch_nix": { - "action": { - "url": "https://releases.nixos.org/nix/nix-2.12.0/nix-2.12.0-x86_64-linux.tar.xz", - "dest": "/nix/temp-install-dir" - }, - "state": "Uncompleted" + "version": "0.1.0-unreleased", + "actions": [ + { + "action": { + "action": "create_directory", + "path": "/home/nix", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": true }, - "create_users_and_group": { - "action": { - "nix_build_user_count": 32, - "nix_build_group_name": "nixbld", - "nix_build_group_id": 3000, - "nix_build_user_prefix": "nixbld", - "nix_build_user_id_base": 3000, - "create_group": { - "action": { - "name": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" + "state": "Uncompleted" + }, + { + "action": { + "action": "create_file", + "path": "/etc/systemd/system/nix-directory.service", + "user": null, + "group": null, + "mode": 420, + "buf": "[Unit]\nDescription=Create a `/nix` directory to be used for bind mounting\nPropagatesStopTo=nix-daemon.service\nPropagatesStopTo=nix.mount\nDefaultDependencies=no\nAfter=grub-recordfail.service\nAfter=steamos-finish-oobe-migration.service\n\n[Service]\nType=oneshot\nExecStart=steamos-readonly disable\nExecStart=mkdir -vp /nix\nExecStart=chmod -v 0755 /nix\nExecStart=chown -v root /nix\nExecStart=chgrp -v root /nix\nExecStart=steamos-readonly enable\nExecStop=steamos-readonly disable\nExecStop=rmdir /nix\nExecStop=steamos-readonly enable\nRemainAfterExit=true\n", + "force": false + }, + "state": "Uncompleted" + }, + { + "action": { + "action": "create_file", + "path": "/etc/systemd/system/nix.mount", + "user": null, + "group": null, + "mode": 420, + "buf": "[Unit]\nDescription=Mount `/home/nix` on `/nix`\nPropagatesStopTo=nix-daemon.service\nPropagatesStopTo=nix-directory.service\nAfter=nix-directory.service\nRequires=nix-directory.service\nConditionPathIsDirectory=/nix\nDefaultDependencies=no\n\n[Mount]\nWhat=/home/nix\nWhere=/nix\nType=none\nDirectoryMode=0755\nOptions=bind\n", + "force": false + }, + "state": "Uncompleted" + }, + { + "action": { + "action": "create_file", + "path": "/etc/systemd/system/ensure-symlinked-units-resolve.service", + "user": null, + "group": null, + "mode": 420, + "buf": "[Unit]\nDescription=Ensure Nix related units which are symlinked resolve\nAfter=nix.mount\nRequires=nix-directory.service\nRequires=nix.mount\nPropagatesStopTo=nix-directory.service\nPropagatesStopTo=nix.mount\nDefaultDependencies=no\n\n[Service]\nType=oneshot\nRemainAfterExit=yes\nExecStart=/usr/bin/systemctl daemon-reload\nExecStart=/usr/bin/systemctl restart --no-block sockets.target timers.target multi-user.target\n\n[Install]\nWantedBy=sysinit.target\n", + "force": false + }, + "state": "Uncompleted" + }, + { + "action": { + "action": "start_systemd_unit", + "unit": "ensure-symlinked-units-resolve.service" + }, + "state": "Uncompleted" + }, + { + "action": { + "action": "provision_nix", + "fetch_nix": { + "action": { + "url": "https://releases.nixos.org/nix/nix-2.12.0/nix-2.12.0-x86_64-linux.tar.xz", + "dest": "/nix/temp-install-dir" }, - "create_users": [ - { - "action": { - "name": "nixbld0", - "uid": 3000, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld1", - "uid": 3001, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld2", - "uid": 3002, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld3", - "uid": 3003, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld4", - "uid": 3004, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld5", - "uid": 3005, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld6", - "uid": 3006, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld7", - "uid": 3007, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld8", - "uid": 3008, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld9", - "uid": 3009, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld10", - "uid": 3010, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld11", - "uid": 3011, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld12", - "uid": 3012, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld13", - "uid": 3013, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld14", - "uid": 3014, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld15", - "uid": 3015, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld16", - "uid": 3016, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld17", - "uid": 3017, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld18", - "uid": 3018, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld19", - "uid": 3019, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld20", - "uid": 3020, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld21", - "uid": 3021, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld22", - "uid": 3022, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld23", - "uid": 3023, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld24", - "uid": 3024, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld25", - "uid": 3025, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld26", - "uid": 3026, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld27", - "uid": 3027, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld28", - "uid": 3028, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld29", - "uid": 3029, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld30", - "uid": 3030, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - }, - { - "action": { - "name": "nixbld31", - "uid": 3031, - "groupname": "nixbld", - "gid": 3000 - }, - "state": "Uncompleted" - } - ] + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - "create_nix_tree": { - "action": { - "create_directories": [ - { + "create_users_and_group": { + "action": { + "nix_build_user_count": 32, + "nix_build_group_name": "nixbld", + "nix_build_group_id": 3000, + "nix_build_user_prefix": "nixbld", + "nix_build_user_id_base": 3000, + "create_group": { "action": { - "path": "/nix/var", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": false + "name": "nixbld", + "gid": 3000 }, "state": "Uncompleted" }, - { - "action": { - "path": "/nix/var/log", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": false + "create_users": [ + { + "action": { + "name": "nixbld0", + "uid": 3000, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - { - "action": { - "path": "/nix/var/log/nix", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": false + { + "action": { + "name": "nixbld1", + "uid": 3001, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - { - "action": { - "path": "/nix/var/log/nix/drvs", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": false + { + "action": { + "name": "nixbld2", + "uid": 3002, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - { - "action": { - "path": "/nix/var/nix", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": false + { + "action": { + "name": "nixbld3", + "uid": 3003, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - { - "action": { - "path": "/nix/var/nix/db", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": false + { + "action": { + "name": "nixbld4", + "uid": 3004, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - { - "action": { - "path": "/nix/var/nix/gcroots", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": false + { + "action": { + "name": "nixbld5", + "uid": 3005, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - { - "action": { - "path": "/nix/var/nix/gcroots/per-user", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": false + { + "action": { + "name": "nixbld6", + "uid": 3006, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - { - "action": { - "path": "/nix/var/nix/profiles", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": false + { + "action": { + "name": "nixbld7", + "uid": 3007, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - { - "action": { - "path": "/nix/var/nix/profiles/per-user", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": false + { + "action": { + "name": "nixbld8", + "uid": 3008, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - { - "action": { - "path": "/nix/var/nix/temproots", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": false + { + "action": { + "name": "nixbld9", + "uid": 3009, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - { - "action": { - "path": "/nix/var/nix/userpool", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": false + { + "action": { + "name": "nixbld10", + "uid": 3010, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - { - "action": { - "path": "/nix/var/nix/daemon-socket", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": false + { + "action": { + "name": "nixbld11", + "uid": 3011, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - } - ] - }, - "state": "Uncompleted" - }, - "move_unpacked_nix": { - "action": { - "src": "/nix/temp-install-dir" - }, - "state": "Uncompleted" - } - }, - "state": "Uncompleted" - }, - { - "action": { - "action": "configure_nix", - "setup_default_profile": { - "action": { - "channels": [ - "nixpkgs" - ] - }, - "state": "Uncompleted" - }, - "configure_shell_profile": { - "action": { - "create_directories": [], - "create_or_insert_into_files": [ - { - "action": { - "path": "/etc/bashrc", - "user": null, - "group": null, - "mode": 493, - "buf": "\n# Nix\nif [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then\n . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'\nfi\n# End Nix\n\n \n", - "position": "Beginning" + { + "action": { + "name": "nixbld12", + "uid": 3012, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - { - "action": { - "path": "/etc/profile.d/nix.sh", - "user": null, - "group": null, - "mode": 493, - "buf": "\n# Nix\nif [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then\n . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'\nfi\n# End Nix\n\n \n", - "position": "Beginning" + { + "action": { + "name": "nixbld13", + "uid": 3013, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - { - "action": { - "path": "/etc/zshenv", - "user": null, - "group": null, - "mode": 493, - "buf": "\n# Nix\nif [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then\n . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'\nfi\n# End Nix\n\n \n", - "position": "Beginning" + { + "action": { + "name": "nixbld14", + "uid": 3014, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - }, - { - "action": { - "path": "/etc/bash.bashrc", - "user": null, - "group": null, - "mode": 493, - "buf": "\n# Nix\nif [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then\n . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'\nfi\n# End Nix\n\n \n", - "position": "Beginning" + { + "action": { + "name": "nixbld15", + "uid": 3015, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" }, - "state": "Uncompleted" - } - ] - }, - "state": "Uncompleted" - }, - "place_channel_configuration": { - "action": { - "channels": [ - [ - "nixpkgs", - "https://nixos.org/channels/nixpkgs-unstable" + { + "action": { + "name": "nixbld16", + "uid": 3016, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld17", + "uid": 3017, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld18", + "uid": 3018, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld19", + "uid": 3019, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld20", + "uid": 3020, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld21", + "uid": 3021, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld22", + "uid": 3022, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld23", + "uid": 3023, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld24", + "uid": 3024, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld25", + "uid": 3025, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld26", + "uid": 3026, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld27", + "uid": 3027, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld28", + "uid": 3028, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld29", + "uid": 3029, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld30", + "uid": 3030, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + }, + { + "action": { + "name": "nixbld31", + "uid": 3031, + "groupname": "nixbld", + "gid": 3000 + }, + "state": "Uncompleted" + } ] - ], - "create_file": { - "action": { - "path": "/root/.nix-channels", - "user": null, - "group": null, - "mode": 436, - "buf": "https://nixos.org/channels/nixpkgs-unstable nixpkgs", - "force": false - }, - "state": "Uncompleted" - } - }, - "state": "Uncompleted" - }, - "place_nix_configuration": { - "action": { - "create_directory": { - "action": { - "path": "/etc/nix", - "user": null, - "group": null, - "mode": 493, - "force_prune_on_revert": false - }, - "state": "Uncompleted" }, - "create_file": { - "action": { - "path": "/etc/nix/nix.conf", - "user": null, - "group": null, - "mode": 436, - "buf": "\n\nbuild-users-group = nixbld\n\nexperimental-features = nix-command flakes\n\nauto-optimise-store = true\n", - "force": false - }, - "state": "Uncompleted" - } + "state": "Uncompleted" }, - "state": "Uncompleted" + "create_nix_tree": { + "action": { + "create_directories": [ + { + "action": { + "path": "/nix/var", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": false + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/nix/var/log", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": false + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/nix/var/log/nix", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": false + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/nix/var/log/nix/drvs", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": false + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/nix/var/nix", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": false + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/nix/var/nix/db", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": false + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/nix/var/nix/gcroots", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": false + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/nix/var/nix/gcroots/per-user", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": false + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/nix/var/nix/profiles", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": false + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/nix/var/nix/profiles/per-user", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": false + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/nix/var/nix/temproots", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": false + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/nix/var/nix/userpool", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": false + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/nix/var/nix/daemon-socket", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": false + }, + "state": "Uncompleted" + } + ] + }, + "state": "Uncompleted" + }, + "move_unpacked_nix": { + "action": { + "src": "/nix/temp-install-dir" + }, + "state": "Uncompleted" + } }, - "configure_nix_daemon_service": { - "action": {}, - "state": "Uncompleted" - } + "state": "Uncompleted" }, - "state": "Uncompleted" + { + "action": { + "action": "configure_nix", + "setup_default_profile": { + "action": { + "channels": [ + [ + "nixpkgs", + "https://nixos.org/channels/nixpkgs-unstable" + ] + ] + }, + "state": "Uncompleted" + }, + "configure_shell_profile": { + "action": { + "create_directories": [], + "create_or_insert_into_files": [ + { + "action": { + "path": "/etc/bashrc", + "user": null, + "group": null, + "mode": 493, + "buf": "\n# Nix\nif [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then\n . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'\nfi\n# End Nix\n\n \n", + "position": "Beginning" + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/etc/profile.d/nix.sh", + "user": null, + "group": null, + "mode": 493, + "buf": "\n# Nix\nif [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then\n . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'\nfi\n# End Nix\n\n \n", + "position": "Beginning" + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/etc/zshenv", + "user": null, + "group": null, + "mode": 493, + "buf": "\n# Nix\nif [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then\n . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'\nfi\n# End Nix\n\n \n", + "position": "Beginning" + }, + "state": "Uncompleted" + }, + { + "action": { + "path": "/etc/bash.bashrc", + "user": null, + "group": null, + "mode": 493, + "buf": "\n# Nix\nif [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then\n . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'\nfi\n# End Nix\n\n \n", + "position": "Beginning" + }, + "state": "Uncompleted" + } + ] + }, + "state": "Uncompleted" + }, + "place_channel_configuration": { + "action": { + "channels": [ + [ + "nixpkgs", + "https://nixos.org/channels/nixpkgs-unstable" + ] + ], + "create_file": { + "action": { + "path": "/home/ana/.nix-channels", + "user": null, + "group": null, + "mode": 436, + "buf": "https://nixos.org/channels/nixpkgs-unstable nixpkgs", + "force": false + }, + "state": "Uncompleted" + } + }, + "state": "Uncompleted" + }, + "place_nix_configuration": { + "action": { + "create_directory": { + "action": { + "path": "/etc/nix", + "user": null, + "group": null, + "mode": 493, + "force_prune_on_revert": false + }, + "state": "Uncompleted" + }, + "create_file": { + "action": { + "path": "/etc/nix/nix.conf", + "user": null, + "group": null, + "mode": 436, + "buf": "# Generated by https://github.com/DeterminateSystems/nix-installer, version 0.1.0-unreleased.\n\n\n\nbuild-users-group = nixbld\n\nexperimental-features = nix-command flakes\n\nauto-optimise-store = true\n\nbash-prompt-prefix = (nix:$name)\\040\n", + "force": false + }, + "state": "Uncompleted" + } + }, + "state": "Uncompleted" + } + }, + "state": "Uncompleted" + }, + { + "action": { + "action": "configure_nix_daemon", + "init": "Systemd", + "start_daemon": true + }, + "state": "Uncompleted" + } + ], + "planner": { + "planner": "steam-deck", + "persistence": "/home/nix", + "settings": { + "channels": [ + [ + "nixpkgs", + "https://nixos.org/channels/nixpkgs-unstable" + ] + ], + "modify_profile": true, + "nix_build_user_count": 32, + "nix_build_group_name": "nixbld", + "nix_build_group_id": 3000, + "nix_build_user_prefix": "nixbld", + "nix_build_user_id_base": 3000, + "nix_package_url": "https://releases.nixos.org/nix/nix-2.12.0/nix-2.12.0-x86_64-linux.tar.xz", + "extra_conf": [], + "force": false + } } - ], - "planner": { - "planner": "steam-deck", - "persistence": "/home/nix", - "settings": { - "channels": [ - [ - "nixpkgs", - "https://nixos.org/channels/nixpkgs-unstable" - ] - ], - "modify_profile": true, - "nix_build_user_count": 32, - "nix_build_group_name": "nixbld", - "nix_build_group_id": 3000, - "nix_build_user_prefix": "nixbld", - "nix_build_user_id_base": 3000, - "nix_package_url": "https://releases.nixos.org/nix/nix-2.12.0/nix-2.12.0-x86_64-linux.tar.xz", - "extra_conf": [], - "force": false - } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/tests/plan.rs b/tests/plan.rs index 05653de..bf5d8e2 100644 --- a/tests/plan.rs +++ b/tests/plan.rs @@ -1,11 +1,15 @@ use nix_installer::InstallPlan; +#[cfg(target_os = "linux")] const LINUX_MULTI: &str = include_str!("./fixtures/linux/linux-multi.json"); +#[cfg(target_os = "linux")] const STEAM_DECK: &str = include_str!("./fixtures/linux/steam-deck.json"); +#[cfg(target_os = "macos")] const DARWIN_MULTI: &str = include_str!("./fixtures/darwin/darwin-multi.json"); // Ensure existing plans still parse // If this breaks and you need to update the fixture, disable these tests, bump `nix_installer` to a new version, and update the plans. +#[cfg(target_os = "linux")] #[test] fn plan_compat_linux_multi() -> eyre::Result<()> { let _: InstallPlan = serde_json::from_str(LINUX_MULTI)?; @@ -14,6 +18,7 @@ fn plan_compat_linux_multi() -> eyre::Result<()> { // Ensure existing plans still parse // If this breaks and you need to update the fixture, disable these tests, bump `nix_installer` to a new version, and update the plans. +#[cfg(target_os = "linux")] #[test] fn plan_compat_steam_deck() -> eyre::Result<()> { let _: InstallPlan = serde_json::from_str(STEAM_DECK)?; @@ -22,6 +27,7 @@ fn plan_compat_steam_deck() -> eyre::Result<()> { // Ensure existing plans still parse // If this breaks and you need to update the fixture, disable these tests, bump `nix_installer` to a new version, and update the plans. +#[cfg(target_os = "macos")] #[test] fn plan_compat_darwin_multi() -> eyre::Result<()> { let _: InstallPlan = serde_json::from_str(DARWIN_MULTI)?; diff --git a/tests/windows/test-wsl.ps1 b/tests/windows/test-wsl.ps1 new file mode 100644 index 0000000..8eae4fd --- /dev/null +++ b/tests/windows/test-wsl.ps1 @@ -0,0 +1,75 @@ +param([switch]$Systemd = $false) +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" + + +# 22.04 https://cloud-images.ubuntu.com/wsl/jammy/current/ +$url = "https://cloud-images.ubuntu.com/wsl/jammy/current/ubuntu-jammy-wsl-amd64-wsl.rootfs.tar.gz" +$File = "ubuntu-jammy-wsl-amd64-wsl.rootfs.tar.gz" +$Name = "ubuntu-jammy" + + +$TemporaryDirectory = "$HOME/nix-installer-wsl-tests-temp" +$Image = "$TemporaryDirectory\$File" +if (!(Test-Path -Path $Image)) { + Write-Output "Fetching $File to $Image..." + New-Item $TemporaryDirectory -ItemType Directory | Out-Null + Invoke-WebRequest -Uri "https://cloud-images.ubuntu.com/wsl/jammy/current/ubuntu-jammy-wsl-amd64-wsl.rootfs.tar.gz" -OutFile $Image +} else { + Write-Output "Found existing $Image..." +} + +$DistroName = "nix-installer-test-$Name" +$InstallRoot = "$TemporaryDirectory\wsl-$Name" +Write-Output "Creating WSL distribution $DistroName from $Image at $InstallRoot..." +wsl --import $DistroName $InstallRoot $Image +if ($LastExitCode -ne 0) { + exit $LastExitCode +} + +Write-Output "Preparing $DistroName for nix-installer..." +wsl --distribution $DistroName bash --login -c "apt update --quiet" +if ($LastExitCode -ne 0) { + exit $LastExitCode +} +wsl --distribution $DistroName bash --login -c "apt install --quiet --yes curl build-essential" +if ($LastExitCode -ne 0) { + exit $LastExitCode +} +wsl --distribution $DistroName bash --login -c "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --quiet" +if ($LastExitCode -ne 0) { + exit $LastExitCode +} + +if ($Systemd) { + $wslConf = "[boot]`nsystemd=true" + New-Item -Path "\\wsl$\$DistroName\etc\wsl.conf" -ItemType "file" -Value $wslConf + wsl --shutdown + if ($LastExitCode -ne 0) { + exit $LastExitCode + } +} + +Write-Output "Building and runnings nix-installer in $DistroName..." +Copy-Item -Recurse "$PSScriptRoot\..\.." -Destination "\\wsl$\$DistroName\nix-installer" +$MaybeInitChoice = switch ($Systemd) { + $true { "" } + $false { "--init none" } +} +wsl --distribution $DistroName bash --login -c "/root/.cargo/bin/cargo run --quiet --manifest-path /nix-installer/Cargo.toml -- install linux-multi --no-confirm $MaybeInitChoice" +if ($LastExitCode -ne 0) { + exit $LastExitCode +} + +Write-Output "Testing installed Nix on $DistroName..." +wsl --distribution $DistroName bash --login -c "nix run nixpkgs#hello" +if ($LastExitCode -ne 0) { + exit $LastExitCode +} + +Write-Output "Unregistering $DistroName and removing $InstallRoot..." +wsl --unregister $DistroName +if ($LastExitCode -ne 0) { + exit $LastExitCode +} +Remove-Item $InstallRoot \ No newline at end of file