Interactive Prompts
This commit is contained in:
parent
3b9ad58ce3
commit
310d0e54a6
@ -634,4 +634,224 @@ silent()
|
|||||||
- `SILENT_LOGFILE`: Silent execution log file path
|
- `SILENT_LOGFILE`: Silent execution log file path
|
||||||
- `SPINNER_PID`: Spinner process ID
|
- `SPINNER_PID`: Spinner process ID
|
||||||
- `SPINNER_MSG`: Spinner message text
|
- `SPINNER_MSG`: Spinner message text
|
||||||
- `MSG_INFO_SHOWN`: Tracks shown info messages
|
- `MSG_INFO_SHOWN`: Tracks shown info messages- `PHS_SILENT`: Unattended mode flag (1 = silent)
|
||||||
|
- `var_unattended`: Unattended mode variable (yes/no)
|
||||||
|
- `UNATTENDED`: Alternative unattended mode variable
|
||||||
|
|
||||||
|
## Unattended/Interactive Prompt Functions
|
||||||
|
|
||||||
|
These functions provide a unified way to handle user prompts in both interactive and unattended modes. They automatically detect the execution context and either prompt the user (with timeout) or use default values silently.
|
||||||
|
|
||||||
|
### `is_unattended()`
|
||||||
|
**Purpose**: Detect if script is running in unattended/silent mode
|
||||||
|
**Parameters**: None
|
||||||
|
**Returns**:
|
||||||
|
- `0` (true): Running unattended
|
||||||
|
- `1` (false): Running interactively
|
||||||
|
**Side Effects**: None
|
||||||
|
**Dependencies**: None
|
||||||
|
**Environment Variables Used**: `PHS_SILENT`, `var_unattended`, `UNATTENDED`
|
||||||
|
|
||||||
|
**Usage Example**:
|
||||||
|
```bash
|
||||||
|
if is_unattended; then
|
||||||
|
echo "Running in unattended mode"
|
||||||
|
else
|
||||||
|
echo "Running interactively"
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
|
### `prompt_confirm()`
|
||||||
|
**Purpose**: Prompt user for yes/no confirmation with timeout and unattended support
|
||||||
|
**Parameters**:
|
||||||
|
- `$1` - Prompt message (required)
|
||||||
|
- `$2` - Default value: "y" or "n" (optional, default: "n")
|
||||||
|
- `$3` - Timeout in seconds (optional, default: 60)
|
||||||
|
**Returns**:
|
||||||
|
- `0`: User confirmed (yes)
|
||||||
|
- `1`: User declined (no) or timeout with default "n"
|
||||||
|
**Side Effects**: Displays prompt to terminal
|
||||||
|
**Dependencies**: `is_unattended()`
|
||||||
|
**Environment Variables Used**: Color variables (`YW`, `CL`)
|
||||||
|
|
||||||
|
**Behavior**:
|
||||||
|
- **Unattended mode**: Immediately returns default value
|
||||||
|
- **Non-TTY**: Immediately returns default value
|
||||||
|
- **Interactive**: Displays prompt with timeout countdown
|
||||||
|
- **Timeout**: Auto-applies default value after specified seconds
|
||||||
|
|
||||||
|
**Usage Examples**:
|
||||||
|
```bash
|
||||||
|
# Basic confirmation (default: no)
|
||||||
|
if prompt_confirm "Proceed with installation?"; then
|
||||||
|
install_package
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Default to yes, 30 second timeout
|
||||||
|
if prompt_confirm "Continue?" "y" 30; then
|
||||||
|
continue_operation
|
||||||
|
fi
|
||||||
|
|
||||||
|
# In unattended mode (will use default immediately)
|
||||||
|
var_unattended=yes
|
||||||
|
prompt_confirm "Delete files?" "n" && echo "Deleting" || echo "Skipped"
|
||||||
|
```
|
||||||
|
|
||||||
|
### `prompt_input()`
|
||||||
|
**Purpose**: Prompt user for text input with timeout and unattended support
|
||||||
|
**Parameters**:
|
||||||
|
- `$1` - Prompt message (required)
|
||||||
|
- `$2` - Default value (optional, default: "")
|
||||||
|
- `$3` - Timeout in seconds (optional, default: 60)
|
||||||
|
**Output**: Prints the user input or default value to stdout
|
||||||
|
**Returns**: `0` always
|
||||||
|
**Side Effects**: Displays prompt to stderr (keeps stdout clean for value)
|
||||||
|
**Dependencies**: `is_unattended()`
|
||||||
|
**Environment Variables Used**: Color variables (`YW`, `CL`)
|
||||||
|
|
||||||
|
**Behavior**:
|
||||||
|
- **Unattended mode**: Returns default value immediately
|
||||||
|
- **Non-TTY**: Returns default value immediately
|
||||||
|
- **Interactive**: Waits for user input with timeout
|
||||||
|
- **Empty input**: Returns default value
|
||||||
|
- **Timeout**: Returns default value
|
||||||
|
|
||||||
|
**Usage Examples**:
|
||||||
|
```bash
|
||||||
|
# Get username with default
|
||||||
|
username=$(prompt_input "Enter username:" "admin" 30)
|
||||||
|
echo "Using username: $username"
|
||||||
|
|
||||||
|
# With validation loop
|
||||||
|
while true; do
|
||||||
|
port=$(prompt_input "Enter port:" "8080" 30)
|
||||||
|
[[ "$port" =~ ^[0-9]+$ ]] && break
|
||||||
|
echo "Invalid port number"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Capture value in unattended mode
|
||||||
|
var_unattended=yes
|
||||||
|
db_name=$(prompt_input "Database name:" "myapp_db")
|
||||||
|
```
|
||||||
|
|
||||||
|
### `prompt_select()`
|
||||||
|
**Purpose**: Prompt user to select from a list of options with timeout support
|
||||||
|
**Parameters**:
|
||||||
|
- `$1` - Prompt message (required)
|
||||||
|
- `$2` - Default option number, 1-based (optional, default: 1)
|
||||||
|
- `$3` - Timeout in seconds (optional, default: 60)
|
||||||
|
- `$4+` - Options to display (required, at least 1)
|
||||||
|
**Output**: Prints the selected option value to stdout
|
||||||
|
**Returns**:
|
||||||
|
- `0`: Success
|
||||||
|
- `1`: No options provided
|
||||||
|
**Side Effects**: Displays numbered menu to stderr
|
||||||
|
**Dependencies**: `is_unattended()`
|
||||||
|
**Environment Variables Used**: Color variables (`YW`, `GN`, `CL`)
|
||||||
|
|
||||||
|
**Behavior**:
|
||||||
|
- **Unattended mode**: Returns default selection immediately
|
||||||
|
- **Non-TTY**: Returns default selection immediately
|
||||||
|
- **Interactive**: Displays numbered menu with timeout
|
||||||
|
- **Invalid selection**: Uses default
|
||||||
|
- **Timeout**: Auto-selects default
|
||||||
|
|
||||||
|
**Usage Examples**:
|
||||||
|
```bash
|
||||||
|
# Simple selection
|
||||||
|
choice=$(prompt_select "Select database:" 1 30 "PostgreSQL" "MySQL" "SQLite")
|
||||||
|
echo "Selected: $choice"
|
||||||
|
|
||||||
|
# Using array
|
||||||
|
options=("Production" "Staging" "Development")
|
||||||
|
env=$(prompt_select "Select environment:" 2 60 "${options[@]}")
|
||||||
|
|
||||||
|
# In automation scripts
|
||||||
|
var_unattended=yes
|
||||||
|
db=$(prompt_select "Database:" 1 30 "postgres" "mysql" "sqlite")
|
||||||
|
# Returns "postgres" immediately without menu
|
||||||
|
```
|
||||||
|
|
||||||
|
### `prompt_password()`
|
||||||
|
**Purpose**: Prompt user for password input with hidden characters and auto-generation
|
||||||
|
**Parameters**:
|
||||||
|
- `$1` - Prompt message (required)
|
||||||
|
- `$2` - Default value or "generate" for auto-generation (optional)
|
||||||
|
- `$3` - Timeout in seconds (optional, default: 60)
|
||||||
|
- `$4` - Minimum length for validation (optional, default: 0)
|
||||||
|
**Output**: Prints the password to stdout
|
||||||
|
**Returns**: `0` always
|
||||||
|
**Side Effects**: Displays prompt to stderr with hidden input
|
||||||
|
**Dependencies**: `is_unattended()`, `openssl` (for generation)
|
||||||
|
**Environment Variables Used**: Color variables (`YW`, `CL`)
|
||||||
|
|
||||||
|
**Behavior**:
|
||||||
|
- **"generate" default**: Creates random 16-character password
|
||||||
|
- **Unattended mode**: Returns default/generated password immediately
|
||||||
|
- **Non-TTY**: Returns default/generated password immediately
|
||||||
|
- **Interactive**: Hidden input with timeout
|
||||||
|
- **Min length validation**: Falls back to default if too short
|
||||||
|
- **Timeout**: Returns default/generated password
|
||||||
|
|
||||||
|
**Usage Examples**:
|
||||||
|
```bash
|
||||||
|
# Auto-generate password if user doesn't provide one
|
||||||
|
password=$(prompt_password "Enter password:" "generate" 30)
|
||||||
|
echo "Password has been set"
|
||||||
|
|
||||||
|
# Require minimum length
|
||||||
|
db_pass=$(prompt_password "Database password:" "" 60 12)
|
||||||
|
|
||||||
|
# With default password
|
||||||
|
admin_pass=$(prompt_password "Admin password:" "changeme123" 30)
|
||||||
|
|
||||||
|
# In unattended mode with auto-generation
|
||||||
|
var_unattended=yes
|
||||||
|
password=$(prompt_password "Password:" "generate")
|
||||||
|
# Returns randomly generated password
|
||||||
|
```
|
||||||
|
|
||||||
|
## Prompt Function Decision Flow
|
||||||
|
|
||||||
|
```
|
||||||
|
prompt_confirm() / prompt_input() / prompt_select() / prompt_password()
|
||||||
|
│
|
||||||
|
├── is_unattended()? ─────────────────────┐
|
||||||
|
│ └── PHS_SILENT=1? │
|
||||||
|
│ └── var_unattended=yes? ├── YES → Return default immediately
|
||||||
|
│ └── UNATTENDED=yes? │
|
||||||
|
│ │
|
||||||
|
├── TTY available? ─────────────── NO ────┘
|
||||||
|
│
|
||||||
|
└── Interactive Mode
|
||||||
|
├── Display prompt with timeout hint
|
||||||
|
├── read -t $timeout
|
||||||
|
│ ├── User input received → Validate and return
|
||||||
|
│ ├── Empty input → Return default
|
||||||
|
│ └── Timeout → Return default with message
|
||||||
|
└── Return value
|
||||||
|
```
|
||||||
|
|
||||||
|
## Migration Guide: Converting read Commands
|
||||||
|
|
||||||
|
To make existing scripts unattended-compatible, replace `read` commands with the appropriate prompt function:
|
||||||
|
|
||||||
|
### Before (blocking):
|
||||||
|
```bash
|
||||||
|
read -rp "Continue? [y/N]: " confirm
|
||||||
|
[[ "$confirm" =~ ^[Yy]$ ]] && do_something
|
||||||
|
|
||||||
|
read -p "Enter port: " port
|
||||||
|
port="${port:-8080}"
|
||||||
|
|
||||||
|
read -p "Select (1-3): " choice
|
||||||
|
```
|
||||||
|
|
||||||
|
### After (unattended-safe):
|
||||||
|
```bash
|
||||||
|
prompt_confirm "Continue?" "n" && do_something
|
||||||
|
|
||||||
|
port=$(prompt_input "Enter port:" "8080")
|
||||||
|
|
||||||
|
choice=$(prompt_select "Select option:" 1 60 "Option 1" "Option 2" "Option 3")
|
||||||
|
```
|
||||||
|
|||||||
@ -12,19 +12,19 @@ setting_up_container
|
|||||||
network_check
|
network_check
|
||||||
update_os
|
update_os
|
||||||
|
|
||||||
if [[ -z "$var_forgejo_instance" ]]; then
|
# Get required configuration with sensible fallbacks for unattended mode
|
||||||
read -rp "Forgejo Instance URL (e.g. https://code.forgejo.org): " var_forgejo_instance
|
# These will show a warning if defaults are used
|
||||||
fi
|
var_forgejo_instance=$(prompt_input_required \
|
||||||
|
"Forgejo Instance URL:" \
|
||||||
|
"${var_forgejo_instance:-https://codeberg.org}" \
|
||||||
|
120 \
|
||||||
|
"var_forgejo_instance")
|
||||||
|
|
||||||
if [[ -z "$var_forgejo_runner_token" ]]; then
|
var_forgejo_runner_token=$(prompt_input_required \
|
||||||
read -rp "Forgejo Runner Registration Token: " var_forgejo_runner_token
|
"Forgejo Runner Registration Token:" \
|
||||||
echo
|
"${var_forgejo_runner_token:-REPLACE_WITH_YOUR_TOKEN}" \
|
||||||
fi
|
120 \
|
||||||
|
"var_forgejo_runner_token")
|
||||||
if [[ -z "$var_forgejo_instance" || -z "$var_forgejo_runner_token" ]]; then
|
|
||||||
echo "❌ Forgejo instance URL and runner token are required."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
export FORGEJO_INSTANCE="$var_forgejo_instance"
|
export FORGEJO_INSTANCE="$var_forgejo_instance"
|
||||||
export FORGEJO_RUNNER_TOKEN="$var_forgejo_runner_token"
|
export FORGEJO_RUNNER_TOKEN="$var_forgejo_runner_token"
|
||||||
@ -78,6 +78,9 @@ EOF
|
|||||||
systemctl enable -q --now forgejo-runner
|
systemctl enable -q --now forgejo-runner
|
||||||
msg_ok "Created Services"
|
msg_ok "Created Services"
|
||||||
|
|
||||||
|
# Show warning if any required values used fallbacks
|
||||||
|
show_missing_values_warning
|
||||||
|
|
||||||
motd_ssh
|
motd_ssh
|
||||||
customize
|
customize
|
||||||
cleanup_lxc
|
cleanup_lxc
|
||||||
|
|||||||
@ -110,8 +110,7 @@ msg_ok "Installed garmin-grafana"
|
|||||||
|
|
||||||
msg_info "Setting up garmin-grafana"
|
msg_info "Setting up garmin-grafana"
|
||||||
# Check if using Chinese garmin servers
|
# Check if using Chinese garmin servers
|
||||||
read -rp "Are you using Garmin in mainland China? (y/N): " prompt
|
if prompt_confirm "Are you using Garmin in mainland China?" "n" 60; then
|
||||||
if [[ "${prompt,,}" =~ ^(y|yes|Y)$ ]]; then
|
|
||||||
GARMIN_CN="True"
|
GARMIN_CN="True"
|
||||||
else
|
else
|
||||||
GARMIN_CN="False"
|
GARMIN_CN="False"
|
||||||
@ -131,9 +130,9 @@ EOF
|
|||||||
# garmin-grafana usually prompts the user for email and password (and MFA) on first run,
|
# garmin-grafana usually prompts the user for email and password (and MFA) on first run,
|
||||||
# then stores a refreshable token. We try to avoid storing user credentials in the env vars
|
# then stores a refreshable token. We try to avoid storing user credentials in the env vars
|
||||||
if [ -z "$(ls -A /opt/garmin-grafana/.garminconnect)" ]; then
|
if [ -z "$(ls -A /opt/garmin-grafana/.garminconnect)" ]; then
|
||||||
read -r -p "Please enter your Garmin Connect Email: " GARMIN_EMAIL
|
GARMIN_EMAIL=$(prompt_input "Please enter your Garmin Connect Email:" "" 120)
|
||||||
read -r -p "Please enter your Garmin Connect Password (this is used to generate a token and NOT stored): " GARMIN_PASSWORD
|
GARMIN_PASSWORD=$(prompt_password "Please enter your Garmin Connect Password (used to generate token, NOT stored):" "" 120)
|
||||||
read -r -p "Please enter your MFA Code (if applicable, leave blank if not): " GARMIN_MFA
|
GARMIN_MFA=$(prompt_input "Please enter your MFA Code (leave blank if not applicable):" "" 60)
|
||||||
# Run the script once to prompt for credential
|
# Run the script once to prompt for credential
|
||||||
msg_info "Creating Garmin credentials, this will timeout in 60 seconds"
|
msg_info "Creating Garmin credentials, this will timeout in 60 seconds"
|
||||||
timeout 60s uv run --env-file /opt/garmin-grafana/.env --project /opt/garmin-grafana/ /opt/garmin-grafana/src/garmin_grafana/garmin_fetch.py <<EOF
|
timeout 60s uv run --env-file /opt/garmin-grafana/.env --project /opt/garmin-grafana/ /opt/garmin-grafana/src/garmin_grafana/garmin_fetch.py <<EOF
|
||||||
|
|||||||
@ -3685,12 +3685,8 @@ EOF
|
|||||||
selected_gpu="${available_gpus[0]}"
|
selected_gpu="${available_gpus[0]}"
|
||||||
msg_ok "Automatically configuring ${selected_gpu} GPU passthrough"
|
msg_ok "Automatically configuring ${selected_gpu} GPU passthrough"
|
||||||
else
|
else
|
||||||
# Multiple GPUs - ask user
|
# Multiple GPUs - ask user (use first as default in unattended mode)
|
||||||
echo -e "\n${INFO} Multiple GPU types detected:"
|
selected_gpu=$(prompt_select "Which GPU type to passthrough?" 1 60 "${available_gpus[@]}")
|
||||||
for gpu in "${available_gpus[@]}"; do
|
|
||||||
echo " - $gpu"
|
|
||||||
done
|
|
||||||
read -rp "Which GPU type to passthrough? (${available_gpus[*]}): " selected_gpu
|
|
||||||
selected_gpu="${selected_gpu^^}"
|
selected_gpu="${selected_gpu^^}"
|
||||||
|
|
||||||
# Validate selection
|
# Validate selection
|
||||||
@ -4113,29 +4109,16 @@ destroy_lxc() {
|
|||||||
# Abort on Ctrl-C / Ctrl-D / ESC
|
# Abort on Ctrl-C / Ctrl-D / ESC
|
||||||
trap 'echo; msg_error "Aborted by user (SIGINT/SIGQUIT)"; return 130' INT QUIT
|
trap 'echo; msg_error "Aborted by user (SIGINT/SIGQUIT)"; return 130' INT QUIT
|
||||||
|
|
||||||
local prompt
|
if prompt_confirm "Remove this Container?" "n" 60; then
|
||||||
if ! read -rp "Remove this Container? <y/N> " prompt; then
|
|
||||||
# read returns non-zero on Ctrl-D/ESC
|
|
||||||
msg_error "Aborted input (Ctrl-D/ESC)"
|
|
||||||
return 130
|
|
||||||
fi
|
|
||||||
|
|
||||||
case "${prompt,,}" in
|
|
||||||
y | yes)
|
|
||||||
if pct stop "$CT_ID" &>/dev/null && pct destroy "$CT_ID" &>/dev/null; then
|
if pct stop "$CT_ID" &>/dev/null && pct destroy "$CT_ID" &>/dev/null; then
|
||||||
msg_ok "Removed Container $CT_ID"
|
msg_ok "Removed Container $CT_ID"
|
||||||
else
|
else
|
||||||
msg_error "Failed to remove Container $CT_ID"
|
msg_error "Failed to remove Container $CT_ID"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
;;
|
else
|
||||||
"" | n | no)
|
|
||||||
msg_custom "ℹ️" "${BL}" "Container was not removed."
|
msg_custom "ℹ️" "${BL}" "Container was not removed."
|
||||||
;;
|
fi
|
||||||
*)
|
|
||||||
msg_warn "Invalid response. Container was not removed."
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
@ -4452,9 +4435,7 @@ create_lxc_container() {
|
|||||||
echo " pve-container: installed=${_pvec_i:-n/a} candidate=${_pvec_c:-n/a}"
|
echo " pve-container: installed=${_pvec_i:-n/a} candidate=${_pvec_c:-n/a}"
|
||||||
echo " lxc-pve : installed=${_lxcp_i:-n/a} candidate=${_lxcp_c:-n/a}"
|
echo " lxc-pve : installed=${_lxcp_i:-n/a} candidate=${_lxcp_c:-n/a}"
|
||||||
echo
|
echo
|
||||||
read -rp "Do you want to upgrade now? [y/N] " _ans
|
if prompt_confirm "Do you want to upgrade now?" "n" 60; then
|
||||||
case "${_ans,,}" in
|
|
||||||
y | yes)
|
|
||||||
msg_info "Upgrading Proxmox LXC stack (pve-container, lxc-pve)"
|
msg_info "Upgrading Proxmox LXC stack (pve-container, lxc-pve)"
|
||||||
if $STD apt-get update && $STD apt-get install -y --only-upgrade pve-container lxc-pve; then
|
if $STD apt-get update && $STD apt-get install -y --only-upgrade pve-container lxc-pve; then
|
||||||
msg_ok "LXC stack upgraded."
|
msg_ok "LXC stack upgraded."
|
||||||
@ -4473,9 +4454,9 @@ create_lxc_container() {
|
|||||||
msg_error "Upgrade failed. Please check APT output."
|
msg_error "Upgrade failed. Please check APT output."
|
||||||
return 3
|
return 3
|
||||||
fi
|
fi
|
||||||
;;
|
else
|
||||||
*) return 2 ;;
|
return 2
|
||||||
esac
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
@ -4650,16 +4631,12 @@ create_lxc_container() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if [[ ${#AVAILABLE_VERSIONS[@]} -gt 0 ]]; then
|
if [[ ${#AVAILABLE_VERSIONS[@]} -gt 0 ]]; then
|
||||||
echo ""
|
# Use prompt_select for version selection (supports unattended mode)
|
||||||
echo "${BL}Available ${PCT_OSTYPE} versions:${CL}"
|
local selected_version
|
||||||
for i in "${!AVAILABLE_VERSIONS[@]}"; do
|
selected_version=$(prompt_select "Select ${PCT_OSTYPE} version:" 1 60 "${AVAILABLE_VERSIONS[@]}")
|
||||||
echo " [$((i + 1))] ${AVAILABLE_VERSIONS[$i]}"
|
|
||||||
done
|
|
||||||
echo ""
|
|
||||||
read -p "Select version [1-${#AVAILABLE_VERSIONS[@]}] or press Enter to cancel: " choice
|
|
||||||
|
|
||||||
if [[ "$choice" =~ ^[0-9]+$ ]] && [[ "$choice" -ge 1 ]] && [[ "$choice" -le ${#AVAILABLE_VERSIONS[@]} ]]; then
|
if [[ -n "$selected_version" ]]; then
|
||||||
PCT_OSVERSION="${AVAILABLE_VERSIONS[$((choice - 1))]}"
|
PCT_OSVERSION="$selected_version"
|
||||||
TEMPLATE_SEARCH="${PCT_OSTYPE}-${PCT_OSVERSION}"
|
TEMPLATE_SEARCH="${PCT_OSTYPE}-${PCT_OSVERSION}"
|
||||||
|
|
||||||
ONLINE_TEMPLATES=()
|
ONLINE_TEMPLATES=()
|
||||||
@ -4713,16 +4690,12 @@ create_lxc_container() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if [[ ${#AVAILABLE_VERSIONS[@]} -gt 0 ]]; then
|
if [[ ${#AVAILABLE_VERSIONS[@]} -gt 0 ]]; then
|
||||||
echo -e "\n${BL}Available versions:${CL}"
|
# Use prompt_select for version selection (supports unattended mode)
|
||||||
for i in "${!AVAILABLE_VERSIONS[@]}"; do
|
local selected_version
|
||||||
echo " [$((i + 1))] ${AVAILABLE_VERSIONS[$i]}"
|
selected_version=$(prompt_select "Select ${PCT_OSTYPE} version:" 1 60 "${AVAILABLE_VERSIONS[@]}")
|
||||||
done
|
|
||||||
|
|
||||||
echo ""
|
if [[ -n "$selected_version" ]]; then
|
||||||
read -p "Select version [1-${#AVAILABLE_VERSIONS[@]}] or Enter to exit: " choice
|
export var_version="$selected_version"
|
||||||
|
|
||||||
if [[ "$choice" =~ ^[0-9]+$ ]] && [[ "$choice" -ge 1 ]] && [[ "$choice" -le ${#AVAILABLE_VERSIONS[@]} ]]; then
|
|
||||||
export var_version="${AVAILABLE_VERSIONS[$((choice - 1))]}"
|
|
||||||
export PCT_OSVERSION="$var_version"
|
export PCT_OSVERSION="$var_version"
|
||||||
msg_ok "Switched to ${PCT_OSTYPE} ${var_version}"
|
msg_ok "Switched to ${PCT_OSTYPE} ${var_version}"
|
||||||
|
|
||||||
@ -4767,10 +4740,6 @@ create_lxc_container() {
|
|||||||
msg_error "Template still not found after version change"
|
msg_error "Template still not found after version change"
|
||||||
exit 220
|
exit 220
|
||||||
}
|
}
|
||||||
else
|
|
||||||
msg_custom "🚫" "${YW}" "Installation cancelled"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
msg_error "No ${PCT_OSTYPE} templates available"
|
msg_error "No ${PCT_OSTYPE} templates available"
|
||||||
exit 220
|
exit 220
|
||||||
|
|||||||
519
misc/core.func
519
misc/core.func
@ -810,6 +810,517 @@ is_verbose_mode() {
|
|||||||
[[ "$verbose" != "no" || ! -t 2 ]]
|
[[ "$verbose" != "no" || ! -t 2 ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# is_unattended()
|
||||||
|
#
|
||||||
|
# - Detects if script is running in unattended/silent mode
|
||||||
|
# - Checks PHS_SILENT, var_unattended, and UNATTENDED variables
|
||||||
|
# - Returns 0 (true) if unattended, 1 (false) otherwise
|
||||||
|
# - Used by prompt functions to auto-apply defaults
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
is_unattended() {
|
||||||
|
[[ "${PHS_SILENT:-0}" == "1" ]] && return 0
|
||||||
|
[[ "${var_unattended:-}" =~ ^(yes|true|1)$ ]] && return 0
|
||||||
|
[[ "${UNATTENDED:-}" =~ ^(yes|true|1)$ ]] && return 0
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# show_missing_values_warning()
|
||||||
|
#
|
||||||
|
# - Displays a summary of required values that used fallback defaults
|
||||||
|
# - Should be called at the end of install scripts
|
||||||
|
# - Only shows warning if MISSING_REQUIRED_VALUES array has entries
|
||||||
|
# - Provides clear guidance on what needs manual configuration
|
||||||
|
#
|
||||||
|
# Global:
|
||||||
|
# MISSING_REQUIRED_VALUES - Array of variable names that need configuration
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# # At end of install script:
|
||||||
|
# show_missing_values_warning
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
show_missing_values_warning() {
|
||||||
|
if [[ ${#MISSING_REQUIRED_VALUES[@]} -gt 0 ]]; then
|
||||||
|
echo ""
|
||||||
|
echo -e "${YW}╔════════════════════════════════════════════════════════════╗${CL}"
|
||||||
|
echo -e "${YW}║ ⚠️ MANUAL CONFIGURATION REQUIRED ║${CL}"
|
||||||
|
echo -e "${YW}╠════════════════════════════════════════════════════════════╣${CL}"
|
||||||
|
echo -e "${YW}║ The following values were not provided and need to be ║${CL}"
|
||||||
|
echo -e "${YW}║ configured manually for the service to work properly: ║${CL}"
|
||||||
|
echo -e "${YW}╟────────────────────────────────────────────────────────────╢${CL}"
|
||||||
|
for val in "${MISSING_REQUIRED_VALUES[@]}"; do
|
||||||
|
printf "${YW}║${CL} • %-56s ${YW}║${CL}\n" "$val"
|
||||||
|
done
|
||||||
|
echo -e "${YW}╟────────────────────────────────────────────────────────────╢${CL}"
|
||||||
|
echo -e "${YW}║ Check the service configuration files or environment ║${CL}"
|
||||||
|
echo -e "${YW}║ variables and update the placeholder values. ║${CL}"
|
||||||
|
echo -e "${YW}╚════════════════════════════════════════════════════════════╝${CL}"
|
||||||
|
echo ""
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# prompt_confirm()
|
||||||
|
#
|
||||||
|
# - Prompts user for yes/no confirmation with timeout and unattended support
|
||||||
|
# - In unattended mode: immediately returns default value
|
||||||
|
# - In interactive mode: waits for user input with configurable timeout
|
||||||
|
# - After timeout: auto-applies default value
|
||||||
|
#
|
||||||
|
# Arguments:
|
||||||
|
# $1 - Prompt message (required)
|
||||||
|
# $2 - Default value: "y" or "n" (optional, default: "n")
|
||||||
|
# $3 - Timeout in seconds (optional, default: 60)
|
||||||
|
#
|
||||||
|
# Returns:
|
||||||
|
# 0 - User confirmed (yes)
|
||||||
|
# 1 - User declined (no) or timeout with default "n"
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# if prompt_confirm "Proceed with installation?" "y" 30; then
|
||||||
|
# echo "Installing..."
|
||||||
|
# fi
|
||||||
|
#
|
||||||
|
# # Unattended: prompt_confirm will use default without waiting
|
||||||
|
# var_unattended=yes
|
||||||
|
# prompt_confirm "Delete files?" "n" && echo "Deleting" || echo "Skipped"
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
prompt_confirm() {
|
||||||
|
local message="${1:-Confirm?}"
|
||||||
|
local default="${2:-n}"
|
||||||
|
local timeout="${3:-60}"
|
||||||
|
local response
|
||||||
|
|
||||||
|
# Normalize default to lowercase
|
||||||
|
default="${default,,}"
|
||||||
|
[[ "$default" != "y" ]] && default="n"
|
||||||
|
|
||||||
|
# Build prompt hint
|
||||||
|
local hint
|
||||||
|
if [[ "$default" == "y" ]]; then
|
||||||
|
hint="[Y/n]"
|
||||||
|
else
|
||||||
|
hint="[y/N]"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Unattended mode: apply default immediately
|
||||||
|
if is_unattended; then
|
||||||
|
if [[ "$default" == "y" ]]; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if running in a TTY
|
||||||
|
if [[ ! -t 0 ]]; then
|
||||||
|
# Not a TTY, use default
|
||||||
|
if [[ "$default" == "y" ]]; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Interactive prompt with timeout
|
||||||
|
echo -en "${YW}${message} ${hint} (auto-${default} in ${timeout}s): ${CL}"
|
||||||
|
|
||||||
|
if read -t "$timeout" -r response; then
|
||||||
|
# User provided input
|
||||||
|
response="${response,,}" # lowercase
|
||||||
|
case "$response" in
|
||||||
|
y|yes)
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
n|no)
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
"")
|
||||||
|
# Empty response, use default
|
||||||
|
if [[ "$default" == "y" ]]; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# Invalid input, use default
|
||||||
|
echo -e "${YW}Invalid response, using default: ${default}${CL}"
|
||||||
|
if [[ "$default" == "y" ]]; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
# Timeout occurred
|
||||||
|
echo "" # Newline after timeout
|
||||||
|
echo -e "${YW}Timeout - auto-selecting: ${default}${CL}"
|
||||||
|
if [[ "$default" == "y" ]]; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# prompt_input()
|
||||||
|
#
|
||||||
|
# - Prompts user for text input with timeout and unattended support
|
||||||
|
# - In unattended mode: immediately returns default value
|
||||||
|
# - In interactive mode: waits for user input with configurable timeout
|
||||||
|
# - After timeout: auto-applies default value
|
||||||
|
#
|
||||||
|
# Arguments:
|
||||||
|
# $1 - Prompt message (required)
|
||||||
|
# $2 - Default value (optional, default: "")
|
||||||
|
# $3 - Timeout in seconds (optional, default: 60)
|
||||||
|
#
|
||||||
|
# Output:
|
||||||
|
# Prints the user input or default value to stdout
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# username=$(prompt_input "Enter username:" "admin" 30)
|
||||||
|
# echo "Using username: $username"
|
||||||
|
#
|
||||||
|
# # With validation
|
||||||
|
# while true; do
|
||||||
|
# port=$(prompt_input "Enter port:" "8080" 30)
|
||||||
|
# [[ "$port" =~ ^[0-9]+$ ]] && break
|
||||||
|
# echo "Invalid port number"
|
||||||
|
# done
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
prompt_input() {
|
||||||
|
local message="${1:-Enter value:}"
|
||||||
|
local default="${2:-}"
|
||||||
|
local timeout="${3:-60}"
|
||||||
|
local response
|
||||||
|
|
||||||
|
# Build display default hint
|
||||||
|
local hint=""
|
||||||
|
[[ -n "$default" ]] && hint=" (default: ${default})"
|
||||||
|
|
||||||
|
# Unattended mode: return default immediately
|
||||||
|
if is_unattended; then
|
||||||
|
echo "$default"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if running in a TTY
|
||||||
|
if [[ ! -t 0 ]]; then
|
||||||
|
# Not a TTY, use default
|
||||||
|
echo "$default"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Interactive prompt with timeout
|
||||||
|
echo -en "${YW}${message}${hint} (auto-default in ${timeout}s): ${CL}" >&2
|
||||||
|
|
||||||
|
if read -t "$timeout" -r response; then
|
||||||
|
# User provided input (or pressed Enter for empty)
|
||||||
|
if [[ -n "$response" ]]; then
|
||||||
|
echo "$response"
|
||||||
|
else
|
||||||
|
echo "$default"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Timeout occurred
|
||||||
|
echo "" >&2 # Newline after timeout
|
||||||
|
echo -e "${YW}Timeout - using default: ${default}${CL}" >&2
|
||||||
|
echo "$default"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# prompt_input_required()
|
||||||
|
#
|
||||||
|
# - Prompts user for REQUIRED text input with fallback support
|
||||||
|
# - In unattended mode: Uses fallback value if no env var set (with warning)
|
||||||
|
# - In interactive mode: loops until user provides non-empty input
|
||||||
|
# - Tracks missing required values for end-of-script summary
|
||||||
|
#
|
||||||
|
# Arguments:
|
||||||
|
# $1 - Prompt message (required)
|
||||||
|
# $2 - Fallback/example value for unattended mode (optional)
|
||||||
|
# $3 - Timeout in seconds (optional, default: 120)
|
||||||
|
# $4 - Environment variable name hint for error messages (optional)
|
||||||
|
#
|
||||||
|
# Output:
|
||||||
|
# Prints the user input or fallback value to stdout
|
||||||
|
#
|
||||||
|
# Returns:
|
||||||
|
# 0 - Success (value provided or fallback used)
|
||||||
|
# 1 - Failed (interactive timeout without input)
|
||||||
|
#
|
||||||
|
# Global:
|
||||||
|
# MISSING_REQUIRED_VALUES - Array tracking fields that used fallbacks
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# # With fallback - script continues even in unattended mode
|
||||||
|
# token=$(prompt_input_required "Enter API Token:" "YOUR_TOKEN_HERE" 60 "var_api_token")
|
||||||
|
#
|
||||||
|
# # Check at end of script if any values need manual configuration
|
||||||
|
# if [[ ${#MISSING_REQUIRED_VALUES[@]} -gt 0 ]]; then
|
||||||
|
# msg_warn "Please configure: ${MISSING_REQUIRED_VALUES[*]}"
|
||||||
|
# fi
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Global array to track missing required values
|
||||||
|
declare -g -a MISSING_REQUIRED_VALUES=()
|
||||||
|
|
||||||
|
prompt_input_required() {
|
||||||
|
local message="${1:-Enter required value:}"
|
||||||
|
local fallback="${2:-CHANGE_ME}"
|
||||||
|
local timeout="${3:-120}"
|
||||||
|
local env_var_hint="${4:-}"
|
||||||
|
local response=""
|
||||||
|
|
||||||
|
# Check if value is already set via environment variable (if hint provided)
|
||||||
|
if [[ -n "$env_var_hint" ]]; then
|
||||||
|
local env_value="${!env_var_hint:-}"
|
||||||
|
if [[ -n "$env_value" ]]; then
|
||||||
|
echo "$env_value"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Unattended mode: use fallback with warning
|
||||||
|
if is_unattended; then
|
||||||
|
if [[ -n "$env_var_hint" ]]; then
|
||||||
|
echo -e "${YW}⚠ Required value '${env_var_hint}' not set - using fallback: ${fallback}${CL}" >&2
|
||||||
|
MISSING_REQUIRED_VALUES+=("$env_var_hint")
|
||||||
|
else
|
||||||
|
echo -e "${YW}⚠ Required value not provided - using fallback: ${fallback}${CL}" >&2
|
||||||
|
MISSING_REQUIRED_VALUES+=("(unnamed)")
|
||||||
|
fi
|
||||||
|
echo "$fallback"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if running in a TTY
|
||||||
|
if [[ ! -t 0 ]]; then
|
||||||
|
echo -e "${YW}⚠ Not interactive - using fallback: ${fallback}${CL}" >&2
|
||||||
|
MISSING_REQUIRED_VALUES+=("${env_var_hint:-unnamed}")
|
||||||
|
echo "$fallback"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Interactive prompt - loop until non-empty input or use fallback on timeout
|
||||||
|
local attempts=0
|
||||||
|
while [[ -z "$response" ]]; do
|
||||||
|
((attempts++))
|
||||||
|
|
||||||
|
if [[ $attempts -gt 3 ]]; then
|
||||||
|
echo -e "${YW}Too many empty inputs - using fallback: ${fallback}${CL}" >&2
|
||||||
|
MISSING_REQUIRED_VALUES+=("${env_var_hint:-manual_input}")
|
||||||
|
echo "$fallback"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -en "${YW}${message} (required, timeout ${timeout}s): ${CL}" >&2
|
||||||
|
|
||||||
|
if read -t "$timeout" -r response; then
|
||||||
|
if [[ -z "$response" ]]; then
|
||||||
|
echo -e "${YW}This field is required. Please enter a value. (attempt ${attempts}/3)${CL}" >&2
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Timeout occurred - use fallback
|
||||||
|
echo "" >&2
|
||||||
|
echo -e "${YW}Timeout - using fallback value: ${fallback}${CL}" >&2
|
||||||
|
MISSING_REQUIRED_VALUES+=("${env_var_hint:-timeout}")
|
||||||
|
echo "$fallback"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "$response"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# prompt_select()
|
||||||
|
#
|
||||||
|
# - Prompts user to select from a list of options with timeout support
|
||||||
|
# - In unattended mode: immediately returns default selection
|
||||||
|
# - In interactive mode: displays numbered menu and waits for choice
|
||||||
|
# - After timeout: auto-applies default selection
|
||||||
|
#
|
||||||
|
# Arguments:
|
||||||
|
# $1 - Prompt message (required)
|
||||||
|
# $2 - Default option number, 1-based (optional, default: 1)
|
||||||
|
# $3 - Timeout in seconds (optional, default: 60)
|
||||||
|
# $4+ - Options to display (required, at least 2)
|
||||||
|
#
|
||||||
|
# Output:
|
||||||
|
# Prints the selected option value to stdout
|
||||||
|
#
|
||||||
|
# Returns:
|
||||||
|
# 0 - Success
|
||||||
|
# 1 - No options provided or invalid state
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# choice=$(prompt_select "Select database:" 1 30 "PostgreSQL" "MySQL" "SQLite")
|
||||||
|
# echo "Selected: $choice"
|
||||||
|
#
|
||||||
|
# # With array
|
||||||
|
# options=("Option A" "Option B" "Option C")
|
||||||
|
# selected=$(prompt_select "Choose:" 2 60 "${options[@]}")
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
prompt_select() {
|
||||||
|
local message="${1:-Select option:}"
|
||||||
|
local default="${2:-1}"
|
||||||
|
local timeout="${3:-60}"
|
||||||
|
shift 3
|
||||||
|
|
||||||
|
local options=("$@")
|
||||||
|
local num_options=${#options[@]}
|
||||||
|
|
||||||
|
# Validate options
|
||||||
|
if [[ $num_options -eq 0 ]]; then
|
||||||
|
echo "" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validate default
|
||||||
|
if [[ ! "$default" =~ ^[0-9]+$ ]] || [[ "$default" -lt 1 ]] || [[ "$default" -gt "$num_options" ]]; then
|
||||||
|
default=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Unattended mode: return default immediately
|
||||||
|
if is_unattended; then
|
||||||
|
echo "${options[$((default - 1))]}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if running in a TTY
|
||||||
|
if [[ ! -t 0 ]]; then
|
||||||
|
echo "${options[$((default - 1))]}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Display menu
|
||||||
|
echo -e "${YW}${message}${CL}" >&2
|
||||||
|
local i
|
||||||
|
for i in "${!options[@]}"; do
|
||||||
|
local num=$((i + 1))
|
||||||
|
if [[ $num -eq $default ]]; then
|
||||||
|
echo -e " ${GN}${num})${CL} ${options[$i]} ${YW}(default)${CL}" >&2
|
||||||
|
else
|
||||||
|
echo -e " ${GN}${num})${CL} ${options[$i]}" >&2
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Interactive prompt with timeout
|
||||||
|
echo -en "${YW}Select [1-${num_options}] (auto-select ${default} in ${timeout}s): ${CL}" >&2
|
||||||
|
|
||||||
|
local response
|
||||||
|
if read -t "$timeout" -r response; then
|
||||||
|
if [[ -z "$response" ]]; then
|
||||||
|
# Empty response, use default
|
||||||
|
echo "${options[$((default - 1))]}"
|
||||||
|
elif [[ "$response" =~ ^[0-9]+$ ]] && [[ "$response" -ge 1 ]] && [[ "$response" -le "$num_options" ]]; then
|
||||||
|
# Valid selection
|
||||||
|
echo "${options[$((response - 1))]}"
|
||||||
|
else
|
||||||
|
# Invalid input, use default
|
||||||
|
echo -e "${YW}Invalid selection, using default: ${options[$((default - 1))]}${CL}" >&2
|
||||||
|
echo "${options[$((default - 1))]}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Timeout occurred
|
||||||
|
echo "" >&2 # Newline after timeout
|
||||||
|
echo -e "${YW}Timeout - auto-selecting: ${options[$((default - 1))]}${CL}" >&2
|
||||||
|
echo "${options[$((default - 1))]}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# prompt_password()
|
||||||
|
#
|
||||||
|
# - Prompts user for password input with hidden characters
|
||||||
|
# - In unattended mode: returns default or generates random password
|
||||||
|
# - Supports auto-generation of secure passwords
|
||||||
|
# - After timeout: generates random password if allowed
|
||||||
|
#
|
||||||
|
# Arguments:
|
||||||
|
# $1 - Prompt message (required)
|
||||||
|
# $2 - Default value or "generate" for auto-generation (optional)
|
||||||
|
# $3 - Timeout in seconds (optional, default: 60)
|
||||||
|
# $4 - Minimum length for validation (optional, default: 0 = no minimum)
|
||||||
|
#
|
||||||
|
# Output:
|
||||||
|
# Prints the password to stdout
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# password=$(prompt_password "Enter password:" "generate" 30 8)
|
||||||
|
# echo "Password set"
|
||||||
|
#
|
||||||
|
# # Require user input (no default)
|
||||||
|
# db_pass=$(prompt_password "Database password:" "" 60 12)
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
prompt_password() {
|
||||||
|
local message="${1:-Enter password:}"
|
||||||
|
local default="${2:-}"
|
||||||
|
local timeout="${3:-60}"
|
||||||
|
local min_length="${4:-0}"
|
||||||
|
local response
|
||||||
|
|
||||||
|
# Generate random password if requested
|
||||||
|
local generated=""
|
||||||
|
if [[ "$default" == "generate" ]]; then
|
||||||
|
generated=$(openssl rand -base64 16 2>/dev/null | tr -dc 'a-zA-Z0-9' | head -c 16)
|
||||||
|
[[ -z "$generated" ]] && generated=$(head /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c 16)
|
||||||
|
default="$generated"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Unattended mode: return default immediately
|
||||||
|
if is_unattended; then
|
||||||
|
echo "$default"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if running in a TTY
|
||||||
|
if [[ ! -t 0 ]]; then
|
||||||
|
echo "$default"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build hint
|
||||||
|
local hint=""
|
||||||
|
if [[ -n "$generated" ]]; then
|
||||||
|
hint=" (Enter for auto-generated)"
|
||||||
|
elif [[ -n "$default" ]]; then
|
||||||
|
hint=" (Enter for default)"
|
||||||
|
fi
|
||||||
|
[[ "$min_length" -gt 0 ]] && hint="${hint} [min ${min_length} chars]"
|
||||||
|
|
||||||
|
# Interactive prompt with timeout (silent input)
|
||||||
|
echo -en "${YW}${message}${hint} (timeout ${timeout}s): ${CL}" >&2
|
||||||
|
|
||||||
|
if read -t "$timeout" -rs response; then
|
||||||
|
echo "" >&2 # Newline after hidden input
|
||||||
|
if [[ -n "$response" ]]; then
|
||||||
|
# Validate minimum length
|
||||||
|
if [[ "$min_length" -gt 0 ]] && [[ ${#response} -lt "$min_length" ]]; then
|
||||||
|
echo -e "${YW}Password too short (min ${min_length}), using default${CL}" >&2
|
||||||
|
echo "$default"
|
||||||
|
else
|
||||||
|
echo "$response"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "$default"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Timeout occurred
|
||||||
|
echo "" >&2 # Newline after timeout
|
||||||
|
echo -e "${YW}Timeout - using generated password${CL}" >&2
|
||||||
|
echo "$default"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# SECTION 6: CLEANUP & MAINTENANCE
|
# SECTION 6: CLEANUP & MAINTENANCE
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
@ -898,15 +1409,13 @@ check_or_create_swap() {
|
|||||||
|
|
||||||
msg_error "No active swap detected"
|
msg_error "No active swap detected"
|
||||||
|
|
||||||
read -p "Do you want to create a swap file? [y/N]: " create_swap
|
if ! prompt_confirm "Do you want to create a swap file?" "n" 60; then
|
||||||
create_swap="${create_swap,,}" # to lowercase
|
|
||||||
|
|
||||||
if [[ "$create_swap" != "y" && "$create_swap" != "yes" ]]; then
|
|
||||||
msg_info "Skipping swap file creation"
|
msg_info "Skipping swap file creation"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
read -p "Enter swap size in MB (e.g., 2048 for 2GB): " swap_size_mb
|
local swap_size_mb
|
||||||
|
swap_size_mb=$(prompt_input "Enter swap size in MB (e.g., 2048 for 2GB):" "2048" 60)
|
||||||
if ! [[ "$swap_size_mb" =~ ^[0-9]+$ ]]; then
|
if ! [[ "$swap_size_mb" =~ ^[0-9]+$ ]]; then
|
||||||
msg_error "Invalid size input. Aborting."
|
msg_error "Invalid size input. Aborting."
|
||||||
return 1
|
return 1
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user