Merge pull request #307 from alexcrichton/installers
Add an experimental installer for wasm-packmaster
commit
5304a49625
@ -0,0 +1,30 @@ |
|||||||
|
use std::fs; |
||||||
|
|
||||||
|
fn main() { |
||||||
|
fs::create_dir_all("docs/book/installer").unwrap(); |
||||||
|
fs::copy( |
||||||
|
"docs/installer/wasm-pack.js", |
||||||
|
"docs/book/installer/wasm-pack.js", |
||||||
|
).unwrap(); |
||||||
|
let index = fs::read_to_string("docs/installer/index.html").unwrap(); |
||||||
|
fs::write( |
||||||
|
"docs/book/installer/index.html", |
||||||
|
fixup(&index), |
||||||
|
).unwrap(); |
||||||
|
|
||||||
|
let init = fs::read_to_string("docs/installer/init.sh").unwrap(); |
||||||
|
fs::write( |
||||||
|
"docs/book/installer/init.sh", |
||||||
|
fixup(&init), |
||||||
|
).unwrap(); |
||||||
|
} |
||||||
|
|
||||||
|
fn fixup(input: &str) -> String { |
||||||
|
let manifest = fs::read_to_string("Cargo.toml").unwrap(); |
||||||
|
let version = manifest.lines() |
||||||
|
.find(|line| line.starts_with("version =")) |
||||||
|
.unwrap(); |
||||||
|
let version = &version[version.find('"').unwrap() + 1..version.rfind('"').unwrap()]; |
||||||
|
|
||||||
|
input.replace("$VERSION", &format!("v{}", version)) |
||||||
|
} |
@ -0,0 +1,106 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
|
||||||
|
<head> |
||||||
|
<meta charset="utf-8"> |
||||||
|
<title>wasm-pack</title> |
||||||
|
<style> |
||||||
|
body { |
||||||
|
text-align: center; |
||||||
|
margin: 100px; |
||||||
|
font-size: 150%; |
||||||
|
} |
||||||
|
#main { |
||||||
|
padding: 100px; |
||||||
|
} |
||||||
|
.instructions { |
||||||
|
padding: 100px; |
||||||
|
border: 1px solid black; |
||||||
|
} |
||||||
|
.winlink { |
||||||
|
display: block; |
||||||
|
} |
||||||
|
</style> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
|
||||||
|
<div id='main'> |
||||||
|
Install wasm-pack! A tool with a blurb here. |
||||||
|
</div> |
||||||
|
|
||||||
|
<div id="platform-instructions-unix" style="display: none;"> |
||||||
|
<pre>curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh</pre> |
||||||
|
<p> |
||||||
|
You appear to be running Unix. If not, |
||||||
|
<a class="default-platform-button" href="#">display all supported installers</a>. |
||||||
|
</p> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div id="platform-instructions-win64" class="instructions" style="display: none;"> |
||||||
|
<p> |
||||||
|
You appear to be running windows 64-bit, download and run |
||||||
|
<a class='winlink' href="https://github.com/rustwasm/wasm-pack/releases/download/$VERSION/wasm-pack-init.exe">wasm-pack-init.exe</a> |
||||||
|
then follow the onscreen |
||||||
|
instructions. |
||||||
|
</p> |
||||||
|
<hr/> |
||||||
|
<p> |
||||||
|
If you're a Windows Subsystem for Linux user run the following in your |
||||||
|
terminal, then follow the onscreen instructions to install wasm-pack. |
||||||
|
</p> |
||||||
|
<pre>curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh</pre> |
||||||
|
<hr/> |
||||||
|
<p> |
||||||
|
You appear to be running Windows 64-bit. If not, |
||||||
|
<a class="default-platform-button" href="#"> |
||||||
|
display all supported installers |
||||||
|
</a>. |
||||||
|
</p> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div id="platform-instructions-unknown" class="instructions" style="display: none;"> |
||||||
|
<p>I don't recognize your platform.</p> |
||||||
|
<p> |
||||||
|
We would appreciate it if you |
||||||
|
<a href="https://github.com/rustwasm/wasm-pack/issues/new">reported an issue</a>, |
||||||
|
along with the following values: |
||||||
|
</p> |
||||||
|
|
||||||
|
<div> |
||||||
|
<div>navigator.platform:</div> |
||||||
|
<div id="nav-plat"></div> |
||||||
|
<div>navigator.appVersion:</div> |
||||||
|
<div id="nav-app"></div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div id="platform-instructions-default" class="instructions"> |
||||||
|
<div> |
||||||
|
<p> |
||||||
|
To install wasm-pack, if you are running Unix,<br/> |
||||||
|
run the following in your terminal, then follow the onscreen |
||||||
|
instructions. |
||||||
|
</p> |
||||||
|
<pre>curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh</pre> |
||||||
|
</div> |
||||||
|
|
||||||
|
<hr/> |
||||||
|
|
||||||
|
<div> |
||||||
|
<p> |
||||||
|
If you are running Windows 64-bit,<br/>download and run |
||||||
|
<a class='winlink' href="https://github.com/rustwasm/wasm-pack/releases/download/$VERSION/wasm-pack-init.exe">wasm-pack-init.exe</a> |
||||||
|
then follow the onscreen instructions. |
||||||
|
</p> |
||||||
|
</div> |
||||||
|
|
||||||
|
<hr/> |
||||||
|
|
||||||
|
<div> |
||||||
|
<p> |
||||||
|
For all other platforms, run the following in your terminal: |
||||||
|
</p> |
||||||
|
<pre>cargo install wasm-pack</pre> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<script type="text/javascript" src="wasm-pack.js"></script> |
@ -0,0 +1,190 @@ |
|||||||
|
#!/bin/bash |
||||||
|
# Copyright 2016 The Rust Project Developers. See the COPYRIGHT |
||||||
|
# file at the top-level directory of this distribution and at |
||||||
|
# http://rust-lang.org/COPYRIGHT. |
||||||
|
# |
||||||
|
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
||||||
|
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
||||||
|
# option. This file may not be copied, modified, or distributed |
||||||
|
# except according to those terms. |
||||||
|
|
||||||
|
# This is just a little script that can be downloaded from the internet to |
||||||
|
# install wasm-pack. It just does platform detection, downloads the installer |
||||||
|
# and runs it. |
||||||
|
|
||||||
|
set -u |
||||||
|
|
||||||
|
UPDATE_ROOT="https://github.com/rustwasm/wasm-pack/releases/download/$VERSION" |
||||||
|
|
||||||
|
main() { |
||||||
|
downloader --check |
||||||
|
need_cmd uname |
||||||
|
need_cmd mktemp |
||||||
|
need_cmd chmod |
||||||
|
need_cmd mkdir |
||||||
|
need_cmd rm |
||||||
|
need_cmd rmdir |
||||||
|
need_cmd tar |
||||||
|
need_cmd which |
||||||
|
need_cmd dirname |
||||||
|
|
||||||
|
get_architecture || return 1 |
||||||
|
local _arch="$RETVAL" |
||||||
|
assert_nz "$_arch" "arch" |
||||||
|
|
||||||
|
local _ext="" |
||||||
|
case "$_arch" in |
||||||
|
*windows*) |
||||||
|
_ext=".exe" |
||||||
|
;; |
||||||
|
esac |
||||||
|
|
||||||
|
which rustup > /dev/null 2>&1 |
||||||
|
need_ok "failed to find Rust installation, is rustup installed?" |
||||||
|
local _rustup=`which rustup` |
||||||
|
local _tardir="wasm-pack-$VERSION-${_arch}" |
||||||
|
local _url="$UPDATE_ROOT/${_tardir}.tar.gz" |
||||||
|
local _dir="$(mktemp -d 2>/dev/null || ensure mktemp -d -t wasm-pack)" |
||||||
|
local _file="$_dir/input.tar.gz" |
||||||
|
local _wasmpack="$_dir/wasm-pack$_ext" |
||||||
|
local _wasmpackinit="$_dir/wasm-pack-init$_ext" |
||||||
|
|
||||||
|
printf '%s\n' 'info: downloading wasm-pack' 1>&2 |
||||||
|
|
||||||
|
ensure mkdir -p "$_dir" |
||||||
|
downloader "$_url" "$_file" |
||||||
|
if [ $? != 0 ]; then |
||||||
|
say "failed to download $_url" |
||||||
|
say "this may be a standard network error, but it may also indicate" |
||||||
|
say "that wasm-pack's release process is not working. When in doubt" |
||||||
|
say "please feel free to open an issue!" |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
ensure tar xf "$_file" --strip-components 1 -C "$_dir" |
||||||
|
mv "$_wasmpack" "$_wasmpackinit" |
||||||
|
|
||||||
|
# The installer may want to ask for confirmation on stdin for various |
||||||
|
# operations. We were piped through `sh` though so we probably don't have |
||||||
|
# access to a tty naturally. If it looks like we're attached to a terminal |
||||||
|
# (`-t 1`) then pass the tty down to the installer explicitly. |
||||||
|
if [ -t 1 ]; then |
||||||
|
"$_wasmpackinit" "$@" < /dev/tty |
||||||
|
else |
||||||
|
"$_wasmpackinit" "$@" |
||||||
|
fi |
||||||
|
|
||||||
|
local _retval=$? |
||||||
|
|
||||||
|
ignore rm -rf "$_dir" |
||||||
|
|
||||||
|
return "$_retval" |
||||||
|
} |
||||||
|
|
||||||
|
get_architecture() { |
||||||
|
local _ostype="$(uname -s)" |
||||||
|
local _cputype="$(uname -m)" |
||||||
|
|
||||||
|
if [ "$_ostype" = Darwin -a "$_cputype" = i386 ]; then |
||||||
|
# Darwin `uname -s` lies |
||||||
|
if sysctl hw.optional.x86_64 | grep -q ': 1'; then |
||||||
|
local _cputype=x86_64 |
||||||
|
fi |
||||||
|
fi |
||||||
|
|
||||||
|
case "$_ostype" in |
||||||
|
Linux) |
||||||
|
local _ostype=unknown-linux-musl |
||||||
|
;; |
||||||
|
|
||||||
|
Darwin) |
||||||
|
local _ostype=apple-darwin |
||||||
|
;; |
||||||
|
|
||||||
|
MINGW* | MSYS* | CYGWIN*) |
||||||
|
local _ostype=pc-windows-msvc |
||||||
|
;; |
||||||
|
|
||||||
|
*) |
||||||
|
err "no precompiled binaries available for OS: $_ostype" |
||||||
|
;; |
||||||
|
esac |
||||||
|
|
||||||
|
case "$_cputype" in |
||||||
|
x86_64 | x86-64 | x64 | amd64) |
||||||
|
local _cputype=x86_64 |
||||||
|
;; |
||||||
|
*) |
||||||
|
err "no precompiled binaries available for CPU architecture: $_cputype" |
||||||
|
|
||||||
|
esac |
||||||
|
|
||||||
|
local _arch="$_cputype-$_ostype" |
||||||
|
|
||||||
|
RETVAL="$_arch" |
||||||
|
} |
||||||
|
|
||||||
|
say() { |
||||||
|
echo "wasm-pack-init: $1" |
||||||
|
} |
||||||
|
|
||||||
|
err() { |
||||||
|
say "$1" >&2 |
||||||
|
exit 1 |
||||||
|
} |
||||||
|
|
||||||
|
need_cmd() { |
||||||
|
if ! check_cmd "$1" |
||||||
|
then err "need '$1' (command not found)" |
||||||
|
fi |
||||||
|
} |
||||||
|
|
||||||
|
check_cmd() { |
||||||
|
command -v "$1" > /dev/null 2>&1 |
||||||
|
return $? |
||||||
|
} |
||||||
|
|
||||||
|
need_ok() { |
||||||
|
if [ $? != 0 ]; then err "$1"; fi |
||||||
|
} |
||||||
|
|
||||||
|
assert_nz() { |
||||||
|
if [ -z "$1" ]; then err "assert_nz $2"; fi |
||||||
|
} |
||||||
|
|
||||||
|
# Run a command that should never fail. If the command fails execution |
||||||
|
# will immediately terminate with an error showing the failing |
||||||
|
# command. |
||||||
|
ensure() { |
||||||
|
"$@" |
||||||
|
need_ok "command failed: $*" |
||||||
|
} |
||||||
|
|
||||||
|
# This is just for indicating that commands' results are being |
||||||
|
# intentionally ignored. Usually, because it's being executed |
||||||
|
# as part of error handling. |
||||||
|
ignore() { |
||||||
|
"$@" |
||||||
|
} |
||||||
|
|
||||||
|
# This wraps curl or wget. Try curl first, if not installed, |
||||||
|
# use wget instead. |
||||||
|
downloader() { |
||||||
|
if check_cmd curl |
||||||
|
then _dld=curl |
||||||
|
elif check_cmd wget |
||||||
|
then _dld=wget |
||||||
|
else _dld='curl or wget' # to be used in error message of need_cmd |
||||||
|
fi |
||||||
|
|
||||||
|
if [ "$1" = --check ] |
||||||
|
then need_cmd "$_dld" |
||||||
|
elif [ "$_dld" = curl ] |
||||||
|
then curl -sSfL "$1" -o "$2" |
||||||
|
elif [ "$_dld" = wget ] |
||||||
|
then wget "$1" -O "$2" |
||||||
|
else err "Unknown downloader" # should not reach here |
||||||
|
fi |
||||||
|
} |
||||||
|
|
||||||
|
main "$@" || exit 1 |
@ -0,0 +1,92 @@ |
|||||||
|
var platforms = ["default", "unknown", "win64", "unix"]; |
||||||
|
var platform_override = null; |
||||||
|
|
||||||
|
function detect_platform() { |
||||||
|
"use strict"; |
||||||
|
|
||||||
|
if (platform_override !== null) { |
||||||
|
return platforms[platform_override]; |
||||||
|
} |
||||||
|
|
||||||
|
var os = "unknown"; |
||||||
|
|
||||||
|
if (navigator.platform == "Linux x86_64") {os = "unix";} |
||||||
|
if (navigator.platform == "Linux i686") {os = "unix";} |
||||||
|
if (navigator.platform == "Linux i686 on x86_64") {os = "unix";} |
||||||
|
if (navigator.platform == "Linux aarch64") {os = "unix";} |
||||||
|
if (navigator.platform == "Linux armv6l") {os = "unix";} |
||||||
|
if (navigator.platform == "Linux armv7l") {os = "unix";} |
||||||
|
if (navigator.platform == "Linux armv8l") {os = "unix";} |
||||||
|
if (navigator.platform == "Linux ppc64") {os = "unix";} |
||||||
|
if (navigator.platform == "Linux mips") {os = "unix";} |
||||||
|
if (navigator.platform == "Linux mips64") {os = "unix";} |
||||||
|
if (navigator.platform == "Mac") {os = "unix";} |
||||||
|
// if (navigator.platform == "Win32") {os = "win32";}
|
||||||
|
if (navigator.platform == "Win64" || |
||||||
|
navigator.userAgent.indexOf("WOW64") != -1 || |
||||||
|
navigator.userAgent.indexOf("Win64") != -1) { os = "win64"; } |
||||||
|
if (navigator.platform == "FreeBSD x86_64") {os = "unix";} |
||||||
|
if (navigator.platform == "FreeBSD amd64") {os = "unix";} |
||||||
|
if (navigator.platform == "NetBSD x86_64") {os = "unix";} |
||||||
|
if (navigator.platform == "NetBSD amd64") {os = "unix";} |
||||||
|
|
||||||
|
// I wish I knew by now, but I don't. Try harder.
|
||||||
|
if (os == "unknown") { |
||||||
|
// if (navigator.appVersion.indexOf("Win")!=-1) {os = "win32";}
|
||||||
|
if (navigator.appVersion.indexOf("Mac")!=-1) {os = "unix";} |
||||||
|
// rust-www/#692 - FreeBSD epiphany!
|
||||||
|
if (navigator.appVersion.indexOf("FreeBSD")!=-1) {os = "unix";} |
||||||
|
} |
||||||
|
|
||||||
|
// Firefox Quantum likes to hide platform and appVersion but oscpu works
|
||||||
|
if (navigator.oscpu) { |
||||||
|
// if (navigator.oscpu.indexOf("Win32")!=-1) {os = "win32";}
|
||||||
|
if (navigator.oscpu.indexOf("Win64")!=-1) {os = "win64";} |
||||||
|
if (navigator.oscpu.indexOf("Mac")!=-1) {os = "unix";} |
||||||
|
if (navigator.oscpu.indexOf("Linux")!=-1) {os = "unix";} |
||||||
|
if (navigator.oscpu.indexOf("FreeBSD")!=-1) {os = "unix";} |
||||||
|
if (navigator.oscpu.indexOf("NetBSD")!=-1) {os = "unix";} |
||||||
|
} |
||||||
|
|
||||||
|
return os; |
||||||
|
} |
||||||
|
|
||||||
|
function adjust_for_platform() { |
||||||
|
"use strict"; |
||||||
|
|
||||||
|
var platform = detect_platform(); |
||||||
|
|
||||||
|
platforms.forEach(function (platform_elem) { |
||||||
|
var platform_div = document.getElementById("platform-instructions-" + platform_elem); |
||||||
|
platform_div.style.display = "none"; |
||||||
|
if (platform == platform_elem || |
||||||
|
(platform == 'unknown' && platform_elem == 'default')) { |
||||||
|
platform_div.style.display = "block"; |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
function go_to_default_platform() { |
||||||
|
platform_override = 0; |
||||||
|
adjust_for_platform(); |
||||||
|
} |
||||||
|
|
||||||
|
function set_up_default_platform_buttons() { |
||||||
|
var defaults_buttons = document.getElementsByClassName('default-platform-button'); |
||||||
|
for (var i = 0; i < defaults_buttons.length; i++) { |
||||||
|
defaults_buttons[i].onclick = go_to_default_platform; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function fill_in_bug_report_values() { |
||||||
|
var nav_plat = document.getElementById("nav-plat"); |
||||||
|
var nav_app = document.getElementById("nav-app"); |
||||||
|
nav_plat.textContent = navigator.platform; |
||||||
|
nav_app.textContent = navigator.appVersion; |
||||||
|
} |
||||||
|
|
||||||
|
(function () { |
||||||
|
adjust_for_platform(); |
||||||
|
set_up_default_platform_buttons(); |
||||||
|
fill_in_bug_report_values(); |
||||||
|
}()); |
@ -0,0 +1,122 @@ |
|||||||
|
//! Self-installation of `wasm-pack`
|
||||||
|
//!
|
||||||
|
//! This module contains one public function which will self-install the
|
||||||
|
//! currently running executable as `wasm-pack`. Our goal is to install this in
|
||||||
|
//! a place that's already in `PATH`, ideally in an idiomatic location. To that
|
||||||
|
//! end we place `wasm-pack` next to the `rustup` executable in `PATH`.
|
||||||
|
//!
|
||||||
|
//! This installer is run directly (probably by clicking on it) on Windows,
|
||||||
|
//! meaning it will pop up a console (as we're a console app). Output goes to
|
||||||
|
//! the console and users interact with it through the console. On Unix this is
|
||||||
|
//! intended to be run from a shell script (docs/installer/init.sh) which is
|
||||||
|
//! downloaded via curl/sh, and then the shell script downloads this executable
|
||||||
|
//! and runs it.
|
||||||
|
//!
|
||||||
|
//! This may get more complicated over time (self upates anyone?) but for now
|
||||||
|
//! it's pretty simple! We're largely just moving over our currently running
|
||||||
|
//! executable to a different path.
|
||||||
|
|
||||||
|
use std::env; |
||||||
|
use std::fs; |
||||||
|
use std::io; |
||||||
|
use std::path::Path; |
||||||
|
use std::process; |
||||||
|
|
||||||
|
use atty; |
||||||
|
use failure::{Error, ResultExt}; |
||||||
|
use which; |
||||||
|
|
||||||
|
pub fn install() -> ! { |
||||||
|
if let Err(e) = do_install() { |
||||||
|
eprintln!("{}", e); |
||||||
|
for cause in e.iter_causes() { |
||||||
|
eprintln!("Caused by: {}", cause); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// On Windows we likely popped up a console for the installation. If we were
|
||||||
|
// to exit here immediately then the user wouldn't see any error that
|
||||||
|
// happened above or any successful message. Let's wait for them to say
|
||||||
|
// they've read everything and then continue.
|
||||||
|
if cfg!(windows) { |
||||||
|
println!("Press enter to close this window..."); |
||||||
|
let mut line = String::new(); |
||||||
|
drop(io::stdin().read_line(&mut line)); |
||||||
|
} |
||||||
|
|
||||||
|
process::exit(0); |
||||||
|
} |
||||||
|
|
||||||
|
fn do_install() -> Result<(), Error> { |
||||||
|
// Find `rustup.exe` in PATH, we'll be using its installation directory as
|
||||||
|
// our installation directory.
|
||||||
|
let rustup = match which::which("rustup") { |
||||||
|
Ok(path) => path, |
||||||
|
Err(_) => { |
||||||
|
bail!( |
||||||
|
"failed to find an installation of `rustup` in `PATH`, \ |
||||||
|
is rustup already installed?" |
||||||
|
); |
||||||
|
} |
||||||
|
}; |
||||||
|
let installation_dir = match rustup.parent() { |
||||||
|
Some(parent) => parent, |
||||||
|
None => bail!("can't install when `rustup` is at the root of the filesystem"), |
||||||
|
}; |
||||||
|
let destination = installation_dir |
||||||
|
.join("wasm-pack") |
||||||
|
.with_extension(env::consts::EXE_EXTENSION); |
||||||
|
|
||||||
|
if destination.exists() { |
||||||
|
confirm_can_overwrite(&destination)?; |
||||||
|
} |
||||||
|
|
||||||
|
// Our relatively simple install step!
|
||||||
|
let me = env::current_exe()?; |
||||||
|
fs::copy(&me, &destination) |
||||||
|
.with_context(|_| format!("failed to copy executable to `{}`", destination.display()))?; |
||||||
|
println!( |
||||||
|
"info: successfully installed wasm-pack to `{}`", |
||||||
|
destination.display() |
||||||
|
); |
||||||
|
|
||||||
|
// ... and that's it!
|
||||||
|
|
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
|
||||||
|
fn confirm_can_overwrite(dst: &Path) -> Result<(), Error> { |
||||||
|
// If the `-f` argument was passed, we can always overwrite everything.
|
||||||
|
if env::args().any(|arg| arg == "-f") { |
||||||
|
return Ok(()); |
||||||
|
} |
||||||
|
|
||||||
|
// If we're not attached to a TTY then we can't get user input, so there's
|
||||||
|
// nothing to do except inform the user about the `-f` flag.
|
||||||
|
if !atty::is(atty::Stream::Stdin) { |
||||||
|
bail!( |
||||||
|
"existing wasm-pack installation found at `{}`, pass `-f` to \ |
||||||
|
force installation over this file, otherwise aborting \ |
||||||
|
installation now", |
||||||
|
dst.display() |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
// It looks like we're at an interactive prompt, so ask the user if they'd
|
||||||
|
// like to overwrite the previous installation.
|
||||||
|
eprintln!( |
||||||
|
"info: existing wasm-pack installation found at `{}`", |
||||||
|
dst.display() |
||||||
|
); |
||||||
|
eprint!("info: would you like to overwrite this file? [y/N]: "); |
||||||
|
let mut line = String::new(); |
||||||
|
io::stdin() |
||||||
|
.read_line(&mut line) |
||||||
|
.with_context(|_| "failed to read stdin")?; |
||||||
|
|
||||||
|
if line.starts_with("y") || line.starts_with("Y") { |
||||||
|
return Ok(()); |
||||||
|
} |
||||||
|
|
||||||
|
bail!("aborting installation"); |
||||||
|
} |
Loading…
Reference in new issue