Fixup Mac curl $URL | sudo sh -s (#99)

* Fixup Mac curl sh

* We not longer require sudo for the script
This commit is contained in:
Ana Hobden 2022-12-08 08:04:49 -08:00 committed by GitHub
parent 0e4fcd3c3b
commit fe83b35199
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 87 additions and 41 deletions

39
Cargo.lock generated
View file

@ -492,6 +492,16 @@ dependencies = [
"dirs-sys", "dirs-sys",
] ]
[[package]]
name = "dirs-next"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
dependencies = [
"cfg-if",
"dirs-sys-next",
]
[[package]] [[package]]
name = "dirs-sys" name = "dirs-sys"
version = "0.3.7" version = "0.3.7"
@ -503,6 +513,17 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "dirs-sys-next"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
dependencies = [
"libc",
"redox_users",
"winapi",
]
[[package]] [[package]]
name = "dyn-clone" name = "dyn-clone"
version = "1.0.9" version = "1.0.9"
@ -805,6 +826,7 @@ dependencies = [
"sxd-xpath", "sxd-xpath",
"tar", "tar",
"target-lexicon", "target-lexicon",
"term",
"thiserror", "thiserror",
"tokio", "tokio",
"tokio-util", "tokio-util",
@ -1595,6 +1617,12 @@ dependencies = [
"base64", "base64",
] ]
[[package]]
name = "rustversion"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8"
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.11" version = "1.0.11"
@ -1859,6 +1887,17 @@ version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9410d0f6853b1d94f0e519fb95df60f29d2c1eff2d921ffdf01a4c8a3b54f12d" checksum = "9410d0f6853b1d94f0e519fb95df60f29d2c1eff2d921ffdf01a4c8a3b54f12d"
[[package]]
name = "term"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f"
dependencies = [
"dirs-next",
"rustversion",
"winapi",
]
[[package]] [[package]]
name = "termcolor" name = "termcolor"
version = "1.1.3" version = "1.1.3"

View file

@ -57,6 +57,7 @@ typetag = "0.2.3"
dyn-clone = "1.0.9" dyn-clone = "1.0.9"
rand = "0.8.5" rand = "0.8.5"
semver = { version = "1.0.14", features = ["serde"] } semver = { version = "1.0.14", features = ["serde"] }
term = "0.7.0"
[dev-dependencies] [dev-dependencies]
eyre = "0.6.8" eyre = "0.6.8"

View file

@ -7,7 +7,7 @@ Harmonic is an opinionated, experimental Nix installer.
> Try it on a machine/VM you don't care about! > Try it on a machine/VM you don't care about!
> >
> ```bash > ```bash
> curl -L https://install.determinate.systems/nix | sudo sh -s -- install > curl -L https://install.determinate.systems/nix | sh -s -- install
> ``` > ```
## Status ## Status

View file

@ -93,6 +93,11 @@ main() {
exit 1 exit 1
fi fi
local maybe_sudo=""
if [ "$EUID" -ne 0 ] && command -v sudo > /dev/null; then
maybe_sudo="sudo"
fi
if [ "$need_tty" = "yes" ] && [ ! -t 0 ]; then if [ "$need_tty" = "yes" ] && [ ! -t 0 ]; then
# The installer is going to want to ask for confirmation by # The installer is going to want to ask for confirmation by
# reading stdin. This script was piped into `sh` though and # reading stdin. This script was piped into `sh` though and
@ -102,9 +107,9 @@ main() {
err "Unable to run interactively. Run with -y to accept defaults, --help for additional options" err "Unable to run interactively. Run with -y to accept defaults, --help for additional options"
fi fi
ignore "$_file" "$@" < /dev/tty ignore "$maybe_sudo" "$_file" "$@" < /dev/tty
else else
ignore "$_file" "$@" ignore "$maybe_sudo" "$_file" "$@"
fi fi
local _retval=$? local _retval=$?

View file

@ -1,11 +1,18 @@
use std::io::{stdin, stdout, BufRead, Write};
use crossterm::event::{EventStream, KeyCode}; use crossterm::event::{EventStream, KeyCode};
use eyre::{eyre, WrapErr}; use eyre::{eyre, WrapErr};
use futures::{FutureExt, StreamExt}; use futures::{FutureExt, StreamExt};
use owo_colors::OwoColorize; use owo_colors::OwoColorize;
use tokio::io::AsyncWriteExt;
pub(crate) async fn confirm(question: impl AsRef<str>) -> eyre::Result<bool> { // Do not try to get clever!
let mut stdout = tokio::io::stdout(); //
// Mac is extremely janky if you `curl $URL | sudo sh` and the TTY may not be set up right.
// 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 confirm(question: impl AsRef<str>, default: bool) -> eyre::Result<bool> {
let stdout = stdout();
let mut term =
term::terminfo::TerminfoTerminal::new(stdout).ok_or(eyre!("Couldn't get terminal"))?;
let with_confirm = format!( let with_confirm = format!(
"\ "\
{question}\n\ {question}\n\
@ -18,42 +25,31 @@ pub(crate) async fn confirm(question: impl AsRef<str>) -> eyre::Result<bool> {
yes = "y".green(), yes = "y".green(),
); );
stdout.write_all(with_confirm.as_bytes()).await?; term.write_all(with_confirm.as_bytes())?;
stdout.flush().await?; term.flush()?;
// crossterm::terminal::enable_raw_mode()?; let input = read_line()?;
let mut reader = EventStream::new();
let retval = loop { let r = match &*input.to_lowercase() {
let event = reader.next().fuse().await; "y" | "yes" => true,
match event { "n" | "no" => false,
Some(Ok(event)) => { "" => default,
if let crossterm::event::Event::Key(key) = event { _ => false,
match key.code {
KeyCode::Char('y') | KeyCode::Char('Y') => {
stdout
.write_all("Confirmed!\n".green().to_string().as_bytes())
.await?;
stdout.flush().await?;
break Ok(true);
},
KeyCode::Char('N') | KeyCode::Char('n') => {
stdout
.write_all("Cancelled!\n".red().to_string().as_bytes())
.await?;
stdout.flush().await?;
break Ok(false);
},
KeyCode::Enter | _ => continue,
}
}
},
Some(Err(err)) => break Err(err).wrap_err("Getting response"),
None => break Err(eyre!("Bailed, no confirmation event")),
}
}; };
// crossterm::terminal::disable_raw_mode()?;
retval Ok(r)
}
pub(crate) fn read_line() -> eyre::Result<String> {
let stdin = stdin();
let stdin = stdin.lock();
let mut lines = stdin.lines();
let lines = lines.next().transpose()?;
match lines {
None => Err(eyre!("no lines found from stdin")),
Some(v) => Ok(v),
}
.context("unable to read from stdin for confirmation")
} }
pub(crate) async fn clean_exit_with_message(message: impl AsRef<str>) -> ! { pub(crate) async fn clean_exit_with_message(message: impl AsRef<str>) -> ! {

View file

@ -111,6 +111,7 @@ impl CommandExecute for Install {
install_plan install_plan
.describe_install(explain) .describe_install(explain)
.map_err(|e| eyre!(e))?, .map_err(|e| eyre!(e))?,
true,
) )
.await? .await?
{ {
@ -128,6 +129,7 @@ impl CommandExecute for Install {
install_plan install_plan
.describe_uninstall(explain) .describe_uninstall(explain)
.map_err(|e| eyre!(e))?, .map_err(|e| eyre!(e))?,
true,
) )
.await? .await?
{ {

View file

@ -53,8 +53,11 @@ impl CommandExecute for Uninstall {
let mut plan: InstallPlan = serde_json::from_str(&install_receipt_string)?; let mut plan: InstallPlan = serde_json::from_str(&install_receipt_string)?;
if !no_confirm { if !no_confirm {
if !interaction::confirm(plan.describe_uninstall(explain).map_err(|e| eyre!(e))?) if !interaction::confirm(
.await? plan.describe_uninstall(explain).map_err(|e| eyre!(e))?,
true,
)
.await?
{ {
interaction::clean_exit_with_message("Okay, didn't do anything! Bye!").await; interaction::clean_exit_with_message("Okay, didn't do anything! Bye!").await;
} }