148 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
			
		
		
	
	
			148 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
| #!/bin/bash
 | |
| # tmux-daemon.sh
 | |
| # Idempotent tmux daemon manager with config file support
 | |
| 
 | |
| # Load config file if it exists
 | |
| SCRIPT_DIR=$(dirname "$0")
 | |
| SCRIPT_NAME=$(basename "$0" .sh)
 | |
| CONFIG_FILE="${SCRIPT_DIR}/${SCRIPT_NAME}.conf"
 | |
| if [ -f "$CONFIG_FILE" ]; then
 | |
|     echo "Loading config from $CONFIG_FILE"
 | |
|     source "$CONFIG_FILE"
 | |
| else
 | |
|     echo "Config file $CONFIG_FILE not found, generating template..."
 | |
|     cat > "$CONFIG_FILE" << 'EOF'
 | |
| # tmux-daemon.conf
 | |
| # Configuration file for tmux-daemon.sh
 | |
| 
 | |
| # Session name
 | |
| SESSION="example"
 | |
| 
 | |
| # Whether to attach to session after setup (0 or 1)
 | |
| ATTACH_SESSION=0
 | |
| 
 | |
| # Commands to run (array format)
 | |
| # Format: "workdir:::command" OR just "command"
 | |
| CMDS=(
 | |
|     "ping google.com"
 | |
|     "ping google.com"
 | |
|     "ping google.com"
 | |
|     "ping google.com"
 | |
|     "ping google.com"
 | |
|     "ping google.com"
 | |
|     "ping google.com"
 | |
| )
 | |
| EOF
 | |
|     echo "Generated $CONFIG_FILE with default values. Please edit and run again."
 | |
|     exit 0
 | |
| fi
 | |
| 
 | |
| # Validate required variables
 | |
| if [ -z "$SESSION" ]; then
 | |
|     echo "Error: SESSION must be set in $CONFIG_FILE" >&2
 | |
|     exit 1
 | |
| fi
 | |
| 
 | |
| if [ ${#CMDS[@]} -eq 0 ]; then
 | |
|     echo "Error: CMDS array must be set in $CONFIG_FILE" >&2
 | |
|     exit 1
 | |
| fi
 | |
| 
 | |
| echo "[main] SESSION: $SESSION"
 | |
| echo "[main] Commands: ${CMDS[*]}"
 | |
| 
 | |
| # Create session if missing
 | |
| if ! tmux has-session -t $SESSION 2>/dev/null; then
 | |
|     echo "[main] Creating tmux session: $SESSION"
 | |
|     tmux new-session -d -s $SESSION -n win0
 | |
| else
 | |
|     echo "[main] Session $SESSION exists, reusing..."
 | |
| fi
 | |
| 
 | |
| win=0
 | |
| pane=0
 | |
| 
 | |
| for i in "${!CMDS[@]}"; do
 | |
|     entry="${CMDS[$i]}"
 | |
|     echo "[loop:$i] entry: $entry"
 | |
|     if [[ "$entry" == *":::"* ]]; then
 | |
|         workdir="${entry%%:::*}"
 | |
|         echo "[loop:$i] workdir set from entry: $workdir"
 | |
|         cmd="${entry#*:::}"
 | |
|         echo "[loop:$i] cmd set from entry: $cmd"
 | |
|     else
 | |
|         workdir="$PWD"
 | |
|         echo "[loop:$i] workdir set to PWD: $workdir"
 | |
|         cmd="$entry"
 | |
|         echo "[loop:$i] cmd set to entry: $cmd"
 | |
|     fi
 | |
|     echo "[loop:$i] Processing command: $cmd (workdir: $workdir)"
 | |
| 
 | |
|     # Determine target window/pane
 | |
|     win=$((i / 4))
 | |
|     echo "[loop:$i] win updated: $win"
 | |
|     pane=$((i % 4))
 | |
|     echo "[loop:$i] pane updated: $pane"
 | |
| 
 | |
|     # Create window if missing
 | |
|     if ! tmux list-windows -t $SESSION | grep -q "^$win:"; then
 | |
|         echo "[loop:$i] Creating window $win"
 | |
|         tmux new-window -t $SESSION:$win -n win$win
 | |
|     fi
 | |
| 
 | |
|     # Get current pane count in window
 | |
|     panes=($(tmux list-panes -t $SESSION:$win -F '#P'))
 | |
|     echo "[loop:$i] panes in window $win: ${panes[*]}"
 | |
| 
 | |
|     # Create missing pane if needed
 | |
|     if [ $pane -ge ${#panes[@]} ]; then
 | |
|         echo "[loop:$i] Splitting pane $((pane-1)) to create pane $pane in window $win"
 | |
|         if [ $pane -eq 1 ]; then
 | |
|             tmux split-window -h -t $SESSION:$win
 | |
|         elif [ $pane -eq 2 ]; then
 | |
|             tmux split-window -v -t $SESSION:$win
 | |
|         elif [ $pane -eq 3 ]; then
 | |
|             tmux split-window -v -t $SESSION:$win.1
 | |
|         fi
 | |
|     fi
 | |
|     
 | |
|     # Always apply appropriate layout based on current pane count
 | |
|     current_panes=($(tmux list-panes -t $SESSION:$win -F '#P'))
 | |
|     if [ ${#current_panes[@]} -eq 2 ]; then
 | |
|         tmux select-layout -t $SESSION:$win even-horizontal
 | |
|     else
 | |
|         tmux select-layout -t $SESSION:$win tiled
 | |
|     fi
 | |
| 
 | |
|     # Check if command is already running in the pane
 | |
|     running=$(tmux list-panes -t $SESSION:$win -F '#{pane_current_command}' | sed -n "$((pane+1))p")
 | |
|     echo "[loop:$i] running in pane $pane: $running"
 | |
|     if [[ "$running" == "$(basename "$cmd" | awk '{print $1}')" ]]; then
 | |
|         echo "[loop:$i] Command already running in pane $pane, skipping..."
 | |
|         continue
 | |
|     fi
 | |
| 
 | |
|     # Create temporary script to run command in auto-restart loop
 | |
|     tmpfile=$(mktemp)
 | |
|     echo "[loop:$i] tmpfile created: $tmpfile"
 | |
|     cat >"$tmpfile" <<EOF
 | |
| #!/bin/bash
 | |
| cd "$workdir" || exit 1
 | |
| while true; do
 | |
|     echo '[tmux-daemon] Starting: $cmd (in $workdir)'
 | |
|     bash -c '$cmd'
 | |
|     echo '[tmux-daemon] Command exited with code \$?'
 | |
|     sleep 2
 | |
| done
 | |
| EOF
 | |
|     chmod +x "$tmpfile"
 | |
|     echo "[loop:$i] Sending command to pane $pane in window $win"
 | |
|     tmux send-keys -t $SESSION:$win.$pane "$tmpfile" C-m
 | |
| done
 | |
| 
 | |
| echo "[main] Done."
 | |
| 
 | |
| if [ $ATTACH_SESSION -eq 1 ]; then
 | |
|     echo "[main] Attaching to tmux session: $SESSION"
 | |
|     tmux attach -t $SESSION
 | |
| fi |