From 88b07ea934c9e2c1fa20dfd3e72ea93bd0059f32 Mon Sep 17 00:00:00 2001 From: Micheal Wilkinson Date: Fri, 20 Mar 2026 17:49:55 +0000 Subject: [PATCH] feat(destroy): implement destroy command parity --- internal/homesick/cli/cli.go | 18 ++++++++++-------- internal/homesick/core/core.go | 27 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/internal/homesick/cli/cli.go b/internal/homesick/cli/cli.go index 4e90d75..de5a062 100644 --- a/internal/homesick/cli/cli.go +++ b/internal/homesick/cli/cli.go @@ -168,7 +168,9 @@ type commitCmd struct { Castle string `arg:"" optional:"" name:"CASTLE" help:"Castle name."` } -type destroyCmd struct{} +type destroyCmd struct { + Castle string `arg:"" optional:"" name:"CASTLE" help:"Castle name."` +} type cdCmd struct{} @@ -189,13 +191,13 @@ func (c *pushCmd) Run(app *core.App) error { return app.Push(defaultCastle(c.Cas func (c *commitCmd) Run(app *core.App) error { return app.Commit(defaultCastle(c.Castle), c.Message) } -func (c *destroyCmd) Run() error { return notImplemented("destroy") } -func (c *cdCmd) Run() error { return notImplemented("cd") } -func (c *openCmd) Run() error { return notImplemented("open") } -func (c *execCmd) Run() error { return notImplemented("exec") } -func (c *execAllCmd) Run() error { return notImplemented("exec_all") } -func (c *rcCmd) Run(app *core.App) error { return app.Rc(defaultCastle(c.Castle)) } -func (c *generateCmd) Run() error { return notImplemented("generate") } +func (c *destroyCmd) Run(app *core.App) error { return app.Destroy(defaultCastle(c.Castle)) } +func (c *cdCmd) Run() error { return notImplemented("cd") } +func (c *openCmd) Run() error { return notImplemented("open") } +func (c *execCmd) Run() error { return notImplemented("exec") } +func (c *execAllCmd) Run() error { return notImplemented("exec_all") } +func (c *rcCmd) Run(app *core.App) error { return app.Rc(defaultCastle(c.Castle)) } +func (c *generateCmd) Run() error { return notImplemented("generate") } func defaultCastle(castle string) string { if strings.TrimSpace(castle) == "" { diff --git a/internal/homesick/core/core.go b/internal/homesick/core/core.go index 8b7a282..a16cd6e 100644 --- a/internal/homesick/core/core.go +++ b/internal/homesick/core/core.go @@ -165,6 +165,33 @@ func (a *App) Commit(castle string, message string) error { return runGitWithIO(castledir, a.Stdout, a.Stderr, "commit", "-m", trimmedMessage) } +func (a *App) Destroy(castle string) error { + if strings.TrimSpace(castle) == "" { + castle = "dotfiles" + } + + castleRoot := filepath.Join(a.ReposDir, castle) + castleInfo, err := os.Lstat(castleRoot) + if err != nil { + if errors.Is(err, os.ErrNotExist) { + return fmt.Errorf("castle %q not found", castle) + } + return err + } + + // Only attempt unlinking managed home files for regular castle directories. + if castleInfo.Mode()&os.ModeSymlink == 0 { + castleHome := filepath.Join(castleRoot, "home") + if info, statErr := os.Stat(castleHome); statErr == nil && info.IsDir() { + if unlinkErr := a.UnlinkCastle(castle); unlinkErr != nil { + return unlinkErr + } + } + } + + return os.RemoveAll(castleRoot) +} + func (a *App) Link(castle string) error { if strings.TrimSpace(castle) == "" { castle = "dotfiles"