feat(install): optional add-ons via --with and interactive prompt
Wire install_<name>.sh into the main installer through a shared catalog so fnm/pyenv/nvm (and future tools) share one CLI and prompt path.
This commit is contained in:
@@ -10,10 +10,21 @@ fzf-tab, k), plus eza, zoxide, fzf, and Nerd Fonts.
|
|||||||
curl -fsSL https://git.miomio.moe/mio/easyzsh/raw/branch/master/install.sh | bash
|
curl -fsSL https://git.miomio.moe/mio/easyzsh/raw/branch/master/install.sh | bash
|
||||||
```
|
```
|
||||||
|
|
||||||
Options: `--cp-hist` / `-c` imports bash history; `--non-interactive` / `-n`
|
Options:
|
||||||
skips the default-shell change.
|
|
||||||
|
|
||||||
From a git checkout:
|
- `--cp-hist` / `-c` — import bash history
|
||||||
|
- `--non-interactive` / `-n` — skip default-shell change and optional prompts
|
||||||
|
- `--with <names>` — install optional add-ons (comma-separated, repeatable).
|
||||||
|
Each name runs `install_<name>.sh` (currently: `fnm`, `pyenv`, `nvm`).
|
||||||
|
Interactive installs (without `-n` and without `--with`) prompt for the same list.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./install.sh --with fnm
|
||||||
|
./install.sh --with fnm,pyenv -n
|
||||||
|
curl -fsSL …/install.sh | bash -s -- --with fnm
|
||||||
|
```
|
||||||
|
|
||||||
|
From a git checkout (shell stubs only):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./deploy.sh
|
./deploy.sh
|
||||||
|
|||||||
+137
-5
@@ -5,27 +5,120 @@ set -euo pipefail
|
|||||||
# Save the original working directory
|
# Save the original working directory
|
||||||
ORIGINAL_DIR="$(pwd)"
|
ORIGINAL_DIR="$(pwd)"
|
||||||
|
|
||||||
|
# Optional add-ons: each name maps to install_<name>.sh in this repo.
|
||||||
|
# Append here when adding a new optional installer.
|
||||||
|
OPTIONAL_ADDONS=(fnm pyenv nvm)
|
||||||
|
|
||||||
|
# When run from a git checkout, prefer local install_*.sh; curl|bash uses EASYZSH_RAW_BASE.
|
||||||
|
SCRIPT_DIR=""
|
||||||
|
if [[ -n "${BASH_SOURCE[0]:-}" && "${BASH_SOURCE[0]}" != "bash" && -f "${BASH_SOURCE[0]}" ]]; then
|
||||||
|
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||||
|
fi
|
||||||
|
|
||||||
# Flags to determine if the arguments were passed
|
# Flags to determine if the arguments were passed
|
||||||
cp_hist_flag=false
|
cp_hist_flag=false
|
||||||
noninteractive_flag=false
|
noninteractive_flag=false
|
||||||
|
with_flag_set=false
|
||||||
|
selected_addons=()
|
||||||
|
|
||||||
# Loop through all arguments
|
usage() {
|
||||||
for arg in "$@"
|
cat <<'EOF'
|
||||||
do
|
Usage: install.sh [options]
|
||||||
case $arg in
|
|
||||||
|
Options:
|
||||||
|
-c, --cp-hist Copy bash history into zsh history
|
||||||
|
-n, --non-interactive Skip default-shell change and optional prompts
|
||||||
|
--with <names> Install optional add-ons (comma-separated).
|
||||||
|
Repeatable. Names match install_<name>.sh
|
||||||
|
(currently: fnm, pyenv, nvm).
|
||||||
|
-h, --help Show this help
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
./install.sh
|
||||||
|
./install.sh --with fnm
|
||||||
|
./install.sh --with fnm,pyenv -n
|
||||||
|
curl -fsSL …/install.sh | bash -s -- --with fnm
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
is_known_addon() {
|
||||||
|
local name="$1"
|
||||||
|
local known
|
||||||
|
for known in "${OPTIONAL_ADDONS[@]}"; do
|
||||||
|
[[ "$known" == "$name" ]] && return 0
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
append_addons_csv() {
|
||||||
|
local csv="$1"
|
||||||
|
local part
|
||||||
|
local IFS=','
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
for part in $csv; do
|
||||||
|
part="${part#"${part%%[![:space:]]*}"}"
|
||||||
|
part="${part%"${part##*[![:space:]]}"}"
|
||||||
|
[[ -z "$part" ]] && continue
|
||||||
|
if ! is_known_addon "$part"; then
|
||||||
|
echo "Unknown optional add-on: $part (known: ${OPTIONAL_ADDONS[*]})" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
selected_addons+=("$part")
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
--cp-hist|-c)
|
--cp-hist|-c)
|
||||||
cp_hist_flag=true
|
cp_hist_flag=true
|
||||||
|
shift
|
||||||
;;
|
;;
|
||||||
--non-interactive|-n)
|
--non-interactive|-n)
|
||||||
noninteractive_flag=true
|
noninteractive_flag=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--with)
|
||||||
|
with_flag_set=true
|
||||||
|
shift
|
||||||
|
if [[ $# -eq 0 || "$1" == -* ]]; then
|
||||||
|
echo "--with requires a comma-separated list of add-on names" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
append_addons_csv "$1"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--with=*)
|
||||||
|
with_flag_set=true
|
||||||
|
append_addons_csv "${1#--with=}"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Unknown option: $arg" >&2
|
echo "Unknown option: $1" >&2
|
||||||
|
usage >&2
|
||||||
exit 2
|
exit 2
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
dedupe_selected_addons() {
|
||||||
|
local _deduped=()
|
||||||
|
local _name _d _seen
|
||||||
|
for _name in "${selected_addons[@]+"${selected_addons[@]}"}"; do
|
||||||
|
_seen=false
|
||||||
|
for _d in "${_deduped[@]+"${_deduped[@]}"}"; do
|
||||||
|
[[ "$_d" == "$_name" ]] && _seen=true && break
|
||||||
|
done
|
||||||
|
[[ "$_seen" == false ]] && _deduped+=("$_name")
|
||||||
|
done
|
||||||
|
selected_addons=("${_deduped[@]+"${_deduped[@]}"}")
|
||||||
|
}
|
||||||
|
|
||||||
|
dedupe_selected_addons
|
||||||
|
|
||||||
if [ -f ~/.gitconfig ]; then
|
if [ -f ~/.gitconfig ]; then
|
||||||
cp ~/.gitconfig ~/.gitconfig.backup
|
cp ~/.gitconfig ~/.gitconfig.backup
|
||||||
echo "Backup of .gitconfig created."
|
echo "Backup of .gitconfig created."
|
||||||
@@ -424,6 +517,45 @@ else
|
|||||||
echo -e "\nNot copying bash_history to zsh_history, as --cp-hist or -c is not supplied\n"
|
echo -e "\nNot copying bash_history to zsh_history, as --cp-hist or -c is not supplied\n"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Optional add-ons (install_<name>.sh). After shell stubs so patches land correctly.
|
||||||
|
run_optional_addon() {
|
||||||
|
local name="$1"
|
||||||
|
local script="install_${name}.sh"
|
||||||
|
echo -e "\n=== Optional add-on: ${name} ===\n"
|
||||||
|
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/$script" ]]; then
|
||||||
|
bash "$SCRIPT_DIR/$script"
|
||||||
|
else
|
||||||
|
curl -fsSL "${EASYZSH_RAW_BASE}/${script}" | bash
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
prompt_optional_addons() {
|
||||||
|
# Only when interactive and user did not pass --with.
|
||||||
|
echo -e "\nOptional add-ons (each is install_<name>.sh):"
|
||||||
|
local name
|
||||||
|
for name in "${OPTIONAL_ADDONS[@]}"; do
|
||||||
|
echo " - $name"
|
||||||
|
done
|
||||||
|
echo -n "Install which? Comma-separated names, or Enter to skip: "
|
||||||
|
local reply
|
||||||
|
read -r reply || reply=""
|
||||||
|
[[ -z "${reply//[[:space:]]/}" ]] && return 0
|
||||||
|
append_addons_csv "$reply"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ "$with_flag_set" == false && "$noninteractive_flag" == false ]]; then
|
||||||
|
prompt_optional_addons
|
||||||
|
dedupe_selected_addons
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ((${#selected_addons[@]})); then
|
||||||
|
for name in "${selected_addons[@]}"; do
|
||||||
|
run_optional_addon "$name"
|
||||||
|
done
|
||||||
|
elif [[ "$with_flag_set" == true ]]; then
|
||||||
|
echo -e "\n--with given but no add-ons selected; skipping optionals\n"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$noninteractive_flag" = true ]; then
|
if [ "$noninteractive_flag" = true ]; then
|
||||||
echo -e "Installation complete, exit terminal and enter a new zsh session\n"
|
echo -e "Installation complete, exit terminal and enter a new zsh session\n"
|
||||||
echo -e "Make sure to change zsh to default shell by running: chsh -s $(command -v zsh)"
|
echo -e "Make sure to change zsh to default shell by running: chsh -s $(command -v zsh)"
|
||||||
|
|||||||
@@ -99,6 +99,15 @@ grep -Fq '"$ZSH_CONFIGS_DIR"/*(DN)' "$ROOT/.zshrc" || fail "existing extensionle
|
|||||||
grep -Fq '_resolve_trash_cmd' "$ROOT/.zshrc" || fail "trash-backed rm helper is missing"
|
grep -Fq '_resolve_trash_cmd' "$ROOT/.zshrc" || fail "trash-backed rm helper is missing"
|
||||||
grep -Fq 'libglib2.0-bin' "$ROOT/install.sh" || fail "Ubuntu Trash support is not installed"
|
grep -Fq 'libglib2.0-bin' "$ROOT/install.sh" || fail "Ubuntu Trash support is not installed"
|
||||||
grep -Fq 'deploy.sh' "$ROOT/install.sh" || fail "install.sh does not invoke deploy.sh"
|
grep -Fq 'deploy.sh' "$ROOT/install.sh" || fail "install.sh does not invoke deploy.sh"
|
||||||
|
grep -Fq 'OPTIONAL_ADDONS=' "$ROOT/install.sh" || fail "install.sh missing OPTIONAL_ADDONS catalog"
|
||||||
|
grep -Fq -- '--with' "$ROOT/install.sh" || fail "install.sh missing --with option"
|
||||||
|
# --with parses known add-ons and rejects unknown ones without network.
|
||||||
|
if HOME="$TEMP_DIR" PATH="/usr/bin:/bin" bash "$ROOT/install.sh" --with nosuch >/dev/null 2>&1; then
|
||||||
|
fail "install.sh accepted an unknown --with add-on"
|
||||||
|
fi
|
||||||
|
if ! HOME="$TEMP_DIR" PATH="/usr/bin:/bin" bash "$ROOT/install.sh" --help >/dev/null; then
|
||||||
|
fail "install.sh --help failed"
|
||||||
|
fi
|
||||||
grep -Fq 'brew shellenv' "$ROOT/.zshenv" || fail "Homebrew is not initialized in .zshenv"
|
grep -Fq 'brew shellenv' "$ROOT/.zshenv" || fail "Homebrew is not initialized in .zshenv"
|
||||||
grep -Fq '/usr/local/bin/brew' "$ROOT/.zshenv" || fail "Intel Homebrew path is missing from .zshenv"
|
grep -Fq '/usr/local/bin/brew' "$ROOT/.zshenv" || fail "Intel Homebrew path is missing from .zshenv"
|
||||||
grep -Fq '$HOME/.local/bin' "$ROOT/.zshenv" || fail "~/.local/bin is not added in .zshenv"
|
grep -Fq '$HOME/.local/bin' "$ROOT/.zshenv" || fail "~/.local/bin is not added in .zshenv"
|
||||||
|
|||||||
Reference in New Issue
Block a user