Fix panics in dep commands when daemon is running (#72)
Multiple dep commands were directly accessing store without checking if daemon was available, causing nil pointer dereferences when daemon was running. Fixed commands: - dep add: Now uses RPC when daemon is available - dep remove: Now uses RPC when daemon is available - dep tree: Added fallback to direct storage when daemon lacks RPC support - dep cycles: Added fallback to direct storage when daemon lacks RPC support The commands with RPC support (add/remove) now use the daemon client when available. Commands without RPC support (tree/cycles) fall back to opening a direct database connection when the daemon is running.
This commit is contained in:
@@ -8,6 +8,8 @@ import (
|
|||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/steveyegge/beads/internal/rpc"
|
||||||
|
"github.com/steveyegge/beads/internal/storage/sqlite"
|
||||||
"github.com/steveyegge/beads/internal/types"
|
"github.com/steveyegge/beads/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -23,6 +25,32 @@ var depAddCmd = &cobra.Command{
|
|||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
depType, _ := cmd.Flags().GetString("type")
|
depType, _ := cmd.Flags().GetString("type")
|
||||||
|
|
||||||
|
// If daemon is running, use RPC
|
||||||
|
if daemonClient != nil {
|
||||||
|
depArgs := &rpc.DepAddArgs{
|
||||||
|
FromID: args[0],
|
||||||
|
ToID: args[1],
|
||||||
|
DepType: depType,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := daemonClient.AddDependency(depArgs)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if jsonOutput {
|
||||||
|
fmt.Println(string(resp.Data))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
green := color.New(color.FgGreen).SprintFunc()
|
||||||
|
fmt.Printf("%s Added dependency: %s depends on %s (%s)\n",
|
||||||
|
green("✓"), args[0], args[1], depType)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Direct mode
|
||||||
dep := &types.Dependency{
|
dep := &types.Dependency{
|
||||||
IssueID: args[0],
|
IssueID: args[0],
|
||||||
DependsOnID: args[1],
|
DependsOnID: args[1],
|
||||||
@@ -84,6 +112,31 @@ var depRemoveCmd = &cobra.Command{
|
|||||||
Short: "Remove a dependency",
|
Short: "Remove a dependency",
|
||||||
Args: cobra.ExactArgs(2),
|
Args: cobra.ExactArgs(2),
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
// If daemon is running, use RPC
|
||||||
|
if daemonClient != nil {
|
||||||
|
depArgs := &rpc.DepRemoveArgs{
|
||||||
|
FromID: args[0],
|
||||||
|
ToID: args[1],
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := daemonClient.RemoveDependency(depArgs)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if jsonOutput {
|
||||||
|
fmt.Println(string(resp.Data))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
green := color.New(color.FgGreen).SprintFunc()
|
||||||
|
fmt.Printf("%s Removed dependency: %s no longer depends on %s\n",
|
||||||
|
green("✓"), args[0], args[1])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Direct mode
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
if err := store.RemoveDependency(ctx, args[0], args[1], actor); err != nil {
|
if err := store.RemoveDependency(ctx, args[0], args[1], actor); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||||
@@ -113,6 +166,17 @@ var depTreeCmd = &cobra.Command{
|
|||||||
Short: "Show dependency tree",
|
Short: "Show dependency tree",
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.ExactArgs(1),
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
// If daemon is running but doesn't support this command, use direct storage
|
||||||
|
if daemonClient != nil && store == nil {
|
||||||
|
var err error
|
||||||
|
store, err = sqlite.New(dbPath)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error: failed to open database: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
defer store.Close()
|
||||||
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
tree, err := store.GetDependencyTree(ctx, args[0], 50)
|
tree, err := store.GetDependencyTree(ctx, args[0], 50)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -163,6 +227,17 @@ var depCyclesCmd = &cobra.Command{
|
|||||||
Use: "cycles",
|
Use: "cycles",
|
||||||
Short: "Detect dependency cycles",
|
Short: "Detect dependency cycles",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
// If daemon is running but doesn't support this command, use direct storage
|
||||||
|
if daemonClient != nil && store == nil {
|
||||||
|
var err error
|
||||||
|
store, err = sqlite.New(dbPath)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error: failed to open database: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
defer store.Close()
|
||||||
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
cycles, err := store.DetectCycles(ctx)
|
cycles, err := store.DetectCycles(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user