#!/bin/bash # 1. Define your strings BASE_FOLDER="/sf/bernina/applications/python" ENVS_DIR="${BASE_FOLDER}/environments" DEFAULT_ENV="bpy-default" ENV_NAME=$1 # 2. Gather available environments into an array using the -L fix ENVS=() if [ -d "$ENVS_DIR" ]; then while read -r bin_dir; do name=$(basename "$(dirname "$bin_dir")") ENVS+=("$name") done < <(find -L "$ENVS_DIR" -maxdepth 2 -mindepth 2 -type d -name "bin" 2>/dev/null | sort) fi # 3. Interactive selection logic if no argument is passed (or if invalid) VALID_ENV=false if [ -n "$ENV_NAME" ]; then for e in "${ENVS[@]}"; do if [ "$e" == "$ENV_NAME" ]; then VALID_ENV=true break fi done fi if [ -z "$ENV_NAME" ] || [ "$VALID_ENV" = false ]; then if [ -n "$ENV_NAME" ]; then echo "Error: Could not find an environment folder for '${ENV_NAME}'" echo "" fi if [ ${#ENVS[@]} -eq 0 ]; then echo "Error: No environments found in $ENVS_DIR" return 1 2>/dev/null || exit 1 fi # Display usage hint and menu instructions echo "💡 Pro-Tip: Skip this menu by passing the name directly: bpy-select " echo "Use ↑/↓ arrow keys to choose an environment. Press ENTER to select." echo "" # Menu settings selected=0 timeout_duration=5 start_time=$(date +%s) countdown_active=true # Render menu function draw_menu() { local idx=0 for e in "${ENVS[@]}"; do if [ $idx -eq $selected ]; then printf "\r\033[K\033[1;36m > %s\033[0m\n" "$e" # Cyan highlight else printf "\r\033[K %s\n" "$e" fi ((idx++)) done # Calculate precise countdown remaining or handle frozen timer state if [ "$countdown_active" = true ]; then local current_time=$(date +%s) local elapsed=$((current_time - start_time)) local remaining=$((timeout_duration - elapsed)) if [ $remaining -le 0 ]; then remaining=0 fi printf "\r\033[K\033[1;33mTimeout defaulting to '$DEFAULT_ENV' in %ss...\033[0m\n" "$remaining" else printf "\r\033[K\033[1;32mSelection active. Countdown stopped.\033[0m\n" fi # Move cursor back up to the top of the menu list (number of envs + 1 for timer line) local total_lines=$((${#ENVS[@]} + 1)) printf "\033[%dA" "$total_lines" } # Hide cursor and draw the baseline menu printf "\033[?25l" draw_menu while true; do # Non-blocking 1-second interval read to allow real-time timer updates if read -s -n 1 -t 1 key 2>/dev/null; then # Handle arrow keys if [[ $key == $'\033' ]]; then read -s -n 2 -t 0.1 next_chars if [[ $next_chars == "[A" ]]; then # Up arrow countdown_active=false # Stop countdown instantly if [ $selected -gt 0 ]; then ((selected--)) fi elif [[ $next_chars == "[B" ]]; then # Down arrow countdown_active=false # Stop countdown instantly if [ $selected -lt $((${#ENVS[@]} - 1)) ]; then ((selected++)) fi fi elif [[ $key == "" ]]; then # Enter key pressed ENV_NAME="${ENVS[$selected]}" break fi fi # Check if total countdown duration has passed (only if countdown hasn't been disabled) if [ "$countdown_active" = true ]; then current_time=$(date +%s) elapsed=$((current_time - start_time)) if [ $elapsed -ge $timeout_duration ]; then ENV_NAME="$DEFAULT_ENV" break fi fi # Redraw layout with updated status draw_menu done # --- CLEANUP ARTIFACTS ROUTINE --- local total_lines=$((${#ENVS[@]} + 1)) for ((i=0; i/dev/null || exit 1 fi # 5. Clean up the PATH (strips out any prior environments from ENVS_DIR) NEW_PATH="" IFS=':' read -ra PATH_ARRAY <<< "$PATH" for segment in "${PATH_ARRAY[@]}"; do if [[ "$segment" != *"${ENVS_DIR}"* ]]; then if [ -z "$NEW_PATH" ]; then NEW_PATH="$segment" else NEW_PATH="$NEW_PATH:$segment" fi fi done # 6. Rebuild PATH and export environment variables #export PATH="${BIN_PATH}:${NEW_PATH}" echo $BIN_PATH export PATH="${BIN_PATH}:${ENV_PATH}/bin:${NEW_PATH}" export CONDA_PREFIX="${ENV_PATH}" export CONDA_DEFAULT_ENV="${ENV_NAME}" export PIXI_ENVIRONMENT_NAME="${ENV_NAME}" # Optional: Source package-specific startup scripts if they exist if [ -d "${ENV_PATH}/etc/conda/activate.d" ]; then for f in "${ENV_PATH}/etc/conda/activate.d"/*.sh; do [ -r "$f" ] && source "$f" done fi echo "Activated '${ENV_NAME}' successfully (Raw Path Mode)."