BUGFIX: Call nix-store --load-db & add sandboxed Qemu tests (#138)

* Add metadata do Cargo.toml

* Add docs link

* wip

* Get it mostly working

* Handle empty channels, local files, offline mode

* Get them working

* Expand CONTRIBUTING.md

* Expand more

* Correct some formatting/mistypes

* More notes about steps

* Correct speeling

* Improve ubuntu naming

* Add note about specific branch/checkout testing

* Review corrections

* Change match to if
This commit is contained in:
Ana Hobden 2022-12-23 11:07:14 -08:00 committed by GitHub
parent 44b9e623cc
commit 3706bd387a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 588 additions and 36 deletions

View file

@ -74,7 +74,7 @@ Create an issue on [the issue page](https://github.com/DeterminateSystems/nix-in
It should contain:
1. Your OS (Linux, Mac) and architecture (x86_64, aarch64)
2. Your `nix-installer`` version (`nix-installer --version`)
2. Your `nix-installer` version (`nix-installer --version`)
3. The thing you tried to run (eg `nix-installer`)
4. What happened (the output of the command, please)
5. What you expected to happen
@ -107,6 +107,136 @@ Please open an [issue](https://github.com/DeterminateSystems/nix-installer/issue
to chat about your contribution and figure out how to best integrate it into
the project.
# Development
Some snippets or workflows for development.
## Direnv support
While `nix develop` should work perfectly fine for development, contributors may prefer to enable [`direnv`](https://direnv.net/) or [`nix-direnv`](https://github.com/nix-community/nix-direnv) support.
From the project folder:
```bash
direnv allow
```
If using an editor, it may be preferable to adopt an addon to enter the environment:
* [`vim`](https://github.com/direnv/direnv.vim)
* [VSCode](https://marketplace.visualstudio.com/items?itemName=mkhl.direnv)
## Testing Installs
If you're hacking on `nix-installer`, you likely already have Nix and cannot test locally.
> That's probably a good thing! You should test in a sandbox.
Automated [`qemu` tests][#qemu-vm-tests] exist and should be preferred for oneshot testing of changes.
For interactive testing, tools like [`libvirt`](https://libvirt.org/) via [`virt-manager`](https://virt-manager.org/) or [`vagrant`](https://www.vagrantup.com/) can be used to spin up machines and run experiments.
When running such interactive tests, consider creating a snapshot of the VM right before running the installer, so you can quickly roll back if something happens.
In general, it's a good idea to test on the closest you can get to the desired target environment. For example, when testing the Steam Deck planner it's a good idea to run that test in a Steam Deck VM as described in detail in the planner.
<details>
<summary><strong>Adding a planner for specific hardware?</strong></summary>
Please include an full guide on how to create the best known virtual testing environment for that device.
**A link is not sufficient, it may break.** Please provide a full summary of steps to take, link to any original source and give them credit if it is appropriate.
It's perfectly fine if they are manual or labor intensive, as these should be a one time thing and get snapshotted prior to running tests.
</details>
## `qemu` VM tests
In `nix/tests/vm-test` there exists some Nix derivations which we expose in the flake via `hydraJobs`.
These should be visible in `nix flake show`:
```
nix flake show
warning: Git tree '/home/ana/git/determinatesystems/nix-installer' is dirty
git+file:///home/ana/git/determinatesystems/nix-installer
# ...
├───hydraJobs
│ └───vm-test
│ ├───all
│ │ └───x86_64-linux
│ │ └───install-default: derivation 'all'
│ ├───fedora-v36
│ │ └───x86_64-linux
│ │ └───install-default: derivation 'installer-test-fedora-v36-install-default'
│ ├───rhel-v7
│ │ └───x86_64-linux
│ │ └───install-default: derivation 'installer-test-rhel-v7-install-default'
│ ├───rhel-v8
│ │ └───x86_64-linux
│ │ └───install-default: derivation 'installer-test-rhel-v8-install-default'
│ ├───rhel-v9
│ │ └───x86_64-linux
│ │ └───install-default: derivation 'installer-test-rhel-v9-install-default'
│ └───ubuntu-v22_04
│ └───x86_64-linux
│ └───install-default: derivation 'installer-test-ubuntu-v22_04-install-default'
```
To run all of the currently supported tests:
```bash
nix build .#hydraJobs.vm-test.all.x86_64-linux.install-default -L
```
To run a specific distribution listed in the `nix flake show` output:
```bash
nix build .#hydraJobs.vm-test.rhel-v7.x86_64-linux.install-default -L
```
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>
<summary><strong>Adding a distro?</strong></summary>
Notice how `rhel-v7` has a `v7`, not just `7`? That's so the test output shows correctly, as Nix will interpret the first `-\d` (eg `-7`, `-123213`) as a version, and not show it in the output.
Using `v7` instead turns:
```
# ...
installer-test-rhel> Unpacking Vagrant box /nix/store/8maga4w267f77agb93inbg54whh5lxhn-libvirt.box...
installer-test-rhel> Vagrantfile
installer-test-rhel> box.img
installer-test-rhel> info.json
installer-test-rhel> metadata.json
installer-test-rhel> Formatting './disk.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=137438953472 backing_file=./box.img backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
# ...
```
Into this:
```
# ...
installer-test-rhel-v7-install-default> Unpacking Vagrant box /nix/store/8maga4w267f77agb93inbg54whh5lxhn-libvirt.box...
installer-test-rhel-v7-install-default> Vagrantfile
installer-test-rhel-v7-install-default> box.img
installer-test-rhel-v7-install-default> info.json
installer-test-rhel-v7-install-default> metadata.json
installer-test-rhel-v7-install-default> Formatting './disk.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=137438953472 backing_file=./box.img backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
# ...
```
</details>
# Who maintains `nix-installer` and why?

View file

@ -21,6 +21,22 @@
"type": "github"
}
},
"lowdown-src": {
"flake": false,
"locked": {
"lastModified": 1633514407,
"narHash": "sha256-Dw32tiMjdK9t3ETl5fzGrutQTzh2rufgZV4A/BbxuD4=",
"owner": "kristapsdz",
"repo": "lowdown",
"rev": "d2c2b44ff6c27b936ec27358a2653caaef8f73b8",
"type": "github"
},
"original": {
"owner": "kristapsdz",
"repo": "lowdown",
"type": "github"
}
},
"naersk": {
"inputs": {
"nixpkgs": [
@ -41,6 +57,28 @@
"type": "github"
}
},
"nix": {
"inputs": {
"lowdown-src": "lowdown-src",
"nixpkgs": [
"nixpkgs"
],
"nixpkgs-regression": "nixpkgs-regression"
},
"locked": {
"lastModified": 1671624594,
"narHash": "sha256-OOPFRuEGzLRIaMHw93fFlqVTT+vAwlOWQut/emCnJgc=",
"owner": "nixos",
"repo": "nix",
"rev": "b1223e1b621ed4ad11562f0ef65c65d1c78c5e4b",
"type": "github"
},
"original": {
"owner": "nixos",
"repo": "nix",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1671323474,
@ -57,10 +95,27 @@
"type": "github"
}
},
"nixpkgs-regression": {
"locked": {
"lastModified": 1643052045,
"narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
"type": "github"
}
},
"root": {
"inputs": {
"fenix": "fenix",
"naersk": "naersk",
"nix": "nix",
"nixpkgs": "nixpkgs"
}
},

View file

@ -13,6 +13,12 @@
url = "github:nix-community/naersk";
inputs.nixpkgs.follows = "nixpkgs";
};
nix = {
url = "github:nixos/nix";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs =
@ -20,16 +26,19 @@
, nixpkgs
, fenix
, naersk
, nix
, ...
} @ inputs:
let
supportedSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
forAllSystems = f: nixpkgs.lib.genAttrs supportedSystems (system: f rec {
forAllSystems = f: nixpkgs.lib.genAttrs supportedSystems (system: (forSystem system f));
forSystem = system: f: f rec {
inherit system;
pkgs = import nixpkgs { inherit system; overlays = [ self.overlays.default ]; };
lib = pkgs.lib;
});
};
fenixToolchain = system: with fenix.packages.${system};
combine ([
@ -55,7 +64,11 @@
sharedAttrs = {
pname = "nix-installer";
version = "0.0.0-unreleased";
src = self;
src = builtins.path {
name = "nix-installer-source";
path = self;
filter = (path: type: baseNameOf path != "nix" || baseNameOf path != ".github");
};
nativeBuildInputs = with final; [ ];
buildInputs = with final; [ ] ++ lib.optionals (final.stdenv.isDarwin) (with final.darwin.apple_sdk.frameworks; [
@ -163,5 +176,12 @@
} // nixpkgs.lib.optionalAttrs (pkgs.stdenv.isDarwin) {
default = pkgs.nix-installer;
});
hydraJobs = {
vm-test = import ./nix/tests/vm-test {
inherit forSystem;
inherit (nix.hydraJobs) binaryTarball;
};
};
};
}

View file

@ -0,0 +1,222 @@
# Largely derived from https://github.com/NixOS/nix/blob/14f7dae3e4eb0c34192d0077383a7f2a2d630129/tests/installer/default.nix
{ forSystem, binaryTarball }:
let
installScripts = {
install-default = {
script = ''
NIX_PATH=$(readlink -f nix.tar.xz)
RUST_BACKTRACE="full" ./nix-installer install --logger pretty --log-directive nix_installer=trace --channel --nix-package-url "file://$NIX_PATH" --no-confirm
'';
};
};
disableSELinux = "sudo setenforce 0";
images = {
# End of standard support https://wiki.ubuntu.com/Releases
/*
"ubuntu-v14_04" = {
image = import <nix/fetchurl.nix> {
url = "https://app.vagrantup.com/ubuntu/boxes/trusty64/versions/20190514.0.0/providers/virtualbox.box";
hash = "sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8=";
};
rootDisk = "box-disk1.vmdk";
system = "x86_64-linux";
};
*/
# End of standard support https://wiki.ubuntu.com/Releases
/* "ubuntu-v16_04" = {
image = import <nix/fetchurl.nix> {
url = "https://app.vagrantup.com/generic/boxes/ubuntu1604/versions/4.1.12/providers/libvirt.box";
hash = "sha256-lO4oYQR2tCh5auxAYe6bPOgEqOgv3Y3GC1QM1tEEEU8=";
};
rootDisk = "box.img";
system = "x86_64-linux";
};
*/
"ubuntu-v22_04" = {
image = import <nix/fetchurl.nix> {
url = "https://app.vagrantup.com/generic/boxes/ubuntu2204/versions/4.1.12/providers/libvirt.box";
hash = "sha256-HNll0Qikw/xGIcogni5lz01vUv+R3o8xowP2EtqjuUQ=";
};
rootDisk = "box.img";
system = "x86_64-linux";
};
"fedora-v36" = {
image = import <nix/fetchurl.nix> {
url = "https://app.vagrantup.com/generic/boxes/fedora36/versions/4.1.12/providers/libvirt.box";
hash = "sha256-rxPgnDnFkTDwvdqn2CV3ZUo3re9AdPtSZ9SvOHNvaks=";
};
rootDisk = "box.img";
system = "x86_64-linux";
postBoot = disableSELinux;
};
# Currently fails with 'error while loading shared libraries:
# libsodium.so.23: cannot stat shared object: Invalid argument'.
/*
"rhel-v6" = {
image = import <nix/fetchurl.nix> {
url = "https://app.vagrantup.com/generic/boxes/rhel6/versions/4.1.12/providers/libvirt.box";
hash = "sha256-QwzbvRoRRGqUCQptM7X/InRWFSP2sqwRt2HaaO6zBGM=";
};
rootDisk = "box.img";
system = "x86_64-linux";
};
*/
"rhel-v7" = {
image = import <nix/fetchurl.nix> {
url = "https://app.vagrantup.com/generic/boxes/rhel7/versions/4.1.12/providers/libvirt.box";
hash = "sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U=";
};
rootDisk = "box.img";
postBoot = disableSELinux;
system = "x86_64-linux";
};
"rhel-v8" = {
image = import <nix/fetchurl.nix> {
url = "https://app.vagrantup.com/generic/boxes/rhel8/versions/4.1.12/providers/libvirt.box";
hash = "sha256-zFOPjSputy1dPgrQRixBXmlyN88cAKjJ21VvjSWUCUY=";
};
rootDisk = "box.img";
system = "x86_64-linux";
postBoot = disableSELinux;
};
"rhel-v9" = {
image = import <nix/fetchurl.nix> {
url = "https://app.vagrantup.com/generic/boxes/rhel9/versions/4.1.12/providers/libvirt.box";
hash = "sha256-vL/FbB3kK1rcSaR627nWmScYGKGk4seSmAdq6N5diMg=";
};
rootDisk = "box.img";
system = "x86_64-linux";
postBoot = disableSELinux;
extraQemuOpts = "-cpu Westmere-v2";
};
};
makeTest = imageName: testName:
let image = images.${imageName}; in
with (forSystem image.system ({ system, pkgs, ... }: pkgs));
runCommand
"installer-test-${imageName}-${testName}"
{
buildInputs = [ qemu_kvm openssh ];
image = image.image;
postBoot = image.postBoot or "";
installScript = installScripts.${testName}.script;
installer = nix-installer-static;
binaryTarball = binaryTarball.${system};
}
''
shopt -s nullglob
echo "Unpacking Vagrant box $image..."
tar xvf $image
image_type=$(qemu-img info ${image.rootDisk} | sed 's/file format: \(.*\)/\1/; t; d')
qemu-img create -b ./${image.rootDisk} -F "$image_type" -f qcow2 ./disk.qcow2
extra_qemu_opts="${image.extraQemuOpts or ""}"
# Add the config disk, required by the Ubuntu images.
config_drive=$(echo *configdrive.vmdk || true)
if [[ -n $config_drive ]]; then
extra_qemu_opts+=" -drive id=disk2,file=$config_drive,if=virtio"
fi
echo "Starting qemu..."
qemu-kvm -m 4096 -nographic \
-drive id=disk1,file=./disk.qcow2,if=virtio \
-netdev user,id=net0,restrict=yes,hostfwd=tcp::20022-:22 -device virtio-net-pci,netdev=net0 \
$extra_qemu_opts &
qemu_pid=$!
trap "kill $qemu_pid" EXIT
if ! [ -e ./vagrant_insecure_key ]; then
cp ${./vagrant_insecure_key} vagrant_insecure_key
fi
chmod 0400 ./vagrant_insecure_key
ssh_opts="-o StrictHostKeyChecking=no -o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa -i ./vagrant_insecure_key"
ssh="ssh -p 20022 -q $ssh_opts vagrant@localhost"
echo "Waiting for SSH..."
for ((i = 0; i < 120; i++)); do
echo "[ssh] Trying to connect..."
if $ssh -- true; then
echo "[ssh] Connected!"
break
fi
if ! kill -0 $qemu_pid; then
echo "qemu died unexpectedly"
exit 1
fi
sleep 1
done
if [[ -n $postBoot ]]; then
echo "Running post-boot commands..."
$ssh "set -ex; $postBoot"
fi
echo "Copying installer..."
scp -P 20022 $ssh_opts $installer/bin/nix-installer vagrant@localhost:nix-installer
echo "Copying nix tarball..."
scp -P 20022 $ssh_opts $binaryTarball/nix-*.tar.xz vagrant@localhost:nix.tar.xz
echo "Running installer..."
$ssh "set -eux; $installScript"
echo "Testing Nix installation..."
$ssh <<EOF
set -ex
# FIXME: get rid of this; ideally ssh should just work.
source ~/.bash_profile || true
source ~/.bash_login || true
source ~/.profile || true
source /etc/bashrc || true
nix-env --version
nix --extra-experimental-features nix-command store ping
out=\$(nix-build --no-substitute -E 'derivation { name = "foo"; system = "x86_64-linux"; builder = "/bin/sh"; args = ["-c" "echo foobar > \$out"]; }')
[[ \$(cat \$out) = foobar ]]
EOF
echo "Done!"
touch $out
'';
vm-tests = builtins.mapAttrs
(imageName: image:
{
${image.system} = builtins.mapAttrs
(testName: test:
makeTest imageName testName
)
installScripts;
}
)
images;
in
vm-tests // {
all."x86_64-linux".install-default = (with (forSystem "x86_64-linux" ({ system, pkgs, ... }: pkgs)); pkgs.releaseTools.aggregate {
name = "all";
constituents = pkgs.lib.mapAttrsToList (name: value: value."x86_64-linux".install-default) vm-tests;
});
}

View file

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzI
w+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoP
kcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2
hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NO
Td0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcW
yLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQIBIwKCAQEA4iqWPJXtzZA68mKd
ELs4jJsdyky+ewdZeNds5tjcnHU5zUYE25K+ffJED9qUWICcLZDc81TGWjHyAqD1
Bw7XpgUwFgeUJwUlzQurAv+/ySnxiwuaGJfhFM1CaQHzfXphgVml+fZUvnJUTvzf
TK2Lg6EdbUE9TarUlBf/xPfuEhMSlIE5keb/Zz3/LUlRg8yDqz5w+QWVJ4utnKnK
iqwZN0mwpwU7YSyJhlT4YV1F3n4YjLswM5wJs2oqm0jssQu/BT0tyEXNDYBLEF4A
sClaWuSJ2kjq7KhrrYXzagqhnSei9ODYFShJu8UWVec3Ihb5ZXlzO6vdNQ1J9Xsf
4m+2ywKBgQD6qFxx/Rv9CNN96l/4rb14HKirC2o/orApiHmHDsURs5rUKDx0f9iP
cXN7S1uePXuJRK/5hsubaOCx3Owd2u9gD6Oq0CsMkE4CUSiJcYrMANtx54cGH7Rk
EjFZxK8xAv1ldELEyxrFqkbE4BKd8QOt414qjvTGyAK+OLD3M2QdCQKBgQDtx8pN
CAxR7yhHbIWT1AH66+XWN8bXq7l3RO/ukeaci98JfkbkxURZhtxV/HHuvUhnPLdX
3TwygPBYZFNo4pzVEhzWoTtnEtrFueKxyc3+LjZpuo+mBlQ6ORtfgkr9gBVphXZG
YEzkCD3lVdl8L4cw9BVpKrJCs1c5taGjDgdInQKBgHm/fVvv96bJxc9x1tffXAcj
3OVdUN0UgXNCSaf/3A/phbeBQe9xS+3mpc4r6qvx+iy69mNBeNZ0xOitIjpjBo2+
dBEjSBwLk5q5tJqHmy/jKMJL4n9ROlx93XS+njxgibTvU6Fp9w+NOFD/HvxB3Tcz
6+jJF85D5BNAG3DBMKBjAoGBAOAxZvgsKN+JuENXsST7F89Tck2iTcQIT8g5rwWC
P9Vt74yboe2kDT531w8+egz7nAmRBKNM751U/95P9t88EDacDI/Z2OwnuFQHCPDF
llYOUI+SpLJ6/vURRbHSnnn8a/XG+nzedGH5JGqEJNQsz+xT2axM0/W/CRknmGaJ
kda/AoGANWrLCz708y7VYgAtW2Uf1DPOIYMdvo6fxIB5i9ZfISgcJ/bbCUkFrhoH
+vq/5CIWxCPp0f85R4qxxQ5ihxJ0YDQT9Jpx4TMss4PSavPaBH3RXow5Ohe+bYoQ
NE5OgEXk2wVfZczCZpigBKbKZHNYcelXtTt/nP3rsCuGcM4h53s=
-----END RSA PRIVATE KEY-----

View file

@ -1,6 +1,6 @@
use std::path::PathBuf;
use bytes::Buf;
use bytes::{Buf, Bytes};
use reqwest::Url;
use tracing::{span, Span};
@ -21,6 +21,15 @@ impl FetchAndUnpackNix {
// TODO(@hoverbear): Check URL exists?
// TODO(@hoverbear): Check tempdir exists
match url.scheme() {
"https" | "http" | "file" => (),
_ => {
return Err(ActionError::Custom(Box::new(
FetchUrlError::UnknownUrlScheme,
)))
},
};
Ok(Self { url, dest }.into())
}
}
@ -49,13 +58,28 @@ impl Action for FetchAndUnpackNix {
async fn execute(&mut self) -> Result<(), ActionError> {
let Self { url, dest } = self;
let bytes = match url.scheme() {
"https" | "http" => {
let res = reqwest::get(url.clone())
.await
.map_err(|e| ActionError::Custom(Box::new(FetchUrlError::Reqwest(e))))?;
let bytes = res
.bytes()
res.bytes()
.await
.map_err(|e| ActionError::Custom(Box::new(FetchUrlError::Reqwest(e))))?;
.map_err(|e| ActionError::Custom(Box::new(FetchUrlError::Reqwest(e))))?
},
"file" => {
let buf = tokio::fs::read(url.path())
.await
.map_err(|e| ActionError::Read(PathBuf::from(url.path()), e))?;
Bytes::from(buf)
},
_ => {
return Err(ActionError::Custom(Box::new(
FetchUrlError::UnknownUrlScheme,
)))
},
};
// TODO(@Hoverbear): Pick directory
tracing::trace!("Unpacking tar.xz");
let dest_clone = dest.clone();
@ -91,4 +115,6 @@ pub enum FetchUrlError {
),
#[error("Unarchiving error")]
Unarchive(#[source] std::io::Error),
#[error("Unknown url scheme")]
UnknownUrlScheme,
}

View file

@ -4,7 +4,7 @@ use tracing::{span, Span};
use crate::action::{Action, ActionDescription, ActionError, StatefulAction};
const DEST: &str = "/nix/store";
pub(crate) const DEST: &str = "/nix/";
/**
Move an unpacked Nix at `src` to `/nix`
@ -64,15 +64,23 @@ impl Action for MoveUnpackedNix {
);
let found_nix_path = found_nix_paths.into_iter().next().unwrap();
let src_store = found_nix_path.join("store");
let dest = Path::new(DEST);
let dest = Path::new(DEST).join("store");
tracing::trace!(src = %src_store.display(), dest = %dest.display(), "Renaming");
tokio::fs::rename(src_store.clone(), dest)
tokio::fs::rename(&src_store, &dest)
.await
.map_err(|e| ActionError::Rename(src_store.clone(), dest.to_owned(), e))?;
tokio::fs::remove_dir_all(src)
let src_reginfo = found_nix_path.join(".reginfo");
// Move_unpacked_nix expects it here
let dest_reginfo = Path::new(DEST).join(".reginfo");
tokio::fs::rename(&src_reginfo, &dest_reginfo)
.await
.map_err(|e| ActionError::Rename(src_store, dest.to_owned(), e))?;
.map_err(|e| ActionError::Rename(src_reginfo.clone(), dest_reginfo.to_owned(), e))?;
tokio::fs::remove_dir_all(&src)
.await
.map_err(|e| ActionError::Remove(src.clone(), e))?;
Ok(())
}

View file

@ -1,3 +1,5 @@
use std::path::{Path, PathBuf};
use crate::{
action::{ActionError, StatefulAction},
execute_command, set_env,
@ -5,7 +7,7 @@ use crate::{
use glob::glob;
use tokio::process::Command;
use tokio::{io::AsyncWriteExt, process::Command};
use tracing::{span, Span};
use crate::action::{Action, ActionDescription};
@ -94,12 +96,87 @@ impl Action for SetupDefaultProfile {
)));
};
{
let reginfo_path =
Path::new(crate::action::base::move_unpacked_nix::DEST).join(".reginfo");
let reginfo = tokio::fs::read(&reginfo_path)
.await
.map_err(|e| ActionError::Read(reginfo_path.to_path_buf(), e))?;
let mut load_db_command = Command::new(nix_pkg.join("bin/nix-store"));
load_db_command.process_group(0);
load_db_command.arg("--load-db");
load_db_command.stdin(std::process::Stdio::piped());
load_db_command.env(
"HOME",
dirs::home_dir().ok_or_else(|| {
ActionError::Custom(Box::new(SetupDefaultProfileError::NoRootHome))
})?,
);
let load_db_command_str = format!("{:?}", load_db_command.as_std());
tracing::trace!(
"Executing `{load_db_command_str}` with stdin from `{}`",
reginfo_path.display()
);
let mut handle = load_db_command
.spawn()
.map_err(|e| ActionError::Command(e))?;
let mut stdin = handle.stdin.take().unwrap();
stdin
.write_all(&reginfo)
.await
.map_err(|e| ActionError::Write(PathBuf::from("/dev/stdin"), e))?;
stdin
.flush()
.await
.map_err(|e| ActionError::Write(PathBuf::from("/dev/stdin"), e))?;
drop(stdin);
tracing::trace!(
"Wrote `{}` to stdin of `nix-store --load-db`",
reginfo_path.display()
);
let output = handle
.wait_with_output()
.await
.map_err(ActionError::Command)?;
if !output.status.success() {
return Err(ActionError::Command(std::io::Error::new(
std::io::ErrorKind::Other,
format!(
"Command `{load_db_command_str}` failed status, stderr:\n{}\n",
String::from_utf8(output.stderr)
.unwrap_or_else(|_e| String::from("<Non-UTF-8>"))
),
)));
};
}
// Install `nix` itself into the store
execute_command(
Command::new(nix_pkg.join("bin/nix-env"))
.process_group(0)
.arg("-i")
.arg(&nix_pkg)
.stdin(std::process::Stdio::null())
.env(
"HOME",
dirs::home_dir().ok_or_else(|| {
ActionError::Custom(Box::new(SetupDefaultProfileError::NoRootHome))
})?,
)
.env(
"NIX_SSL_CERT_FILE",
nss_ca_cert_pkg.join("etc/ssl/certs/ca-bundle.crt"),
), /* This is apparently load bearing... */
)
.await
.map_err(|e| ActionError::Command(e))?;
// Install `nix` itself into the store
execute_command(
Command::new(nix_pkg.join("bin/nix-env"))
.process_group(0)
.arg("-i")
.arg(&nss_ca_cert_pkg)
.stdin(std::process::Stdio::null())
@ -117,19 +194,6 @@ impl Action for SetupDefaultProfile {
.await
.map_err(|e| ActionError::Command(e))?;
// Install `nss-cacert` into the store
// execute_command(
// Command::new(nix_pkg.join("bin/nix-env"))
// .arg("-i")
// .arg(&nss_ca_cert_pkg)
// .env(
// "NIX_SSL_CERT_FILE",
// nss_ca_cert_pkg.join("etc/ssl/certs/ca-bundle.crt"),
// ),
// )
// .await
// .map_err(|e| SetupDefaultProfileError::Command(e).boxed())?;
set_env(
"NIX_SSL_CERT_FILE",
"/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt",

View file

@ -290,7 +290,7 @@ pub enum ActionError {
std::path::PathBuf,
#[source] std::io::Error,
),
#[error("Remove path `{0}`")]
#[error("Read path `{0}`")]
Read(std::path::PathBuf, #[source] std::io::Error),
#[error("Open path `{0}`")]
Open(std::path::PathBuf, #[source] std::io::Error),

View file

@ -40,7 +40,7 @@ impl clap::builder::TypedValueParser for ChannelValueParser {
let (name, url) = buf.split_once('=').ok_or_else(|| {
clap::Error::raw(
clap::error::ErrorKind::InvalidValue,
"Should be formatted `name=url`",
"`--channel` should be formatted `name=url`, eg `--channel nixpkgs=https://nixos.org/channels/nixpkgs-unstable`. To not use a channel, pass `--channel`",
)
})?;
let name = name.to_owned();

View file

@ -30,13 +30,13 @@ Settings which only apply to certain [`Planner`](crate::planner::Planner)s shoul
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
#[cfg_attr(feature = "cli", derive(clap::Parser))]
pub struct CommonSettings {
/// Channel(s) to add
/// Channel(s) to add, for no default channel, pass `--channel`
#[cfg_attr(
feature = "cli",
clap(
long,
value_parser,
name = "channel",
long = "channel",
num_args = 0..,
action = clap::ArgAction::Append,
env = "NIX_INSTALLER_CHANNELS",
default_value = "nixpkgs=https://nixos.org/channels/nixpkgs-unstable",