Allow deleting projects from the project picker with x/X.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
||||
type Store interface {
|
||||
List() ([]Project, error)
|
||||
Ensure(id string) error
|
||||
Delete(id string) error
|
||||
}
|
||||
|
||||
// DirStore discovers projects as subdirectories of dataDir/projects.
|
||||
@@ -63,3 +64,25 @@ func (s *DirStore) Ensure(id string) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete removes the project directory and all of its files.
|
||||
func (s *DirStore) Delete(id string) error {
|
||||
if id == "" {
|
||||
return fmt.Errorf("project id is required")
|
||||
}
|
||||
dir := filepath.Join(s.projectsRoot(), id)
|
||||
st, err := os.Stat(dir)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return fmt.Errorf("project %s: not found", id)
|
||||
}
|
||||
return fmt.Errorf("stat project %s: %w", id, err)
|
||||
}
|
||||
if !st.IsDir() {
|
||||
return fmt.Errorf("project %s: not a directory", id)
|
||||
}
|
||||
if err := os.RemoveAll(dir); err != nil {
|
||||
return fmt.Errorf("delete project %s: %w", id, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package project_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"task/internal/project"
|
||||
)
|
||||
|
||||
func TestDirStoreDelete(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
store := project.NewDirStore(dir)
|
||||
|
||||
if err := store.Ensure("inbox"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := store.Ensure("client"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Drop a marker file so RemoveAll has something to wipe.
|
||||
marker := filepath.Join(dir, "projects", "client", "tickets.json")
|
||||
if err := os.WriteFile(marker, []byte("[]\n"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
list, err := store.List()
|
||||
if err != nil || len(list) != 2 {
|
||||
t.Fatalf("list before: %v len=%d", err, len(list))
|
||||
}
|
||||
|
||||
if err := store.Delete("client"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
list, err = store.List()
|
||||
if err != nil || len(list) != 1 || list[0].ID != "inbox" {
|
||||
t.Fatalf("list after: %v %+v", err, list)
|
||||
}
|
||||
if _, err := os.Stat(filepath.Join(dir, "projects", "client")); !os.IsNotExist(err) {
|
||||
t.Fatalf("client dir still present: %v", err)
|
||||
}
|
||||
|
||||
if err := store.Delete("missing"); err == nil {
|
||||
t.Fatal("expected error deleting missing project")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user