Uninstalling from /nix/harmonic works (#100)

* Move binary out of /nix if it is there during uninstall

* Add tracing

* Stick some random bytes on the end of the tmp exe
This commit is contained in:
Ana Hobden 2022-12-09 07:36:44 -08:00 committed by GitHub
parent ac5660b3e0
commit cfded4bb8a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 51 additions and 13 deletions

View file

@ -122,9 +122,7 @@ jobs:
- name: Initial install
run: sudo GITHUB_PATH=$GITHUB_PATH PATH=$PATH:$HOME/bin RUST_LOG=harmonic=trace RUST_BACKTRACE=full ./harmonic install steam-deck --persistence `pwd`/ci-test-nix --extra-conf "access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}" --no-confirm
- name: Initial uninstall (without a `nix run` first)
run: |
cp /nix/harmonic ./harmonic # Since /nix is a mount we must avoid requiring it to remain existing
sudo GITHUB_PATH=$GITHUB_PATH PATH=$PATH:$HOME/bin RUST_LOG=harmonic=trace RUST_BACKTRACE=full ./harmonic uninstall --no-confirm
run: sudo GITHUB_PATH=$GITHUB_PATH PATH=$PATH:$HOME/bin RUST_LOG=harmonic=trace RUST_BACKTRACE=full /nix/harmonic uninstall --no-confirm
- name: Repeated install
run: sudo GITHUB_PATH=$GITHUB_PATH PATH=$PATH:$HOME/bin RUST_LOG=harmonic=trace RUST_BACKTRACE=full ./harmonic install steam-deck --persistence `pwd`/ci-test-nix --extra-conf "access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}" --no-confirm
- name: echo $PATH
@ -150,9 +148,7 @@ jobs:
# if: success() || failure()
# shell: fish --login {0}
- name: Repeated uninstall
run: |
cp /nix/harmonic ./harmonic # Since /nix is a mount we must avoid requiring it to remain existing
sudo GITHUB_PATH=$GITHUB_PATH PATH=$PATH:$HOME/bin RUST_LOG=harmonic=trace RUST_BACKTRACE=full ./harmonic uninstall --no-confirm
run: sudo GITHUB_PATH=$GITHUB_PATH PATH=$PATH:$HOME/bin RUST_LOG=harmonic=trace RUST_BACKTRACE=full /nix/harmonic uninstall --no-confirm
build-x86_64-darwin:
name: Build x86_64 Darwin
@ -187,9 +183,7 @@ jobs:
- name: Initial install
run: sudo GITHUB_PATH=$GITHUB_PATH RUST_LOG=harmonic=trace RUST_BACKTRACE=full ./harmonic install darwin-multi --extra-conf "access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}" --no-confirm
- name: Initial uninstall (without a `nix run` first)
run: |
cp /nix/harmonic ./harmonic # Since /nix is a mount we must avoid requiring it to remain existing
sudo GITHUB_PATH=$GITHUB_PATH RUST_LOG=harmonic=trace RUST_BACKTRACE=full ./harmonic uninstall --no-confirm
run: sudo GITHUB_PATH=$GITHUB_PATH RUST_LOG=harmonic=trace RUST_BACKTRACE=full /nix/harmonic uninstall --no-confirm
- name: Repeated install
run: sudo GITHUB_PATH=$GITHUB_PATH RUST_LOG=harmonic=trace RUST_BACKTRACE=full ./harmonic install darwin-multi --extra-conf "access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}" --no-confirm
- name: echo $PATH
@ -214,7 +208,5 @@ jobs:
if: success() || failure()
shell: fish --login {0}
- name: Repeated uninstall
run: |
cp /nix/harmonic ./harmonic # Since /nix is a mount we must avoid requiring it to remain existing
sudo GITHUB_PATH=$GITHUB_PATH RUST_LOG=harmonic=trace RUST_BACKTRACE=full ./harmonic uninstall --no-confirm
run: sudo GITHUB_PATH=$GITHUB_PATH RUST_LOG=harmonic=trace RUST_BACKTRACE=full /nix/harmonic uninstall --no-confirm

View file

@ -1,4 +1,8 @@
use std::{path::PathBuf, process::ExitCode};
use std::{
ffi::CString,
path::{Path, PathBuf},
process::ExitCode,
};
use crate::{
cli::{is_root, signal_channel},
@ -7,6 +11,7 @@ use crate::{
};
use clap::{ArgAction, Parser};
use eyre::{eyre, WrapErr};
use rand::Rng;
use crate::cli::{interaction, CommandExecute};
@ -47,6 +52,47 @@ impl CommandExecute for Uninstall {
));
}
// During install, `harmonic` will store a copy of itself in `/nix/harmonic`
// If the user opted to run that particular copy of Harmonic to do this uninstall,
// well, we have a problem, since the binary would delete itself.
// Instead, detect if we're in that location, if so, move the binary and `execv` it.
if let Ok(current_exe) = std::env::current_exe() {
if current_exe.as_path() == Path::new("/nix/harmonic") {
tracing::debug!(
"Detected uninstall from `/nix/harmonic`, moving executable and re-executing"
);
let temp = std::env::temp_dir();
let random_trailer: String = {
const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
abcdefghijklmnopqrstuvwxyz\
0123456789";
const PASSWORD_LEN: usize = 16;
let mut rng = rand::thread_rng();
(0..PASSWORD_LEN)
.map(|_| {
let idx = rng.gen_range(0..CHARSET.len());
CHARSET[idx] as char
})
.collect()
};
let temp_exe = temp.join(&format!("harmonic-{random_trailer}"));
tokio::fs::copy(&current_exe, &temp_exe)
.await
.wrap_err("Copying harmonic to tempdir")?;
let args = std::env::args();
let mut arg_vec_cstring = vec![];
for arg in args {
arg_vec_cstring.push(CString::new(arg).wrap_err("Making arg into C string")?);
}
let temp_exe_cstring = CString::new(temp_exe.to_string_lossy().into_owned())
.wrap_err("Making C string of executable path")?;
nix::unistd::execv(&temp_exe_cstring, &arg_vec_cstring)
.wrap_err("Executing copied Harmonic")?;
}
}
let install_receipt_string = tokio::fs::read_to_string(receipt)
.await
.wrap_err("Reading receipt")?;