Merge pull request #91 from vessenes/refactor/town-session-helper
CI failures unrelated to this PR (formula embed issue)
This commit is contained in:
@@ -5,9 +5,9 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/steveyegge/gastown/internal/boot"
|
|
||||||
"github.com/steveyegge/gastown/internal/daemon"
|
"github.com/steveyegge/gastown/internal/daemon"
|
||||||
"github.com/steveyegge/gastown/internal/events"
|
"github.com/steveyegge/gastown/internal/events"
|
||||||
|
"github.com/steveyegge/gastown/internal/session"
|
||||||
"github.com/steveyegge/gastown/internal/style"
|
"github.com/steveyegge/gastown/internal/style"
|
||||||
"github.com/steveyegge/gastown/internal/tmux"
|
"github.com/steveyegge/gastown/internal/tmux"
|
||||||
"github.com/steveyegge/gastown/internal/workspace"
|
"github.com/steveyegge/gastown/internal/workspace"
|
||||||
@@ -73,35 +73,20 @@ func runDown(cmd *cobra.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get session names
|
// 2. Stop town-level sessions (Mayor, Boot, Deacon) in correct order
|
||||||
mayorSession := getMayorSessionName()
|
for _, ts := range session.TownSessions() {
|
||||||
deaconSession := getDeaconSessionName()
|
stopped, err := session.StopTownSession(t, ts, downForce)
|
||||||
|
if err != nil {
|
||||||
// 2. Stop Mayor
|
printDownStatus(ts.Name, false, err.Error())
|
||||||
if err := stopSession(t, mayorSession); err != nil {
|
allOK = false
|
||||||
printDownStatus("Mayor", false, err.Error())
|
} else if stopped {
|
||||||
allOK = false
|
printDownStatus(ts.Name, true, "stopped")
|
||||||
} else {
|
} else {
|
||||||
printDownStatus("Mayor", true, "stopped")
|
printDownStatus(ts.Name, true, "not running")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Stop Boot (Deacon's watchdog)
|
// 3. Stop Daemon last
|
||||||
if err := stopSession(t, boot.SessionName); err != nil {
|
|
||||||
printDownStatus("Boot", false, err.Error())
|
|
||||||
allOK = false
|
|
||||||
} else {
|
|
||||||
printDownStatus("Boot", true, "stopped")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. Stop Deacon
|
|
||||||
if err := stopSession(t, deaconSession); err != nil {
|
|
||||||
printDownStatus("Deacon", false, err.Error())
|
|
||||||
allOK = false
|
|
||||||
} else {
|
|
||||||
printDownStatus("Deacon", true, "stopped")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 5. Stop Daemon last
|
|
||||||
running, _, _ := daemon.IsRunning(townRoot)
|
running, _, _ := daemon.IsRunning(townRoot)
|
||||||
if running {
|
if running {
|
||||||
if err := daemon.StopDaemon(townRoot); err != nil {
|
if err := daemon.StopDaemon(townRoot); err != nil {
|
||||||
@@ -114,7 +99,7 @@ func runDown(cmd *cobra.Command, args []string) error {
|
|||||||
printDownStatus("Daemon", true, "not running")
|
printDownStatus("Daemon", true, "not running")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6. Kill tmux server if --all
|
// 4. Kill tmux server if --all
|
||||||
if downAll {
|
if downAll {
|
||||||
if err := t.KillServer(); err != nil {
|
if err := t.KillServer(); err != nil {
|
||||||
printDownStatus("Tmux server", false, err.Error())
|
printDownStatus("Tmux server", false, err.Error())
|
||||||
|
|||||||
53
internal/session/town.go
Normal file
53
internal/session/town.go
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
// Package session provides polecat session lifecycle management.
|
||||||
|
package session
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/steveyegge/gastown/internal/boot"
|
||||||
|
"github.com/steveyegge/gastown/internal/tmux"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TownSession represents a town-level tmux session.
|
||||||
|
type TownSession struct {
|
||||||
|
Name string // Display name (e.g., "Mayor")
|
||||||
|
SessionID string // Tmux session ID (e.g., "gt-mayor")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TownSessions returns the list of town-level sessions in shutdown order.
|
||||||
|
// Order matters: Boot (Deacon's watchdog) must be stopped before Deacon,
|
||||||
|
// otherwise Boot will try to restart Deacon.
|
||||||
|
func TownSessions() []TownSession {
|
||||||
|
return []TownSession{
|
||||||
|
{"Mayor", MayorSessionName()},
|
||||||
|
{"Boot", boot.SessionName},
|
||||||
|
{"Deacon", DeaconSessionName()},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StopTownSession stops a single town-level tmux session.
|
||||||
|
// If force is true, skips graceful shutdown (Ctrl-C) and kills immediately.
|
||||||
|
// Returns true if the session was running and stopped, false if not running.
|
||||||
|
func StopTownSession(t *tmux.Tmux, ts TownSession, force bool) (bool, error) {
|
||||||
|
running, err := t.HasSession(ts.SessionID)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if !running {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try graceful shutdown first (unless forced)
|
||||||
|
if !force {
|
||||||
|
_ = t.SendKeysRaw(ts.SessionID, "C-c")
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kill the session
|
||||||
|
if err := t.KillSession(ts.SessionID); err != nil {
|
||||||
|
return false, fmt.Errorf("killing %s session: %w", ts.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user