89 lines
2.0 KiB
Go
89 lines
2.0 KiB
Go
package project
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
)
|
|
|
|
// Store manages project directories under DataDir/projects.
|
|
type Store interface {
|
|
List() ([]Project, error)
|
|
Ensure(id string) error
|
|
Delete(id string) error
|
|
}
|
|
|
|
// DirStore discovers projects as subdirectories of dataDir/projects.
|
|
type DirStore struct {
|
|
dataDir string
|
|
}
|
|
|
|
// NewDirStore creates a project store rooted at dataDir.
|
|
func NewDirStore(dataDir string) *DirStore {
|
|
return &DirStore{dataDir: dataDir}
|
|
}
|
|
|
|
func (s *DirStore) projectsRoot() string {
|
|
return filepath.Join(s.dataDir, "projects")
|
|
}
|
|
|
|
// List returns all project directories, sorted by name.
|
|
func (s *DirStore) List() ([]Project, error) {
|
|
root := s.projectsRoot()
|
|
entries, err := os.ReadDir(root)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return []Project{}, nil
|
|
}
|
|
return nil, fmt.Errorf("list projects: %w", err)
|
|
}
|
|
|
|
var projects []Project
|
|
for _, e := range entries {
|
|
if !e.IsDir() {
|
|
continue
|
|
}
|
|
name := e.Name()
|
|
projects = append(projects, Project{ID: name, Name: name})
|
|
}
|
|
sort.Slice(projects, func(i, j int) bool {
|
|
return projects[i].Name < projects[j].Name
|
|
})
|
|
return projects, nil
|
|
}
|
|
|
|
// Ensure creates the project directory if it does not exist.
|
|
func (s *DirStore) Ensure(id string) error {
|
|
if id == "" {
|
|
return fmt.Errorf("project id is required")
|
|
}
|
|
dir := filepath.Join(s.projectsRoot(), id)
|
|
if err := os.MkdirAll(dir, 0o755); err != nil {
|
|
return fmt.Errorf("create project %s: %w", id, err)
|
|
}
|
|
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
|
|
}
|