forked from lix-project/lix-installer
Compare commits
4 commits
main
...
grahamc/70
Author | SHA1 | Date | |
---|---|---|---|
2164106795 | |||
52aff53955 | |||
576f3f688f | |||
eaea1483f7 |
51
.buildkite/pipeline.yml
Normal file
51
.buildkite/pipeline.yml
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
steps:
|
||||||
|
- label: nix-installer-x86_64-darwin
|
||||||
|
agents:
|
||||||
|
mac: 1
|
||||||
|
system: x86_64-darwin
|
||||||
|
nix: 1
|
||||||
|
command:
|
||||||
|
- nix --extra-experimental-features "nix-command flakes" build .#packages.x86_64-darwin.nix-installer -L
|
||||||
|
- cp result/bin/nix-installer ./nix-installer-x86_64-darwin
|
||||||
|
- buildkite-agent artifact upload nix-installer-x86_64-darwin
|
||||||
|
- label: nix-installer-aarch64-darwin
|
||||||
|
agents:
|
||||||
|
mac: 1
|
||||||
|
system: aarch64-darwin
|
||||||
|
nix: 1
|
||||||
|
command:
|
||||||
|
- nix --extra-experimental-features "nix-command flakes" build .#packages.aarch64-darwin.nix-installer -L
|
||||||
|
- cp result/bin/nix-installer ./nix-installer-aarch64-darwin
|
||||||
|
- buildkite-agent artifact upload nix-installer-aarch64-darwin
|
||||||
|
- label: nix-installer-x86_64-linux
|
||||||
|
agents:
|
||||||
|
system: x86_64-linux
|
||||||
|
nix: 1
|
||||||
|
command:
|
||||||
|
- nix --extra-experimental-features "nix-command flakes" build .#packages.x86_64-linux.nix-installer-static -L
|
||||||
|
- cp result/bin/nix-installer ./nix-installer-x86_64-linux
|
||||||
|
- buildkite-agent artifact upload nix-installer-x86_64-linux
|
||||||
|
- label: nix-installer-x86_64-linux-variants
|
||||||
|
agents:
|
||||||
|
system: x86_64-linux
|
||||||
|
nix: 1
|
||||||
|
command:
|
||||||
|
- nix --extra-experimental-features "nix-command flakes" develop --store ~/.ci-store --print-build-logs .# --command "cargo" build --no-default-features
|
||||||
|
- nix --extra-experimental-features "nix-command flakes" develop --store ~/.ci-store --print-build-logs .# --command "cargo" build --all-features
|
||||||
|
- nix --extra-experimental-features "nix-command flakes" build --store ~/.ci-store --print-build-logs .#packages.x86_64-linux.nix-installer
|
||||||
|
- label: nix-installer-i686-linux
|
||||||
|
agents:
|
||||||
|
system: x86_64-linux
|
||||||
|
nix: 1
|
||||||
|
command:
|
||||||
|
- nix --extra-experimental-features "nix-command flakes" build .#packages.i686-linux.nix-installer-static -L
|
||||||
|
- cp result/bin/nix-installer ./nix-installer-i686-linux
|
||||||
|
- buildkite-agent artifact upload nix-installer-i686-linux
|
||||||
|
- label: nix-installer-aarch64-linux
|
||||||
|
agents:
|
||||||
|
system: aarch64-linux
|
||||||
|
nix: 1
|
||||||
|
command:
|
||||||
|
- nix --extra-experimental-features "nix-command flakes" build .#packages.aarch64-linux.nix-installer-static -L
|
||||||
|
- cp result/bin/nix-installer ./nix-installer-aarch64-linux
|
||||||
|
- buildkite-agent artifact upload nix-installer-aarch64-linux
|
22
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
22
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
##### Description
|
||||||
|
|
||||||
|
<!---
|
||||||
|
Please include a short description of what your PR does and / or the motivation behind it
|
||||||
|
--->
|
||||||
|
|
||||||
|
##### Checklist
|
||||||
|
|
||||||
|
- [ ] Formatted with `cargo fmt`
|
||||||
|
- [ ] Built with `nix build`
|
||||||
|
- [ ] Ran flake checks with `nix flake check`
|
||||||
|
- [ ] Added or updated relevant tests (leave unchecked if not applicable)
|
||||||
|
- [ ] Added or updated relevant documentation (leave unchecked if not applicable)
|
||||||
|
- [ ] Linked to related issues (leave unchecked if not applicable)
|
||||||
|
|
||||||
|
##### Validating with `install.determinate.systems`
|
||||||
|
|
||||||
|
If a maintainer has added the `upload to s3` label to this PR, it will become available for installation via `install.determinate.systems`:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix/pr/$PR_NUMBER | sh -s -- install
|
||||||
|
```
|
10
.github/dependabot.yml
vendored
Normal file
10
.github/dependabot.yml
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "monthly"
|
||||||
|
- package-ecosystem: "cargo"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "monthly"
|
340
.github/workflows/ci.yml
vendored
Normal file
340
.github/workflows/ci.yml
vendored
Normal file
|
@ -0,0 +1,340 @@
|
||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lints:
|
||||||
|
name: Lints
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Check Nixpkgs input
|
||||||
|
uses: DeterminateSystems/flake-checker-action@main
|
||||||
|
with:
|
||||||
|
fail-mode: true
|
||||||
|
check-outdated: false # PRs shouldn't fail because main's nixpkgs is out of date
|
||||||
|
- name: Install Nix
|
||||||
|
uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- name: Check rustfmt
|
||||||
|
run: nix develop --command check-rustfmt
|
||||||
|
- name: Check Clippy
|
||||||
|
run: nix develop --command check-clippy
|
||||||
|
- name: Check Spelling
|
||||||
|
run: nix develop --command check-spelling
|
||||||
|
- name: Check nixpkgs-fmt formatting
|
||||||
|
run: nix develop --command check-nixpkgs-fmt
|
||||||
|
- name: Check EditorConfig conformance
|
||||||
|
run: nix develop --command check-editorconfig
|
||||||
|
- name: Download Buildkite Artifacts
|
||||||
|
uses: EnricoMi/download-buildkite-artifact-action@v1.14
|
||||||
|
with:
|
||||||
|
buildkite_token: ${{ secrets.BUILDKITE_TOKEN }}
|
||||||
|
output_path: artifacts
|
||||||
|
- name: Output list of Buildkite artifacts
|
||||||
|
run: |
|
||||||
|
ls -lah artifacts/
|
||||||
|
ls -lah artifacts/**/*
|
||||||
|
# Mac's can't run this action, so we're forced to do this.
|
||||||
|
- name: Create Github cache from Buildkite artifacts
|
||||||
|
id: cache-buildkite-artifacts
|
||||||
|
uses: actions/cache/save@v3
|
||||||
|
with:
|
||||||
|
path: artifacts
|
||||||
|
key: buildkite-artifacts-${{ github.sha }}
|
||||||
|
|
||||||
|
run-x86_64-linux:
|
||||||
|
name: Run x86_64 Linux
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
needs: [lints]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Restore Github cache of Buildkite artifacts
|
||||||
|
id: cache-buildkite-artifacts
|
||||||
|
uses: actions/cache/restore@v3
|
||||||
|
with:
|
||||||
|
path: artifacts
|
||||||
|
key: buildkite-artifacts-${{ github.sha }}
|
||||||
|
- run: sudo apt install fish zsh
|
||||||
|
- name: Move & set executable
|
||||||
|
run: |
|
||||||
|
mkdir install-root
|
||||||
|
cp nix-installer.sh install-root/nix-installer.sh
|
||||||
|
mv ./artifacts/nix-installer-x86_64-linux-*/* install-root/nix-installer-x86_64-linux
|
||||||
|
chmod +x install-root/nix-installer-x86_64-linux install-root/nix-installer.sh
|
||||||
|
- name: Initial install
|
||||||
|
uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
with:
|
||||||
|
local-root: install-root/
|
||||||
|
logger: pretty
|
||||||
|
log-directives: nix_installer=debug
|
||||||
|
backtrace: full
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- 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=debug
|
||||||
|
RUST_BACKTRACE: full
|
||||||
|
- name: Ensure `nix` is removed
|
||||||
|
run: |
|
||||||
|
if systemctl is-active nix-daemon.socket; then
|
||||||
|
echo "nix-daemon.socket was still running"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if systemctl is-active nix-daemon.service; then
|
||||||
|
echo "nix-daemon.service was still running"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -e /nix ]; then
|
||||||
|
echo "/nix exists"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
- name: Repeated install
|
||||||
|
uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
with:
|
||||||
|
local-root: install-root/
|
||||||
|
logger: pretty
|
||||||
|
log-directives: nix_installer=debug
|
||||||
|
backtrace: full
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: echo $PATH
|
||||||
|
run: echo $PATH
|
||||||
|
- name: Test `nix` with `$GITHUB_PATH`
|
||||||
|
if: success() || failure()
|
||||||
|
run: |
|
||||||
|
nix run nixpkgs#hello
|
||||||
|
nix profile install nixpkgs#hello
|
||||||
|
hello
|
||||||
|
nix store gc
|
||||||
|
nix run nixpkgs#hello
|
||||||
|
- name: Test bash
|
||||||
|
run: nix-instantiate -E 'builtins.currentTime' --eval
|
||||||
|
if: success() || failure()
|
||||||
|
shell: bash --login {0}
|
||||||
|
- name: Test sh
|
||||||
|
run: nix-instantiate -E 'builtins.currentTime' --eval
|
||||||
|
if: success() || failure()
|
||||||
|
shell: sh -l {0}
|
||||||
|
- name: Test zsh
|
||||||
|
run: nix-instantiate -E 'builtins.currentTime' --eval
|
||||||
|
if: success() || failure()
|
||||||
|
shell: zsh --login --interactive {0}
|
||||||
|
- name: Test fish
|
||||||
|
run: 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=debug
|
||||||
|
RUST_BACKTRACE: full
|
||||||
|
- name: Ensure `nix` is removed
|
||||||
|
run: |
|
||||||
|
if systemctl is-active nix-daemon.socket; then
|
||||||
|
echo "nix-daemon.socket was still running"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if systemctl is-active nix-daemon.service; then
|
||||||
|
echo "nix-daemon.service was still running"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -e /nix ]; then
|
||||||
|
echo "/nix exists"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
run-x86_64-linux-no-init:
|
||||||
|
name: Run x86_64 Linux (No init)
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
needs: [lints]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Restore Github cache of Buildkite artifacts
|
||||||
|
id: cache-buildkite-artifacts
|
||||||
|
uses: actions/cache/restore@v3
|
||||||
|
with:
|
||||||
|
path: artifacts
|
||||||
|
key: buildkite-artifacts-${{ github.sha }}
|
||||||
|
- run: sudo apt install fish zsh
|
||||||
|
- name: Move & set executable
|
||||||
|
run: |
|
||||||
|
mkdir install-root
|
||||||
|
cp nix-installer.sh install-root/nix-installer.sh
|
||||||
|
mv ./artifacts/nix-installer-x86_64-linux-*/* install-root/nix-installer-x86_64-linux
|
||||||
|
chmod +x install-root/nix-installer-x86_64-linux install-root/nix-installer.sh
|
||||||
|
- name: Initial install
|
||||||
|
uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
with:
|
||||||
|
init: none
|
||||||
|
planner: linux
|
||||||
|
local-root: install-root/
|
||||||
|
logger: pretty
|
||||||
|
log-directives: nix_installer=debug
|
||||||
|
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=debug
|
||||||
|
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@main
|
||||||
|
with:
|
||||||
|
init: none
|
||||||
|
planner: linux
|
||||||
|
local-root: install-root/
|
||||||
|
logger: pretty
|
||||||
|
log-directives: nix_installer=debug
|
||||||
|
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#hello
|
||||||
|
sudo -i nix profile install nixpkgs#hello
|
||||||
|
hello
|
||||||
|
sudo -i nix store gc
|
||||||
|
sudo -i nix run nixpkgs#hello
|
||||||
|
- 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=debug
|
||||||
|
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-x86_64-darwin:
|
||||||
|
name: Run x86_64 Darwin
|
||||||
|
runs-on: macos-12
|
||||||
|
needs: [lints]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Restore Github cache of Buildkite artifacts
|
||||||
|
id: cache-buildkite-artifacts
|
||||||
|
uses: actions/cache/restore@v3
|
||||||
|
with:
|
||||||
|
path: artifacts
|
||||||
|
key: buildkite-artifacts-${{ github.sha }}
|
||||||
|
- run: brew install fish coreutils
|
||||||
|
- name: Move & set executable
|
||||||
|
run: |
|
||||||
|
mkdir install-root
|
||||||
|
cp nix-installer.sh install-root/nix-installer.sh
|
||||||
|
mv ./artifacts/nix-installer-x86_64-darwin-*/* install-root/nix-installer-x86_64-darwin
|
||||||
|
chmod +x install-root/nix-installer-x86_64-darwin install-root/nix-installer.sh
|
||||||
|
- name: Initial install
|
||||||
|
uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
with:
|
||||||
|
local-root: install-root/
|
||||||
|
logger: pretty
|
||||||
|
log-directives: nix_installer=debug
|
||||||
|
backtrace: full
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
extra-conf: |
|
||||||
|
trusted-users = root runner
|
||||||
|
- 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=debug
|
||||||
|
RUST_BACKTRACE: full
|
||||||
|
- name: Repeated install
|
||||||
|
uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
with:
|
||||||
|
local-root: install-root/
|
||||||
|
logger: pretty
|
||||||
|
log-directives: nix_installer=debug
|
||||||
|
backtrace: full
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
extra-conf: trusted-users = root runner
|
||||||
|
- name: echo $PATH
|
||||||
|
run: echo $PATH
|
||||||
|
- name: Test `nix` with `$GITHUB_PATH`
|
||||||
|
if: success() || failure()
|
||||||
|
run: |
|
||||||
|
nix run nixpkgs#hello
|
||||||
|
nix profile install nixpkgs#hello
|
||||||
|
hello
|
||||||
|
nix store gc
|
||||||
|
nix run nixpkgs#hello
|
||||||
|
- name: Test bash
|
||||||
|
run: nix-instantiate -E 'builtins.currentTime' --eval
|
||||||
|
if: success() || failure()
|
||||||
|
shell: bash --login {0}
|
||||||
|
- name: Test sh
|
||||||
|
run: nix-instantiate -E 'builtins.currentTime' --eval
|
||||||
|
if: success() || failure()
|
||||||
|
shell: sh -l {0}
|
||||||
|
- name: Test zsh
|
||||||
|
run: nix-instantiate -E 'builtins.currentTime' --eval
|
||||||
|
if: success() || failure()
|
||||||
|
shell: zsh --login --interactive {0}
|
||||||
|
- name: Test fish
|
||||||
|
run: 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=debug
|
||||||
|
RUST_BACKTRACE: full
|
46
.github/workflows/release-branches.yml
vendored
Normal file
46
.github/workflows/release-branches.yml
vendored
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
name: Release Branch
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
# NOTE: make sure any branches here are also valid directory names,
|
||||||
|
# otherwise creating the directory and uploading to s3 will fail
|
||||||
|
- 'main'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
concurrency: release
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
id-token: write # In order to request a JWT for AWS auth
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Download Buildkite Artifacts
|
||||||
|
uses: EnricoMi/download-buildkite-artifact-action@v1.14
|
||||||
|
with:
|
||||||
|
buildkite_token: ${{ secrets.BUILDKITE_TOKEN }}
|
||||||
|
output_path: artifacts
|
||||||
|
- name: Configure AWS Credentials
|
||||||
|
uses: aws-actions/configure-aws-credentials@v2
|
||||||
|
with:
|
||||||
|
role-to-assume: ${{ secrets.AWS_S3_UPLOAD_ROLE }}
|
||||||
|
aws-region: us-east-2
|
||||||
|
- name: Publish Release (Branch)
|
||||||
|
env:
|
||||||
|
AWS_BUCKET: ${{ secrets.AWS_S3_UPLOAD_BUCKET }}
|
||||||
|
run: |
|
||||||
|
BRANCH="branch_${{ github.ref_name }}"
|
||||||
|
GIT_ISH="$GITHUB_SHA"
|
||||||
|
./upload_s3.sh "$BRANCH" "$GIT_ISH" "https://install.determinate.systems/nix/rev/$GIT_ISH"
|
||||||
|
- name: Install Instructions (Branch)
|
||||||
|
run: |
|
||||||
|
cat <<EOF
|
||||||
|
This commit can be installed by running the following command:
|
||||||
|
|
||||||
|
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix/rev/$GITHUB_SHA | sh -s -- install
|
||||||
|
|
||||||
|
The latest commit from this branch can be installed by running the following command:
|
||||||
|
|
||||||
|
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix/branch/${{ github.ref_name }} | sh -s -- install
|
||||||
|
EOF
|
55
.github/workflows/release-prs.yml
vendored
Normal file
55
.github/workflows/release-prs.yml
vendored
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
name: Release PR
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types:
|
||||||
|
- opened
|
||||||
|
- reopened
|
||||||
|
- synchronize
|
||||||
|
- labeled
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
concurrency: release
|
||||||
|
# Only intra-repo PRs are allowed to have PR artifacts uploaded
|
||||||
|
# We only want to trigger once the upload once in the case the upload label is added, not when any label is added
|
||||||
|
if: |
|
||||||
|
github.event.pull_request.head.repo.full_name == 'DeterminateSystems/nix-installer'
|
||||||
|
&& (
|
||||||
|
(github.event.action == 'labeled' && github.event.label.name == 'upload to s3')
|
||||||
|
|| (github.event.action != 'labeled' && contains(github.event.pull_request.labels.*.name, 'upload to s3'))
|
||||||
|
)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
id-token: write # In order to request a JWT for AWS auth
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Download Buildkite Artifacts
|
||||||
|
uses: EnricoMi/download-buildkite-artifact-action@v1.14
|
||||||
|
with:
|
||||||
|
buildkite_token: ${{ secrets.BUILDKITE_TOKEN }}
|
||||||
|
output_path: artifacts
|
||||||
|
- name: Configure AWS Credentials
|
||||||
|
uses: aws-actions/configure-aws-credentials@v2
|
||||||
|
with:
|
||||||
|
role-to-assume: ${{ secrets.AWS_S3_UPLOAD_ROLE }}
|
||||||
|
aws-region: us-east-2
|
||||||
|
- name: Publish Release (PR)
|
||||||
|
env:
|
||||||
|
AWS_BUCKET: ${{ secrets.AWS_S3_UPLOAD_BUCKET }}
|
||||||
|
run: |
|
||||||
|
PR="pr_${{ github.event.pull_request.number }}"
|
||||||
|
GIT_ISH="${{ github.event.pull_request.head.sha }}"
|
||||||
|
./upload_s3.sh "$PR" "$GIT_ISH" "https://install.determinate.systems/nix/rev/$GIT_ISH"
|
||||||
|
- name: Install Instructions (PR)
|
||||||
|
run: |
|
||||||
|
cat <<EOF
|
||||||
|
This commit can be installed by running the following command:
|
||||||
|
|
||||||
|
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix/rev/${{ github.event.pull_request.head.sha }} | sh -s -- install
|
||||||
|
|
||||||
|
The latest commit from this PR can be installed by running the following command:
|
||||||
|
|
||||||
|
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix/pr/${{ github.event.pull_request.number }} | sh -s -- install
|
||||||
|
EOF
|
47
.github/workflows/release-tags.yml
vendored
Normal file
47
.github/workflows/release-tags.yml
vendored
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
name: Release Tags
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "v*.*.*"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
concurrency: release
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write # In order to upload artifacts to GitHub releases
|
||||||
|
id-token: write # In order to request a JWT for AWS auth
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Download Buildkite Artifacts
|
||||||
|
uses: EnricoMi/download-buildkite-artifact-action@v1.14
|
||||||
|
with:
|
||||||
|
buildkite_token: ${{ secrets.BUILDKITE_TOKEN }}
|
||||||
|
output_path: artifacts
|
||||||
|
- name: Configure AWS Credentials
|
||||||
|
uses: aws-actions/configure-aws-credentials@v2
|
||||||
|
with:
|
||||||
|
role-to-assume: ${{ secrets.AWS_S3_UPLOAD_ROLE }}
|
||||||
|
aws-region: us-east-2
|
||||||
|
- name: Publish Release to S3 (Tag)
|
||||||
|
env:
|
||||||
|
AWS_BUCKET: ${{ secrets.AWS_S3_UPLOAD_BUCKET }}
|
||||||
|
run: |
|
||||||
|
./upload_s3.sh "$GITHUB_REF_NAME" "$GITHUB_SHA" "https://install.determinate.systems/nix/tag/$GITHUB_REF_NAME"
|
||||||
|
- name: Publish Release to GitHub (Tag)
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
with:
|
||||||
|
fail_on_unmatched_files: true
|
||||||
|
draft: true
|
||||||
|
files: |
|
||||||
|
artifacts/**
|
||||||
|
nix-installer.sh
|
||||||
|
- name: Install Instructions (Tag)
|
||||||
|
run: |
|
||||||
|
cat <<EOF
|
||||||
|
This tag can be installed by running the following command:
|
||||||
|
|
||||||
|
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix/tag/$GITHUB_REF_NAME | sh -s -- install
|
||||||
|
EOF
|
20
.github/workflows/update.yml
vendored
Normal file
20
.github/workflows/update.yml
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
name: update-flake-lock
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0 * * 0'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lockfile:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Install Nix
|
||||||
|
uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- name: Enable magic Nix cache
|
||||||
|
uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- name: Check flake
|
||||||
|
uses: DeterminateSystems/flake-checker-action@main
|
||||||
|
- name: Update flake.lock
|
||||||
|
uses: DeterminateSystems/update-flake-lock@main
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -2,6 +2,4 @@
|
||||||
.ci-store
|
.ci-store
|
||||||
.direnv
|
.direnv
|
||||||
result*
|
result*
|
||||||
release-assets
|
|
||||||
src/action/linux/selinux/nix.mod
|
src/action/linux/selinux/nix.mod
|
||||||
.idea
|
|
||||||
|
|
|
@ -60,7 +60,8 @@ representative at an online or offline event.
|
||||||
## Enforcement
|
## Enforcement
|
||||||
|
|
||||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
reported to the community leaders responsible for enforcement at [community@lix.systems](community@lix.systems).
|
reported to the community leaders responsible for enforcement at
|
||||||
|
[coc-grahamc@determinate.systems](coc-grahamc@determinate.systems) or [coc-ana@determinate.systems](coc-ana@determinate.systems) .
|
||||||
All complaints will be reviewed and investigated promptly and fairly.
|
All complaints will be reviewed and investigated promptly and fairly.
|
||||||
|
|
||||||
All community leaders are obligated to respect the privacy and security of the
|
All community leaders are obligated to respect the privacy and security of the
|
||||||
|
|
|
@ -69,7 +69,7 @@ Here are how to do various kinds of contributions.
|
||||||
|
|
||||||
## Bug Reports
|
## Bug Reports
|
||||||
|
|
||||||
Create an issue on [the issue page](https://git.lix.systems/lix-project/lix-installer/issues).
|
Create an issue on [the issue page](https://github.com/DeterminateSystems/nix-installer/issues).
|
||||||
|
|
||||||
It should contain:
|
It should contain:
|
||||||
|
|
||||||
|
@ -85,10 +85,10 @@ It should contain:
|
||||||
|
|
||||||
For **minor** fixes, documentation, or changes which **do not** have a
|
For **minor** fixes, documentation, or changes which **do not** have a
|
||||||
tangible impact on user experience, feel free to open a
|
tangible impact on user experience, feel free to open a
|
||||||
[pull request](https://git.lix.systems/lix-project/lix-installer/pulls) directly.
|
[pull request](https://github.com/DeterminateSystems/nix-installer/pulls) directly.
|
||||||
|
|
||||||
If the code improvement is not minor, such as new features or user facing
|
If the code improvement is not minor, such as new features or user facing
|
||||||
changes, an [issue](https://git.lix.systems/lix-project/lix-installer/issues)
|
changes, an [issue](https://github.com/DeterminateSystems/nix-installer/issues)
|
||||||
proposing the change is **required** for non-maintainers.
|
proposing the change is **required** for non-maintainers.
|
||||||
|
|
||||||
Please:
|
Please:
|
||||||
|
@ -103,7 +103,7 @@ Please:
|
||||||
|
|
||||||
## Non-code contributions
|
## Non-code contributions
|
||||||
|
|
||||||
Please open an [issue](https://git.lix.systems/lix-project/lix-installer/issues)
|
Please open an [issue](https://github.com/DeterminateSystems/nix-installer/issues)
|
||||||
to chat about your contribution and figure out how to best integrate it into
|
to chat about your contribution and figure out how to best integrate it into
|
||||||
the project.
|
the project.
|
||||||
|
|
||||||
|
@ -162,8 +162,8 @@ These should be visible in `nix flake show`:
|
||||||
|
|
||||||
```
|
```
|
||||||
❯ nix flake show
|
❯ nix flake show
|
||||||
warning: Git tree '/home/ana/git/detsys/nix-installer' is dirty
|
warning: Git tree '/home/ana/git/determinatesystems/nix-installer' is dirty
|
||||||
git+file:///home/ana/git/detsys/nix-installer
|
git+file:///home/ana/git/determinatesystems/nix-installer
|
||||||
# ...
|
# ...
|
||||||
├───hydraJobs
|
├───hydraJobs
|
||||||
│ └───vm-test
|
│ └───vm-test
|
||||||
|
@ -201,6 +201,12 @@ nix build .#hydraJobs.vm-test.rhel-v7.x86_64-linux.all -L -j 4
|
||||||
|
|
||||||
> You may wish to set `-j 4` to some other number. Some OS's (Ubuntu 16.04) exhibit problems rapidly updating their users/groups on a system running dozens of VMs.
|
> You may wish to set `-j 4` to some other number. Some OS's (Ubuntu 16.04) exhibit problems rapidly updating their users/groups on a system running dozens of VMs.
|
||||||
|
|
||||||
|
For PR review, you can also test arbitrary branches or checkouts like so:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix build github:determinatesystems/nix-installer/${BRANCH}#hydraJobs.vm-test.ubuntu-v22_04.x86_64-linux.install-default -L
|
||||||
|
```
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary><strong>Adding a distro?</strong></summary>
|
<summary><strong>Adding a distro?</strong></summary>
|
||||||
|
|
||||||
|
@ -243,8 +249,8 @@ These should be visible in `nix flake show`:
|
||||||
|
|
||||||
```
|
```
|
||||||
❯ nix flake show
|
❯ nix flake show
|
||||||
warning: Git tree '/home/ana/git/detsys/nix-installer' is dirty
|
warning: Git tree '/home/ana/git/determinatesystems/nix-installer' is dirty
|
||||||
git+file:///home/ana/git/detsys/nix-installer
|
git+file:///home/ana/git/determinatesystems/nix-installer
|
||||||
# ...
|
# ...
|
||||||
├───hydraJobs
|
├───hydraJobs
|
||||||
│ ├───container-test
|
│ ├───container-test
|
||||||
|
@ -285,6 +291,12 @@ To run a specific distribution listed in the `nix flake show` output:
|
||||||
nix build .#hydraJobs.container-test.ubuntu-v22_04.x86_64-linux.docker -L
|
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
|
||||||
|
```
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary><strong>Adding a distro?</strong></summary>
|
<summary><strong>Adding a distro?</strong></summary>
|
||||||
|
|
||||||
|
@ -353,9 +365,9 @@ This package uses [Semantic Versioning](https://semver.org/). When determining t
|
||||||
To cut a release:
|
To cut a release:
|
||||||
|
|
||||||
* Ensure the `flake.lock`, `Cargo.lock`, and Rust dependencies are up-to-date with the following:
|
* Ensure the `flake.lock`, `Cargo.lock`, and Rust dependencies are up-to-date with the following:
|
||||||
+ `nix flake update --commit-lock-file`
|
+ `nix flake update`
|
||||||
+ `cargo outdated --ignore-external-rel --aggressive`
|
+ `cargo update`
|
||||||
+ `cargo update --aggressive`
|
+ `cargo outdated`
|
||||||
+ Make a PR for for this and let it get merged separately
|
+ Make a PR for for this and let it get merged separately
|
||||||
* Create a release branch from `main` (`git checkout -b release-v0.0.1`)
|
* Create a release branch from `main` (`git checkout -b release-v0.0.1`)
|
||||||
* Remove the `-unreleased` from the `version` field in `Cargo.toml`, `flake.nix`, and the fixture JSON files
|
* Remove the `-unreleased` from the `version` field in `Cargo.toml`, `flake.nix`, and the fixture JSON files
|
||||||
|
@ -378,6 +390,11 @@ To cut a release:
|
||||||
+ **Warning:** While you can re-release Github releases, it is not possible to do the same on `crates.io`
|
+ **Warning:** While you can re-release Github releases, it is not possible to do the same on `crates.io`
|
||||||
* Create a PR bumping the version up one minor in the `Cargo.toml`, `flake.nix`, and fixture JSON files, adding `-unreleased` at the end (`v0.0.2-unreleased`)
|
* Create a PR bumping the version up one minor in the `Cargo.toml`, `flake.nix`, and fixture JSON files, adding `-unreleased` at the end (`v0.0.2-unreleased`)
|
||||||
|
|
||||||
# Who maintains `lix-installer` and why?
|
# Who maintains `nix-installer` and why?
|
||||||
|
|
||||||
`lix-installer` is maintained by [the Lix community](https://lix.systems/) as part of the Lix Project.
|
`nix-installer` is maintained by [Determinate Systems](https://determinate.systems/) in
|
||||||
|
an effort to explore Nix installer ideas.
|
||||||
|
|
||||||
|
Determinate Systems has no plans to monetize or relicense `nix-installer`. If your
|
||||||
|
enterprise requires a support contact in order to adopt a tool, please contact
|
||||||
|
Determinate Systems and something can be worked out.
|
||||||
|
|
1123
Cargo.lock
generated
1123
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
21
Cargo.toml
21
Cargo.toml
|
@ -1,12 +1,12 @@
|
||||||
[package]
|
[package]
|
||||||
name = "lix-installer"
|
name = "nix-installer"
|
||||||
description = "The Determinate Nix Installer"
|
description = "The Determinate Nix Installer"
|
||||||
version = "0.17.1"
|
version = "0.14.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
license = "LGPL-2.1"
|
license = "LGPL-2.1"
|
||||||
repository = "https://git.lix.systems/lix-project/lix-installer"
|
repository = "https://github.com/DeterminateSystems/nix-installer"
|
||||||
documentation = "https://docs.rs/lix-installer/latest/lix_installer"
|
documentation = "https://docs.rs/nix-installer/latest/nix_installer"
|
||||||
|
|
||||||
[package.metadata.riff.targets.aarch64-apple-darwin]
|
[package.metadata.riff.targets.aarch64-apple-darwin]
|
||||||
build-inputs = ["darwin.apple_sdk.frameworks.Security"]
|
build-inputs = ["darwin.apple_sdk.frameworks.Security"]
|
||||||
|
@ -15,11 +15,12 @@ build-inputs = ["darwin.apple_sdk.frameworks.Security"]
|
||||||
build-inputs = ["darwin.apple_sdk.frameworks.Security"]
|
build-inputs = ["darwin.apple_sdk.frameworks.Security"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["cli"]
|
default = ["cli", "diagnostics"]
|
||||||
cli = ["eyre", "color-eyre", "clap", "tracing-subscriber", "tracing-error"]
|
cli = ["eyre", "color-eyre", "clap", "tracing-subscriber", "tracing-error"]
|
||||||
|
diagnostics = ["is_ci"]
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "lix-installer"
|
name = "nix-installer"
|
||||||
required-features = [ "cli" ]
|
required-features = [ "cli" ]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
@ -29,8 +30,8 @@ clap = { version = "4", features = ["std", "color", "usage", "help", "error-cont
|
||||||
color-eyre = { version = "0.6.2", default-features = false, features = [ "track-caller", "issue-url", "tracing-error", "capture-spantrace", "color-spantrace" ], optional = true }
|
color-eyre = { version = "0.6.2", default-features = false, features = [ "track-caller", "issue-url", "tracing-error", "capture-spantrace", "color-spantrace" ], optional = true }
|
||||||
eyre = { version = "0.6.8", default-features = false, features = [ "track-caller" ], optional = true }
|
eyre = { version = "0.6.8", default-features = false, features = [ "track-caller" ], optional = true }
|
||||||
glob = { version = "0.3.0", default-features = false }
|
glob = { version = "0.3.0", default-features = false }
|
||||||
nix = { version = "0.28.0", default-features = false, features = ["user", "fs", "process", "term"] }
|
nix = { version = "0.27.0", default-features = false, features = ["user", "fs", "process", "term"] }
|
||||||
owo-colors = { version = "4.0.0", default-features = false, features = [ "supports-colors" ] }
|
owo-colors = { version = "3.5.0", default-features = false, features = [ "supports-colors" ] }
|
||||||
reqwest = { version = "0.11.11", default-features = false, features = ["rustls-tls-native-roots", "stream", "socks"] }
|
reqwest = { version = "0.11.11", default-features = false, features = ["rustls-tls-native-roots", "stream", "socks"] }
|
||||||
serde = { version = "1.0.144", default-features = false, features = [ "std", "derive" ] }
|
serde = { version = "1.0.144", default-features = false, features = [ "std", "derive" ] }
|
||||||
serde_json = { version = "1.0.85", default-features = false, features = [ "std" ] }
|
serde_json = { version = "1.0.85", default-features = false, features = [ "std" ] }
|
||||||
|
@ -54,9 +55,9 @@ term = { version = "0.7.0", default-features = false }
|
||||||
uuid = { version = "1.2.2", features = ["serde"] }
|
uuid = { version = "1.2.2", features = ["serde"] }
|
||||||
os-release = { version = "0.1.0", default-features = false }
|
os-release = { version = "0.1.0", default-features = false }
|
||||||
is_ci = { version = "1.1.1", default-features = false, optional = true }
|
is_ci = { version = "1.1.1", default-features = false, optional = true }
|
||||||
strum = { version = "0.26.1", features = ["derive"] }
|
strum = { version = "0.25.0", features = ["derive"] }
|
||||||
nix-config-parser = { version = "0.2", features = ["serde"] }
|
nix-config-parser = { version = "0.2", features = ["serde"] }
|
||||||
which = "6.0.0"
|
which = "4.4.0"
|
||||||
sysctl = "0.5.4"
|
sysctl = "0.5.4"
|
||||||
walkdir = "2.3.3"
|
walkdir = "2.3.3"
|
||||||
indexmap = { version = "2.0.2", features = ["serde"] }
|
indexmap = { version = "2.0.2", features = ["serde"] }
|
||||||
|
|
279
README.md
279
README.md
|
@ -1,39 +1,57 @@
|
||||||
# The Lix Installer
|
# The Determinate Nix Installer
|
||||||
|
|
||||||
A fast, friendly, and reliable tool to help you use Lix, the community implementation of the nix tooling.
|
[![Crates.io](https://img.shields.io/crates/v/nix-installer)](https://crates.io/crates/nix-installer)
|
||||||
Based on the [Determinate Installer](https://install.determinate.systems).
|
[![Docs.rs](https://img.shields.io/docsrs/nix-installer)](https://docs.rs/nix-installer/latest/nix_installer/)
|
||||||
|
|
||||||
|
A fast, friendly, and reliable tool to help you use Nix with Flakes everywhere.
|
||||||
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl --proto '=https' --tlsv1.2 -sSf -L https://install.lix.systems/lix | sh -s -- install
|
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The `nix-installer` has successfully completed over 500,000 installs in a number of environments, including [Github Actions](#as-a-github-action):
|
||||||
|
|
||||||
|
| Platform | Multi User | `root` only | Maturity |
|
||||||
|
|------------------------------|:------------------:|:-----------:|:-----------------:|
|
||||||
|
| Linux (x86_64 & aarch64) | ✓ (via [systemd]) | ✓ | Stable |
|
||||||
|
| MacOS (x86_64 & aarch64) | ✓ | | Stable (See note) |
|
||||||
|
| Valve Steam Deck (SteamOS) | ✓ | | Stable |
|
||||||
|
| WSL2 (x86_64 & aarch64) | ✓ (via [systemd]) | ✓ | Stable |
|
||||||
|
| Podman Linux Containers | ✓ (via [systemd]) | ✓ | Stable |
|
||||||
|
| Docker Containers | | ✓ | Stable |
|
||||||
|
| Linux (i686) | ✓ (via [systemd]) | ✓ | Unstable |
|
||||||
|
|
||||||
|
> **Note**
|
||||||
|
> On **MacOS only**, removing users and/or groups may fail if there are no users who are logged in graphically.
|
||||||
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Install Nix with the default planner and options:
|
Install Nix with the default planner and options:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl --proto '=https' --tlsv1.2 -sSf -L https://install.lix.systems/lix | sh -s -- install
|
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
|
||||||
```
|
```
|
||||||
|
|
||||||
Or, to download a platform specific Installer binary yourself:
|
Or, to download a platform specific Installer binary yourself:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ curl -sL -o lix-installer https://install.lix.systems/lix/lix-installer-x86_64-linux
|
$ curl -sL -o nix-installer https://install.determinate.systems/nix/nix-installer-x86_64-linux
|
||||||
$ chmod +x lix-installer
|
$ chmod +x nix-installer
|
||||||
$ ./lix-installer
|
$ ./nix-installer
|
||||||
```
|
```
|
||||||
|
|
||||||
`lix-installer` installs Lix by following a *plan* made by a *planner*. Review the available planners:
|
`nix-installer` installs Nix by following a *plan* made by a *planner*. Review the available planners:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ ./lix-installer install --help
|
$ ./nix-installer install --help
|
||||||
Execute an install (possibly using an existing plan)
|
Execute an install (possibly using an existing plan)
|
||||||
|
|
||||||
To pass custom options, select a planner, for example `lix-installer install linux-multi --help`
|
To pass custom options, select a planner, for example `nix-installer install linux-multi --help`
|
||||||
|
|
||||||
Usage: lix-installer install [OPTIONS] [PLAN]
|
Usage: nix-installer install [OPTIONS] [PLAN]
|
||||||
lix-installer install <COMMAND>
|
nix-installer install <COMMAND>
|
||||||
|
|
||||||
Commands:
|
Commands:
|
||||||
linux
|
linux
|
||||||
|
@ -48,10 +66,10 @@ Commands:
|
||||||
Planners have their own options and defaults, sharing most of them in common:
|
Planners have their own options and defaults, sharing most of them in common:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ ./lix-installer install linux --help
|
$ ./nix-installer install linux --help
|
||||||
A planner for Linux installs
|
A planner for Linux installs
|
||||||
|
|
||||||
Usage: lix-installer install linux [OPTIONS]
|
Usage: nix-installer install linux [OPTIONS]
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
# ...
|
# ...
|
||||||
|
@ -72,33 +90,56 @@ Options:
|
||||||
Planners can be configured via environment variable or command arguments:
|
Planners can be configured via environment variable or command arguments:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ curl --proto '=https' --tlsv1.2 -sSf -L https://install.lix.systems/lix | NIX_BUILD_GROUP_NAME=nixbuilder sh -s -- install linux-multi --nix-build-group-id 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...
|
# Or...
|
||||||
$ NIX_BUILD_GROUP_NAME=nixbuilder ./lix-installer install linux-multi --nix-build-group-id 4000
|
$ NIX_BUILD_GROUP_NAME=nixbuilder ./nix-installer install linux-multi --nix-build-group-id 4000
|
||||||
```
|
```
|
||||||
|
|
||||||
### Upgrading Lix
|
### Upgrading Nix
|
||||||
|
|
||||||
You can upgrade Lix with:
|
You can upgrade Nix (to the version specified [here](https://raw.githubusercontent.com/NixOS/nixpkgs/master/nixos/modules/installer/tools/nix-fallback-paths.nix)) by running:
|
||||||
|
|
||||||
```
|
```
|
||||||
sudo -i nix upgrade-nix
|
sudo -i nix upgrade-nix
|
||||||
```
|
```
|
||||||
|
|
||||||
Alternatively, you can [uninstall](#uninstalling) and [reinstall](#usage) with a different version of the `lix-installer`.
|
Alternatively, you can [uninstall](#uninstalling) and [reinstall](#usage) with a different version of the `nix-installer`.
|
||||||
|
|
||||||
### Uninstalling
|
### Uninstalling
|
||||||
|
|
||||||
You can remove a `lix-installer`-installed Nix by running
|
You can remove a `nix-installer`-installed Nix by running
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
/nix/lix-installer uninstall
|
/nix/nix-installer uninstall
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### As a Github Action
|
||||||
|
|
||||||
|
You can use the [`nix-installer-action`](https://github.com/DeterminateSystems/nix-installer-action) Github Action like so:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lints:
|
||||||
|
name: Build
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Install Nix
|
||||||
|
uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- name: Run `nix build`
|
||||||
|
run: nix build .
|
||||||
```
|
```
|
||||||
|
|
||||||
### Without systemd (Linux only)
|
### Without systemd (Linux only)
|
||||||
|
|
||||||
> **Warning**
|
> **Warning**
|
||||||
> When `--init none` is used, _only_ `root` or users who can elevate to `root` privileges can run Lix's nix command:
|
> When `--init none` is used, _only_ `root` or users who can elevate to `root` privileges can run Nix:
|
||||||
>
|
>
|
||||||
> ```bash
|
> ```bash
|
||||||
> sudo -i nix run nixpkgs#hello
|
> sudo -i nix run nixpkgs#hello
|
||||||
|
@ -107,7 +148,7 @@ You can remove a `lix-installer`-installed Nix by running
|
||||||
If you don't use [systemd], you can still install Nix by explicitly specifying the `linux` plan and `--init none`:
|
If you don't use [systemd], you can still install Nix by explicitly specifying the `linux` plan and `--init none`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl --proto '=https' --tlsv1.2 -sSf -L https://install.lix.systems/lix | sh -s -- install linux --init none
|
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install linux --init none
|
||||||
```
|
```
|
||||||
|
|
||||||
### In a container
|
### In a container
|
||||||
|
@ -117,7 +158,7 @@ In Docker/Podman containers or WSL2 instances where an init (like `systemd`) is
|
||||||
For containers (without an init):
|
For containers (without an init):
|
||||||
|
|
||||||
> **Warning**
|
> **Warning**
|
||||||
> When `--init none` is used, _only_ `root` or users who can elevate to `root` privileges can run Lix's nix command:
|
> When `--init none` is used, _only_ `root` or users who can elevate to `root` privileges can run Nix:
|
||||||
>
|
>
|
||||||
> ```bash
|
> ```bash
|
||||||
> sudo -i nix run nixpkgs#hello
|
> sudo -i nix run nixpkgs#hello
|
||||||
|
@ -128,7 +169,7 @@ For containers (without an init):
|
||||||
FROM ubuntu:latest
|
FROM ubuntu:latest
|
||||||
RUN apt update -y
|
RUN apt update -y
|
||||||
RUN apt install curl -y
|
RUN apt install curl -y
|
||||||
RUN curl --proto '=https' --tlsv1.2 -sSf -L https://install.lix.systems/lix | sh -s -- install linux \
|
RUN curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install linux \
|
||||||
--extra-conf "sandbox = false" \
|
--extra-conf "sandbox = false" \
|
||||||
--init none \
|
--init none \
|
||||||
--no-confirm
|
--no-confirm
|
||||||
|
@ -153,7 +194,7 @@ For containers with a systemd init:
|
||||||
FROM ubuntu:latest
|
FROM ubuntu:latest
|
||||||
RUN apt update -y
|
RUN apt update -y
|
||||||
RUN apt install curl systemd -y
|
RUN apt install curl systemd -y
|
||||||
RUN curl --proto '=https' --tlsv1.2 -sSf -L https://install.lix.systems/lix | sh -s -- install linux \
|
RUN curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install linux \
|
||||||
--extra-conf "sandbox = false" \
|
--extra-conf "sandbox = false" \
|
||||||
--no-start-daemon \
|
--no-start-daemon \
|
||||||
--no-confirm
|
--no-confirm
|
||||||
|
@ -175,11 +216,11 @@ On some container tools, such as `docker`, `sandbox = false` can be omitted. Omi
|
||||||
|
|
||||||
### In WSL2
|
### In WSL2
|
||||||
|
|
||||||
We **strongly recommend** [enabling systemd](https://ubuntu.com/blog/ubuntu-wsl-enable-systemd), then installing Lix as normal:
|
We **strongly recommend** [enabling systemd](https://ubuntu.com/blog/ubuntu-wsl-enable-systemd), then installing Nix as normal:
|
||||||
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl --proto '=https' --tlsv1.2 -sSf -L https://install.lix.systems/lix | sh -s -- install
|
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
|
||||||
```
|
```
|
||||||
|
|
||||||
If [WSLg][wslg] is enabled, you can do things like open a Linux Firefox from Windows on Powershell:
|
If [WSLg][wslg] is enabled, you can do things like open a Linux Firefox from Windows on Powershell:
|
||||||
|
@ -195,10 +236,10 @@ wsl nix run --impure github:guibou/nixGL nix run nixpkgs#obs-studio
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
If enabling systemd is not an option, pass `--init none` at the end of the command:
|
If enabling system is not an option, pass `--init none` at the end of the command:
|
||||||
|
|
||||||
> **Warning**
|
> **Warning**
|
||||||
> When `--init none` is used, _only_ `root` or users who can elevate to `root` privileges can run Lix's nix commands:
|
> When `--init none` is used, _only_ `root` or users who can elevate to `root` privileges can run Nix:
|
||||||
>
|
>
|
||||||
> ```bash
|
> ```bash
|
||||||
> sudo -i nix run nixpkgs#hello
|
> sudo -i nix run nixpkgs#hello
|
||||||
|
@ -206,7 +247,7 @@ If enabling systemd is not an option, pass `--init none` at the end of the comma
|
||||||
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl --proto '=https' --tlsv1.2 -sSf -L https://install.lix.systems/lix | sh -s -- install linux --init none
|
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install linux --init none
|
||||||
```
|
```
|
||||||
|
|
||||||
### Skip confirmation
|
### Skip confirmation
|
||||||
|
@ -214,7 +255,7 @@ curl --proto '=https' --tlsv1.2 -sSf -L https://install.lix.systems/lix | sh -s
|
||||||
If you'd like to bypass the confirmation step, you can apply the `--no-confirm` flag:
|
If you'd like to bypass the confirmation step, you can apply the `--no-confirm` flag:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl --proto '=https' --tlsv1.2 -sSf -L https://install.lix.systems/lix | sh -s -- install --no-confirm
|
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install --no-confirm
|
||||||
```
|
```
|
||||||
|
|
||||||
This is especially useful when using the installer in non-interactive scripts.
|
This is especially useful when using the installer in non-interactive scripts.
|
||||||
|
@ -222,11 +263,54 @@ This is especially useful when using the installer in non-interactive scripts.
|
||||||
|
|
||||||
## Quirks
|
## Quirks
|
||||||
|
|
||||||
While `lix-installer` tries to provide a comprehensive and unquirky experience, there are unfortunately some issues which may require manual intervention or operator choices.
|
While `nix-installer` tries to provide a comprehensive and unquirky experience, there are unfortunately some issues which may require manual intervention or operator choices.
|
||||||
|
|
||||||
|
### Using MacOS remote SSH builders, Nix binaries are not on `$PATH`
|
||||||
|
|
||||||
|
When connecting to a Mac remote SSH builder users may sometimes see this error:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ nix store ping --store "ssh://$USER@$HOST"
|
||||||
|
Store URL: ssh://$USER@$HOST
|
||||||
|
zsh:1: command not found: nix-store
|
||||||
|
error: cannot connect to '$USER@$HOST'
|
||||||
|
```
|
||||||
|
|
||||||
|
The way MacOS populates the `PATH` environment differs from other environments. ([Some background](https://gist.github.com/Linerre/f11ad4a6a934dcf01ee8415c9457e7b2))
|
||||||
|
|
||||||
|
There are two possible workarounds for this:
|
||||||
|
|
||||||
|
* **(Preferred)** Update the remote builder URL to include the `remote-program` parameter pointing to `nix-store`. For example:
|
||||||
|
```bash
|
||||||
|
nix store ping --store "ssh://$USER@$HOST?remote-program=/nix/var/nix/profiles/default/bin/nix-store"
|
||||||
|
```
|
||||||
|
If you are unsure where the `nix-store` binary is located, run `which nix-store` on the remote.
|
||||||
|
* Update `/etc/zshenv` on the remote so that `zsh` populates the Nix path for every shell, even those that are neither *interactive* or *login*:
|
||||||
|
```bash
|
||||||
|
# Nix
|
||||||
|
if [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then
|
||||||
|
. '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'
|
||||||
|
fi
|
||||||
|
# End Nix
|
||||||
|
```
|
||||||
|
<details>
|
||||||
|
<summary>This strategy has some behavioral caveats, namely, <code>$PATH</code> may have unexpected contents</summary>
|
||||||
|
|
||||||
|
For example, if `$PATH` gets unset then a script invoked, `$PATH` may not be as empty as expected:
|
||||||
|
```bash
|
||||||
|
$ cat example.sh
|
||||||
|
#! /bin/zsh
|
||||||
|
echo $PATH
|
||||||
|
$ PATH= ./example.sh
|
||||||
|
/Users/ephemeraladmin/.nix-profile/bin:/nix/var/nix/profiles/default/bin:
|
||||||
|
```
|
||||||
|
This strategy results in Nix's paths being present on `$PATH` twice and may have a minor impact on performance.
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
### Using MacOS after removing `nix` while `nix-darwin` was still installed, network requests fail
|
### Using MacOS after removing `nix` while `nix-darwin` was still installed, network requests fail
|
||||||
|
|
||||||
If any variant of `nix` was previously uninstalled without uninstalling `nix-darwin` first, users may experience errors similar to this:
|
If `nix` was previously uninstalled without uninstalling `nix-darwin` first, users may experience errors similar to this:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ nix shell nixpkgs#curl
|
$ nix shell nixpkgs#curl
|
||||||
|
@ -251,46 +335,56 @@ It's possible to resolve this situation by removing the `org.nixos.activate-syst
|
||||||
```bash
|
```bash
|
||||||
$ sudo rm /Library/LaunchDaemons/org.nixos.activate-system.plist
|
$ sudo rm /Library/LaunchDaemons/org.nixos.activate-system.plist
|
||||||
$ sudo launchctl bootout system/org.nixos.activate-system
|
$ sudo launchctl bootout system/org.nixos.activate-system
|
||||||
$ /nix/lix-installer uninstall
|
$ /nix/nix-installer uninstall
|
||||||
$ sudo rm /etc/ssl/certs/ca-certificates.crt
|
$ sudo rm /etc/ssl/certs/ca-certificates.crt
|
||||||
```
|
```
|
||||||
|
|
||||||
Then run the `lix-installer` again, and it should work.
|
Then run the `nix-installer` again, and it should work.
|
||||||
|
|
||||||
Up-to-date versions of the `lix-installer` will refuse to uninstall until `nix-darwin` is uninstalled first, helping mitigate this problem.
|
Up-to-date versions of the `nix-installer` will refuse to uninstall until `nix-darwin` is uninstalled first, helping mitigate this problem.
|
||||||
|
|
||||||
## Building a binary
|
## Building a binary
|
||||||
|
|
||||||
Since you'll be using `lix-installer` to install Nix on systems without Nix, the default build is a static 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 Linux binary on a system with Nix:
|
Build a portable Linux binary on a system with Nix:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# to build a local copy
|
# to build a local copy
|
||||||
nix build -L ".#lix-installer-static"
|
nix build -L ".#nix-installer-static"
|
||||||
|
# to build the remote main development branch
|
||||||
|
nix build -L "github:determinatesystems/nix-installer#nix-installer-static"
|
||||||
|
# for a specific version of the installer:
|
||||||
|
export NIX_INSTALLER_TAG="v0.6.0"
|
||||||
|
nix build -L "github:determinatesystems/nix-installer/$NIX_INSTALLER_TAG#nix-installer-static"
|
||||||
```
|
```
|
||||||
|
|
||||||
On Mac:
|
On Mac:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# to build a local copy
|
# to build a local copy
|
||||||
nix build -L ".#lix-installer"
|
nix build -L ".#nix-installer"
|
||||||
|
# to build the remote main development branch
|
||||||
|
nix build -L "github:determinatesystems/nix-installer#nix-installer"
|
||||||
|
# for a specific version of the installer:
|
||||||
|
export NIX_INSTALLER_TAG="v0.6.0"
|
||||||
|
nix build -L "github:determinatesystems/nix-installer/$NIX_INSTALLER_TAG#nix-installer"
|
||||||
```
|
```
|
||||||
|
|
||||||
Then copy the `result/bin/lix-installer` to the machine you wish to run it on.
|
Then copy the `result/bin/nix-installer` to the machine you wish to run it on.
|
||||||
|
|
||||||
You can also add `lix-installer` to a system without Lix via `cargo`. There are no system dependencies to worry about:
|
You can also add `nix-installer` to a system without Nix via `cargo`, there are no system dependencies to worry about:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# to build and run a local copy
|
# to build and run a local copy
|
||||||
RUSTFLAGS="--cfg tokio_unstable" cargo run -- --help
|
RUSTFLAGS="--cfg tokio_unstable" cargo run -- --help
|
||||||
# to build the remote main development branch
|
# to build the remote main development branch
|
||||||
RUSTFLAGS="--cfg tokio_unstable" cargo install --git https://git.lix.systems/lix-project/lix-installer
|
RUSTFLAGS="--cfg tokio_unstable" cargo install --git https://github.com/DeterminateSystems/nix-installer
|
||||||
lix-installer --help
|
nix-installer --help
|
||||||
# for a specific version of the installer:
|
# for a specific version of the installer:
|
||||||
export NIX_INSTALLER_TAG="v0.6.0"
|
export NIX_INSTALLER_TAG="v0.6.0"
|
||||||
RUSTFLAGS="--cfg tokio_unstable" cargo install --git https://git.lix.systems/lix-project/lix-installer --tag $NIX_INSTALLER_TAG
|
RUSTFLAGS="--cfg tokio_unstable" cargo install --git https://github.com/DeterminateSystems/nix-installer --tag $NIX_INSTALLER_TAG
|
||||||
lix-installer --help
|
nix-installer --help
|
||||||
```
|
```
|
||||||
|
|
||||||
To make this build portable, pass ` --target x86_64-unknown-linux-musl`.
|
To make this build portable, pass ` --target x86_64-unknown-linux-musl`.
|
||||||
|
@ -302,12 +396,12 @@ To make this build portable, pass ` --target x86_64-unknown-linux-musl`.
|
||||||
## As a library
|
## As a library
|
||||||
|
|
||||||
> **Warning**
|
> **Warning**
|
||||||
> Use as a library is still experimental. This feature is likely to be removed in the future without an advocate. If you're using this, please let us know and we can make a path to stabilization.
|
> Use as a library is still experimental. This feature is likely to be removed in the future without an advocate. If you're using this, please let us know and we can make a path to stablization.
|
||||||
|
|
||||||
Add `lix-installer` to your dependencies:
|
Add `nix-installer` to your dependencies:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cargo add lix-installer
|
cargo add nix-installer
|
||||||
```
|
```
|
||||||
|
|
||||||
If you are **building a CLI**, check out the `cli` feature flag for `clap` integration.
|
If you are **building a CLI**, check out the `cli` feature flag for `clap` integration.
|
||||||
|
@ -320,21 +414,39 @@ You'll also need to edit your `.cargo/config.toml` to use `tokio_unstable` as we
|
||||||
rustflags=["--cfg", "tokio_unstable"]
|
rustflags=["--cfg", "tokio_unstable"]
|
||||||
```
|
```
|
||||||
|
|
||||||
Then it's possible to review the [documentation](https://docs.rs/lix-installer/latest/lix_installer/):
|
Then it's possible to review the [documentation](https://docs.rs/nix-installer/latest/nix_installer/):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cargo doc --open -p lix-installer
|
cargo doc --open -p nix-installer
|
||||||
|
```
|
||||||
|
|
||||||
|
Documentation is also available via `nix` build:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix build github:DeterminateSystems/nix-installer#nix-installer.doc
|
||||||
|
firefox result-doc/nix-installer/index.html
|
||||||
```
|
```
|
||||||
|
|
||||||
## Accessing other versions
|
## Accessing other versions
|
||||||
|
|
||||||
Each installer version has an [associated supported nix version](src/settings.rs) -- if you pin the installer version, you'll also indirectly pin to the associated nix version.
|
For users who desire version pinning, the version of `nix-installer` to use can be specified in the `curl` command:
|
||||||
|
|
||||||
You can also override the `nix` version via `--nix-package-url` or `NIX_INSTALLER_NIX_PACKAGE_URL=` but doing so is not recommended since we haven't tested that combination.
|
```bash
|
||||||
Here are some example `nix` package URLs including nix version, OS and architecture:
|
VERSION="v0.6.0"
|
||||||
|
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix/tag/${VERSION} | sh -s -- install
|
||||||
|
```
|
||||||
|
|
||||||
|
To discover which versions are available, or download the binaries for any release, check the [Github Releases](https://github.com/DeterminateSystems/nix-installer/releases).
|
||||||
|
|
||||||
|
These releases can be downloaded and used directly:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
VERSION="v0.6.0"
|
||||||
|
ARCH="aarch64-linux"
|
||||||
|
curl -sSf -L https://github.com/DeterminateSystems/nix-installer/releases/download/${VERSION}/nix-installer-${ARCH} -o nix-installer
|
||||||
|
./nix-installer install
|
||||||
|
```
|
||||||
|
|
||||||
* https://releases.nixos.org/nix/nix-2.18.1/nix-2.18.1-x86_64-linux.tar.xz
|
|
||||||
* https://releases.nixos.org/nix/nix-2.18.1/nix-2.18.1-aarch64-darwin.tar.xz
|
|
||||||
|
|
||||||
## Installation Differences
|
## Installation Differences
|
||||||
|
|
||||||
|
@ -345,13 +457,58 @@ Differing from the upstream [Nix](https://github.com/NixOS/nix) installer script
|
||||||
+ `bash-prompt-prefix` is set
|
+ `bash-prompt-prefix` is set
|
||||||
+ `auto-optimise-store` is set to `true` (On Linux only)
|
+ `auto-optimise-store` is set to `true` (On Linux only)
|
||||||
* `extra-nix-path` is set to `nixpkgs=flake:nixpkgs`
|
* `extra-nix-path` is set to `nixpkgs=flake:nixpkgs`
|
||||||
* `max-jobs` is set to `auto`
|
* an installation receipt (for uninstalling) is stored at `/nix/receipt.json` as well as a copy of the install binary at `/nix/nix-installer`
|
||||||
* an installation receipt (for uninstalling) is stored at `/nix/receipt.json` as well as a copy of the install binary at `/nix/lix-installer`
|
|
||||||
* `nix-channel --update` is not run, `~/.nix-channels` is not provisioned
|
* `nix-channel --update` is not run, `~/.nix-channels` is not provisioned
|
||||||
* `ssl-cert-file` is set in `/etc/nix/nix.conf` if the `ssl-cert-file` argument is used.
|
* `ssl-cert-file` is set in `/etc/nix/nix.conf` if the `ssl-cert-file` argument is used.
|
||||||
|
|
||||||
|
## Motivations
|
||||||
|
|
||||||
## No Telemetry Included
|
The existing upstream scripts do a good job, however they are difficult to maintain.
|
||||||
|
|
||||||
The Lix installer respects user privacy, and thus collects no information.
|
Subtle differences in the shell implementations and tool used in the scripts make it difficult to make meaningful changes to the installer.
|
||||||
|
|
||||||
|
The Determinate Nix installer has numerous advantages:
|
||||||
|
|
||||||
|
* keeping an installation receipt for easy uninstallation
|
||||||
|
* offering users a chance to review an accurate, calculated install plan
|
||||||
|
* having 'planners' which can create appropriate install plans for complicated targets
|
||||||
|
* offering users with a failing install the chance to do a best-effort revert
|
||||||
|
* improving performance by maximizing parallel operations
|
||||||
|
* supporting a expanded test suite including 'curing' cases
|
||||||
|
* supporting SELinux and OSTree based distributions without asking users to make compromises
|
||||||
|
* operating as a single, static binary with external dependencies such as `openssl`, only calling existing system tools (like `useradd`) where necessary
|
||||||
|
|
||||||
|
It has been wonderful to collaborate with other participants in the Nix Installer Working Group and members of the broader community. The working group maintains a [foundation owned fork of the installer](https://github.com/nixos/experimental-nix-installer/).
|
||||||
|
|
||||||
|
|
||||||
|
## Diagnostics
|
||||||
|
|
||||||
|
The goal of the Determinate Nix Installer is to successfully and correctly install Nix.
|
||||||
|
The `curl | sh` pipeline and the installer collects a little bit of diagnostic information to help us make that true.
|
||||||
|
|
||||||
|
Here is a table of the [diagnostic data we collect][diagnosticdata]:
|
||||||
|
|
||||||
|
| Field | Use |
|
||||||
|
| --------------------- | ----------------------------------------------------------------------------------------------------- |
|
||||||
|
| `version` | The version of the Determinate Nix Installer. |
|
||||||
|
| `planner` | The method of installing Nix (`linux`, `macos`, `steam-deck`) |
|
||||||
|
| `configured_settings` | The names of planner settings which were changed from their default. Does _not_ include the values. |
|
||||||
|
| `os_name` | The running operating system. |
|
||||||
|
| `os_version` | The version of the operating system. |
|
||||||
|
| `triple` | The architecture/operating system/binary format of your system. |
|
||||||
|
| `is_ci` | Whether the installer is being used in CI (e.g. GitHub Actions). |
|
||||||
|
| `action` | Either `Install` or `Uninstall`. |
|
||||||
|
| `status` | One of `Success`, `Failure`, `Pending`, or `Cancelled`. |
|
||||||
|
| `attribution` | Optionally defined by the user, associate the diagnostics of this run to the provided value. |
|
||||||
|
| `failure_chain` | A high level description of what the failure was, if any. For example: `Command("diskutil")` if the command `diskutil list` failed. |
|
||||||
|
|
||||||
|
To disable diagnostic reporting, set the diagnostics URL to an empty string by passing `--diagnostic-endpoint=""` or setting `NIX_INSTALLER_DIAGNOSTIC_ENDPOINT=""`.
|
||||||
|
|
||||||
|
You can read the full privacy policy for [Determinate Systems][detsys], the creators of the Determinate Nix Installer, [here][privacy].
|
||||||
|
|
||||||
|
[detsys]: https://determinate.systems/
|
||||||
|
[diagnosticdata]: https://github.com/DeterminateSystems/nix-installer/blob/f9f927840d532b71f41670382a30cfcbea2d8a35/src/diagnostics.rs#L29-L43
|
||||||
|
[privacy]: https://determinate.systems/privacy
|
||||||
|
[systemd]: https://systemd.io
|
||||||
|
[wslg]: https://github.com/microsoft/wslg
|
||||||
|
[nixgl]: https://github.com/guibou/nixGL
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
#! /usr/bin/env nix-shell
|
|
||||||
#! nix-shell -i xonsh -p xonsh rustup cargo-zigbuild zig
|
|
||||||
#
|
|
||||||
# vim: ts=4 sw=4 et
|
|
||||||
#
|
|
||||||
# If the shebang line above was necessary, you probably should have used
|
|
||||||
# the flake, instead. But that's okay! You're valid. <3
|
|
||||||
#
|
|
||||||
""" Lix installer generation script.
|
|
||||||
|
|
||||||
This uses cargo-zigbuild to generate a cross-compiled variant for each platform,
|
|
||||||
and places the results in the `results` subdirectory of the current working dir.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import xonsh
|
|
||||||
import functools
|
|
||||||
|
|
||||||
# Ensure we fail if any of our subcommands do.
|
|
||||||
$RAISE_SUBPROC_ERROR=True
|
|
||||||
|
|
||||||
# Specify the platforms we want to build for.
|
|
||||||
TARGET_PLATFORMS = [
|
|
||||||
"aarch64-apple-darwin",
|
|
||||||
"x86_64-apple-darwin",
|
|
||||||
"x86_64-unknown-linux-musl",
|
|
||||||
"aarch64-unknown-linux-musl",
|
|
||||||
]
|
|
||||||
|
|
||||||
# Create an alias for printing to stderr.
|
|
||||||
printerr = functools.partial(print, file=sys.stderr)
|
|
||||||
|
|
||||||
# Platform helpers.
|
|
||||||
IS_MACOS = not (xonsh.tools.ON_LINUX or xonsh.tools.ON_WINDOWS)
|
|
||||||
|
|
||||||
# Until our flake ships this with osxcross, we'll have to run this on macOS.
|
|
||||||
if not IS_MACOS:
|
|
||||||
printerr("This currently must be run from macOS due to cross-compile wonk. Sorry :(.")
|
|
||||||
sys.exit(-1)
|
|
||||||
|
|
||||||
|
|
||||||
# Pre-flight check: ensure we have all the rustup platforms we need.
|
|
||||||
all_targets_present = True
|
|
||||||
for platform in TARGET_PLATFORMS:
|
|
||||||
if platform not in $(rustup target list --installed):
|
|
||||||
printerr(f"ERROR: You don't have a rustup toolchain for {platform}! Install it with `rustup target add {platform}`")
|
|
||||||
all_targets_present = False
|
|
||||||
|
|
||||||
if not all_targets_present:
|
|
||||||
printerr("Failing out; install the platforms above and retry.")
|
|
||||||
sys.exit(-2)
|
|
||||||
|
|
||||||
# Build for each of our platforms.
|
|
||||||
printerr("> Building any platforms that need updating.")
|
|
||||||
for platform in TARGET_PLATFORMS:
|
|
||||||
|
|
||||||
# Build...
|
|
||||||
printerr(f"> Building for target {platform}")
|
|
||||||
cargo zigbuild --quiet --release --target=@(platform)
|
|
||||||
|
|
||||||
# ... and copy the output to the "results" directory.
|
|
||||||
mkdir -p ./results
|
|
||||||
cp target/@(platform)/release/lix-installer ./results/lix-installer-@(platform)
|
|
99
enter-env.sh
Executable file
99
enter-env.sh
Executable file
|
@ -0,0 +1,99 @@
|
||||||
|
#!/usr/bin/env nix-shell
|
||||||
|
#!nix-shell -p vault awscli2 jq -i bash
|
||||||
|
# shellcheck shell=bash
|
||||||
|
|
||||||
|
set +x # don't leak secrets!
|
||||||
|
set -eu
|
||||||
|
umask 077
|
||||||
|
|
||||||
|
scriptroot=$(dirname "$(realpath "$0")")
|
||||||
|
scratch=$(mktemp -d -t tmp.XXXXXXXXXX)
|
||||||
|
|
||||||
|
vault token lookup &>/dev/null || {
|
||||||
|
echo "You're not logged in to vault! Exiting."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function finish {
|
||||||
|
set +e
|
||||||
|
rm -rf "$scratch"
|
||||||
|
if [ "${VAULT_EXIT_ACCESSOR:-}" != "" ]; then
|
||||||
|
if vault token lookup &>/dev/null; then
|
||||||
|
echo "--> Revoking my token..." >&2
|
||||||
|
vault token revoke -self
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
set -e
|
||||||
|
}
|
||||||
|
trap finish EXIT
|
||||||
|
|
||||||
|
assume_role() {
|
||||||
|
role=$1
|
||||||
|
echo "--> Assuming role: $role" >&2
|
||||||
|
vault_creds=$(vault token create \
|
||||||
|
-display-name="$role" \
|
||||||
|
-format=json \
|
||||||
|
-role "$role")
|
||||||
|
|
||||||
|
VAULT_EXIT_ACCESSOR=$(jq -r .auth.accessor <<<"$vault_creds")
|
||||||
|
export VAULT_TOKEN
|
||||||
|
VAULT_TOKEN=$(jq -r .auth.client_token <<<"$vault_creds")
|
||||||
|
}
|
||||||
|
|
||||||
|
function provision_aws_creds() {
|
||||||
|
url="$1"
|
||||||
|
local ok=
|
||||||
|
echo "--> Setting AWS variables: " >&2
|
||||||
|
echo " AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN" >&2
|
||||||
|
|
||||||
|
aws_creds=$(vault kv get -format=json "$url")
|
||||||
|
export AWS_ACCESS_KEY_ID
|
||||||
|
AWS_ACCESS_KEY_ID=$(jq -r .data.access_key <<<"$aws_creds")
|
||||||
|
export AWS_SECRET_ACCESS_KEY
|
||||||
|
AWS_SECRET_ACCESS_KEY=$(jq -r .data.secret_key <<<"$aws_creds")
|
||||||
|
export AWS_SESSION_TOKEN
|
||||||
|
AWS_SESSION_TOKEN=$(jq -r .data.security_token <<<"$aws_creds")
|
||||||
|
if [ -z "$AWS_SESSION_TOKEN" ] || [ "$AWS_SESSION_TOKEN" == "null" ]; then
|
||||||
|
unset AWS_SESSION_TOKEN
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "--> Preflight testing the AWS credentials..." >&2
|
||||||
|
for _ in {0..20}; do
|
||||||
|
if check_output=$(aws sts get-caller-identity 2>&1 >/dev/null); then
|
||||||
|
ok=1
|
||||||
|
break
|
||||||
|
else
|
||||||
|
echo -n "." >&2
|
||||||
|
sleep 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [[ -z "$ok" ]]; then
|
||||||
|
echo $'\nPreflight test failed:\n'"$check_output" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
unset aws_creds
|
||||||
|
}
|
||||||
|
|
||||||
|
assume_role "internalservices_nix_installer_developer"
|
||||||
|
provision_aws_creds "internalservices/aws/creds/nix_installer"
|
||||||
|
|
||||||
|
if [ "${1:-}" == "" ]; then
|
||||||
|
cat <<\BASH > "$scratch/bashrc"
|
||||||
|
expiration_ts=$(date +%s -d "$(vault token lookup -format=json | jq -r '.data.expire_time')")
|
||||||
|
vault_prompt() {
|
||||||
|
local remaining=$(( $expiration_ts - $(date '+%s')))
|
||||||
|
if [[ "$remaining" -lt 1 ]]; then
|
||||||
|
remaining=expired
|
||||||
|
printf '\n\e[01;33mtoken expired\e[m';
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
printf '\n\e[01;32mTTL:%ss\e[m' "$remaining"
|
||||||
|
}
|
||||||
|
PROMPT_COMMAND=vault_prompt
|
||||||
|
BASH
|
||||||
|
|
||||||
|
bash --init-file "$scratch/bashrc"
|
||||||
|
else
|
||||||
|
"$@"
|
||||||
|
fi
|
81
flake.lock
81
flake.lock
|
@ -8,22 +8,19 @@
|
||||||
"rust-analyzer-src": "rust-analyzer-src"
|
"rust-analyzer-src": "rust-analyzer-src"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1714890282,
|
"narHash": "sha256-0dZpggYjjmWEk+rGixiBHOHuQfLzEzNfrtjSig04s6Q=",
|
||||||
"narHash": "sha256-0dRK2ChvkhWrLM6H3d4r+rXP/UDxTJ6Vkdr22uGb1H0=",
|
"rev": "9ccae1754eec0341b640d5705302ac0923d22875",
|
||||||
"owner": "nix-community",
|
"revCount": 1618,
|
||||||
"repo": "fenix",
|
"type": "tarball",
|
||||||
"rev": "24d83329e95a3bc48cbe9f3cd23813c210a25ea6",
|
"url": "https://api.flakehub.com/f/pinned/nix-community/fenix/0.1.1618%2Brev-9ccae1754eec0341b640d5705302ac0923d22875/018aea4c-03c9-7734-95d5-b84cc8881e3d/source.tar.gz"
|
||||||
"type": "github"
|
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "nix-community",
|
"type": "tarball",
|
||||||
"repo": "fenix",
|
"url": "https://flakehub.com/f/nix-community/fenix/0.1.1584.tar.gz"
|
||||||
"type": "github"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flake-compat": {
|
"flake-compat": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1696426674,
|
|
||||||
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
||||||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||||
"revCount": 57,
|
"revCount": 57,
|
||||||
|
@ -51,19 +48,19 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"libgit2": {
|
"lowdown-src": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1697646580,
|
"lastModified": 1633514407,
|
||||||
"narHash": "sha256-oX4Z3S9WtJlwvj0uH9HlYcWv+x1hqp8mhXl7HsLu2f0=",
|
"narHash": "sha256-Dw32tiMjdK9t3ETl5fzGrutQTzh2rufgZV4A/BbxuD4=",
|
||||||
"owner": "libgit2",
|
"owner": "kristapsdz",
|
||||||
"repo": "libgit2",
|
"repo": "lowdown",
|
||||||
"rev": "45fd9ed7ae1a9b74b957ef4f337bc3c8b3df01b5",
|
"rev": "d2c2b44ff6c27b936ec27358a2653caaef8f73b8",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "libgit2",
|
"owner": "kristapsdz",
|
||||||
"repo": "libgit2",
|
"repo": "lowdown",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -74,11 +71,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1698420672,
|
"lastModified": 1694081375,
|
||||||
"narHash": "sha256-/TdeHMPRjjdJub7p7+w55vyABrsJlt5QkznPYy55vKA=",
|
"narHash": "sha256-vzJXOUnmkMCm3xw8yfPP5m8kypQ3BhAIRe4RRCWpzy8=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "naersk",
|
"repo": "naersk",
|
||||||
"rev": "aeb58d5e8faead8980a807c840232697982d47b9",
|
"rev": "3f976d822b7b37fc6fb8e6f157c2dd05e7e94e89",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -90,30 +87,29 @@
|
||||||
"nix": {
|
"nix": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-compat": "flake-compat_2",
|
"flake-compat": "flake-compat_2",
|
||||||
"libgit2": "libgit2",
|
"lowdown-src": "lowdown-src",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs",
|
||||||
"nixpkgs-regression": "nixpkgs-regression"
|
"nixpkgs-regression": "nixpkgs-regression"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1709808984,
|
"narHash": "sha256-WNmifcTsN9aG1ONkv+l2BC4sHZZxtNKy0keqBHXXQ7w=",
|
||||||
"narHash": "sha256-bfFe38BkoQws7om4gBtBWoNTLkt9piMXdLLoHYl+vBQ=",
|
"rev": "f5f4de6a550327b4b1a06123c2e450f1b92c73b6",
|
||||||
"rev": "f8170ce9f119e5e6724eb81ff1b5a2d4c0024000",
|
"revCount": 14900,
|
||||||
"revCount": 16143,
|
|
||||||
"type": "tarball",
|
"type": "tarball",
|
||||||
"url": "https://api.flakehub.com/f/pinned/NixOS/nix/2.20.5/018e199b-ae2c-703d-ab99-4c648be473b2/source.tar.gz"
|
"url": "https://api.flakehub.com/f/pinned/NixOS/nix/2.18.1/018af406-b173-7112-9c1c-82f5b645e9d3/source.tar.gz"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"type": "tarball",
|
"type": "tarball",
|
||||||
"url": "https://flakehub.com/f/NixOS/nix/%3D2.20.5.tar.gz"
|
"url": "https://flakehub.com/f/NixOS/nix/2.18.0.tar.gz"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1705033721,
|
"lastModified": 1695283060,
|
||||||
"narHash": "sha256-K5eJHmL1/kev6WuqyqqbS1cdNnSidIZ3jeqJ7GbrYnQ=",
|
"narHash": "sha256-CJz71xhCLlRkdFUSQEL0pIAAfcnWFXMzd9vXhPrnrEg=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "a1982c92d8980a0114372973cbdfe0a307f1bdea",
|
"rev": "31ed632c692e6a36cfc18083b88ece892f863ed4",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -141,18 +137,15 @@
|
||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1714763106,
|
"narHash": "sha256-9NJcFF9CEYPvHJ5ckE8kvINvI84SZZ87PvqMbH6pro0=",
|
||||||
"narHash": "sha256-DrDHo74uTycfpAF+/qxZAMlP/Cpe04BVioJb6fdI0YY=",
|
"rev": "5e4c2ada4fcd54b99d56d7bd62f384511a7e2593",
|
||||||
"owner": "NixOS",
|
"revCount": 534806,
|
||||||
"repo": "nixpkgs",
|
"type": "tarball",
|
||||||
"rev": "e9be42459999a253a9f92559b1f5b72e1b44c13d",
|
"url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.1.534806%2Brev-5e4c2ada4fcd54b99d56d7bd62f384511a7e2593/018b29e9-ae6d-72f2-993b-19cb9a64a3b5/source.tar.gz"
|
||||||
"type": "github"
|
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"type": "tarball",
|
||||||
"ref": "nixos-unstable",
|
"url": "https://flakehub.com/f/NixOS/nixpkgs/0.1.0.tar.gz"
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": {
|
"root": {
|
||||||
|
@ -167,11 +160,11 @@
|
||||||
"rust-analyzer-src": {
|
"rust-analyzer-src": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1706735270,
|
"lastModified": 1696050837,
|
||||||
"narHash": "sha256-IJk+UitcJsxzMQWm9pa1ZbJBriQ4ginXOlPyVq+Cu40=",
|
"narHash": "sha256-2K3Aq4gjPZBDnkAMJaMA4ElE+BNbmrqtSBWtt9kPGaM=",
|
||||||
"owner": "rust-lang",
|
"owner": "rust-lang",
|
||||||
"repo": "rust-analyzer",
|
"repo": "rust-analyzer",
|
||||||
"rev": "42cb1a2bd79af321b0cc503d2960b73f34e2f92b",
|
"rev": "0840038f02daec6ba3238f05d8caa037d28701a0",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
50
flake.nix
50
flake.nix
|
@ -1,11 +1,11 @@
|
||||||
{
|
{
|
||||||
description = "The Lix Installer";
|
description = "The Determinate Nix Installer";
|
||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
nixpkgs.url = "https://flakehub.com/f/NixOS/nixpkgs/0.1.0.tar.gz";
|
||||||
|
|
||||||
fenix = {
|
fenix = {
|
||||||
url = "github:nix-community/fenix";
|
url = "https://flakehub.com/f/nix-community/fenix/0.1.1584.tar.gz";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
nix = {
|
nix = {
|
||||||
url = "https://flakehub.com/f/NixOS/nix/=2.20.5.tar.gz";
|
url = "https://flakehub.com/f/NixOS/nix/2.18.0.tar.gz";
|
||||||
# Omitting `inputs.nixpkgs.follows = "nixpkgs";` on purpose
|
# Omitting `inputs.nixpkgs.follows = "nixpkgs";` on purpose
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -65,10 +65,10 @@
|
||||||
rustc = toolchain;
|
rustc = toolchain;
|
||||||
};
|
};
|
||||||
sharedAttrs = {
|
sharedAttrs = {
|
||||||
pname = "lix-installer";
|
pname = "nix-installer";
|
||||||
version = "0.17.1";
|
version = "0.14.0";
|
||||||
src = builtins.path {
|
src = builtins.path {
|
||||||
name = "lix-installer-source";
|
name = "nix-installer-source";
|
||||||
path = self;
|
path = self;
|
||||||
filter = (path: type: baseNameOf path != "nix" && baseNameOf path != ".github");
|
filter = (path: type: baseNameOf path != "nix" && baseNameOf path != ".github");
|
||||||
};
|
};
|
||||||
|
@ -93,27 +93,27 @@
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
postInstall = ''
|
postInstall = ''
|
||||||
cp lix-installer.sh $out/bin/lix-installer.sh
|
cp nix-installer.sh $out/bin/nix-installer.sh
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
rec {
|
rec {
|
||||||
lix-installer = naerskLib.buildPackage sharedAttrs;
|
nix-installer = naerskLib.buildPackage sharedAttrs;
|
||||||
} // nixpkgs.lib.optionalAttrs (prev.stdenv.system == "x86_64-linux") rec {
|
} // nixpkgs.lib.optionalAttrs (prev.stdenv.system == "x86_64-linux") rec {
|
||||||
default = lix-installer-static;
|
default = nix-installer-static;
|
||||||
lix-installer-static = naerskLib.buildPackage
|
nix-installer-static = naerskLib.buildPackage
|
||||||
(sharedAttrs // {
|
(sharedAttrs // {
|
||||||
CARGO_BUILD_TARGET = "x86_64-unknown-linux-musl";
|
CARGO_BUILD_TARGET = "x86_64-unknown-linux-musl";
|
||||||
});
|
});
|
||||||
} // nixpkgs.lib.optionalAttrs (prev.stdenv.system == "i686-linux") rec {
|
} // nixpkgs.lib.optionalAttrs (prev.stdenv.system == "i686-linux") rec {
|
||||||
default = lix-installer-static;
|
default = nix-installer-static;
|
||||||
lix-installer-static = naerskLib.buildPackage
|
nix-installer-static = naerskLib.buildPackage
|
||||||
(sharedAttrs // {
|
(sharedAttrs // {
|
||||||
CARGO_BUILD_TARGET = "i686-unknown-linux-musl";
|
CARGO_BUILD_TARGET = "i686-unknown-linux-musl";
|
||||||
});
|
});
|
||||||
} // nixpkgs.lib.optionalAttrs (prev.stdenv.system == "aarch64-linux") rec {
|
} // nixpkgs.lib.optionalAttrs (prev.stdenv.system == "aarch64-linux") rec {
|
||||||
default = lix-installer-static;
|
default = nix-installer-static;
|
||||||
lix-installer-static = naerskLib.buildPackage
|
nix-installer-static = naerskLib.buildPackage
|
||||||
(sharedAttrs // {
|
(sharedAttrs // {
|
||||||
CARGO_BUILD_TARGET = "aarch64-unknown-linux-musl";
|
CARGO_BUILD_TARGET = "aarch64-unknown-linux-musl";
|
||||||
});
|
});
|
||||||
|
@ -133,13 +133,9 @@
|
||||||
|
|
||||||
nativeBuildInputs = with pkgs; [ ];
|
nativeBuildInputs = with pkgs; [ ];
|
||||||
buildInputs = with pkgs; [
|
buildInputs = with pkgs; [
|
||||||
zig
|
|
||||||
xonsh
|
|
||||||
awscli2
|
|
||||||
toolchain
|
toolchain
|
||||||
rust-analyzer
|
rust-analyzer
|
||||||
cargo-outdated
|
cargo-outdated
|
||||||
cargo-zigbuild
|
|
||||||
cacert
|
cacert
|
||||||
cargo-audit
|
cargo-audit
|
||||||
cargo-watch
|
cargo-watch
|
||||||
|
@ -194,18 +190,18 @@
|
||||||
|
|
||||||
packages = forAllSystems ({ system, pkgs, ... }:
|
packages = forAllSystems ({ system, pkgs, ... }:
|
||||||
{
|
{
|
||||||
inherit (pkgs) lix-installer;
|
inherit (pkgs) nix-installer;
|
||||||
} // nixpkgs.lib.optionalAttrs (system == "x86_64-linux") {
|
} // nixpkgs.lib.optionalAttrs (system == "x86_64-linux") {
|
||||||
inherit (pkgs) lix-installer-static;
|
inherit (pkgs) nix-installer-static;
|
||||||
default = pkgs.lix-installer-static;
|
default = pkgs.nix-installer-static;
|
||||||
} // nixpkgs.lib.optionalAttrs (system == "i686-linux") {
|
} // nixpkgs.lib.optionalAttrs (system == "i686-linux") {
|
||||||
inherit (pkgs) lix-installer-static;
|
inherit (pkgs) nix-installer-static;
|
||||||
default = pkgs.lix-installer-static;
|
default = pkgs.nix-installer-static;
|
||||||
} // nixpkgs.lib.optionalAttrs (system == "aarch64-linux") {
|
} // nixpkgs.lib.optionalAttrs (system == "aarch64-linux") {
|
||||||
inherit (pkgs) lix-installer-static;
|
inherit (pkgs) nix-installer-static;
|
||||||
default = pkgs.lix-installer-static;
|
default = pkgs.nix-installer-static;
|
||||||
} // nixpkgs.lib.optionalAttrs (pkgs.stdenv.isDarwin) {
|
} // nixpkgs.lib.optionalAttrs (pkgs.stdenv.isDarwin) {
|
||||||
default = pkgs.lix-installer;
|
default = pkgs.nix-installer;
|
||||||
});
|
});
|
||||||
|
|
||||||
hydraJobs = {
|
hydraJobs = {
|
||||||
|
|
|
@ -2,22 +2,22 @@
|
||||||
# shellcheck shell=dash
|
# shellcheck shell=dash
|
||||||
|
|
||||||
# If you need an offline install, or you'd prefer to run the binary directly, head to
|
# If you need an offline install, or you'd prefer to run the binary directly, head to
|
||||||
# https://git.lix.systems/lix-project/lix-installer/releases then pick the version and platform
|
# https://github.com/DeterminateSystems/nix-installer/releases then pick the version and platform
|
||||||
# most appropriate for your deployment target.
|
# most appropriate for your deployment target.
|
||||||
#
|
#
|
||||||
# This is just a little script that selects and downloads the right `lix-installer`. It does
|
# This is just a little script that selects and downloads the right `nix-installer`. It does
|
||||||
# platform detection, downloads the installer, and runs it; that's it.
|
# platform detection, downloads the installer, and runs it; that's it.
|
||||||
#
|
#
|
||||||
# It runs on Unix shells like {a,ba,da,k,z}sh. It uses the common `local`
|
# It runs on Unix shells like {a,ba,da,k,z}sh. It uses the common `local`
|
||||||
# extension. Note: Most shells limit `local` to 1 var per line, contra bash.
|
# extension. Note: Most shells limit `local` to 1 var per line, contra bash.
|
||||||
|
|
||||||
# This script is based off https://github.com/rust-lang/rustup/blob/f8d7b3baba7a63237cb2b82ef49a68a37dd0633c/rustup-init.sh
|
# This script is based off https://github.com/rust-lang/rustup/blob/8f6b53628ad996ad86f9c6225fa500cddf860905/rustup-init.sh
|
||||||
|
|
||||||
if [ "$KSH_VERSION" = 'Version JM 93t+ 2010-03-05' ]; then
|
if [ "$KSH_VERSION" = 'Version JM 93t+ 2010-03-05' ]; then
|
||||||
# The version of ksh93 that ships with many illumos systems does not
|
# The version of ksh93 that ships with many illumos systems does not
|
||||||
# support the "local" extension. Print a message rather than fail in
|
# support the "local" extension. Print a message rather than fail in
|
||||||
# subtle ways later on:
|
# subtle ways later on:
|
||||||
echo 'lix-installer does not work with this ksh93 version; please try bash!' >&2
|
echo 'nix-installer does not work with this ksh93 version; please try bash!' >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ fi
|
||||||
set -u
|
set -u
|
||||||
|
|
||||||
# If NIX_INSTALLER_FORCE_ALLOW_HTTP is unset or empty, default it.
|
# If NIX_INSTALLER_FORCE_ALLOW_HTTP is unset or empty, default it.
|
||||||
NIX_INSTALLER_BINARY_ROOT="${NIX_INSTALLER_BINARY_ROOT:-https://install.lix.systems/lix}"
|
NIX_INSTALLER_BINARY_ROOT="${NIX_INSTALLER_BINARY_ROOT:-https://install.determinate.systems/nix}"
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
downloader --check
|
downloader --check
|
||||||
|
@ -47,7 +47,7 @@ main() {
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
local _url="${NIX_INSTALLER_OVERRIDE_URL-${NIX_INSTALLER_BINARY_ROOT}/lix-installer-${_arch}${_ext}}"
|
local _url="${NIX_INSTALLER_OVERRIDE_URL-${NIX_INSTALLER_BINARY_ROOT}/nix-installer-${_arch}${_ext}}"
|
||||||
|
|
||||||
local _dir
|
local _dir
|
||||||
if ! _dir="$(ensure mktemp -d)"; then
|
if ! _dir="$(ensure mktemp -d)"; then
|
||||||
|
@ -55,7 +55,7 @@ main() {
|
||||||
# propagate exit status.
|
# propagate exit status.
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
local _file="${_dir}/lix-installer${_ext}"
|
local _file="${_dir}/nix-installer${_ext}"
|
||||||
|
|
||||||
local _ansi_escapes_are_valid=false
|
local _ansi_escapes_are_valid=false
|
||||||
if [ -t 2 ]; then
|
if [ -t 2 ]; then
|
||||||
|
@ -95,7 +95,7 @@ main() {
|
||||||
ensure chmod u+x "$_file"
|
ensure chmod u+x "$_file"
|
||||||
if [ ! -x "$_file" ]; then
|
if [ ! -x "$_file" ]; then
|
||||||
printf '%s\n' "Cannot execute $_file (likely because of mounting /tmp as noexec)." 1>&2
|
printf '%s\n' "Cannot execute $_file (likely because of mounting /tmp as noexec)." 1>&2
|
||||||
printf '%s\n' "Please copy the file to a location where you can execute binaries and run ./lix-installer${_ext}." 1>&2
|
printf '%s\n' "Please copy the file to a location where you can execute binaries and run ./nix-installer${_ext}." 1>&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -143,30 +143,10 @@ get_architecture() {
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$_ostype" = Darwin ]; then
|
if [ "$_ostype" = Darwin ] && [ "$_cputype" = i386 ]; then
|
||||||
# Darwin `uname -m` can lie due to Rosetta shenanigans. If you manage to
|
# Darwin `uname -m` lies
|
||||||
# invoke a native shell binary and then a native uname binary, you can
|
if sysctl hw.optional.x86_64 | grep -q ': 1'; then
|
||||||
# get the real answer, but that's hard to ensure, so instead we use
|
_cputype=x86_64
|
||||||
# `sysctl` (which doesn't lie) to check for the actual architecture.
|
|
||||||
if [ "$_cputype" = i386 ]; then
|
|
||||||
# Handling i386 compatibility mode in older macOS versions (<10.15)
|
|
||||||
# running on x86_64-based Macs.
|
|
||||||
# Starting from 10.15, macOS explicitly bans all i386 binaries from running.
|
|
||||||
# See: <https://support.apple.com/en-us/HT208436>
|
|
||||||
|
|
||||||
# Avoid `sysctl: unknown oid` stderr output and/or non-zero exit code.
|
|
||||||
if sysctl hw.optional.x86_64 2> /dev/null || true | grep -q ': 1'; then
|
|
||||||
_cputype=x86_64
|
|
||||||
fi
|
|
||||||
elif [ "$_cputype" = x86_64 ]; then
|
|
||||||
# Handling x86-64 compatibility mode (a.k.a. Rosetta 2)
|
|
||||||
# in newer macOS versions (>=11) running on arm64-based Macs.
|
|
||||||
# Rosetta 2 is built exclusively for x86-64 and cannot run i386 binaries.
|
|
||||||
|
|
||||||
# Avoid `sysctl: unknown oid` stderr output and/or non-zero exit code.
|
|
||||||
if sysctl hw.optional.arm64 2> /dev/null || true | grep -q ': 1'; then
|
|
||||||
_cputype=arm64
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -229,7 +209,7 @@ get_architecture() {
|
||||||
}
|
}
|
||||||
|
|
||||||
say() {
|
say() {
|
||||||
printf 'lix-installer: %s\n' "$1"
|
printf 'nix-installer: %s\n' "$1"
|
||||||
}
|
}
|
||||||
|
|
||||||
err() {
|
err() {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
FROM default
|
FROM default
|
||||||
COPY lix-installer /lix-installer
|
COPY nix-installer /nix-installer
|
||||||
RUN chmod +x /lix-installer
|
RUN chmod +x /nix-installer
|
||||||
COPY binary-tarball /binary-tarball
|
COPY binary-tarball /binary-tarball
|
||||||
RUN mv /binary-tarball/nix-*.tar.xz nix.tar.xz
|
RUN mv /binary-tarball/nix-*.tar.xz nix.tar.xz
|
||||||
RUN /nix-installer/bin/lix-installer install linux --logger pretty --log-directive nix_installer=debug --nix-package-url file:///nix.tar.xz --init none --extra-conf "sandbox = false" --no-confirm -vvv
|
RUN /nix-installer/bin/nix-installer install linux --logger pretty --log-directive nix_installer=debug --nix-package-url file:///nix.tar.xz --init none --extra-conf "sandbox = false" --no-confirm -vvv
|
||||||
ENV PATH="${PATH}:/nix/var/nix/profiles/default/bin"
|
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"]; }'
|
RUN nix-build --no-substitute -E 'derivation { name = "foo"; system = "x86_64-linux"; builder = "/bin/sh"; args = ["-c" "echo foobar > $out"]; }'
|
||||||
RUN /nix/lix-installer uninstall --no-confirm
|
RUN /nix/nix-installer uninstall --no-confirm
|
|
@ -37,7 +37,7 @@ impl CreateGroup {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure group does not exist
|
// Ensure group does not exists
|
||||||
if let Some(group) = Group::from_name(name.as_str())
|
if let Some(group) = Group::from_name(name.as_str())
|
||||||
.map_err(|e| ActionErrorKind::GettingGroupId(name.clone(), e))
|
.map_err(|e| ActionErrorKind::GettingGroupId(name.clone(), e))
|
||||||
.map_err(Self::error)?
|
.map_err(Self::error)?
|
||||||
|
|
|
@ -17,7 +17,7 @@ use crate::action::{
|
||||||
|
|
||||||
/// The `nix.conf` configuration names that are safe to merge.
|
/// The `nix.conf` configuration names that are safe to merge.
|
||||||
// FIXME(@cole-h): make configurable by downstream users?
|
// FIXME(@cole-h): make configurable by downstream users?
|
||||||
const MERGEABLE_CONF_NAMES: &[&str] = &["experimental-features", "substituters", "trusted-public-keys"];
|
const MERGEABLE_CONF_NAMES: &[&str] = &["experimental-features"];
|
||||||
const NIX_CONF_MODE: u32 = 0o664;
|
const NIX_CONF_MODE: u32 = 0o664;
|
||||||
const NIX_CONF_COMMENT_CHAR: char = '#';
|
const NIX_CONF_COMMENT_CHAR: char = '#';
|
||||||
|
|
||||||
|
@ -369,7 +369,7 @@ impl Action for CreateOrMergeNixConfig {
|
||||||
new_config.push_str(name);
|
new_config.push_str(name);
|
||||||
new_config.push_str(" = ");
|
new_config.push_str(" = ");
|
||||||
|
|
||||||
if let Some(merged_value) = merged_nix_config.settings_mut().swap_remove(name) {
|
if let Some(merged_value) = merged_nix_config.settings_mut().remove(name) {
|
||||||
new_config.push_str(&merged_value);
|
new_config.push_str(&merged_value);
|
||||||
new_config.push(' ');
|
new_config.push(' ');
|
||||||
} else {
|
} else {
|
||||||
|
@ -390,7 +390,7 @@ impl Action for CreateOrMergeNixConfig {
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(to_remove) = to_remove {
|
if let Some(to_remove) = to_remove {
|
||||||
existing_nix_config.settings_mut().swap_remove(&to_remove);
|
existing_nix_config.settings_mut().remove(&to_remove);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -409,10 +409,13 @@ impl Action for CreateOrMergeNixConfig {
|
||||||
new_config.push('\n');
|
new_config.push('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
new_config
|
new_config.push_str(
|
||||||
.push_str("# Generated by https://install.lix.systems/.\n");
|
&[
|
||||||
new_config.push_str("# See `/nix/nix-installer --version` for the version details.\n");
|
"# Generated by https://github.com/DeterminateSystems/nix-installer.",
|
||||||
new_config.push('\n');
|
"# See `/nix/nix-installer --version` for the version details.",
|
||||||
|
]
|
||||||
|
.join("\n"),
|
||||||
|
);
|
||||||
|
|
||||||
for (name, value) in merged_nix_config.settings() {
|
for (name, value) in merged_nix_config.settings() {
|
||||||
new_config.push_str(name);
|
new_config.push_str(name);
|
||||||
|
|
|
@ -237,7 +237,6 @@ impl Action for CreateUser {
|
||||||
.args([
|
.args([
|
||||||
"--home",
|
"--home",
|
||||||
"/var/empty",
|
"/var/empty",
|
||||||
"-H", // Don't create a home.
|
|
||||||
"--gecos",
|
"--gecos",
|
||||||
comment,
|
comment,
|
||||||
"--ingroup",
|
"--ingroup",
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use std::{
|
use std::{
|
||||||
|
fs::Permissions,
|
||||||
os::unix::prelude::PermissionsExt,
|
os::unix::prelude::PermissionsExt,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
@ -109,21 +110,13 @@ impl Action for MoveUnpackedNix {
|
||||||
.map_err(|e| ActionErrorKind::Rename(entry.path(), entry_dest.to_owned(), e))
|
.map_err(|e| ActionErrorKind::Rename(entry.path(), entry_dest.to_owned(), e))
|
||||||
.map_err(Self::error)?;
|
.map_err(Self::error)?;
|
||||||
|
|
||||||
|
let perms: Permissions = PermissionsExt::from_mode(0o555);
|
||||||
for entry_item in WalkDir::new(&entry_dest)
|
for entry_item in WalkDir::new(&entry_dest)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(Result::ok)
|
.filter_map(Result::ok)
|
||||||
.filter(|e| !e.file_type().is_symlink())
|
.filter(|e| !e.file_type().is_symlink())
|
||||||
{
|
{
|
||||||
let path = entry_item.path();
|
tokio::fs::set_permissions(&entry_item.path(), perms.clone())
|
||||||
|
|
||||||
let mut perms = path
|
|
||||||
.metadata()
|
|
||||||
.map_err(|e| ActionErrorKind::GetMetadata(path.to_owned(), e))
|
|
||||||
.map_err(Self::error)?
|
|
||||||
.permissions();
|
|
||||||
perms.set_readonly(true);
|
|
||||||
|
|
||||||
tokio::fs::set_permissions(path, perms.clone())
|
|
||||||
.await
|
.await
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
ActionErrorKind::SetPermissions(
|
ActionErrorKind::SetPermissions(
|
||||||
|
|
|
@ -79,14 +79,10 @@ impl ConfigureInitService {
|
||||||
},
|
},
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
InitSystem::Systemd => {
|
InitSystem::Systemd => {
|
||||||
// If `no_start_daemon` is set, then we don't require a running systemd,
|
// If /run/systemd/system exists, we can be reasonably sure the machine is booted
|
||||||
// so we don't need to check if `/run/systemd/system` exists.
|
// with systemd: https://www.freedesktop.org/software/systemd/man/sd_booted.html
|
||||||
if start_daemon {
|
if !Path::new("/run/systemd/system").exists() {
|
||||||
// If /run/systemd/system exists, we can be reasonably sure the machine is booted
|
return Err(Self::error(ActionErrorKind::SystemdMissing));
|
||||||
// with systemd: https://www.freedesktop.org/software/systemd/man/sd_booted.html
|
|
||||||
if !Path::new("/run/systemd/system").exists() {
|
|
||||||
return Err(Self::error(ActionErrorKind::SystemdMissing));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if which::which("systemctl").is_err() {
|
if which::which("systemctl").is_err() {
|
||||||
|
@ -173,7 +169,7 @@ impl Action for ConfigureInitService {
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
InitSystem::Launchd => {
|
InitSystem::Launchd => {
|
||||||
let src = std::path::Path::new(DARWIN_NIX_DAEMON_SOURCE);
|
let src = std::path::Path::new(DARWIN_NIX_DAEMON_SOURCE);
|
||||||
tokio::fs::copy(src, DARWIN_NIX_DAEMON_DEST)
|
tokio::fs::copy(src.clone(), DARWIN_NIX_DAEMON_DEST)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
Self::error(ActionErrorKind::Copy(
|
Self::error(ActionErrorKind::Copy(
|
||||||
|
|
|
@ -46,7 +46,6 @@ impl ConfigureNix {
|
||||||
settings.proxy.clone(),
|
settings.proxy.clone(),
|
||||||
settings.ssl_cert_file.clone(),
|
settings.ssl_cert_file.clone(),
|
||||||
settings.extra_conf.clone(),
|
settings.extra_conf.clone(),
|
||||||
settings.enable_flakes,
|
|
||||||
settings.force,
|
settings.force,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
|
|
@ -44,29 +44,25 @@ impl ConfigureShellProfile {
|
||||||
for profile_target in locations.bash.iter().chain(locations.zsh.iter()) {
|
for profile_target in locations.bash.iter().chain(locations.zsh.iter()) {
|
||||||
let profile_target_path = Path::new(profile_target);
|
let profile_target_path = Path::new(profile_target);
|
||||||
if let Some(parent) = profile_target_path.parent() {
|
if let Some(parent) = profile_target_path.parent() {
|
||||||
// Some tools (eg `nix-darwin`) create symlinks to these files, don't write to them if that's the case.
|
if !parent.exists() {
|
||||||
if !profile_target_path.is_symlink() {
|
create_directories.push(
|
||||||
if !parent.exists() {
|
CreateDirectory::plan(parent, None, None, 0o0755, false)
|
||||||
create_directories.push(
|
.await
|
||||||
CreateDirectory::plan(parent, None, None, 0o0755, false)
|
.map_err(Self::error)?,
|
||||||
.await
|
|
||||||
.map_err(Self::error)?,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
create_or_insert_files.push(
|
|
||||||
CreateOrInsertIntoFile::plan(
|
|
||||||
profile_target_path,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
0o644,
|
|
||||||
shell_buf.to_string(),
|
|
||||||
create_or_insert_into_file::Position::Beginning,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.map_err(Self::error)?,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
create_or_insert_files.push(
|
||||||
|
CreateOrInsertIntoFile::plan(
|
||||||
|
profile_target_path,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
0o644,
|
||||||
|
shell_buf.to_string(),
|
||||||
|
create_or_insert_into_file::Position::Beginning,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(Self::error)?,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,27 +88,23 @@ impl ConfigureShellProfile {
|
||||||
let mut profile_target = fish_prefix_path;
|
let mut profile_target = fish_prefix_path;
|
||||||
profile_target.push(locations.fish.confd_suffix.clone());
|
profile_target.push(locations.fish.confd_suffix.clone());
|
||||||
|
|
||||||
// Some tools (eg `nix-darwin`) create symlinks to these files, don't write to them if that's the case.
|
if let Some(conf_d) = profile_target.parent() {
|
||||||
if !profile_target.is_symlink() {
|
create_directories.push(
|
||||||
if let Some(conf_d) = profile_target.parent() {
|
CreateDirectory::plan(conf_d.to_path_buf(), None, None, 0o755, false).await?,
|
||||||
create_directories.push(
|
|
||||||
CreateDirectory::plan(conf_d.to_path_buf(), None, None, 0o755, false)
|
|
||||||
.await?,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
create_or_insert_files.push(
|
|
||||||
CreateOrInsertIntoFile::plan(
|
|
||||||
profile_target,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
0o644,
|
|
||||||
fish_buf.to_string(),
|
|
||||||
create_or_insert_into_file::Position::Beginning,
|
|
||||||
)
|
|
||||||
.await?,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
create_or_insert_files.push(
|
||||||
|
CreateOrInsertIntoFile::plan(
|
||||||
|
profile_target,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
0o644,
|
||||||
|
fish_buf.to_string(),
|
||||||
|
create_or_insert_into_file::Position::Beginning,
|
||||||
|
)
|
||||||
|
.await?,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
for fish_prefix in &locations.fish.vendor_confd_prefixes {
|
for fish_prefix in &locations.fish.vendor_confd_prefixes {
|
||||||
let fish_prefix_path = PathBuf::from(fish_prefix);
|
let fish_prefix_path = PathBuf::from(fish_prefix);
|
||||||
|
|
|
@ -77,7 +77,7 @@ impl Action for CreateUsersAndGroups {
|
||||||
} else {
|
} else {
|
||||||
format!(
|
format!(
|
||||||
"Create build users (UID {}-{}) and group (GID {})",
|
"Create build users (UID {}-{}) and group (GID {})",
|
||||||
self.nix_build_user_id_base + 1,
|
self.nix_build_user_id_base,
|
||||||
self.nix_build_user_id_base + self.nix_build_user_count,
|
self.nix_build_user_id_base + self.nix_build_user_count,
|
||||||
self.nix_build_group_id
|
self.nix_build_group_id
|
||||||
)
|
)
|
||||||
|
|
|
@ -30,7 +30,6 @@ impl PlaceNixConfiguration {
|
||||||
proxy: Option<Url>,
|
proxy: Option<Url>,
|
||||||
ssl_cert_file: Option<PathBuf>,
|
ssl_cert_file: Option<PathBuf>,
|
||||||
extra_conf: Vec<UrlOrPathOrString>,
|
extra_conf: Vec<UrlOrPathOrString>,
|
||||||
enable_flakes: bool,
|
|
||||||
force: bool,
|
force: bool,
|
||||||
) -> Result<StatefulAction<Self>, ActionError> {
|
) -> Result<StatefulAction<Self>, ActionError> {
|
||||||
let mut extra_conf_text = vec![];
|
let mut extra_conf_text = vec![];
|
||||||
|
@ -92,13 +91,7 @@ impl PlaceNixConfiguration {
|
||||||
let settings = nix_config.settings_mut();
|
let settings = nix_config.settings_mut();
|
||||||
|
|
||||||
settings.insert("build-users-group".to_string(), nix_build_group_name);
|
settings.insert("build-users-group".to_string(), nix_build_group_name);
|
||||||
let mut experimental_features = vec!["nix-command"];
|
let experimental_features = ["nix-command", "flakes", "repl-flake"];
|
||||||
|
|
||||||
// Enable flakes if desired.
|
|
||||||
if enable_flakes {
|
|
||||||
experimental_features.push("flakes");
|
|
||||||
}
|
|
||||||
|
|
||||||
match settings.entry("experimental-features".to_string()) {
|
match settings.entry("experimental-features".to_string()) {
|
||||||
Entry::Occupied(mut slot) => {
|
Entry::Occupied(mut slot) => {
|
||||||
let slot_mut = slot.get_mut();
|
let slot_mut = slot.get_mut();
|
||||||
|
@ -132,23 +125,10 @@ impl PlaceNixConfiguration {
|
||||||
ssl_cert_file_canonical.display().to_string(),
|
ssl_cert_file_canonical.display().to_string(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up our substituters.
|
|
||||||
settings.insert(
|
settings.insert(
|
||||||
"substituters".to_string(),
|
"extra-nix-path".to_string(),
|
||||||
"https://cache.nixos.org https://cache.lix.systems".to_string(),
|
"nixpkgs=flake:nixpkgs".to_string(),
|
||||||
);
|
);
|
||||||
settings.insert(
|
|
||||||
"trusted-public-keys".to_string(),
|
|
||||||
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= cache.lix.systems:aBnZUw8zA7H35Cz2RyKFVs3H4PlGTLawyY5KRbvJR8o=".to_string()
|
|
||||||
);
|
|
||||||
|
|
||||||
if enable_flakes {
|
|
||||||
settings.insert(
|
|
||||||
"extra-nix-path".to_string(),
|
|
||||||
"nixpkgs=flake:nixpkgs".to_string(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let create_directory = CreateDirectory::plan(NIX_CONF_FOLDER, None, None, 0o0755, force)
|
let create_directory = CreateDirectory::plan(NIX_CONF_FOLDER, None, None, 0o0755, force)
|
||||||
.await
|
.await
|
||||||
|
|
|
@ -1,112 +0,0 @@
|
||||||
use crate::action::base::{create_or_insert_into_file, CreateOrInsertIntoFile};
|
|
||||||
use crate::action::{Action, ActionDescription, ActionError, ActionTag, StatefulAction};
|
|
||||||
|
|
||||||
use std::path::Path;
|
|
||||||
use tracing::{span, Instrument, Span};
|
|
||||||
|
|
||||||
const PROFILE_NIX_FILE_SHELL: &str = "/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh";
|
|
||||||
|
|
||||||
/**
|
|
||||||
Configure macOS's zshenv to load the Nix environment when ForceCommand is used.
|
|
||||||
This enables remote building, which requires `ssh host nix` to work.
|
|
||||||
*/
|
|
||||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
|
||||||
pub struct ConfigureRemoteBuilding {
|
|
||||||
create_or_insert_into_file: Option<StatefulAction<CreateOrInsertIntoFile>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ConfigureRemoteBuilding {
|
|
||||||
#[tracing::instrument(level = "debug", skip_all)]
|
|
||||||
pub async fn plan() -> Result<StatefulAction<Self>, ActionError> {
|
|
||||||
let shell_buf = format!(
|
|
||||||
r#"
|
|
||||||
# Set up Nix only on SSH connections
|
|
||||||
# See: https://github.com/DeterminateSystems/nix-installer/pull/714
|
|
||||||
if [ -e '{PROFILE_NIX_FILE_SHELL}' ] && [ -n "${{SSH_CONNECTION}}" ] && [ "${{SHLVL}}" -eq 1 ]; then
|
|
||||||
. '{PROFILE_NIX_FILE_SHELL}'
|
|
||||||
fi
|
|
||||||
# End Nix
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
|
|
||||||
let zshenv = Path::new("/etc/zshenv");
|
|
||||||
|
|
||||||
let create_or_insert_into_file = if !zshenv.is_symlink() {
|
|
||||||
Some(
|
|
||||||
CreateOrInsertIntoFile::plan(
|
|
||||||
zshenv,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
0o644,
|
|
||||||
shell_buf.to_string(),
|
|
||||||
create_or_insert_into_file::Position::Beginning,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.map_err(Self::error)?,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
create_or_insert_into_file,
|
|
||||||
}
|
|
||||||
.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
#[typetag::serde(name = "configure_remote_building")]
|
|
||||||
impl Action for ConfigureRemoteBuilding {
|
|
||||||
fn action_tag() -> ActionTag {
|
|
||||||
ActionTag("configure_remote_building")
|
|
||||||
}
|
|
||||||
fn tracing_synopsis(&self) -> String {
|
|
||||||
"Configuring zsh to support using Nix in non-interactive shells".to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tracing_span(&self) -> Span {
|
|
||||||
span!(tracing::Level::DEBUG, "configure_remote_building",)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_description(&self) -> Vec<ActionDescription> {
|
|
||||||
vec![ActionDescription::new(
|
|
||||||
if self.create_or_insert_into_file.is_none() {
|
|
||||||
"Skipping configuring zsh to support using Nix in non-interactive shells, `/etc/zshenv` is a symlink".to_string()
|
|
||||||
} else {
|
|
||||||
self.tracing_synopsis()
|
|
||||||
},
|
|
||||||
vec!["Update `/etc/zshenv` to import Nix".to_string()],
|
|
||||||
)]
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip_all)]
|
|
||||||
async fn execute(&mut self) -> Result<(), ActionError> {
|
|
||||||
let span = tracing::Span::current().clone();
|
|
||||||
if let Some(create_or_insert_into_file) = &mut self.create_or_insert_into_file {
|
|
||||||
create_or_insert_into_file
|
|
||||||
.try_execute()
|
|
||||||
.instrument(span)
|
|
||||||
.await
|
|
||||||
.map_err(Self::error)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn revert_description(&self) -> Vec<ActionDescription> {
|
|
||||||
vec![ActionDescription::new(
|
|
||||||
"Remove the Nix configuration from zsh's non-login shells".to_string(),
|
|
||||||
vec!["Update `/etc/zshenv` to no longer import Nix".to_string()],
|
|
||||||
)]
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip_all)]
|
|
||||||
async fn revert(&mut self) -> Result<(), ActionError> {
|
|
||||||
if let Some(create_or_insert_into_file) = &mut self.create_or_insert_into_file {
|
|
||||||
create_or_insert_into_file.try_revert().await?
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -27,9 +27,9 @@ impl CreateNixHookService {
|
||||||
pub async fn plan() -> Result<StatefulAction<Self>, ActionError> {
|
pub async fn plan() -> Result<StatefulAction<Self>, ActionError> {
|
||||||
let mut this = Self {
|
let mut this = Self {
|
||||||
path: PathBuf::from(
|
path: PathBuf::from(
|
||||||
"/Library/LaunchDaemons/systems.lix.nix-installer.nix-hook.plist",
|
"/Library/LaunchDaemons/systems.determinate.nix-installer.nix-hook.plist",
|
||||||
),
|
),
|
||||||
service_label: "systems.lix.nix-installer.nix-hook".into(),
|
service_label: "systems.determinate.nix-installer.nix-hook".into(),
|
||||||
needs_bootout: false,
|
needs_bootout: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub(crate) mod bootstrap_launchctl_service;
|
pub(crate) mod bootstrap_launchctl_service;
|
||||||
pub(crate) mod configure_remote_building;
|
|
||||||
pub(crate) mod create_apfs_volume;
|
pub(crate) mod create_apfs_volume;
|
||||||
pub(crate) mod create_fstab_entry;
|
pub(crate) mod create_fstab_entry;
|
||||||
pub(crate) mod create_nix_hook_service;
|
pub(crate) mod create_nix_hook_service;
|
||||||
|
@ -17,7 +16,6 @@ pub(crate) mod set_tmutil_exclusions;
|
||||||
pub(crate) mod unmount_apfs_volume;
|
pub(crate) mod unmount_apfs_volume;
|
||||||
|
|
||||||
pub use bootstrap_launchctl_service::BootstrapLaunchctlService;
|
pub use bootstrap_launchctl_service::BootstrapLaunchctlService;
|
||||||
pub use configure_remote_building::ConfigureRemoteBuilding;
|
|
||||||
pub use create_apfs_volume::CreateApfsVolume;
|
pub use create_apfs_volume::CreateApfsVolume;
|
||||||
pub use create_nix_hook_service::CreateNixHookService;
|
pub use create_nix_hook_service::CreateNixHookService;
|
||||||
pub use create_nix_volume::{CreateNixVolume, NIX_VOLUME_MOUNTD_DEST};
|
pub use create_nix_volume::{CreateNixVolume, NIX_VOLUME_MOUNTD_DEST};
|
||||||
|
|
|
@ -24,7 +24,7 @@ You can manually plan, execute, then revert an [`Action`] like so:
|
||||||
|
|
||||||
```rust,no_run
|
```rust,no_run
|
||||||
# async fn wrapper() {
|
# async fn wrapper() {
|
||||||
use lix_installer::action::base::CreateDirectory;
|
use nix_installer::action::base::CreateDirectory;
|
||||||
let mut action = CreateDirectory::plan("/nix", None, None, 0o0755, true).await.unwrap();
|
let mut action = CreateDirectory::plan("/nix", None, None, 0o0755, true).await.unwrap();
|
||||||
action.try_execute().await.unwrap();
|
action.try_execute().await.unwrap();
|
||||||
action.try_revert().await.unwrap();
|
action.try_revert().await.unwrap();
|
||||||
|
@ -46,7 +46,7 @@ A custom [`Action`] can be created then used in a custom [`Planner`](crate::plan
|
||||||
```rust,no_run
|
```rust,no_run
|
||||||
use std::{error::Error, collections::HashMap};
|
use std::{error::Error, collections::HashMap};
|
||||||
use tracing::{Span, span};
|
use tracing::{Span, span};
|
||||||
use lix_installer::{
|
use nix_installer::{
|
||||||
InstallPlan,
|
InstallPlan,
|
||||||
settings::{CommonSettings, InstallSettingsError},
|
settings::{CommonSettings, InstallSettingsError},
|
||||||
planner::{Planner, PlannerError},
|
planner::{Planner, PlannerError},
|
||||||
|
@ -152,6 +152,20 @@ impl Planner for MyPlanner {
|
||||||
|
|
||||||
Ok(settings)
|
Ok(settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
async fn diagnostic_data(&self) -> Result<nix_installer::diagnostics::DiagnosticData, PlannerError> {
|
||||||
|
Ok(nix_installer::diagnostics::DiagnosticData::new(
|
||||||
|
self.common.diagnostic_attribution.clone(),
|
||||||
|
self.common.diagnostic_endpoint.clone(),
|
||||||
|
self.typetag_name().into(),
|
||||||
|
self.configured_settings()
|
||||||
|
.await?
|
||||||
|
.into_keys()
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
self.common.ssl_cert_file.clone(),
|
||||||
|
)?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# async fn custom_planner_install() -> color_eyre::Result<()> {
|
# async fn custom_planner_install() -> color_eyre::Result<()> {
|
||||||
|
@ -315,6 +329,12 @@ impl ActionError {
|
||||||
pub fn action_tag(&self) -> &ActionTag {
|
pub fn action_tag(&self) -> &ActionTag {
|
||||||
&self.action_tag
|
&self.action_tag
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
pub fn diagnostic(&self) -> String {
|
||||||
|
use crate::diagnostics::ErrorDiagnostic;
|
||||||
|
self.kind.diagnostic()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for ActionError {
|
impl std::fmt::Display for ActionError {
|
||||||
|
@ -402,8 +422,6 @@ pub enum ActionErrorKind {
|
||||||
std::path::PathBuf,
|
std::path::PathBuf,
|
||||||
#[source] std::io::Error,
|
#[source] std::io::Error,
|
||||||
),
|
),
|
||||||
#[error("Getting filesystem metadata for `{0}` on `{1}`")]
|
|
||||||
GetMetadata(std::path::PathBuf, #[source] std::io::Error),
|
|
||||||
#[error("Set mode `{0:#o}` on `{1}`")]
|
#[error("Set mode `{0:#o}` on `{1}`")]
|
||||||
SetPermissions(u32, std::path::PathBuf, #[source] std::io::Error),
|
SetPermissions(u32, std::path::PathBuf, #[source] std::io::Error),
|
||||||
#[error("Remove file `{0}`")]
|
#[error("Remove file `{0}`")]
|
||||||
|
@ -473,6 +491,8 @@ pub enum ActionErrorKind {
|
||||||
command = .command,
|
command = .command,
|
||||||
)]
|
)]
|
||||||
Command {
|
Command {
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
program: String,
|
||||||
command: String,
|
command: String,
|
||||||
#[source]
|
#[source]
|
||||||
error: std::io::Error,
|
error: std::io::Error,
|
||||||
|
@ -489,6 +509,8 @@ pub enum ActionErrorKind {
|
||||||
}
|
}
|
||||||
)]
|
)]
|
||||||
CommandOutput {
|
CommandOutput {
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
program: String,
|
||||||
command: String,
|
command: String,
|
||||||
output: Output,
|
output: Output,
|
||||||
},
|
},
|
||||||
|
@ -531,7 +553,7 @@ pub enum ActionErrorKind {
|
||||||
MissingRemoveUserFromGroupCommand,
|
MissingRemoveUserFromGroupCommand,
|
||||||
#[error("\
|
#[error("\
|
||||||
Could not detect systemd; you may be able to get up and running without systemd with `nix-installer install linux --init none`.\n\
|
Could not detect systemd; you may be able to get up and running without systemd with `nix-installer install linux --init none`.\n\
|
||||||
See https://git.lix.systems/lix-project/lix-installer#without-systemd-linux-only for documentation on usage and drawbacks.\
|
See https://github.com/DeterminateSystems/nix-installer#without-systemd-linux-only for documentation on usage and drawbacks.\
|
||||||
")]
|
")]
|
||||||
SystemdMissing,
|
SystemdMissing,
|
||||||
#[error("`{command}` failed, message: {message}")]
|
#[error("`{command}` failed, message: {message}")]
|
||||||
|
@ -551,12 +573,16 @@ pub enum ActionErrorKind {
|
||||||
impl ActionErrorKind {
|
impl ActionErrorKind {
|
||||||
pub fn command(command: &tokio::process::Command, error: std::io::Error) -> Self {
|
pub fn command(command: &tokio::process::Command, error: std::io::Error) -> Self {
|
||||||
Self::Command {
|
Self::Command {
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
program: command.as_std().get_program().to_string_lossy().into(),
|
||||||
command: format!("{:?}", command.as_std()),
|
command: format!("{:?}", command.as_std()),
|
||||||
error,
|
error,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn command_output(command: &tokio::process::Command, output: std::process::Output) -> Self {
|
pub fn command_output(command: &tokio::process::Command, output: std::process::Output) -> Self {
|
||||||
Self::CommandOutput {
|
Self::CommandOutput {
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
program: command.as_std().get_program().to_string_lossy().into(),
|
||||||
command: format!("{:?}", command.as_std()),
|
command: format!("{:?}", command.as_std()),
|
||||||
output,
|
output,
|
||||||
}
|
}
|
||||||
|
@ -574,3 +600,60 @@ impl HasExpectedErrors for ActionErrorKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
impl crate::diagnostics::ErrorDiagnostic for ActionErrorKind {
|
||||||
|
fn diagnostic(&self) -> String {
|
||||||
|
let static_str: &'static str = (self).into();
|
||||||
|
let context = match self {
|
||||||
|
Self::Child(child) => vec![child.diagnostic()],
|
||||||
|
Self::MultipleChildren(children) => {
|
||||||
|
children.iter().map(|child| child.diagnostic()).collect()
|
||||||
|
},
|
||||||
|
Self::Read(path, _)
|
||||||
|
| Self::Open(path, _)
|
||||||
|
| Self::Write(path, _)
|
||||||
|
| Self::Flush(path, _)
|
||||||
|
| Self::SetPermissions(_, path, _)
|
||||||
|
| Self::GettingMetadata(path, _)
|
||||||
|
| Self::CreateDirectory(path, _)
|
||||||
|
| Self::PathWasNotFile(path)
|
||||||
|
| Self::Remove(path, _) => {
|
||||||
|
vec![path.to_string_lossy().to_string()]
|
||||||
|
},
|
||||||
|
Self::Rename(first_path, second_path, _)
|
||||||
|
| Self::Copy(first_path, second_path, _)
|
||||||
|
| Self::Symlink(first_path, second_path, _) => {
|
||||||
|
vec![
|
||||||
|
first_path.to_string_lossy().to_string(),
|
||||||
|
second_path.to_string_lossy().to_string(),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
Self::NoGroup(name) | Self::NoUser(name) => {
|
||||||
|
vec![name.clone()]
|
||||||
|
},
|
||||||
|
Self::Command {
|
||||||
|
program,
|
||||||
|
command: _,
|
||||||
|
error: _,
|
||||||
|
}
|
||||||
|
| Self::CommandOutput {
|
||||||
|
program,
|
||||||
|
command: _,
|
||||||
|
output: _,
|
||||||
|
} => {
|
||||||
|
vec![program.clone()]
|
||||||
|
},
|
||||||
|
_ => vec![],
|
||||||
|
};
|
||||||
|
format!(
|
||||||
|
"{}({})",
|
||||||
|
static_str,
|
||||||
|
context
|
||||||
|
.iter()
|
||||||
|
.map(|v| format!("\"{v}\""))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{io::IsTerminal, process::ExitCode};
|
use std::{io::IsTerminal, process::ExitCode};
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use lix_installer::cli::CommandExecute;
|
use nix_installer::cli::CommandExecute;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> eyre::Result<ExitCode> {
|
async fn main() -> eyre::Result<ExitCode> {
|
||||||
|
@ -17,7 +17,7 @@ async fn main() -> eyre::Result<ExitCode> {
|
||||||
})
|
})
|
||||||
.install()?;
|
.install()?;
|
||||||
|
|
||||||
let cli = lix_installer::cli::NixInstallerCli::parse();
|
let cli = nix_installer::cli::NixInstallerCli::parse();
|
||||||
|
|
||||||
cli.instrumentation.setup()?;
|
cli.instrumentation.setup()?;
|
||||||
|
|
|
@ -16,7 +16,6 @@ pub enum PromptChoice {
|
||||||
// The below method was adopted from Rustup at https://github.com/rust-lang/rustup/blob/3331f34c01474bf216c99a1b1706725708833de1/src/cli/term2.rs#L37
|
// The below method was adopted from Rustup at https://github.com/rust-lang/rustup/blob/3331f34c01474bf216c99a1b1706725708833de1/src/cli/term2.rs#L37
|
||||||
pub(crate) async fn prompt(
|
pub(crate) async fn prompt(
|
||||||
question: impl AsRef<str>,
|
question: impl AsRef<str>,
|
||||||
prompt_text: impl AsRef<str>,
|
|
||||||
default: PromptChoice,
|
default: PromptChoice,
|
||||||
currently_explaining: bool,
|
currently_explaining: bool,
|
||||||
) -> eyre::Result<PromptChoice> {
|
) -> eyre::Result<PromptChoice> {
|
||||||
|
@ -30,7 +29,7 @@ pub(crate) async fn prompt(
|
||||||
{are_you_sure} ({yes}/{no}{maybe_explain}): \
|
{are_you_sure} ({yes}/{no}{maybe_explain}): \
|
||||||
",
|
",
|
||||||
question = question.as_ref(),
|
question = question.as_ref(),
|
||||||
are_you_sure = prompt_text.as_ref().bold(),
|
are_you_sure = "Proceed?".bold(),
|
||||||
no = if default == PromptChoice::No {
|
no = if default == PromptChoice::No {
|
||||||
"[N]o"
|
"[N]o"
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -20,7 +20,7 @@ pub trait CommandExecute {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The Determinate Nix installer (lix variant)
|
The Determinate Nix installer
|
||||||
|
|
||||||
A fast, friendly, and reliable tool to help you use Nix with Flakes everywhere.
|
A fast, friendly, and reliable tool to help you use Nix with Flakes everywhere.
|
||||||
*/
|
*/
|
||||||
|
@ -92,7 +92,7 @@ pub fn ensure_root() -> eyre::Result<()> {
|
||||||
if !is_root() {
|
if !is_root() {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"{}",
|
"{}",
|
||||||
"`lix-installer` needs to run as `root`, attempting to escalate now via `sudo`..."
|
"`nix-installer` needs to run as `root`, attempting to escalate now via `sudo`..."
|
||||||
.yellow()
|
.yellow()
|
||||||
.dimmed()
|
.dimmed()
|
||||||
);
|
);
|
||||||
|
@ -122,6 +122,13 @@ pub fn ensure_root() -> eyre::Result<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
if is_ci::cached() {
|
||||||
|
// Normally `sudo` would erase those envs, so we detect and pass that along specifically to avoid having to pass around
|
||||||
|
// a bunch of environment variables
|
||||||
|
env_list.push("NIX_INSTALLER_CI=1".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
if !env_list.is_empty() {
|
if !env_list.is_empty() {
|
||||||
arg_vec_cstring
|
arg_vec_cstring
|
||||||
.push(CString::new("env").wrap_err("Building a `env` argument for `sudo`")?);
|
.push(CString::new("env").wrap_err("Building a `env` argument for `sudo`")?);
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use std::{
|
use std::{
|
||||||
io::{stdout, Write},
|
|
||||||
os::unix::prelude::PermissionsExt,
|
os::unix::prelude::PermissionsExt,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
process::ExitCode,
|
process::ExitCode,
|
||||||
|
@ -26,13 +25,13 @@ use color_eyre::{
|
||||||
use owo_colors::OwoColorize;
|
use owo_colors::OwoColorize;
|
||||||
|
|
||||||
const EXISTING_INCOMPATIBLE_PLAN_GUIDANCE: &str = "\
|
const EXISTING_INCOMPATIBLE_PLAN_GUIDANCE: &str = "\
|
||||||
If you are trying to upgrade Lix, try running `sudo -i nix upgrade-nix` instead.\n\
|
If you are trying to upgrade Nix, try running `sudo -i nix upgrade-nix` instead.\n\
|
||||||
If you are trying to install Lix over an existing install (from an incompatible `nix-installer` install), try running `/nix/nix-installer uninstall` then try to install again.\n\
|
If you are trying to install Nix over an existing install (from an incompatible `nix-installer` install), try running `/nix/nix-installer uninstall` then try to install again.\n\
|
||||||
If you are using `lix-installer` in an automated curing process and seeing this message, consider pinning the version you use via https://git.lix.systems/lix-project/lix-installer#accessing-other-versions.\
|
If you are using `nix-installer` in an automated curing process and seeing this message, consider pinning the version you use via https://github.com/DeterminateSystems/nix-installer#accessing-other-versions.\
|
||||||
";
|
";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Install Lix-Nix using a planner
|
Install Nix using a planner
|
||||||
|
|
||||||
By default, an appropriate planner is heuristically determined based on the system.
|
By default, an appropriate planner is heuristically determined based on the system.
|
||||||
|
|
||||||
|
@ -81,22 +80,6 @@ impl CommandExecute for Install {
|
||||||
explain,
|
explain,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
// Get our terminal object, explaining what to do if it's not there.
|
|
||||||
let term =
|
|
||||||
term::terminfo::TerminfoTerminal::new(stdout());
|
|
||||||
if term.is_none() && !no_confirm {
|
|
||||||
eprintln!(
|
|
||||||
"{}",
|
|
||||||
format!("\
|
|
||||||
\n\
|
|
||||||
Couldn't figure out which terminal you're using -- check the value of the $TERM variable.\n\n\
|
|
||||||
If you're using an interactive terminal, it's probably safe to set TERM to \"xterm\",\n\
|
|
||||||
by e.g. running 'export TERM=xterm'.\n\
|
|
||||||
").red()
|
|
||||||
);
|
|
||||||
interaction::clean_exit_with_message("Couldn't get the terminal! Aborting.").await;
|
|
||||||
}
|
|
||||||
|
|
||||||
ensure_root()?;
|
ensure_root()?;
|
||||||
|
|
||||||
let existing_receipt: Option<InstallPlan> = match Path::new(RECEIPT_LOCATION).exists() {
|
let existing_receipt: Option<InstallPlan> = match Path::new(RECEIPT_LOCATION).exists() {
|
||||||
|
@ -107,7 +90,7 @@ impl CommandExecute for Install {
|
||||||
.wrap_err("Reading plan")?;
|
.wrap_err("Reading plan")?;
|
||||||
Some(
|
Some(
|
||||||
serde_json::from_str(&install_plan_string).wrap_err_with(|| {
|
serde_json::from_str(&install_plan_string).wrap_err_with(|| {
|
||||||
format!("Unable to parse existing receipt `{RECEIPT_LOCATION}`, it may be from an incompatible version of `nix-installer` or `lix-installer`. Try running `/nix/nix-installer uninstall`, then installing again.")
|
format!("Unable to parse existing receipt `{RECEIPT_LOCATION}`, it may be from an incompatible version of `nix-installer`. Try running `/nix/nix-installer uninstall`, then installing again.")
|
||||||
})?,
|
})?,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
@ -116,7 +99,7 @@ impl CommandExecute for Install {
|
||||||
|
|
||||||
let uninstall_command = match Path::new("/nix/nix-installer").exists() {
|
let uninstall_command = match Path::new("/nix/nix-installer").exists() {
|
||||||
true => "/nix/nix-installer uninstall".into(),
|
true => "/nix/nix-installer uninstall".into(),
|
||||||
false => format!("curl --proto '=https' --tlsv1.2 -sSf -L https://install.lix.systems/lix/tag/v{} | sh -s -- uninstall", env!("CARGO_PKG_VERSION")),
|
false => format!("curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix/tag/v{} | sh -s -- uninstall", env!("CARGO_PKG_VERSION")),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut install_plan = match (planner, plan) {
|
let mut install_plan = match (planner, plan) {
|
||||||
|
@ -170,39 +153,7 @@ impl CommandExecute for Install {
|
||||||
serde_json::from_str(&install_plan_string)?
|
serde_json::from_str(&install_plan_string)?
|
||||||
},
|
},
|
||||||
(None, None) => {
|
(None, None) => {
|
||||||
let mut settings_to_apply = settings.clone();
|
let builtin_planner = BuiltinPlanner::from_common_settings(settings.clone())
|
||||||
|
|
||||||
if !no_confirm {
|
|
||||||
// Say hello.
|
|
||||||
let mut term = term.expect("Internal consistency: term should have been None checked already!");
|
|
||||||
let hello_message = format!("{}{}", "\n\nWelcome to the Lix installer!".bold(), " Just a couple of quick questions.\n\n");
|
|
||||||
|
|
||||||
term.write_all(hello_message.as_bytes())?;
|
|
||||||
term.flush()?;
|
|
||||||
|
|
||||||
// Ask about flakes.
|
|
||||||
match interaction::prompt(
|
|
||||||
"Flakes are an experimental feature, but widely used in the community.\nYou can change this later in `/etc/nix/nix.conf`.",
|
|
||||||
"Enable flakes?",
|
|
||||||
PromptChoice::Yes,
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
.await?
|
|
||||||
{
|
|
||||||
PromptChoice::Yes => settings_to_apply.enable_flakes = true,
|
|
||||||
PromptChoice::Explain => panic!("This prompt has no explanation."),
|
|
||||||
PromptChoice::No => settings_to_apply.enable_flakes = false,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notify the user about the nix command.
|
|
||||||
let nixcmd_message = format!("{}{}{}{}{}",
|
|
||||||
"\nQUICK NOTE:".bold().yellow(), " we've enabled the experimental", " nix ".bold(), "command for you!\n",
|
|
||||||
"Be aware that commands starting with `nix ` such as `nix build` may change syntax.\n\n".green());
|
|
||||||
term.write_all(nixcmd_message.as_bytes())?;
|
|
||||||
term.flush()?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let builtin_planner = BuiltinPlanner::from_common_settings(settings_to_apply)
|
|
||||||
.await
|
.await
|
||||||
.map_err(|e| eyre::eyre!(e))?;
|
.map_err(|e| eyre::eyre!(e))?;
|
||||||
|
|
||||||
|
@ -268,7 +219,6 @@ impl CommandExecute for Install {
|
||||||
.describe_install(currently_explaining)
|
.describe_install(currently_explaining)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| eyre!(e))?,
|
.map_err(|e| eyre!(e))?,
|
||||||
"Proceed?",
|
|
||||||
PromptChoice::Yes,
|
PromptChoice::Yes,
|
||||||
currently_explaining,
|
currently_explaining,
|
||||||
)
|
)
|
||||||
|
@ -309,7 +259,6 @@ impl CommandExecute for Install {
|
||||||
.describe_uninstall(currently_explaining)
|
.describe_uninstall(currently_explaining)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| eyre!(e))?,
|
.map_err(|e| eyre!(e))?,
|
||||||
"Proceed?",
|
|
||||||
PromptChoice::Yes,
|
PromptChoice::Yes,
|
||||||
currently_explaining,
|
currently_explaining,
|
||||||
)
|
)
|
||||||
|
|
|
@ -38,23 +38,9 @@ impl CommandExecute for Repair {
|
||||||
|
|
||||||
if let Err(err) = reconfigure.try_execute().await {
|
if let Err(err) = reconfigure.try_execute().await {
|
||||||
println!("{:#?}", err);
|
println!("{:#?}", err);
|
||||||
return Ok(ExitCode::FAILURE);
|
Ok(ExitCode::FAILURE)
|
||||||
|
} else {
|
||||||
|
Ok(ExitCode::SUCCESS)
|
||||||
}
|
}
|
||||||
// TODO: Using `cfg` based on OS is not a long term solution.
|
|
||||||
// Make this read the planner from the `/nix/receipt.json` to determine which tasks to run.
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
{
|
|
||||||
let mut reconfigure = crate::action::macos::ConfigureRemoteBuilding::plan()
|
|
||||||
.await
|
|
||||||
.map_err(PlannerError::Action)?
|
|
||||||
.boxed();
|
|
||||||
|
|
||||||
if let Err(err) = reconfigure.try_execute().await {
|
|
||||||
println!("{:#?}", err);
|
|
||||||
return Ok(ExitCode::FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(ExitCode::SUCCESS)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,7 +129,7 @@ impl CommandExecute for Uninstall {
|
||||||
format!(
|
format!(
|
||||||
"\
|
"\
|
||||||
Unable to parse plan, this plan was created by `nix-installer` version `{plan_version}`, this is `nix-installer` version `{current_version}`\n\
|
Unable to parse plan, this plan was created by `nix-installer` version `{plan_version}`, this is `nix-installer` version `{current_version}`\n\
|
||||||
To uninstall, either run `/nix/nix-installer uninstall` or `curl --proto '=https' --tlsv1.2 -sSf -L https://install.lix.systems/lix/tag/v{plan_version} | sh -s -- uninstall`\
|
To uninstall, either run `/nix/nix-installer uninstall` or `curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix/tag/{plan_version} | sh -s -- uninstall`\
|
||||||
").red().to_string()
|
").red().to_string()
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -147,7 +147,7 @@ impl CommandExecute for Uninstall {
|
||||||
\n\
|
\n\
|
||||||
Found existing plan in `{RECEIPT_LOCATION}` which was created by a version incompatible `nix-installer`.\n\
|
Found existing plan in `{RECEIPT_LOCATION}` which was created by a version incompatible `nix-installer`.\n\
|
||||||
\n
|
\n
|
||||||
To uninstall, either run `/nix/nix-installer uninstall` or `curl --proto '=https' --tlsv1.2 -sSf -L https://install.lix.systems/lix/tag/v${version} | sh -s -- uninstall`\n\
|
To uninstall, either run `/nix/nix-installer uninstall` or `curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix/tag/${version} | sh -s -- uninstall`\n\
|
||||||
\n\
|
\n\
|
||||||
").red()
|
").red()
|
||||||
);
|
);
|
||||||
|
@ -169,7 +169,6 @@ impl CommandExecute for Uninstall {
|
||||||
plan.describe_uninstall(currently_explaining)
|
plan.describe_uninstall(currently_explaining)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| eyre!(e))?,
|
.map_err(|e| eyre!(e))?,
|
||||||
"Proceed?",
|
|
||||||
PromptChoice::Yes,
|
PromptChoice::Yes,
|
||||||
currently_explaining,
|
currently_explaining,
|
||||||
)
|
)
|
||||||
|
|
277
src/diagnostics.rs
Normal file
277
src/diagnostics.rs
Normal file
|
@ -0,0 +1,277 @@
|
||||||
|
/*! Diagnostic reporting functionality
|
||||||
|
|
||||||
|
When enabled with the `diagnostics` feature (default) this module provides automated install success/failure reporting to an endpoint.
|
||||||
|
|
||||||
|
That endpoint can be a URL such as `https://our.project.org/nix-installer/diagnostics` or `file:///home/$USER/diagnostic.json` which receives a [`DiagnosticReport`] in JSON format.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use std::{path::PathBuf, time::Duration};
|
||||||
|
|
||||||
|
use os_release::OsRelease;
|
||||||
|
use reqwest::Url;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
action::ActionError, parse_ssl_cert, planner::PlannerError, settings::InstallSettingsError,
|
||||||
|
CertificateError, NixInstallerError,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The static of an action attempt
|
||||||
|
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||||
|
pub enum DiagnosticStatus {
|
||||||
|
Cancelled,
|
||||||
|
Success,
|
||||||
|
Pending,
|
||||||
|
Failure,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The action attempted
|
||||||
|
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone, Copy)]
|
||||||
|
pub enum DiagnosticAction {
|
||||||
|
Install,
|
||||||
|
Uninstall,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A report sent to an endpoint
|
||||||
|
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||||
|
pub struct DiagnosticReport {
|
||||||
|
pub attribution: Option<String>,
|
||||||
|
pub version: String,
|
||||||
|
pub planner: String,
|
||||||
|
pub configured_settings: Vec<String>,
|
||||||
|
pub os_name: String,
|
||||||
|
pub os_version: String,
|
||||||
|
pub triple: String,
|
||||||
|
pub is_ci: bool,
|
||||||
|
pub action: DiagnosticAction,
|
||||||
|
pub status: DiagnosticStatus,
|
||||||
|
/// Generally this includes the [`strum::IntoStaticStr`] representation of the error, we take special care not to include parameters of the error (which may include secrets)
|
||||||
|
pub failure_chain: Option<Vec<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A preparation of data to be sent to the `endpoint`.
|
||||||
|
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone, Default)]
|
||||||
|
pub struct DiagnosticData {
|
||||||
|
attribution: Option<String>,
|
||||||
|
version: String,
|
||||||
|
planner: String,
|
||||||
|
configured_settings: Vec<String>,
|
||||||
|
os_name: String,
|
||||||
|
os_version: String,
|
||||||
|
triple: String,
|
||||||
|
is_ci: bool,
|
||||||
|
endpoint: Option<Url>,
|
||||||
|
ssl_cert_file: Option<PathBuf>,
|
||||||
|
/// Generally this includes the [`strum::IntoStaticStr`] representation of the error, we take special care not to include parameters of the error (which may include secrets)
|
||||||
|
failure_chain: Option<Vec<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DiagnosticData {
|
||||||
|
pub fn new(
|
||||||
|
attribution: Option<String>,
|
||||||
|
endpoint: Option<String>,
|
||||||
|
planner: String,
|
||||||
|
configured_settings: Vec<String>,
|
||||||
|
ssl_cert_file: Option<PathBuf>,
|
||||||
|
) -> Result<Self, DiagnosticError> {
|
||||||
|
let endpoint = match endpoint {
|
||||||
|
Some(endpoint) => diagnostic_endpoint_parser(&endpoint)?,
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
let (os_name, os_version) = match OsRelease::new() {
|
||||||
|
Ok(os_release) => (os_release.name, os_release.version),
|
||||||
|
Err(_) => ("unknown".into(), "unknown".into()),
|
||||||
|
};
|
||||||
|
let is_ci = is_ci::cached()
|
||||||
|
|| std::env::var("NIX_INSTALLER_CI").unwrap_or_else(|_| "0".into()) == "1";
|
||||||
|
Ok(Self {
|
||||||
|
attribution,
|
||||||
|
endpoint,
|
||||||
|
version: env!("CARGO_PKG_VERSION").into(),
|
||||||
|
planner,
|
||||||
|
configured_settings,
|
||||||
|
os_name,
|
||||||
|
os_version,
|
||||||
|
triple: target_lexicon::HOST.to_string(),
|
||||||
|
is_ci,
|
||||||
|
ssl_cert_file: ssl_cert_file.and_then(|v| v.canonicalize().ok()),
|
||||||
|
failure_chain: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn failure(mut self, err: &NixInstallerError) -> Self {
|
||||||
|
let mut failure_chain = vec![];
|
||||||
|
let diagnostic = err.diagnostic();
|
||||||
|
failure_chain.push(diagnostic);
|
||||||
|
|
||||||
|
let mut walker: &dyn std::error::Error = &err;
|
||||||
|
while let Some(source) = walker.source() {
|
||||||
|
if let Some(downcasted) = source.downcast_ref::<ActionError>() {
|
||||||
|
let downcasted_diagnostic = downcasted.kind().diagnostic();
|
||||||
|
failure_chain.push(downcasted_diagnostic);
|
||||||
|
}
|
||||||
|
if let Some(downcasted) = source.downcast_ref::<Box<ActionError>>() {
|
||||||
|
let downcasted_diagnostic = downcasted.kind().diagnostic();
|
||||||
|
failure_chain.push(downcasted_diagnostic);
|
||||||
|
}
|
||||||
|
if let Some(downcasted) = source.downcast_ref::<PlannerError>() {
|
||||||
|
let downcasted_diagnostic = downcasted.diagnostic();
|
||||||
|
failure_chain.push(downcasted_diagnostic);
|
||||||
|
}
|
||||||
|
if let Some(downcasted) = source.downcast_ref::<InstallSettingsError>() {
|
||||||
|
let downcasted_diagnostic = downcasted.diagnostic();
|
||||||
|
failure_chain.push(downcasted_diagnostic);
|
||||||
|
}
|
||||||
|
if let Some(downcasted) = source.downcast_ref::<DiagnosticError>() {
|
||||||
|
let downcasted_diagnostic = downcasted.diagnostic();
|
||||||
|
failure_chain.push(downcasted_diagnostic);
|
||||||
|
}
|
||||||
|
|
||||||
|
walker = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.failure_chain = Some(failure_chain);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn report(&self, action: DiagnosticAction, status: DiagnosticStatus) -> DiagnosticReport {
|
||||||
|
let Self {
|
||||||
|
attribution,
|
||||||
|
version,
|
||||||
|
planner,
|
||||||
|
configured_settings,
|
||||||
|
os_name,
|
||||||
|
os_version,
|
||||||
|
triple,
|
||||||
|
is_ci,
|
||||||
|
endpoint: _,
|
||||||
|
ssl_cert_file: _,
|
||||||
|
failure_chain,
|
||||||
|
} = self;
|
||||||
|
DiagnosticReport {
|
||||||
|
attribution: attribution.clone(),
|
||||||
|
version: version.clone(),
|
||||||
|
planner: planner.clone(),
|
||||||
|
configured_settings: configured_settings.clone(),
|
||||||
|
os_name: os_name.clone(),
|
||||||
|
os_version: os_version.clone(),
|
||||||
|
triple: triple.clone(),
|
||||||
|
is_ci: *is_ci,
|
||||||
|
action,
|
||||||
|
status,
|
||||||
|
failure_chain: failure_chain.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(level = "debug", skip_all)]
|
||||||
|
pub async fn send(
|
||||||
|
self,
|
||||||
|
action: DiagnosticAction,
|
||||||
|
status: DiagnosticStatus,
|
||||||
|
) -> Result<(), DiagnosticError> {
|
||||||
|
let serialized = serde_json::to_string_pretty(&self.report(action, status))?;
|
||||||
|
|
||||||
|
let endpoint = match self.endpoint {
|
||||||
|
Some(endpoint) => endpoint,
|
||||||
|
None => return Ok(()),
|
||||||
|
};
|
||||||
|
|
||||||
|
match endpoint.scheme() {
|
||||||
|
"https" | "http" => {
|
||||||
|
tracing::debug!("Sending diagnostic to `{endpoint}`");
|
||||||
|
let mut buildable_client = reqwest::Client::builder();
|
||||||
|
if let Some(ssl_cert_file) = &self.ssl_cert_file {
|
||||||
|
let ssl_cert = parse_ssl_cert(ssl_cert_file).await.ok();
|
||||||
|
if let Some(ssl_cert) = ssl_cert {
|
||||||
|
buildable_client = buildable_client.add_root_certificate(ssl_cert);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let client = buildable_client.build().map_err(DiagnosticError::Reqwest)?;
|
||||||
|
|
||||||
|
let res = client
|
||||||
|
.post(endpoint.clone())
|
||||||
|
.body(serialized)
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.timeout(Duration::from_millis(3000))
|
||||||
|
.send()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
if let Err(_err) = res {
|
||||||
|
tracing::info!("Failed to send diagnostic to `{endpoint}`, continuing")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"file" => {
|
||||||
|
let path = endpoint.path();
|
||||||
|
tracing::debug!("Writing diagnostic to `{path}`");
|
||||||
|
let res = tokio::fs::write(path, serialized).await;
|
||||||
|
|
||||||
|
if let Err(_err) = res {
|
||||||
|
tracing::info!("Failed to send diagnostic to `{path}`, continuing")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => return Err(DiagnosticError::UnknownUrlScheme),
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[non_exhaustive]
|
||||||
|
#[derive(thiserror::Error, Debug, strum::IntoStaticStr)]
|
||||||
|
pub enum DiagnosticError {
|
||||||
|
#[error("Unknown url scheme")]
|
||||||
|
UnknownUrlScheme,
|
||||||
|
#[error("Request error")]
|
||||||
|
Reqwest(
|
||||||
|
#[from]
|
||||||
|
#[source]
|
||||||
|
reqwest::Error,
|
||||||
|
),
|
||||||
|
/// Parsing URL
|
||||||
|
#[error("Parsing URL")]
|
||||||
|
Parse(
|
||||||
|
#[source]
|
||||||
|
#[from]
|
||||||
|
url::ParseError,
|
||||||
|
),
|
||||||
|
#[error("Write path `{0}`")]
|
||||||
|
Write(std::path::PathBuf, #[source] std::io::Error),
|
||||||
|
#[error("Serializing receipt")]
|
||||||
|
Serializing(
|
||||||
|
#[from]
|
||||||
|
#[source]
|
||||||
|
serde_json::Error,
|
||||||
|
),
|
||||||
|
#[error(transparent)]
|
||||||
|
Certificate(#[from] CertificateError),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ErrorDiagnostic {
|
||||||
|
fn diagnostic(&self) -> String;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ErrorDiagnostic for DiagnosticError {
|
||||||
|
fn diagnostic(&self) -> String {
|
||||||
|
let static_str: &'static str = (self).into();
|
||||||
|
static_str.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn diagnostic_endpoint_parser(input: &str) -> Result<Option<Url>, DiagnosticError> {
|
||||||
|
match Url::parse(input) {
|
||||||
|
Ok(v) => match v.scheme() {
|
||||||
|
"https" | "http" | "file" => Ok(Some(v)),
|
||||||
|
_ => Err(DiagnosticError::UnknownUrlScheme),
|
||||||
|
},
|
||||||
|
Err(url_error) if url_error == url::ParseError::RelativeUrlWithoutBase => {
|
||||||
|
match Url::parse(&format!("file://{input}")) {
|
||||||
|
Ok(v) => Ok(Some(v)),
|
||||||
|
Err(file_error) => Err(file_error)?,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(url_error) => Err(url_error)?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn diagnostic_endpoint_validator(input: &str) -> Result<String, DiagnosticError> {
|
||||||
|
let _ = diagnostic_endpoint_parser(input)?;
|
||||||
|
Ok(input.to_string())
|
||||||
|
}
|
38
src/error.rs
38
src/error.rs
|
@ -74,6 +74,14 @@ pub enum NixInstallerError {
|
||||||
InstallSettingsError,
|
InstallSettingsError,
|
||||||
),
|
),
|
||||||
|
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
/// Diagnostic error
|
||||||
|
#[error("Diagnostic error")]
|
||||||
|
Diagnostic(
|
||||||
|
#[from]
|
||||||
|
#[source]
|
||||||
|
crate::diagnostics::DiagnosticError,
|
||||||
|
),
|
||||||
/// Could not parse the value as a version requirement in order to ensure it's compatible
|
/// Could not parse the value as a version requirement in order to ensure it's compatible
|
||||||
#[error("Could not parse `{0}` as a version requirement in order to ensure it's compatible")]
|
#[error("Could not parse `{0}` as a version requirement in order to ensure it's compatible")]
|
||||||
InvalidVersionRequirement(String, semver::Error),
|
InvalidVersionRequirement(String, semver::Error),
|
||||||
|
@ -107,6 +115,36 @@ impl HasExpectedErrors for NixInstallerError {
|
||||||
this @ NixInstallerError::IncompatibleVersion { binary: _, plan: _ } => {
|
this @ NixInstallerError::IncompatibleVersion { binary: _, plan: _ } => {
|
||||||
Some(Box::new(this))
|
Some(Box::new(this))
|
||||||
},
|
},
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
NixInstallerError::Diagnostic(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
impl crate::diagnostics::ErrorDiagnostic for NixInstallerError {
|
||||||
|
fn diagnostic(&self) -> String {
|
||||||
|
let static_str: &'static str = (self).into();
|
||||||
|
let context = match self {
|
||||||
|
Self::SelfTest(self_tests) => self_tests
|
||||||
|
.iter()
|
||||||
|
.map(|self_test| self_test.diagnostic())
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
Self::Action(action_error) => vec![action_error.diagnostic()],
|
||||||
|
Self::ActionRevert(action_errors) => action_errors
|
||||||
|
.iter()
|
||||||
|
.map(|action_error| action_error.diagnostic())
|
||||||
|
.collect(),
|
||||||
|
_ => vec![],
|
||||||
|
};
|
||||||
|
format!(
|
||||||
|
"{}({})",
|
||||||
|
static_str,
|
||||||
|
context
|
||||||
|
.iter()
|
||||||
|
.map(|v| format!("\"{v}\""))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
12
src/lib.rs
12
src/lib.rs
|
@ -1,6 +1,6 @@
|
||||||
/*! The [Lix](https://lix.systems) Installer
|
/*! The Determinate [Nix](https://github.com/NixOS/nix) Installer
|
||||||
|
|
||||||
`lix-installer` breaks down into three main concepts:
|
`nix-installer` breaks down into three main concepts:
|
||||||
|
|
||||||
* [`Action`]: An executable or revertable step, possibly orchestrating sub-[`Action`]s using things
|
* [`Action`]: An executable or revertable step, possibly orchestrating sub-[`Action`]s using things
|
||||||
like [`JoinSet`](tokio::task::JoinSet)s.
|
like [`JoinSet`](tokio::task::JoinSet)s.
|
||||||
|
@ -10,12 +10,12 @@
|
||||||
|
|
||||||
It is possible to create custom [`Action`]s and [`Planner`](planner::Planner)s to suit the needs of your project, team, or organization.
|
It is possible to create custom [`Action`]s and [`Planner`](planner::Planner)s to suit the needs of your project, team, or organization.
|
||||||
|
|
||||||
In the simplest case, `lix-installer` can be asked to determine a default plan for the platform and install
|
In the simplest case, `nix-installer` can be asked to determine a default plan for the platform and install
|
||||||
it, uninstalling if anything goes wrong:
|
it, uninstalling if anything goes wrong:
|
||||||
|
|
||||||
```rust,no_run
|
```rust,no_run
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use lix_installer::InstallPlan;
|
use nix_installer::InstallPlan;
|
||||||
|
|
||||||
# async fn default_install() -> color_eyre::Result<()> {
|
# async fn default_install() -> color_eyre::Result<()> {
|
||||||
let mut plan = InstallPlan::default().await?;
|
let mut plan = InstallPlan::default().await?;
|
||||||
|
@ -38,7 +38,7 @@ Sometimes choosing a specific planner is desired:
|
||||||
|
|
||||||
```rust,no_run
|
```rust,no_run
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use lix_installer::{InstallPlan, planner::Planner};
|
use nix_installer::{InstallPlan, planner::Planner};
|
||||||
|
|
||||||
# async fn chosen_planner_install() -> color_eyre::Result<()> {
|
# async fn chosen_planner_install() -> color_eyre::Result<()> {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
|
@ -72,6 +72,8 @@ match plan.install(None).await {
|
||||||
pub mod action;
|
pub mod action;
|
||||||
#[cfg(feature = "cli")]
|
#[cfg(feature = "cli")]
|
||||||
pub mod cli;
|
pub mod cli;
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
pub mod diagnostics;
|
||||||
mod error;
|
mod error;
|
||||||
mod os;
|
mod os;
|
||||||
mod plan;
|
mod plan;
|
||||||
|
|
95
src/plan.rs
95
src/plan.rs
|
@ -22,12 +22,18 @@ pub struct InstallPlan {
|
||||||
pub(crate) actions: Vec<StatefulAction<Box<dyn Action>>>,
|
pub(crate) actions: Vec<StatefulAction<Box<dyn Action>>>,
|
||||||
|
|
||||||
pub(crate) planner: Box<dyn Planner>,
|
pub(crate) planner: Box<dyn Planner>,
|
||||||
|
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
pub(crate) diagnostic_data: Option<crate::diagnostics::DiagnosticData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InstallPlan {
|
impl InstallPlan {
|
||||||
pub async fn default() -> Result<Self, NixInstallerError> {
|
pub async fn default() -> Result<Self, NixInstallerError> {
|
||||||
let planner = BuiltinPlanner::default().await?;
|
let planner = BuiltinPlanner::default().await?;
|
||||||
|
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
let diagnostic_data = Some(planner.diagnostic_data().await?);
|
||||||
|
|
||||||
let planner = planner.boxed();
|
let planner = planner.boxed();
|
||||||
let actions = planner.plan().await?;
|
let actions = planner.plan().await?;
|
||||||
|
|
||||||
|
@ -35,6 +41,8 @@ impl InstallPlan {
|
||||||
planner,
|
planner,
|
||||||
actions,
|
actions,
|
||||||
version: current_version()?,
|
version: current_version()?,
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
diagnostic_data,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +50,9 @@ impl InstallPlan {
|
||||||
where
|
where
|
||||||
P: Planner + 'static,
|
P: Planner + 'static,
|
||||||
{
|
{
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
let diagnostic_data = Some(planner.diagnostic_data().await?);
|
||||||
|
|
||||||
// Some Action `plan` calls may fail if we don't do these checks
|
// Some Action `plan` calls may fail if we don't do these checks
|
||||||
planner.pre_install_check().await?;
|
planner.pre_install_check().await?;
|
||||||
|
|
||||||
|
@ -50,6 +61,8 @@ impl InstallPlan {
|
||||||
planner: planner.boxed(),
|
planner: planner.boxed(),
|
||||||
actions,
|
actions,
|
||||||
version: current_version()?,
|
version: current_version()?,
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
diagnostic_data,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +101,7 @@ impl InstallPlan {
|
||||||
|
|
||||||
let buf = format!(
|
let buf = format!(
|
||||||
"\
|
"\
|
||||||
Lix install plan (v{version})\n\
|
Nix install plan (v{version})\n\
|
||||||
Planner: {planner}{maybe_default_setting_note}\n\
|
Planner: {planner}{maybe_default_setting_note}\n\
|
||||||
\n\
|
\n\
|
||||||
{maybe_plan_settings}\
|
{maybe_plan_settings}\
|
||||||
|
@ -160,6 +173,17 @@ impl InstallPlan {
|
||||||
tracing::error!("Error saving receipt: {:?}", err);
|
tracing::error!("Error saving receipt: {:?}", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
if let Some(diagnostic_data) = &self.diagnostic_data {
|
||||||
|
diagnostic_data
|
||||||
|
.clone()
|
||||||
|
.send(
|
||||||
|
crate::diagnostics::DiagnosticAction::Install,
|
||||||
|
crate::diagnostics::DiagnosticStatus::Cancelled,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
return Err(NixInstallerError::Cancelled);
|
return Err(NixInstallerError::Cancelled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,6 +194,17 @@ impl InstallPlan {
|
||||||
tracing::error!("Error saving receipt: {:?}", err);
|
tracing::error!("Error saving receipt: {:?}", err);
|
||||||
}
|
}
|
||||||
let err = NixInstallerError::Action(err);
|
let err = NixInstallerError::Action(err);
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
if let Some(diagnostic_data) = &self.diagnostic_data {
|
||||||
|
diagnostic_data
|
||||||
|
.clone()
|
||||||
|
.failure(&err)
|
||||||
|
.send(
|
||||||
|
crate::diagnostics::DiagnosticAction::Install,
|
||||||
|
crate::diagnostics::DiagnosticStatus::Failure,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
|
@ -181,7 +216,30 @@ impl InstallPlan {
|
||||||
.await
|
.await
|
||||||
.map_err(NixInstallerError::SelfTest)
|
.map_err(NixInstallerError::SelfTest)
|
||||||
{
|
{
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
if let Some(diagnostic_data) = &self.diagnostic_data {
|
||||||
|
diagnostic_data
|
||||||
|
.clone()
|
||||||
|
.failure(&err)
|
||||||
|
.send(
|
||||||
|
crate::diagnostics::DiagnosticAction::Install,
|
||||||
|
crate::diagnostics::DiagnosticStatus::Failure,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
tracing::warn!("{err:?}")
|
tracing::warn!("{err:?}")
|
||||||
|
} else {
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
if let Some(diagnostic_data) = &self.diagnostic_data {
|
||||||
|
diagnostic_data
|
||||||
|
.clone()
|
||||||
|
.send(
|
||||||
|
crate::diagnostics::DiagnosticAction::Install,
|
||||||
|
crate::diagnostics::DiagnosticStatus::Success,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -212,7 +270,7 @@ impl InstallPlan {
|
||||||
|
|
||||||
let buf = format!(
|
let buf = format!(
|
||||||
"\
|
"\
|
||||||
Lix uninstall plan (v{version})\n\
|
Nix uninstall plan (v{version})\n\
|
||||||
\n\
|
\n\
|
||||||
Planner: {planner}{maybe_default_setting_note}\n\
|
Planner: {planner}{maybe_default_setting_note}\n\
|
||||||
\n\
|
\n\
|
||||||
|
@ -287,6 +345,16 @@ impl InstallPlan {
|
||||||
tracing::error!("Error saving receipt: {:?}", err);
|
tracing::error!("Error saving receipt: {:?}", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
if let Some(diagnostic_data) = &self.diagnostic_data {
|
||||||
|
diagnostic_data
|
||||||
|
.clone()
|
||||||
|
.send(
|
||||||
|
crate::diagnostics::DiagnosticAction::Uninstall,
|
||||||
|
crate::diagnostics::DiagnosticStatus::Cancelled,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
return Err(NixInstallerError::Cancelled);
|
return Err(NixInstallerError::Cancelled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -298,9 +366,32 @@ impl InstallPlan {
|
||||||
}
|
}
|
||||||
|
|
||||||
if errors.is_empty() {
|
if errors.is_empty() {
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
if let Some(diagnostic_data) = &self.diagnostic_data {
|
||||||
|
diagnostic_data
|
||||||
|
.clone()
|
||||||
|
.send(
|
||||||
|
crate::diagnostics::DiagnosticAction::Uninstall,
|
||||||
|
crate::diagnostics::DiagnosticStatus::Success,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
let error = NixInstallerError::ActionRevert(errors);
|
let error = NixInstallerError::ActionRevert(errors);
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
if let Some(diagnostic_data) = &self.diagnostic_data {
|
||||||
|
diagnostic_data
|
||||||
|
.clone()
|
||||||
|
.failure(&error)
|
||||||
|
.send(
|
||||||
|
crate::diagnostics::DiagnosticAction::Uninstall,
|
||||||
|
crate::diagnostics::DiagnosticStatus::Failure,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
Err(error)
|
Err(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,6 +126,19 @@ impl Planner for Linux {
|
||||||
Ok(settings)
|
Ok(settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
async fn diagnostic_data(&self) -> Result<crate::diagnostics::DiagnosticData, PlannerError> {
|
||||||
|
Ok(crate::diagnostics::DiagnosticData::new(
|
||||||
|
self.settings.diagnostic_attribution.clone(),
|
||||||
|
self.settings.diagnostic_endpoint.clone(),
|
||||||
|
self.typetag_name().into(),
|
||||||
|
self.configured_settings()
|
||||||
|
.await?
|
||||||
|
.into_keys()
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
self.settings.ssl_cert_file.clone(),
|
||||||
|
)?)
|
||||||
|
}
|
||||||
async fn pre_uninstall_check(&self) -> Result<(), PlannerError> {
|
async fn pre_uninstall_check(&self) -> Result<(), PlannerError> {
|
||||||
check_not_wsl1()?;
|
check_not_wsl1()?;
|
||||||
|
|
||||||
|
@ -207,9 +220,9 @@ pub(crate) async fn check_nix_not_already_installed() -> Result<(), PlannerError
|
||||||
pub(crate) fn check_systemd_active() -> Result<(), PlannerError> {
|
pub(crate) fn check_systemd_active() -> Result<(), PlannerError> {
|
||||||
if !Path::new("/run/systemd/system").exists() {
|
if !Path::new("/run/systemd/system").exists() {
|
||||||
if std::env::var("WSL_DISTRO_NAME").is_ok() {
|
if std::env::var("WSL_DISTRO_NAME").is_ok() {
|
||||||
return Err(LinuxErrorKind::Wsl2SystemdNotActive.into());
|
return Err(LinuxErrorKind::Wsl2SystemdNotActive)?;
|
||||||
} else {
|
} else {
|
||||||
return Err(LinuxErrorKind::SystemdNotActive.into());
|
return Err(LinuxErrorKind::SystemdNotActive)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,9 +12,7 @@ use crate::{
|
||||||
action::{
|
action::{
|
||||||
base::RemoveDirectory,
|
base::RemoveDirectory,
|
||||||
common::{ConfigureInitService, ConfigureNix, CreateUsersAndGroups, ProvisionNix},
|
common::{ConfigureInitService, ConfigureNix, CreateUsersAndGroups, ProvisionNix},
|
||||||
macos::{
|
macos::{CreateNixHookService, CreateNixVolume, SetTmutilExclusions},
|
||||||
ConfigureRemoteBuilding, CreateNixHookService, CreateNixVolume, SetTmutilExclusions,
|
|
||||||
},
|
|
||||||
StatefulAction,
|
StatefulAction,
|
||||||
},
|
},
|
||||||
execute_command,
|
execute_command,
|
||||||
|
@ -135,7 +133,7 @@ impl Planner for Macos {
|
||||||
CreateNixVolume::plan(
|
CreateNixVolume::plan(
|
||||||
root_disk.unwrap(), /* We just ensured it was populated */
|
root_disk.unwrap(), /* We just ensured it was populated */
|
||||||
self.volume_label.clone(),
|
self.volume_label.clone(),
|
||||||
self.case_sensitive,
|
false,
|
||||||
encrypt,
|
encrypt,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
@ -168,12 +166,6 @@ impl Planner for Macos {
|
||||||
.map_err(PlannerError::Action)?
|
.map_err(PlannerError::Action)?
|
||||||
.boxed(),
|
.boxed(),
|
||||||
);
|
);
|
||||||
plan.push(
|
|
||||||
ConfigureRemoteBuilding::plan()
|
|
||||||
.await
|
|
||||||
.map_err(PlannerError::Action)?
|
|
||||||
.boxed(),
|
|
||||||
);
|
|
||||||
|
|
||||||
if self.settings.modify_profile {
|
if self.settings.modify_profile {
|
||||||
plan.push(
|
plan.push(
|
||||||
|
@ -238,6 +230,20 @@ impl Planner for Macos {
|
||||||
Ok(settings)
|
Ok(settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
async fn diagnostic_data(&self) -> Result<crate::diagnostics::DiagnosticData, PlannerError> {
|
||||||
|
Ok(crate::diagnostics::DiagnosticData::new(
|
||||||
|
self.settings.diagnostic_attribution.clone(),
|
||||||
|
self.settings.diagnostic_endpoint.clone(),
|
||||||
|
self.typetag_name().into(),
|
||||||
|
self.configured_settings()
|
||||||
|
.await?
|
||||||
|
.into_keys()
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
self.settings.ssl_cert_file.clone(),
|
||||||
|
)?)
|
||||||
|
}
|
||||||
|
|
||||||
async fn pre_uninstall_check(&self) -> Result<(), PlannerError> {
|
async fn pre_uninstall_check(&self) -> Result<(), PlannerError> {
|
||||||
check_nix_darwin_not_installed().await?;
|
check_nix_darwin_not_installed().await?;
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ A custom [`Planner`] can be created:
|
||||||
|
|
||||||
```rust,no_run
|
```rust,no_run
|
||||||
use std::{error::Error, collections::HashMap};
|
use std::{error::Error, collections::HashMap};
|
||||||
use lix_installer::{
|
use nix_installer::{
|
||||||
InstallPlan,
|
InstallPlan,
|
||||||
settings::{CommonSettings, InstallSettingsError},
|
settings::{CommonSettings, InstallSettingsError},
|
||||||
planner::{Planner, PlannerError},
|
planner::{Planner, PlannerError},
|
||||||
|
@ -69,6 +69,19 @@ impl Planner for MyPlanner {
|
||||||
Ok(settings)
|
Ok(settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
async fn diagnostic_data(&self) -> Result<nix_installer::diagnostics::DiagnosticData, PlannerError> {
|
||||||
|
Ok(nix_installer::diagnostics::DiagnosticData::new(
|
||||||
|
self.common.diagnostic_attribution.clone(),
|
||||||
|
self.common.diagnostic_endpoint.clone(),
|
||||||
|
self.typetag_name().into(),
|
||||||
|
self.configured_settings()
|
||||||
|
.await?
|
||||||
|
.into_keys()
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
self.common.ssl_cert_file.clone(),
|
||||||
|
)?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# async fn custom_planner_install() -> color_eyre::Result<()> {
|
# async fn custom_planner_install() -> color_eyre::Result<()> {
|
||||||
|
@ -141,6 +154,9 @@ pub trait Planner: std::fmt::Debug + Send + Sync + dyn_clone::DynClone {
|
||||||
async fn pre_install_check(&self) -> Result<(), PlannerError> {
|
async fn pre_install_check(&self) -> Result<(), PlannerError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
async fn diagnostic_data(&self) -> Result<crate::diagnostics::DiagnosticData, PlannerError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
dyn_clone::clone_trait_object!(Planner);
|
dyn_clone::clone_trait_object!(Planner);
|
||||||
|
@ -293,6 +309,21 @@ impl BuiltinPlanner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
pub async fn diagnostic_data(
|
||||||
|
&self,
|
||||||
|
) -> Result<crate::diagnostics::DiagnosticData, PlannerError> {
|
||||||
|
match self {
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
BuiltinPlanner::Linux(i) => i.diagnostic_data().await,
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
BuiltinPlanner::SteamDeck(i) => i.diagnostic_data().await,
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
BuiltinPlanner::Ostree(i) => i.diagnostic_data().await,
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
BuiltinPlanner::Macos(i) => i.diagnostic_data().await,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone)]
|
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone)]
|
||||||
|
@ -361,8 +392,8 @@ impl Default for FishShellProfileLocations {
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
#[derive(thiserror::Error, Debug, strum::IntoStaticStr)]
|
#[derive(thiserror::Error, Debug, strum::IntoStaticStr)]
|
||||||
pub enum PlannerError {
|
pub enum PlannerError {
|
||||||
/// `lix-installer` does not have a default planner for the target architecture right now
|
/// `nix-installer` does not have a default planner for the target architecture right now
|
||||||
#[error("`lix-installer` does not have a default planner for the `{0}` architecture right now, pass a specific archetype")]
|
#[error("`nix-installer` does not have a default planner for the `{0}` architecture right now, pass a specific archetype")]
|
||||||
UnsupportedArchitecture(target_lexicon::Triple),
|
UnsupportedArchitecture(target_lexicon::Triple),
|
||||||
/// Error executing action
|
/// Error executing action
|
||||||
#[error("Error executing action")]
|
#[error("Error executing action")]
|
||||||
|
@ -402,6 +433,9 @@ pub enum PlannerError {
|
||||||
/// Failed to execute command
|
/// Failed to execute command
|
||||||
#[error("Failed to execute command `{0}`")]
|
#[error("Failed to execute command `{0}`")]
|
||||||
Command(String, #[source] std::io::Error),
|
Command(String, #[source] std::io::Error),
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
#[error(transparent)]
|
||||||
|
Diagnostic(#[from] crate::diagnostics::DiagnosticError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HasExpectedErrors for PlannerError {
|
impl HasExpectedErrors for PlannerError {
|
||||||
|
@ -431,7 +465,16 @@ impl HasExpectedErrors for PlannerError {
|
||||||
this @ PlannerError::NixExists => Some(Box::new(this)),
|
this @ PlannerError::NixExists => Some(Box::new(this)),
|
||||||
this @ PlannerError::Wsl1 => Some(Box::new(this)),
|
this @ PlannerError::Wsl1 => Some(Box::new(this)),
|
||||||
PlannerError::Command(_, _) => None,
|
PlannerError::Command(_, _) => None,
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
PlannerError::Diagnostic(diagnostic_error) => Some(Box::new(diagnostic_error)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
impl crate::diagnostics::ErrorDiagnostic for PlannerError {
|
||||||
|
fn diagnostic(&self) -> String {
|
||||||
|
let static_str: &'static str = (self).into();
|
||||||
|
static_str.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -11,7 +11,10 @@ use crate::{
|
||||||
settings::{InitSystem, InstallSettingsError},
|
settings::{InitSystem, InstallSettingsError},
|
||||||
Action, BuiltinPlanner,
|
Action, BuiltinPlanner,
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, path::PathBuf};
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
linux::{
|
linux::{
|
||||||
|
@ -21,6 +24,19 @@ use super::{
|
||||||
ShellProfileLocations,
|
ShellProfileLocations,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Fedora's ostree's fish package creates `/etc/fish` but fish doesn't read from it.
|
||||||
|
// Its fish does read from /usr/local/share/fish/, but the directory doesn't exist --
|
||||||
|
// so we ignore it.
|
||||||
|
//
|
||||||
|
// We use this const to forcefully create this directory and add it to shell locations
|
||||||
|
// to think about updating.
|
||||||
|
//
|
||||||
|
// This may not be suitable for all possible ostree based distros, but it'll fix
|
||||||
|
// a good number of selftest failures we're seeing.
|
||||||
|
//
|
||||||
|
// See: https://github.com/DeterminateSystems/nix-installer/issues/707
|
||||||
|
pub const OSTREE_FISH_PROFILE_LOCATION: &str = "/usr/local/share/fish/";
|
||||||
|
|
||||||
/// A planner suitable for immutable systems using ostree, such as Fedora Silverblue
|
/// A planner suitable for immutable systems using ostree, such as Fedora Silverblue
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[cfg_attr(feature = "cli", derive(clap::Parser))]
|
#[cfg_attr(feature = "cli", derive(clap::Parser))]
|
||||||
|
@ -158,10 +174,8 @@ impl Planner for Ostree {
|
||||||
.iter()
|
.iter()
|
||||||
.position(|v| *v == PathBuf::from("/usr/share/fish/"))
|
.position(|v| *v == PathBuf::from("/usr/share/fish/"))
|
||||||
{
|
{
|
||||||
shell_profile_locations
|
shell_profile_locations.fish.vendor_confd_prefixes =
|
||||||
.fish
|
vec![OSTREE_FISH_PROFILE_LOCATION.into()];
|
||||||
.vendor_confd_prefixes
|
|
||||||
.remove(index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
plan.push(
|
plan.push(
|
||||||
|
@ -183,6 +197,16 @@ impl Planner for Ostree {
|
||||||
.map_err(PlannerError::Action)?
|
.map_err(PlannerError::Action)?
|
||||||
.boxed(),
|
.boxed(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if Path::new("/etc/fish").is_dir() {
|
||||||
|
plan.push(
|
||||||
|
CreateDirectory::plan(&OSTREE_FISH_PROFILE_LOCATION, None, None, 0o0755, true)
|
||||||
|
.await
|
||||||
|
.map_err(PlannerError::Action)?
|
||||||
|
.boxed(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
plan.push(
|
plan.push(
|
||||||
ConfigureNix::plan(shell_profile_locations, &self.settings)
|
ConfigureNix::plan(shell_profile_locations, &self.settings)
|
||||||
.await
|
.await
|
||||||
|
@ -266,6 +290,19 @@ impl Planner for Ostree {
|
||||||
Ok(settings)
|
Ok(settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
async fn diagnostic_data(&self) -> Result<crate::diagnostics::DiagnosticData, PlannerError> {
|
||||||
|
Ok(crate::diagnostics::DiagnosticData::new(
|
||||||
|
self.settings.diagnostic_attribution.clone(),
|
||||||
|
self.settings.diagnostic_endpoint.clone(),
|
||||||
|
self.typetag_name().into(),
|
||||||
|
self.configured_settings()
|
||||||
|
.await?
|
||||||
|
.into_keys()
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
self.settings.ssl_cert_file.clone(),
|
||||||
|
)?)
|
||||||
|
}
|
||||||
async fn pre_uninstall_check(&self) -> Result<(), PlannerError> {
|
async fn pre_uninstall_check(&self) -> Result<(), PlannerError> {
|
||||||
check_not_wsl1()?;
|
check_not_wsl1()?;
|
||||||
|
|
||||||
|
|
|
@ -385,6 +385,20 @@ impl Planner for SteamDeck {
|
||||||
Ok(settings)
|
Ok(settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
async fn diagnostic_data(&self) -> Result<crate::diagnostics::DiagnosticData, PlannerError> {
|
||||||
|
Ok(crate::diagnostics::DiagnosticData::new(
|
||||||
|
self.settings.diagnostic_attribution.clone(),
|
||||||
|
self.settings.diagnostic_endpoint.clone(),
|
||||||
|
self.typetag_name().into(),
|
||||||
|
self.configured_settings()
|
||||||
|
.await?
|
||||||
|
.into_keys()
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
self.settings.ssl_cert_file.clone(),
|
||||||
|
)?)
|
||||||
|
}
|
||||||
|
|
||||||
async fn pre_uninstall_check(&self) -> Result<(), PlannerError> {
|
async fn pre_uninstall_check(&self) -> Result<(), PlannerError> {
|
||||||
super::linux::check_not_wsl1()?;
|
super::linux::check_not_wsl1()?;
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,27 @@ pub enum SelfTestError {
|
||||||
SystemTime(#[from] std::time::SystemTimeError),
|
SystemTime(#[from] std::time::SystemTimeError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
impl crate::diagnostics::ErrorDiagnostic for SelfTestError {
|
||||||
|
fn diagnostic(&self) -> String {
|
||||||
|
let static_str: &'static str = (self).into();
|
||||||
|
let context = match self {
|
||||||
|
Self::ShellFailed { shell, .. } => vec![shell.to_string()],
|
||||||
|
Self::Command { shell, .. } => vec![shell.to_string()],
|
||||||
|
Self::SystemTime(_) => vec![],
|
||||||
|
};
|
||||||
|
format!(
|
||||||
|
"{}({})",
|
||||||
|
static_str,
|
||||||
|
context
|
||||||
|
.iter()
|
||||||
|
.map(|v| format!("\"{v}\""))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum Shell {
|
pub enum Shell {
|
||||||
Sh,
|
Sh,
|
||||||
|
|
|
@ -13,19 +13,19 @@ pub const SCRATCH_DIR: &str = "/nix/temp-install-dir";
|
||||||
|
|
||||||
/// Default [`nix_package_url`](CommonSettings::nix_package_url) for Linux x86_64
|
/// Default [`nix_package_url`](CommonSettings::nix_package_url) for Linux x86_64
|
||||||
pub const NIX_X64_64_LINUX_URL: &str =
|
pub const NIX_X64_64_LINUX_URL: &str =
|
||||||
"https://releases.lix.systems/lix/lix-2.90-beta.1/nix-2.90.0-beta.1-x86_64-linux.tar.xz";
|
"https://releases.nixos.org/nix/nix-2.18.1/nix-2.18.1-x86_64-linux.tar.xz";
|
||||||
/// Default [`nix_package_url`](CommonSettings::nix_package_url) for Linux x86 (32 bit)
|
/// Default [`nix_package_url`](CommonSettings::nix_package_url) for Linux x86 (32 bit)
|
||||||
pub const NIX_I686_LINUX_URL: &str =
|
pub const NIX_I686_LINUX_URL: &str =
|
||||||
"https://releases.lix.systems/lix/lix-2.90-beta.1/nix-2.90.0-beta.1-i686-linux.tar.xz";
|
"https://releases.nixos.org/nix/nix-2.18.1/nix-2.18.1-i686-linux.tar.xz";
|
||||||
/// Default [`nix_package_url`](CommonSettings::nix_package_url) for Linux aarch64
|
/// Default [`nix_package_url`](CommonSettings::nix_package_url) for Linux aarch64
|
||||||
pub const NIX_AARCH64_LINUX_URL: &str =
|
pub const NIX_AARCH64_LINUX_URL: &str =
|
||||||
"https://releases.lix.systems/lix/lix-2.90-beta.1/nix-2.90.0-beta.1-aarch64-linux.tar.xz";
|
"https://releases.nixos.org/nix/nix-2.18.1/nix-2.18.1-aarch64-linux.tar.xz";
|
||||||
/// Default [`nix_package_url`](CommonSettings::nix_package_url) for Darwin x86_64
|
/// Default [`nix_package_url`](CommonSettings::nix_package_url) for Darwin x86_64
|
||||||
pub const NIX_X64_64_DARWIN_URL: &str =
|
pub const NIX_X64_64_DARWIN_URL: &str =
|
||||||
"https://releases.lix.systems/lix/lix-2.90-beta.1/nix-2.90.0-beta.1-x86_64-darwin.tar.xz";
|
"https://releases.nixos.org/nix/nix-2.18.1/nix-2.18.1-x86_64-darwin.tar.xz";
|
||||||
/// Default [`nix_package_url`](CommonSettings::nix_package_url) for Darwin aarch64
|
/// Default [`nix_package_url`](CommonSettings::nix_package_url) for Darwin aarch64
|
||||||
pub const NIX_AARCH64_DARWIN_URL: &str =
|
pub const NIX_AARCH64_DARWIN_URL: &str =
|
||||||
"https://releases.lix.systems/lix/lix-2.90-beta.1/nix-2.90.0-beta.1-aarch64-darwin.tar.xz";
|
"https://releases.nixos.org/nix/nix-2.18.1/nix-2.18.1-aarch64-darwin.tar.xz";
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "cli", derive(clap::ValueEnum))]
|
#[cfg_attr(feature = "cli", derive(clap::ValueEnum))]
|
||||||
|
@ -204,19 +204,47 @@ pub struct CommonSettings {
|
||||||
)]
|
)]
|
||||||
pub force: bool,
|
pub force: bool,
|
||||||
|
|
||||||
/// If `nix-installer` should enable flakes.
|
#[cfg(feature = "diagnostics")]
|
||||||
|
/// Relate the install diagnostic to a specific value
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "cli",
|
feature = "cli",
|
||||||
clap(
|
clap(
|
||||||
long,
|
long,
|
||||||
action(ArgAction::SetFalse),
|
default_value = None,
|
||||||
default_value = "true",
|
env = "NIX_INSTALLER_DIAGNOSTIC_ATTRIBUTION",
|
||||||
global = true,
|
global = true
|
||||||
env = "NIX_INSTALLER_ENABLE_FLAKES"
|
|
||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
pub enable_flakes: bool,
|
pub diagnostic_attribution: Option<String>,
|
||||||
|
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
/// The URL or file path for an installation diagnostic to be sent
|
||||||
|
///
|
||||||
|
/// Sample of the data sent:
|
||||||
|
///
|
||||||
|
/// {
|
||||||
|
/// "attribution": null,
|
||||||
|
/// "version": "0.4.0",
|
||||||
|
/// "planner": "linux",
|
||||||
|
/// "configured_settings": [ "modify_profile" ],
|
||||||
|
/// "os_name": "Ubuntu",
|
||||||
|
/// "os_version": "22.04.1 LTS (Jammy Jellyfish)",
|
||||||
|
/// "triple": "x86_64-unknown-linux-gnu",
|
||||||
|
/// "is_ci": false,
|
||||||
|
/// "action": "Install",
|
||||||
|
/// "status": "Success"
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// To disable diagnostic reporting, unset the default with `--diagnostic-endpoint ""`, or `NIX_INSTALLER_DIAGNOSTIC_ENDPOINT=""`
|
||||||
|
#[clap(
|
||||||
|
long,
|
||||||
|
env = "NIX_INSTALLER_DIAGNOSTIC_ENDPOINT",
|
||||||
|
global = true,
|
||||||
|
value_parser = crate::diagnostics::diagnostic_endpoint_validator,
|
||||||
|
num_args = 0..=1, // Required to allow `--diagnostic-endpoint` or `NIX_INSTALLER_DIAGNOSTIC_ENDPOINT=""`
|
||||||
|
default_value = "https://install.determinate.systems/nix/diagnostic"
|
||||||
|
)]
|
||||||
|
pub diagnostic_endpoint: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommonSettings {
|
impl CommonSettings {
|
||||||
|
@ -284,8 +312,11 @@ impl CommonSettings {
|
||||||
proxy: Default::default(),
|
proxy: Default::default(),
|
||||||
extra_conf: Default::default(),
|
extra_conf: Default::default(),
|
||||||
force: false,
|
force: false,
|
||||||
enable_flakes: true,
|
|
||||||
ssl_cert_file: Default::default(),
|
ssl_cert_file: Default::default(),
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
diagnostic_attribution: None,
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
diagnostic_endpoint: Some("https://install.determinate.systems/nix/diagnostic".into()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,8 +333,11 @@ impl CommonSettings {
|
||||||
proxy,
|
proxy,
|
||||||
extra_conf,
|
extra_conf,
|
||||||
force,
|
force,
|
||||||
enable_flakes,
|
|
||||||
ssl_cert_file,
|
ssl_cert_file,
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
diagnostic_attribution: _,
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
diagnostic_endpoint,
|
||||||
} = self;
|
} = self;
|
||||||
let mut map = HashMap::default();
|
let mut map = HashMap::default();
|
||||||
|
|
||||||
|
@ -338,8 +372,14 @@ impl CommonSettings {
|
||||||
map.insert("proxy".into(), serde_json::to_value(proxy)?);
|
map.insert("proxy".into(), serde_json::to_value(proxy)?);
|
||||||
map.insert("ssl_cert_file".into(), serde_json::to_value(ssl_cert_file)?);
|
map.insert("ssl_cert_file".into(), serde_json::to_value(ssl_cert_file)?);
|
||||||
map.insert("extra_conf".into(), serde_json::to_value(extra_conf)?);
|
map.insert("extra_conf".into(), serde_json::to_value(extra_conf)?);
|
||||||
map.insert("enable_flakes".into(), serde_json::to_value(enable_flakes)?);
|
|
||||||
map.insert("force".into(), serde_json::to_value(force)?);
|
map.insert("force".into(), serde_json::to_value(force)?);
|
||||||
|
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
map.insert(
|
||||||
|
"diagnostic_endpoint".into(),
|
||||||
|
serde_json::to_value(diagnostic_endpoint)?,
|
||||||
|
);
|
||||||
|
|
||||||
Ok(map)
|
Ok(map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -625,6 +665,14 @@ impl clap::builder::TypedValueParser for UrlOrPathOrString {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "diagnostics")]
|
||||||
|
impl crate::diagnostics::ErrorDiagnostic for InstallSettingsError {
|
||||||
|
fn diagnostic(&self) -> String {
|
||||||
|
let static_str: &'static str = (self).into();
|
||||||
|
static_str.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{FromStr, PathBuf, Url, UrlOrPath, UrlOrPathOrString};
|
use super::{FromStr, PathBuf, Url, UrlOrPath, UrlOrPathOrString};
|
||||||
|
|
6
tests/fixtures/linux/linux.json
vendored
6
tests/fixtures/linux/linux.json
vendored
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"version": "0.17.1",
|
"version": "0.14.0",
|
||||||
"actions": [
|
"actions": [
|
||||||
{
|
{
|
||||||
"action": {
|
"action": {
|
||||||
|
@ -416,6 +416,7 @@
|
||||||
"ssl_cert_file": null,
|
"ssl_cert_file": null,
|
||||||
"extra_conf": [],
|
"extra_conf": [],
|
||||||
"force": false,
|
"force": false,
|
||||||
|
"diagnostic_endpoint": "https://install.determinate.systems/nix/diagnostic"
|
||||||
},
|
},
|
||||||
"init": {
|
"init": {
|
||||||
"init": "Systemd",
|
"init": "Systemd",
|
||||||
|
@ -423,13 +424,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"diagnostic_data": {
|
"diagnostic_data": {
|
||||||
"version": "0.17.1",
|
"version": "0.14.0",
|
||||||
"planner": "linux",
|
"planner": "linux",
|
||||||
"configured_settings": [],
|
"configured_settings": [],
|
||||||
"os_name": "Ubuntu",
|
"os_name": "Ubuntu",
|
||||||
"os_version": "22.04.2 LTS (Jammy Jellyfish)",
|
"os_version": "22.04.2 LTS (Jammy Jellyfish)",
|
||||||
"triple": "x86_64-unknown-linux-musl",
|
"triple": "x86_64-unknown-linux-musl",
|
||||||
"is_ci": false,
|
"is_ci": false,
|
||||||
|
"endpoint": "https://install.determinate.systems/nix/diagnostic",
|
||||||
"ssl_cert_file": null,
|
"ssl_cert_file": null,
|
||||||
"failure_chain": null
|
"failure_chain": null
|
||||||
}
|
}
|
||||||
|
|
6
tests/fixtures/linux/steam-deck.json
vendored
6
tests/fixtures/linux/steam-deck.json
vendored
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"version": "0.17.1",
|
"version": "0.14.0",
|
||||||
"actions": [
|
"actions": [
|
||||||
{
|
{
|
||||||
"action": {
|
"action": {
|
||||||
|
@ -400,16 +400,18 @@
|
||||||
"ssl_cert_file": null,
|
"ssl_cert_file": null,
|
||||||
"extra_conf": [],
|
"extra_conf": [],
|
||||||
"force": false,
|
"force": false,
|
||||||
|
"diagnostic_endpoint": "https://install.determinate.systems/nix/diagnostic"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"diagnostic_data": {
|
"diagnostic_data": {
|
||||||
"version": "0.17.1",
|
"version": "0.14.0",
|
||||||
"planner": "steam-deck",
|
"planner": "steam-deck",
|
||||||
"configured_settings": [],
|
"configured_settings": [],
|
||||||
"os_name": "Ubuntu",
|
"os_name": "Ubuntu",
|
||||||
"os_version": "22.04.2 LTS (Jammy Jellyfish)",
|
"os_version": "22.04.2 LTS (Jammy Jellyfish)",
|
||||||
"triple": "x86_64-unknown-linux-musl",
|
"triple": "x86_64-unknown-linux-musl",
|
||||||
"is_ci": false,
|
"is_ci": false,
|
||||||
|
"endpoint": "https://install.determinate.systems/nix/diagnostic",
|
||||||
"ssl_cert_file": null,
|
"ssl_cert_file": null,
|
||||||
"failure_chain": null
|
"failure_chain": null
|
||||||
}
|
}
|
||||||
|
|
6
tests/fixtures/macos/macos.json
vendored
6
tests/fixtures/macos/macos.json
vendored
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"version": "0.17.1",
|
"version": "0.14.0",
|
||||||
"actions": [
|
"actions": [
|
||||||
{
|
{
|
||||||
"action": {
|
"action": {
|
||||||
|
@ -427,6 +427,7 @@
|
||||||
"ssl_cert_file": null,
|
"ssl_cert_file": null,
|
||||||
"extra_conf": [],
|
"extra_conf": [],
|
||||||
"force": false,
|
"force": false,
|
||||||
|
"diagnostic_endpoint": "https://install.determinate.systems/nix/diagnostic"
|
||||||
},
|
},
|
||||||
"encrypt": null,
|
"encrypt": null,
|
||||||
"case_sensitive": false,
|
"case_sensitive": false,
|
||||||
|
@ -434,13 +435,14 @@
|
||||||
"root_disk": "disk3"
|
"root_disk": "disk3"
|
||||||
},
|
},
|
||||||
"diagnostic_data": {
|
"diagnostic_data": {
|
||||||
"version": "0.17.1",
|
"version": "0.14.0",
|
||||||
"planner": "macos",
|
"planner": "macos",
|
||||||
"configured_settings": [],
|
"configured_settings": [],
|
||||||
"os_name": "unknown",
|
"os_name": "unknown",
|
||||||
"os_version": "unknown",
|
"os_version": "unknown",
|
||||||
"triple": "aarch64-apple-darwin",
|
"triple": "aarch64-apple-darwin",
|
||||||
"is_ci": false,
|
"is_ci": false,
|
||||||
|
"endpoint": "https://install.determinate.systems/nix/diagnostic",
|
||||||
"ssl_cert_file": null,
|
"ssl_cert_file": null,
|
||||||
"failure_chain": null
|
"failure_chain": null
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use lix_installer::InstallPlan;
|
use nix_installer::InstallPlan;
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
const LINUX: &str = include_str!("./fixtures/linux/linux.json");
|
const LINUX: &str = include_str!("./fixtures/linux/linux.json");
|
||||||
|
|
|
@ -1,109 +0,0 @@
|
||||||
#! /usr/bin/env nix-shell
|
|
||||||
#! nix-shell -i xonsh -p xonsh awscli2
|
|
||||||
#
|
|
||||||
# vim: ts=4 sw=4 et
|
|
||||||
#
|
|
||||||
# If the shebang line above was necessary, you probably should have used
|
|
||||||
# the flake, instead. But that's okay! You're valid. <3
|
|
||||||
#
|
|
||||||
""" Lix installer uploader.
|
|
||||||
|
|
||||||
Uploads our installers and install script to an S3 instance.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import argparse
|
|
||||||
import functools
|
|
||||||
|
|
||||||
# Specify the platforms we want to build for.
|
|
||||||
TARGET_PLATFORMS = {
|
|
||||||
"aarch64-apple-darwin": "aarch64-darwin",
|
|
||||||
"x86_64-apple-darwin": "x86_64-darwin",
|
|
||||||
"aarch64-unknown-linux-musl": "aarch64-linux",
|
|
||||||
"x86_64-unknown-linux-musl": "x86_64-linux",
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
# Helpers functions.
|
|
||||||
printerr = functools.partial(print, file=sys.stderr)
|
|
||||||
|
|
||||||
#
|
|
||||||
# Arguments -- parsed while you wait!
|
|
||||||
#
|
|
||||||
parser = argparse.ArgumentParser(description="upload a lix-installer binary")
|
|
||||||
parser.add_argument("tag", help="the tag name to use while uploading")
|
|
||||||
parser.add_argument("folder", help="the results folder to use for uploading")
|
|
||||||
parser.add_argument("--make-default", help="makes this version the default for new installations",
|
|
||||||
action="store_true")
|
|
||||||
parser.add_argument("-E", "--endpoint", help="the endpoint URL to use for S3", default="https://s3.lix.systems")
|
|
||||||
parser.add_argument("-R", "--region", help="the region to use for the S3 upload", default="garage")
|
|
||||||
parser.add_argument("-B", "--bucket", help="the s3 bucket to target", default="install")
|
|
||||||
parser.add_argument("--force", help="allows overwriting an existing tag", action="store_true")
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
# Extract our AWS command arguments from our argparse ones.
|
|
||||||
path_for = lambda platform : pf"{args.folder}/lix-installer-{platform}"
|
|
||||||
aws_args = [
|
|
||||||
"--endpoint-url",
|
|
||||||
args.endpoint,
|
|
||||||
"--region",
|
|
||||||
args.region
|
|
||||||
]
|
|
||||||
|
|
||||||
# Validate that we have the environment variables necessary to build.
|
|
||||||
if ('AWS_ACCESS_KEY_ID' not in ${...}) or ('AWS_SECRET_ACCESS_KEY' not in ${...}):
|
|
||||||
printerr("ERROR: the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables must be set")
|
|
||||||
sys.exit(-1)
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# First, make sure we have all of the artifacts that we need before we start.
|
|
||||||
#
|
|
||||||
found_all_files = True
|
|
||||||
for platform in TARGET_PLATFORMS:
|
|
||||||
if not path_for(platform).exists():
|
|
||||||
printerr(f"ERROR: {platform} installer not found in {path_for(platform)}\n")
|
|
||||||
found_all_files = False
|
|
||||||
|
|
||||||
if not found_all_files:
|
|
||||||
printerr("Aborting due to missing results. Perhaps you want to run `build-all.xsh`?\n")
|
|
||||||
sys.exit(-2)
|
|
||||||
|
|
||||||
#
|
|
||||||
# Next, handle our uploads.
|
|
||||||
#
|
|
||||||
tag = args.tag
|
|
||||||
bucket = args.bucket
|
|
||||||
folder = args.folder
|
|
||||||
target_path = f"s3://{bucket}/lix/{tag}"
|
|
||||||
default_path = f"s3://{bucket}/lix"
|
|
||||||
|
|
||||||
# First, check to ensure that the relevant tag does not exist.
|
|
||||||
tag_exists = !(aws s3 @(aws_args) ls @(target_path))
|
|
||||||
if tag_exists:
|
|
||||||
if args.force:
|
|
||||||
printerr(f"WARNING: Overwriting existing tag '{tag}' due to --force!")
|
|
||||||
else:
|
|
||||||
printerr(f"ERROR: Tag '{tag}' already exists! Refusing to overwrite without --force.\n")
|
|
||||||
sys.exit(-3)
|
|
||||||
|
|
||||||
|
|
||||||
# From this point forward, fail if any of our subcommands do.
|
|
||||||
$RAISE_SUBPROC_ERROR=True
|
|
||||||
|
|
||||||
# Copy the core inner pieces...
|
|
||||||
printerr(f"\n>> Uploading tag '{tag}' from folder '{folder}'.")
|
|
||||||
for in_filename, out_filename in TARGET_PLATFORMS.items():
|
|
||||||
aws s3 @(aws_args) cp @(folder)/lix-installer-@(in_filename) @(target_path)/lix-installer-@(out_filename) --acl public-read
|
|
||||||
|
|
||||||
# ... and, if requested, copy the pieces that make this the default.
|
|
||||||
if args.make_default:
|
|
||||||
printerr(f"\n>> Installing {tag} as the default install provider.")
|
|
||||||
for in_filename, out_filename in TARGET_PLATFORMS.items():
|
|
||||||
aws s3 @(aws_args) cp @(folder)/lix-installer-@(in_filename) @(default_path)/lix-installer-@(out_filename) --acl public-read
|
|
||||||
|
|
||||||
printerr(f"\n>> Updating base install script...")
|
|
||||||
aws s3 @(aws_args) cp nix-installer.sh @(default_path) --acl public-read
|
|
||||||
|
|
||||||
# Make sure all of our lines are out.
|
|
||||||
sys.stderr.flush()
|
|
71
upload_s3.sh
Executable file
71
upload_s3.sh
Executable file
|
@ -0,0 +1,71 @@
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
DEST="$1"
|
||||||
|
GIT_ISH="$2"
|
||||||
|
DEST_INSTALL_URL="$3"
|
||||||
|
|
||||||
|
is_tag() {
|
||||||
|
if [[ "$GITHUB_REF_TYPE" == "tag" ]]; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# If the revision directory has already been created in S3 somehow, we don't want to reupload
|
||||||
|
if aws s3 ls "$AWS_BUCKET"/"$GIT_ISH"/; then
|
||||||
|
# Only exit if it's not a tag (since we're tagging a commit previously pushed to main)
|
||||||
|
if ! is_tag; then
|
||||||
|
echo "Revision $GIT_ISH was already uploaded; exiting"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo chown $USER: -R artifacts/
|
||||||
|
|
||||||
|
mkdir "$DEST"
|
||||||
|
mkdir "$GIT_ISH"
|
||||||
|
|
||||||
|
cp nix-installer.sh "$DEST"/
|
||||||
|
cp nix-installer.sh "$GIT_ISH"/
|
||||||
|
|
||||||
|
for artifact in $(find artifacts/ -type f); do
|
||||||
|
chmod +x "$artifact"
|
||||||
|
cp "$artifact" "$DEST"/
|
||||||
|
cp "$artifact" "$GIT_ISH"/
|
||||||
|
done
|
||||||
|
|
||||||
|
sed -i "s@https://install.determinate.systems/nix@$DEST_INSTALL_URL@" "$DEST/nix-installer.sh"
|
||||||
|
sed -i "s@https://install.determinate.systems/nix@https://install.determinate.systems/nix/rev/$GIT_ISH@" "$GIT_ISH/nix-installer.sh"
|
||||||
|
|
||||||
|
if is_tag; then
|
||||||
|
cp "$DEST/nix-installer.sh" ./nix-installer.sh
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If any artifact already exists in S3 and the hash is the same, we don't want to reupload
|
||||||
|
check_reupload() {
|
||||||
|
dest="$1"
|
||||||
|
|
||||||
|
for file in $(find "$dest" -type f); do
|
||||||
|
artifact_path="$dest"/"$(basename "$artifact")"
|
||||||
|
md5="$(md5sum "$artifact" | cut -d' ' -f1)"
|
||||||
|
obj="$(aws s3api head-object --bucket "$AWS_BUCKET" --key "$artifact_path" || echo '{}')"
|
||||||
|
obj_md5="$(jq -r .ETag <<<"$obj" | jq -r)" # head-object call returns ETag quoted, so `jq -r` again to unquote it
|
||||||
|
|
||||||
|
if [[ "$md5" == "$obj_md5" ]]; then
|
||||||
|
echo "Artifact $artifact was already uploaded; exiting"
|
||||||
|
# If we already uploaded to a tag, that's probably bad
|
||||||
|
is_tag && exit 1 || exit 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
check_reupload "$DEST"
|
||||||
|
if ! is_tag; then
|
||||||
|
check_reupload "$GIT_ISH"
|
||||||
|
fi
|
||||||
|
|
||||||
|
aws s3 sync "$DEST"/ s3://"$AWS_BUCKET"/"$DEST"/ --acl public-read
|
||||||
|
if ! is_tag; then
|
||||||
|
aws s3 sync "$GIT_ISH"/ s3://"$AWS_BUCKET"/"$GIT_ISH"/ --acl public-read
|
||||||
|
fi
|
Loading…
Reference in a new issue