mirror of
https://github.com/oh-my-fish/oh-my-fish.git
synced 2024-11-22 15:35:43 +08:00
659 lines
19 KiB
Fish
Executable File
659 lines
19 KiB
Fish
Executable File
#!/usr/bin/env fish
|
|
# Oh My Fish installer. See `install --help` for usage.
|
|
|
|
# Set environment options.
|
|
set -q OMF_REPO_URI; or set OMF_REPO_URI "https://github.com/oh-my-fish/oh-my-fish"
|
|
set -q OMF_REPO_BRANCH; or set OMF_REPO_BRANCH "master"
|
|
|
|
|
|
function main
|
|
# Set default settings
|
|
set -q XDG_DATA_HOME
|
|
and set -g OMF_PATH_DEFAULT "$XDG_DATA_HOME/omf"
|
|
or set -g OMF_PATH_DEFAULT "$HOME/.local/share/omf"
|
|
|
|
set -q XDG_CONFIG_HOME
|
|
and set -g CONFIG_PATH "$XDG_CONFIG_HOME"
|
|
or set -g CONFIG_PATH "$HOME/.config"
|
|
|
|
set -g OMF_CONFIG_DEFAULT "$CONFIG_PATH/omf"
|
|
set -g FISH_CONFIG "$CONFIG_PATH/fish"
|
|
|
|
set -g OMF_PATH "$OMF_PATH_DEFAULT"
|
|
set -g OMF_CONFIG "$OMF_CONFIG_DEFAULT"
|
|
set -g OMF_CHANNEL stable
|
|
|
|
# Ensure repository URL ends with .git
|
|
set OMF_REPO_URI (echo $OMF_REPO_URI | command sed 's/\.git//').git
|
|
|
|
# Parse command args
|
|
while set -q argv[1]
|
|
switch "$argv[1]"
|
|
case --help -h '/?'
|
|
echo "Usage: install [options]
|
|
Install Oh My Fish
|
|
|
|
Options:
|
|
--channel=<channel> Download a specific release channel, either \"stable\" or \"dev\" (default is \"$OMF_CHANNEL\").
|
|
--check Do a system readiness check without installing.
|
|
--config=<path> Put config in a specific path (default is $OMF_CONFIG_DEFAULT).
|
|
--help, -h Show this help message.
|
|
--noninteractive Disable interactive questions (assume no, use with --yes to assume yes).
|
|
--offline[=<path>] Offline install, optionally specifying a tar or directory to use.
|
|
--path=<path> Use a specific install path (default is $OMF_PATH_DEFAULT).
|
|
--uninstall Uninstall existing installation instead of installing.
|
|
--verbose Enable verbose debugging statements for the installer.
|
|
--yes, -y Assume yes for interactive questions.
|
|
"
|
|
return 0
|
|
|
|
case '--channel=stable'
|
|
set -g OMF_CHANNEL stable
|
|
|
|
case '--channel=dev'
|
|
set -g OMF_CHANNEL dev
|
|
|
|
case '--channel=*'
|
|
abort "Unknown release channel \""(echo "$argv[1]" | command cut -d= -f2)"\"."
|
|
|
|
case --check
|
|
set -g CHECK_ONLY
|
|
|
|
case '--config=*'
|
|
echo "$argv[1]" | command cut -d= -f2 | command sed -e "s#~#$HOME#" | read -g OMF_CONFIG
|
|
|
|
case --noninteractive
|
|
set -g NONINTERACTIVE
|
|
|
|
case --offline
|
|
set -g OFFLINE
|
|
|
|
case '--offline=*'
|
|
set -g OFFLINE
|
|
echo "$argv[1]" | command cut -d= -f2 | command sed -e "s#~#$HOME#" | read -g OFFLINE_PATH
|
|
|
|
case '--path=*'
|
|
echo "$argv[1]" | command cut -d= -f2 | command sed -e "s#~#$HOME#" | read -g OMF_PATH
|
|
|
|
case --uninstall
|
|
set -g UNINSTALL
|
|
|
|
case --verbose
|
|
set -g VERBOSE
|
|
debug "verbose turned on"
|
|
|
|
case --yes -y
|
|
set -g ASSUME_YES
|
|
|
|
case '*'
|
|
abort "Unrecognized option '$argv[1]'. Try 'install --help' for usage."
|
|
end
|
|
set -e argv[1]
|
|
end
|
|
|
|
# Do the check only.
|
|
if set -q CHECK_ONLY
|
|
sane_environment_check
|
|
return
|
|
end
|
|
|
|
assert_interactive
|
|
|
|
# Ensure the environment meets all of the requirements.
|
|
if not sane_environment_check
|
|
abort "Environment does not meet the requirements."
|
|
end
|
|
|
|
# If the user wants to uninstall, jump to uninstallation and exit.
|
|
if set -q UNINSTALL
|
|
uninstall_omf
|
|
return
|
|
end
|
|
|
|
# Check if OMF is already installed.
|
|
if test -d "$OMF_PATH"
|
|
if is_install_dir "$OMF_PATH"
|
|
say "Existing installation detected at $OMF_PATH"
|
|
|
|
confirm_yes "Would you like to remove the existing installation?"
|
|
uninstall_omf
|
|
else
|
|
abort "Target directory $OMF_PATH already exists"
|
|
end
|
|
end
|
|
|
|
# Begin the install process.
|
|
install_omf
|
|
|
|
# We made it!
|
|
say "Installation successful!"
|
|
|
|
# Open a brand new shell if we are in interactive mode.
|
|
set -q NONINTERACTIVE
|
|
or exec fish < /dev/tty
|
|
|
|
return 0
|
|
end
|
|
|
|
|
|
# Add an exit hook to display a message if the installer aborts or errors.
|
|
function on_exit -p %self
|
|
if not contains $argv[3] 0 2
|
|
echo "
|
|
Oh My Fish installation failed.
|
|
|
|
If you think that it's a bug, please open an
|
|
issue with the complete installation log here:
|
|
|
|
http://github.com/oh-my-fish/oh-my-fish/issues"
|
|
|
|
if not set -q VERBOSE
|
|
echo
|
|
echo "Try rerunning with --verbose to see additional output."
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
# Installs Oh My Fish.
|
|
function install_omf
|
|
say "Installing Oh My Fish to $OMF_PATH..."
|
|
|
|
# Prepare paths
|
|
command mkdir -p (dirname "$OMF_PATH")
|
|
|
|
# Install step
|
|
if set -q OFFLINE
|
|
install_offline
|
|
else
|
|
install_from_github
|
|
end
|
|
|
|
# Config step
|
|
install_bootstrap
|
|
install_config
|
|
end
|
|
|
|
|
|
# Downloads and installs the framework from GitHub.
|
|
function install_from_github
|
|
say "Using release channel \"$OMF_CHANNEL\"."
|
|
say "Cloning $OMF_REPO_BRANCH from $OMF_REPO_URI..."
|
|
|
|
if not command git clone -q -b "$OMF_REPO_BRANCH" "$OMF_REPO_URI" "$OMF_PATH"
|
|
abort "Error cloning repository!"
|
|
end
|
|
|
|
if test $OMF_CHANNEL = stable
|
|
# Get the commit for the latest release.
|
|
set -l hash (command git --git-dir "$OMF_PATH/.git" --work-tree "$OMF_PATH" rev-list --tags='v*' --max-count=1 ^ /dev/null)
|
|
# Get the release tag.
|
|
and set -l tag (command git --git-dir "$OMF_PATH/.git" --work-tree "$OMF_PATH" describe --tags $hash)
|
|
# Checkout the release.
|
|
and command git --git-dir "$OMF_PATH/.git" --work-tree "$OMF_PATH" checkout --quiet tags/$tag
|
|
or report error "Error getting latest version!"
|
|
end
|
|
|
|
set_git_remotes
|
|
end
|
|
|
|
|
|
# Install the framework from an offline copy of the source.
|
|
function install_offline
|
|
# Prepare the path
|
|
if set -q OFFLINE_PATH
|
|
# Make sure the given path exists
|
|
if not test -e "$OFFLINE_PATH"
|
|
abort "Local installation does not exist"
|
|
end
|
|
else
|
|
# If no path was set, check if the installer is running inside of the source directory.
|
|
set -l path (command dirname (command dirname (builtin status -f)))
|
|
|
|
if is_install_dir "$path"
|
|
set OFFLINE_PATH "$path"
|
|
# Try using the current working directory as the source.
|
|
else if is_install_dir "$PWD"
|
|
set OFFLINE_PATH "$PWD"
|
|
else
|
|
# We tried our best.
|
|
abort "Could not find local installation source"
|
|
end
|
|
end
|
|
|
|
# Check if the path is some sort of tar.
|
|
if test -f "$OFFLINE_PATH"
|
|
say "Offline path is a file, assuming tar archive..."
|
|
|
|
command tar -xf "$OFFLINE_PATH" -C "$OMF_PATH"
|
|
or abort "Could not extract tar file $OFFLINE_PATH"
|
|
|
|
return
|
|
end
|
|
|
|
# At this point, path must be a directory.
|
|
if not test -d "$OFFLINE_PATH"
|
|
abort "$OFFLINE_PATH is not a directory"
|
|
end
|
|
|
|
# Make sure the given path is actually the OMF source.
|
|
if not is_install_dir "$OFFLINE_PATH"
|
|
abort "$OFFLINE_PATH is not a valid local installation source"
|
|
end
|
|
|
|
# Copy the source into the install location.
|
|
command cp -r "$OFFLINE_PATH" "$OMF_PATH"
|
|
or abort "Failed to copy source!"
|
|
|
|
# Set up Git remotes only if the offline install is a Git repository.
|
|
test -d "$OMF_PATH/.git"
|
|
and set_git_remotes
|
|
|
|
return 0
|
|
end
|
|
|
|
|
|
# Set upstream remotes on the framework Git repository.
|
|
function set_git_remotes
|
|
set git_upstream (command git --git-dir "$OMF_PATH/.git" --work-tree "$OMF_PATH" config remote.upstream.url)
|
|
|
|
if test -z "$git_upstream"
|
|
command git --git-dir "$OMF_PATH/.git" --work-tree "$OMF_PATH" remote add upstream $OMF_REPO_URI
|
|
else
|
|
command git --git-dir "$OMF_PATH/.git" --work-tree "$OMF_PATH" remote set-url upstream $OMF_REPO_URI
|
|
end
|
|
end
|
|
|
|
|
|
# Sets up the necessary bootstrap code for Fish to load OMF.
|
|
function install_bootstrap
|
|
set -l fish_config_file "$FISH_CONFIG/config.fish"
|
|
set -l vendor_config_file "$FISH_CONFIG/conf.d/omf.fish"
|
|
|
|
# Create the Fish config directory if it doesn't exist yet (if the first thing the user runs with Fish is this
|
|
# installer, for example).
|
|
command mkdir -p "$FISH_CONFIG"
|
|
|
|
# If Oh My Fish is already configured and ready to go, there's nothing else we need to do here.
|
|
if is_omf_loaded
|
|
return 0
|
|
|
|
# Fish 2.3.0+ supports conf.d which is for vendors to manage, so we can just plop an init file under our control.
|
|
else if is_version_compatible 2.3.0 (get_fish_version)
|
|
say "Writing bootstrap to $vendor_config_file..."
|
|
command mkdir -p "$FISH_CONFIG/conf.d"
|
|
generate_bootstrap > "$vendor_config_file"
|
|
|
|
# If the user doesn't have their own config file, we'll just use that as our bootstrap.
|
|
else if not test -e "$fish_config_file"
|
|
say "Writing bootstrap to $fish_config_file..."
|
|
generate_bootstrap > "$fish_config_file"
|
|
|
|
# Even though config.fish already exists, we can prepend to it if the user is OK with it.
|
|
else if confirm "Would you like Oh My Fish to be added to your configuration automatically?"
|
|
say "Prepending bootstrap to $fish_config_file..."
|
|
|
|
# Create a temporary file to store the combined config so that we can write atomically.
|
|
generate_bootstrap | command cat - "$fish_config_file" > "$fish_config_file.tmp"
|
|
or abort "Error prepending config file"
|
|
|
|
# Swap in the prepended file.
|
|
command mv "$fish_config_file.tmp" "$fish_config_file"
|
|
or abort "Error moving file to $fish_config_file"
|
|
|
|
# We don't have any options left, so let the user set up the bootstrap manually.
|
|
else
|
|
say "For Oh My Fish to work properly, please paste the code below into a file that Fish can run at startup:"
|
|
echo
|
|
generate_bootstrap
|
|
end
|
|
|
|
# Backup the user's theme settings. This can be removed when OMF no longer touches this file to switch themes.
|
|
backup_file "$FISH_CONFIG/functions/fish_prompt.fish"
|
|
end
|
|
|
|
|
|
# Sets up the configuration directory.
|
|
function install_config
|
|
say "Setting up Oh My Fish configuration..."
|
|
|
|
# Set up the Oh My Fish configuration directory.
|
|
if not test -d "$OMF_CONFIG"
|
|
command mkdir -p "$OMF_CONFIG"
|
|
end
|
|
|
|
test -f "$OMF_CONFIG/bundle";
|
|
or echo "theme default" > "$OMF_CONFIG/bundle"
|
|
test -f "$OMF_CONFIG/channel";
|
|
or echo $OMF_CHANNEL > "$OMF_CONFIG/channel"
|
|
test -f "$OMF_CONFIG/theme"
|
|
or echo "default" > "$OMF_CONFIG/theme"
|
|
|
|
# Install plugins
|
|
fish -c "omf install"
|
|
or abort "Error installing plugins"
|
|
end
|
|
|
|
|
|
# Generates the bootstrap code used to initialize Oh My Fish on shell startup.
|
|
function generate_bootstrap
|
|
echo "# Path to Oh My Fish install."
|
|
|
|
if test "$OMF_PATH" = "$OMF_PATH_DEFAULT"
|
|
echo "\
|
|
set -q XDG_DATA_HOME
|
|
and set -gx OMF_PATH \"\$XDG_DATA_HOME/omf\"
|
|
or set -gx OMF_PATH \"\$HOME/.local/share/omf\""
|
|
else
|
|
echo "set -gx OMF_PATH '$OMF_PATH'"
|
|
end
|
|
|
|
if test "$OMF_CONFIG" != "$OMF_CONFIG_DEFAULT"
|
|
echo "
|
|
# Customize Oh My Fish configuration path.
|
|
set -gx OMF_CONFIG '$OMF_CONFIG'"
|
|
end
|
|
|
|
echo "
|
|
# Load Oh My Fish configuration.
|
|
source \$OMF_PATH/init.fish"
|
|
end
|
|
|
|
|
|
# Uninstalls an existing OMF installation.
|
|
function uninstall_omf
|
|
is_install_dir "$OMF_PATH"
|
|
or abort "No installation detected at $OMF_PATH"
|
|
|
|
say (set_color -o red ^ /dev/null)"This will uninstall Oh My Fish and all plugins and themes from $OMF_PATH."(set_color normal ^ /dev/null)
|
|
|
|
# If we installed the bootstrap to the user's config, let them know they need to remove it themselves.
|
|
if begin; test -f "$FISH_CONFIG/config.fish"; and grep -q OMF_PATH "$FISH_CONFIG/config.fish"; end
|
|
say (set_color -o ^ /dev/null)"Your configuration will not be modified. You may need to remove Oh My Fish startup code from $FISH_CONFIG/config.fish."(set_color normal ^ /dev/null)
|
|
end
|
|
|
|
confirm_yes "Are you sure you want to continue?"
|
|
say "Uninstalling from $OMF_PATH..."
|
|
|
|
# Trigger package uninstall events
|
|
for path in $OMF_PATH/pkg/*
|
|
set -l package (command basename "$path")
|
|
|
|
test -f "$path/hooks/uninstall.fish"
|
|
and source "$path/hooks/uninstall.fish"
|
|
|
|
test -f "$path/uninstall.fish"
|
|
and source "$path/uninstall.fish"
|
|
|
|
emit uninstall_$package
|
|
end
|
|
|
|
# Remove the core framework
|
|
command rm -rf "$OMF_PATH"
|
|
or abort "Uninstall failed"
|
|
|
|
# Remove the bootstrap if it is managed by us
|
|
set -l vendor_config_file "$FISH_CONFIG/conf.d/omf.fish"
|
|
if test -e "$vendor_config_file"
|
|
command rm "$vendor_config_file"
|
|
or abort "Failed to remove bootstrap file"
|
|
end
|
|
|
|
# Restore backed-up files
|
|
restore_backup_file "$FISH_CONFIG/functions/fish_prompt.fish"
|
|
|
|
say "Uninstall complete"
|
|
end
|
|
|
|
|
|
# Makes a backup of a given file.
|
|
function backup_file -a file_path
|
|
test -e "$file_path"; or return 1
|
|
|
|
set -l path (command dirname $file_path)
|
|
set -l file (command basename $file_path)
|
|
set -l name (echo $file | command cut -d. -f1)
|
|
|
|
set -l timestamp (command date +%s)
|
|
set -l backup_file "$path/$name.$timestamp.copy"
|
|
|
|
say "Existent $file found at $path"
|
|
say "↳ Moving to $backup_file"
|
|
|
|
if not command cp "$file_path" $backup_file ^/dev/null
|
|
abort "Could not backup $file_path"
|
|
end
|
|
|
|
return 0
|
|
end
|
|
|
|
|
|
# Restores a backed-up file to its original location.
|
|
function restore_backup_file -a file_path
|
|
set -l path (command dirname $file_path)
|
|
set -l file (command basename $file_path)
|
|
set -l name (echo $file | cut -d. -f1)
|
|
set -l backup_file_list $path/$name.*.copy
|
|
set -l backup_file_path (echo $backup_file_list | command tr ' ' '\n' | command sort -r | command head -1)
|
|
|
|
if test -e "$backup_file_path"
|
|
say "Found a backup of $file at $backup_file_path"
|
|
|
|
if confirm "Would you like to restore it (overwrite existing)?"
|
|
say "Restoring backup file to $path/$file"
|
|
command mv "$backup_file_path" "$path/$file" ^/dev/null
|
|
or abort "Could not restore backup $backup_file_path"
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
# Verify we have a sane environment that OMF can run in.
|
|
function sane_environment_check
|
|
say "Checking for a sane environment..."
|
|
assert_cmds
|
|
|
|
debug "Checking for a sane 'head' implementation"
|
|
set -l result (printf 'a\nb\n' | cmd head -n 1)
|
|
and test "$result" = 'a'
|
|
or abort (which head)" is not a sane 'head' implementation"
|
|
|
|
debug "Checking for a sane 'sort' implementation"
|
|
set -l result (printf '1.2.3\n2.2.4\n1.2.4\n' | cmd sort -r -n -t '.' -k 1,1 -k 2,2 -k 3,3 -k 4,4)
|
|
and set -q result[3]
|
|
and test "$result[1]" = 2.2.4
|
|
and test "$result[2]" = 1.2.4
|
|
and test "$result[3]" = 1.2.3
|
|
or abort (which sort)" is not a sane 'sort' implementation"
|
|
|
|
debug "Checking for a working AWK interpreter"
|
|
cmd awk 'BEGIN{exit 42;}' < /dev/null ^ /dev/null
|
|
if not test $status -eq 42
|
|
abort (which awk)" does not look like an AWK interpreter."
|
|
end
|
|
|
|
assert_fish_version_compatible 2.2.0
|
|
assert_git_version_compatible 1.9.5
|
|
|
|
debug "Verifying Git implementation is not buggy Git for Windows"
|
|
if cmd git --version | cmd grep -i -q windows
|
|
abort (which git)" is Git for Windows which is not supported."
|
|
end
|
|
|
|
debug "Verifying Git autocrlf is not enabled"
|
|
if test (cmd git config --bool core.autocrlf; or echo false) = true
|
|
abort "Please disable core.autocrlf in your Git configuration."
|
|
end
|
|
end
|
|
|
|
|
|
# Gets the version of Fish installed.
|
|
function get_fish_version
|
|
if set -q FISH_VERSION
|
|
echo $FISH_VERSION
|
|
else if set -q version
|
|
echo $version
|
|
else
|
|
return 1
|
|
end
|
|
end
|
|
|
|
|
|
# Gets the version of Git installed.
|
|
function get_git_version
|
|
type -f git > /dev/null ^ /dev/null
|
|
and command git --version | command cut -d' ' -f3
|
|
end
|
|
|
|
|
|
# Checks if a path looks like an OMF install.
|
|
function is_install_dir -a path
|
|
test -n "$path"
|
|
and test -d "$path"
|
|
and test -d "$path/pkg/omf"
|
|
end
|
|
|
|
|
|
# Checks if OMF is set up properly and working.
|
|
function is_omf_loaded
|
|
command fish -c "omf --version" > /dev/null ^&1
|
|
end
|
|
|
|
|
|
# Tests if the right-hand side version is equal to or greater than the left-hand side version.
|
|
function is_version_compatible -a lhs rhs
|
|
# Both arguments must be given.
|
|
set -q argv[2]
|
|
or return 1
|
|
|
|
# Right-hand side must be the largest version.
|
|
test "$rhs" = (get_latest_version "$lhs" "$rhs")
|
|
end
|
|
|
|
|
|
# Returns the newest version from a given list of versions.
|
|
function get_latest_version
|
|
# Sort the version in descending order and output the top result.
|
|
for v in $argv
|
|
echo "$v"
|
|
end | command sort -r -n -t '.' -k 1,1 -k 2,2 -k 3,3 -k 4,4 | command head -n 1
|
|
end
|
|
|
|
|
|
# Assert that a minimum required version of Fish is installed.
|
|
function assert_fish_version_compatible -a required_version
|
|
set -l installed_version (get_fish_version)
|
|
and is_version_compatible $required_version $installed_version
|
|
or abort "Fish version $required_version or greater required; you have $installed_version"
|
|
end
|
|
|
|
|
|
# Assert that a minimum required version of Git is installed.
|
|
function assert_git_version_compatible -a required_version
|
|
set -l installed_version (get_git_version)
|
|
and is_version_compatible $required_version $installed_version
|
|
or abort "Git version $required_version or greater required; you have $installed_version"
|
|
end
|
|
|
|
|
|
# Assert that all tools we need are available.
|
|
function assert_cmds
|
|
set -l cmds awk basename cp cut date dirname env fish fold head mkdir mv readlink rm sed sort tar tr which
|
|
|
|
for cmd in $cmds
|
|
type -f $cmd > /dev/null ^ /dev/null
|
|
or abort "Missing required command: $cmd"
|
|
|
|
debug "Command '$cmd' is "(which $cmd)
|
|
end
|
|
end
|
|
|
|
|
|
# Ensures the keyboard is readable if in interactive mode.
|
|
function assert_interactive
|
|
set -q NONINTERACTIVE
|
|
and return
|
|
|
|
test -c /dev/tty -a -r /dev/tty
|
|
and echo -n > /dev/tty ^ /dev/null
|
|
or abort "Running interactively, but can't read from tty (try running with --noninteractive)"
|
|
end
|
|
|
|
|
|
# A link-following `which` wrapper.
|
|
function which
|
|
if type realpath > /dev/null ^ /dev/null
|
|
realpath (command which $argv)
|
|
else
|
|
command readlink (command which $argv)
|
|
end
|
|
end
|
|
|
|
|
|
# Execute an external command.
|
|
function cmd
|
|
if set -q VERBOSE
|
|
command env $argv
|
|
else
|
|
command env $argv ^ /dev/null
|
|
end
|
|
end
|
|
|
|
|
|
# Print a message to the user.
|
|
function say -a message
|
|
printf "$message\n" | command fold -s -w 80
|
|
end
|
|
|
|
|
|
# Write a debug message.
|
|
function debug -a message
|
|
if set -q VERBOSE
|
|
printf 'DEBUG: %s\n' "$message" >&2
|
|
end
|
|
end
|
|
|
|
|
|
# Aborts the installer and displays an error.
|
|
function abort -a message code
|
|
if test -z "$code"
|
|
set code 1
|
|
end
|
|
|
|
if test -n "$message"
|
|
printf "%sInstall aborted: $message%s\n" (set_color -o red ^ /dev/null) (set_color normal ^ /dev/null) >&2
|
|
else
|
|
printf "%sInstall aborted%s\n" (set_color -o red ^ /dev/null) (set_color normal ^ /dev/null) >&2
|
|
end
|
|
|
|
exit $code
|
|
end
|
|
|
|
|
|
# Asks the user for confirmation.
|
|
function confirm -a message
|
|
# Return true if we assume yes for all questions.
|
|
set -q ASSUME_YES
|
|
and return 0
|
|
|
|
# Return false if we can't ask the question.
|
|
set -q NONINTERACTIVE
|
|
and return 1
|
|
|
|
printf "%s$message (y/N): %s" (set_color yellow ^ /dev/null) (set_color normal ^ /dev/null)
|
|
read -l answer < /dev/tty
|
|
or abort "Failed to read from tty"
|
|
|
|
not test "$answer" != y -a "$answer" != Y -a "$answer" != yes
|
|
end
|
|
|
|
|
|
# Asks the user for a confirmation or aborts.
|
|
function confirm_yes -a message
|
|
confirm "$message"
|
|
or abort "Canceled by user" 2
|
|
end
|
|
|
|
|
|
main $argv
|