70 lines
1.6 KiB
Go
70 lines
1.6 KiB
Go
package workspace
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
|
|
"git.michelsen.id/phill/chron/chron-note/internal/domain"
|
|
)
|
|
|
|
func (ws *Workspace) Exists(id domain.ObjectID) (bool, error) {
|
|
_, err := os.Stat(ws.ObjectPath(id))
|
|
if err == nil {
|
|
return true, nil
|
|
}
|
|
if os.IsNotExist(err) {
|
|
return false, nil
|
|
}
|
|
return false, fmt.Errorf("stat object %s: %w", id.String(), err)
|
|
}
|
|
|
|
func (ws *Workspace) Read(id domain.ObjectID) ([]byte, error) {
|
|
b, err := os.ReadFile(ws.ObjectPath(id))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("read object %s: %w", id.String(), err)
|
|
}
|
|
return b, nil
|
|
}
|
|
|
|
func (ws *Workspace) Write(id domain.ObjectID, b []byte) error {
|
|
if err := os.MkdirAll(ws.Dir, 0o755); err != nil {
|
|
return fmt.Errorf("mkdir workspace dir: %w", err)
|
|
}
|
|
|
|
dst := ws.ObjectPath(id)
|
|
|
|
f, err := os.CreateTemp(ws.Dir, id.String()+".*.tmp")
|
|
if err != nil {
|
|
return fmt.Errorf("create temp for object %s: %w", id.String(), err)
|
|
}
|
|
tmp := f.Name()
|
|
|
|
// Best-effort cleanup on failure.
|
|
defer func() { _ = os.Remove(tmp) }()
|
|
|
|
if _, err := f.Write(b); err != nil {
|
|
_ = f.Close()
|
|
return fmt.Errorf("write temp for object %s: %w", id.String(), err)
|
|
}
|
|
if err := f.Close(); err != nil {
|
|
return fmt.Errorf("close temp for object %s: %w", id.String(), err)
|
|
}
|
|
|
|
if err := os.Rename(tmp, dst); err != nil {
|
|
return fmt.Errorf("rename temp for object %s: %w", id.String(), err)
|
|
}
|
|
|
|
// Rename succeeded; prevent deferred cleanup.
|
|
_ = os.Remove(tmp)
|
|
return nil
|
|
}
|
|
|
|
func (ws *Workspace) Delete(id domain.ObjectID) error {
|
|
p := ws.ObjectPath(id)
|
|
err := os.Remove(p)
|
|
if err == nil || os.IsNotExist(err) {
|
|
return nil
|
|
}
|
|
return fmt.Errorf("delete object %s: %w", id.String(), err)
|
|
}
|