fix(daemon): allow read-only daemon commands with Dolt backend
The daemon guard was blocking ALL daemon commands when using Dolt backend, including read-only commands like `status`, `stop`, `logs`. Changes: - Rename guard to `guardDaemonStartForDolt` (more accurate) - Remove `PersistentPreRunE` from `daemonCmd` and `daemonsCmd` - Add `PreRunE` guard only to `daemonStartCmd` and `daemonsRestartCmd` - Update test to use new function name and test start command Now: - `bd daemon status` works with Dolt backend - `bd daemon start` blocked unless `--federation` flag - `bd daemon start --federation` works (starts dolt sql-server) Fixes: bd-n7o47 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
committed by
Steve Yegge
parent
4e3e9d1441
commit
bb4549abdd
@@ -48,7 +48,6 @@ Common operations:
|
|||||||
bd daemon killall Stop all running daemons
|
bd daemon killall Stop all running daemons
|
||||||
|
|
||||||
Run 'bd daemon --help' to see all subcommands.`,
|
Run 'bd daemon --help' to see all subcommands.`,
|
||||||
PersistentPreRunE: guardDaemonUnsupportedForDolt,
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
start, _ := cmd.Flags().GetBool("start")
|
start, _ := cmd.Flags().GetBool("start")
|
||||||
stop, _ := cmd.Flags().GetBool("stop")
|
stop, _ := cmd.Flags().GetBool("stop")
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ func singleProcessBackendHelp(backend string) string {
|
|||||||
return fmt.Sprintf("daemon mode is not supported with the %q backend (single-process only). To use daemon mode, initialize with %q (e.g. `bd init --backend sqlite`). Otherwise run commands in direct mode (default for dolt)", b, configfile.BackendSQLite)
|
return fmt.Sprintf("daemon mode is not supported with the %q backend (single-process only). To use daemon mode, initialize with %q (e.g. `bd init --backend sqlite`). Otherwise run commands in direct mode (default for dolt)", b, configfile.BackendSQLite)
|
||||||
}
|
}
|
||||||
|
|
||||||
// guardDaemonUnsupportedForDolt blocks all daemon-related commands when the current
|
// guardDaemonStartForDolt blocks daemon start/restart commands when the current
|
||||||
// workspace backend is Dolt.
|
// workspace backend is Dolt, unless --federation is specified.
|
||||||
//
|
//
|
||||||
// Rationale: embedded Dolt is effectively single-writer at the OS-process level. The
|
// Rationale: embedded Dolt is effectively single-writer at the OS-process level. The
|
||||||
// daemon architecture relies on multiple processes (CLI + daemon + helper spawns),
|
// daemon architecture relies on multiple processes (CLI + daemon + helper spawns),
|
||||||
@@ -28,8 +28,12 @@ func singleProcessBackendHelp(backend string) string {
|
|||||||
//
|
//
|
||||||
// Exception: --federation flag enables dolt sql-server mode which is multi-writer.
|
// Exception: --federation flag enables dolt sql-server mode which is multi-writer.
|
||||||
//
|
//
|
||||||
|
// Note: This guard should only be attached to commands that START a daemon process
|
||||||
|
// (start, restart). Read-only commands (status, stop, logs, health, list) are allowed
|
||||||
|
// even with Dolt backend.
|
||||||
|
//
|
||||||
// We still allow help output so users can discover the command surface.
|
// We still allow help output so users can discover the command surface.
|
||||||
func guardDaemonUnsupportedForDolt(cmd *cobra.Command, _ []string) error {
|
func guardDaemonStartForDolt(cmd *cobra.Command, _ []string) error {
|
||||||
// Allow `--help` for any daemon subcommand.
|
// Allow `--help` for any daemon subcommand.
|
||||||
if helpFlag := cmd.Flags().Lookup("help"); helpFlag != nil {
|
if helpFlag := cmd.Flags().Lookup("help"); helpFlag != nil {
|
||||||
if help, _ := cmd.Flags().GetBool("help"); help {
|
if help, _ := cmd.Flags().GetBool("help"); help {
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ Examples:
|
|||||||
bd daemon start --foreground # Run in foreground (for systemd/supervisord)
|
bd daemon start --foreground # Run in foreground (for systemd/supervisord)
|
||||||
bd daemon start --local # Local-only mode (no git sync)
|
bd daemon start --local # Local-only mode (no git sync)
|
||||||
bd daemon start --federation # Enable federation mode (dolt sql-server)`,
|
bd daemon start --federation # Enable federation mode (dolt sql-server)`,
|
||||||
|
PreRunE: guardDaemonStartForDolt,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
interval, _ := cmd.Flags().GetDuration("interval")
|
interval, _ := cmd.Flags().GetDuration("interval")
|
||||||
autoCommit, _ := cmd.Flags().GetBool("auto-commit")
|
autoCommit, _ := cmd.Flags().GetBool("auto-commit")
|
||||||
|
|||||||
@@ -79,7 +79,6 @@ Subcommands:
|
|||||||
logs - View daemon logs
|
logs - View daemon logs
|
||||||
killall - Stop all running daemons
|
killall - Stop all running daemons
|
||||||
restart - Restart a specific daemon (not yet implemented)`,
|
restart - Restart a specific daemon (not yet implemented)`,
|
||||||
PersistentPreRunE: guardDaemonUnsupportedForDolt,
|
|
||||||
}
|
}
|
||||||
var daemonsListCmd = &cobra.Command{
|
var daemonsListCmd = &cobra.Command{
|
||||||
Use: "list",
|
Use: "list",
|
||||||
@@ -225,7 +224,8 @@ var daemonsRestartCmd = &cobra.Command{
|
|||||||
Short: "Restart a specific bd daemon",
|
Short: "Restart a specific bd daemon",
|
||||||
Long: `Restart a specific bd daemon by workspace path or PID.
|
Long: `Restart a specific bd daemon by workspace path or PID.
|
||||||
Stops the daemon gracefully, then starts a new one.`,
|
Stops the daemon gracefully, then starts a new one.`,
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.ExactArgs(1),
|
||||||
|
PreRunE: guardDaemonStartForDolt,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
target := args[0]
|
target := args[0]
|
||||||
searchRoots, _ := cmd.Flags().GetStringSlice("search")
|
searchRoots, _ := cmd.Flags().GetStringSlice("search")
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ func TestDoltSingleProcess_TryAutoStartDoesNotCreateStartlock(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDoltSingleProcess_DaemonGuardBlocksCommands(t *testing.T) {
|
func TestDoltSingleProcess_DaemonGuardBlocksStartCommand(t *testing.T) {
|
||||||
oldDBPath := dbPath
|
oldDBPath := dbPath
|
||||||
t.Cleanup(func() { dbPath = oldDBPath })
|
t.Cleanup(func() { dbPath = oldDBPath })
|
||||||
dbPath = ""
|
dbPath = ""
|
||||||
@@ -78,12 +78,14 @@ func TestDoltSingleProcess_DaemonGuardBlocksCommands(t *testing.T) {
|
|||||||
beadsDir, _ := writeDoltWorkspace(t, ws)
|
beadsDir, _ := writeDoltWorkspace(t, ws)
|
||||||
t.Setenv("BEADS_DIR", beadsDir)
|
t.Setenv("BEADS_DIR", beadsDir)
|
||||||
|
|
||||||
// Ensure help flag exists (cobra adds it during execution; for unit testing we add it explicitly).
|
// Use daemonStartCmd which has the guard attached.
|
||||||
cmd := daemonCmd
|
// Ensure help and federation flags exist (cobra adds them during execution).
|
||||||
|
cmd := daemonStartCmd
|
||||||
cmd.Flags().Bool("help", false, "help")
|
cmd.Flags().Bool("help", false, "help")
|
||||||
err := guardDaemonUnsupportedForDolt(cmd, nil)
|
// Note: federation flag is already registered in init()
|
||||||
|
err := guardDaemonStartForDolt(cmd, nil)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("expected daemon guard error for dolt backend")
|
t.Fatalf("expected daemon guard error for dolt backend without --federation")
|
||||||
}
|
}
|
||||||
if !strings.Contains(err.Error(), "single-process") {
|
if !strings.Contains(err.Error(), "single-process") {
|
||||||
t.Fatalf("expected error to mention single-process, got: %v", err)
|
t.Fatalf("expected error to mention single-process, got: %v", err)
|
||||||
|
|||||||
Reference in New Issue
Block a user