mirror of
https://github.com/esengine/DeepSeek-Reasonix.git
synced 2026-11-07 10:45:59 -10:00
refactor(memory): keep index read fix within lint budgets
This commit is contained in:
1 parent
2eb878989e
commit
79acaf6e99
5 files changed
+140
-127
No files matched your search
@@ -381,36 +381,6 @@ func repairOwnerWrite(root *os.Root, path string, dir bool) {
|
||||
// MEMORY.md.
|
||||
var indexLineRe = regexp.MustCompile(`(?m)^\s*-\s\[.+?\]\(([^)]+)\.md\)\s*—\s.*$`)
|
||||
|
||||
// readIndexIn treats a missing index as empty, but does not hide other read errors.
|
||||
func readIndexIn(dir string) ([]byte, error) {
|
||||
existing, err := fileencoding.ReadFileUTF8(filepath.Join(dir, indexFile))
|
||||
if os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
}
|
||||
return existing, err
|
||||
}
|
||||
|
||||
// indexLinesExceptIn returns the managed MEMORY.md lines keyed by filename stem,
|
||||
// dropping the entry for name and reporting whether it was present.
|
||||
func indexLinesExceptIn(dir, name string) (map[string]string, bool, error) {
|
||||
existing, err := readIndexIn(dir)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
keep := map[string]string{}
|
||||
contains := false
|
||||
for line := range strings.SplitSeq(string(existing), "\n") {
|
||||
if mt := indexLineRe.FindStringSubmatch(line); mt != nil {
|
||||
if mt[1] == name {
|
||||
contains = true
|
||||
} else {
|
||||
keep[mt[1]] = strings.TrimRight(line, "\r")
|
||||
}
|
||||
}
|
||||
}
|
||||
return keep, contains, nil
|
||||
}
|
||||
|
||||
// flushIndexIn rewrites MEMORY.md in the given directory from the managed lines,
|
||||
// preserving hand-written content. Managed lines are updated or removed, and
|
||||
// new managed entries are appended in sorted order.
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package memory
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
fileencoding "reasonix/internal/fileutil/encoding"
|
||||
)
|
||||
|
||||
// readIndexIn treats a missing index as empty, but does not hide other read errors.
|
||||
func readIndexIn(dir string) ([]byte, error) {
|
||||
existing, err := fileencoding.ReadFileUTF8(filepath.Join(dir, indexFile))
|
||||
if os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
}
|
||||
return existing, err
|
||||
}
|
||||
|
||||
// indexLinesExceptIn returns the managed MEMORY.md lines keyed by filename stem,
|
||||
// dropping the entry for name and reporting whether it was present.
|
||||
func indexLinesExceptIn(dir, name string) (map[string]string, bool, error) {
|
||||
existing, err := readIndexIn(dir)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
keep := map[string]string{}
|
||||
contains := false
|
||||
for line := range strings.SplitSeq(string(existing), "\n") {
|
||||
if mt := indexLineRe.FindStringSubmatch(line); mt != nil {
|
||||
if mt[1] == name {
|
||||
contains = true
|
||||
} else {
|
||||
keep[mt[1]] = strings.TrimRight(line, "\r")
|
||||
}
|
||||
}
|
||||
}
|
||||
return keep, contains, nil
|
||||
}
|
||||
|
||||
func removeMemoryFromDir(path, name string) error {
|
||||
dir := filepath.Dir(path)
|
||||
lines, _, err := indexLinesExceptIn(dir, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.Remove(path); err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
return flushIndexIn(dir, lines)
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package memory
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStoreSavePreservesUnreadableIndex(t *testing.T) {
|
||||
s := Store{Dir: t.TempDir()}
|
||||
if _, err := s.Save(Memory{Name: "alpha", Description: "keep", Type: TypeProject, Body: "body"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
indexPath := filepath.Join(s.Dir, indexFile)
|
||||
before := mustReadString(t, indexPath)
|
||||
if err := os.Chmod(indexPath, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { _ = os.Chmod(indexPath, 0o644) })
|
||||
if _, err := os.ReadFile(indexPath); err == nil {
|
||||
t.Skip("this user can read files without read permission")
|
||||
}
|
||||
if _, err := s.Save(Memory{Name: "beta", Description: "new", Type: TypeProject, Body: "body"}); err == nil {
|
||||
t.Fatal("Save should report the index read error")
|
||||
}
|
||||
if err := os.Chmod(indexPath, 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := mustReadString(t, indexPath); got != before {
|
||||
t.Fatalf("Save overwrote an unreadable index:\n%s", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStoreArchivePreservesUnreadableIndex(t *testing.T) {
|
||||
s := Store{Dir: t.TempDir()}
|
||||
for _, name := range []string{"alpha", "beta"} {
|
||||
if _, err := s.Save(Memory{Name: name, Description: "keep", Type: TypeProject, Body: "body"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
indexPath := filepath.Join(s.Dir, indexFile)
|
||||
before := mustReadString(t, indexPath)
|
||||
if err := os.Chmod(indexPath, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { _ = os.Chmod(indexPath, 0o644) })
|
||||
if _, err := os.ReadFile(indexPath); err == nil {
|
||||
t.Skip("this user can read files without read permission")
|
||||
}
|
||||
if _, err := s.Archive("alpha"); err == nil {
|
||||
t.Fatal("Archive should report the index read error")
|
||||
}
|
||||
if err := os.Chmod(indexPath, 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := mustReadString(t, indexPath); got != before {
|
||||
t.Fatalf("Archive overwrote an unreadable index:\n%s", got)
|
||||
}
|
||||
if _, err := os.Stat(filepath.Join(s.Dir, "alpha.md")); err != nil {
|
||||
t.Fatalf("Archive moved the fact before checking the index: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlushIndexPreservesUnreadableFile(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
indexPath := filepath.Join(dir, indexFile)
|
||||
before := "# Memory\n\nHand-written note.\n"
|
||||
if err := os.WriteFile(indexPath, []byte(before), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Chmod(indexPath, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { _ = os.Chmod(indexPath, 0o644) })
|
||||
if _, err := os.ReadFile(indexPath); err == nil {
|
||||
t.Skip("this user can read files without read permission")
|
||||
}
|
||||
if err := flushIndexIn(dir, map[string]string{"beta": "- [beta](beta.md) — new"}); err == nil {
|
||||
t.Fatal("flushIndexIn should report the index read error")
|
||||
}
|
||||
if err := os.Chmod(indexPath, 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := mustReadString(t, indexPath); got != before {
|
||||
t.Fatalf("flushIndexIn overwrote hand-written content:\n%s", got)
|
||||
}
|
||||
}
|
||||
@@ -412,86 +412,6 @@ func TestStoreArchiveFlushesStaleIndexWithoutFile(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestStoreSavePreservesUnreadableIndex(t *testing.T) {
|
||||
s := Store{Dir: t.TempDir()}
|
||||
if _, err := s.Save(Memory{Name: "alpha", Description: "keep", Type: TypeProject, Body: "body"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
indexPath := filepath.Join(s.Dir, indexFile)
|
||||
before := mustReadString(t, indexPath)
|
||||
if err := os.Chmod(indexPath, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { _ = os.Chmod(indexPath, 0o644) })
|
||||
if _, err := os.ReadFile(indexPath); err == nil {
|
||||
t.Skip("this user can read files without read permission")
|
||||
}
|
||||
if _, err := s.Save(Memory{Name: "beta", Description: "new", Type: TypeProject, Body: "body"}); err == nil {
|
||||
t.Fatal("Save should report the index read error")
|
||||
}
|
||||
if err := os.Chmod(indexPath, 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := mustReadString(t, indexPath); got != before {
|
||||
t.Fatalf("Save overwrote an unreadable index:\n%s", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStoreArchivePreservesUnreadableIndex(t *testing.T) {
|
||||
s := Store{Dir: t.TempDir()}
|
||||
for _, name := range []string{"alpha", "beta"} {
|
||||
if _, err := s.Save(Memory{Name: name, Description: "keep", Type: TypeProject, Body: "body"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
indexPath := filepath.Join(s.Dir, indexFile)
|
||||
before := mustReadString(t, indexPath)
|
||||
if err := os.Chmod(indexPath, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { _ = os.Chmod(indexPath, 0o644) })
|
||||
if _, err := os.ReadFile(indexPath); err == nil {
|
||||
t.Skip("this user can read files without read permission")
|
||||
}
|
||||
if _, err := s.Archive("alpha"); err == nil {
|
||||
t.Fatal("Archive should report the index read error")
|
||||
}
|
||||
if err := os.Chmod(indexPath, 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := mustReadString(t, indexPath); got != before {
|
||||
t.Fatalf("Archive overwrote an unreadable index:\n%s", got)
|
||||
}
|
||||
if _, err := os.Stat(filepath.Join(s.Dir, "alpha.md")); err != nil {
|
||||
t.Fatalf("Archive moved the fact before checking the index: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlushIndexPreservesUnreadableFile(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
indexPath := filepath.Join(dir, indexFile)
|
||||
before := "# Memory\n\nHand-written note.\n"
|
||||
if err := os.WriteFile(indexPath, []byte(before), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Chmod(indexPath, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { _ = os.Chmod(indexPath, 0o644) })
|
||||
if _, err := os.ReadFile(indexPath); err == nil {
|
||||
t.Skip("this user can read files without read permission")
|
||||
}
|
||||
if err := flushIndexIn(dir, map[string]string{"beta": "- [beta](beta.md) — new"}); err == nil {
|
||||
t.Fatal("flushIndexIn should report the index read error")
|
||||
}
|
||||
if err := os.Chmod(indexPath, 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := mustReadString(t, indexPath); got != before {
|
||||
t.Fatalf("flushIndexIn overwrote hand-written content:\n%s", got)
|
||||
}
|
||||
}
|
||||
|
||||
func mustReadString(t *testing.T, path string) string {
|
||||
t.Helper()
|
||||
b, err := os.ReadFile(path)
|
||||
|
||||
@@ -254,15 +254,7 @@ func (s Store) SaveWithOptions(m Memory, opts SaveOptions) (SaveResult, error) {
|
||||
return SaveResult{}, err
|
||||
}
|
||||
if exists && cleanMemoryPath(existingPath) != cleanMemoryPath(path) {
|
||||
oldDir := filepath.Dir(existingPath)
|
||||
lines, _, err := indexLinesExceptIn(oldDir, existing.Name)
|
||||
if err != nil {
|
||||
return SaveResult{}, err
|
||||
}
|
||||
if err := os.Remove(existingPath); err != nil && !os.IsNotExist(err) {
|
||||
return SaveResult{}, err
|
||||
}
|
||||
if err := flushIndexIn(oldDir, lines); err != nil {
|
||||
if err := removeMemoryFromDir(existingPath, existing.Name); err != nil {
|
||||
return SaveResult{}, err
|
||||
}
|
||||
}
|
||||
@@ -278,14 +270,7 @@ func (s Store) SaveWithOptions(m Memory, opts SaveOptions) (SaveResult, error) {
|
||||
continue
|
||||
}
|
||||
if duplicate, _, ok := s.findActiveInDir(otherDir, m.Name); ok && duplicate.ID != m.ID {
|
||||
lines, _, err := indexLinesExceptIn(otherDir, duplicate.Name)
|
||||
if err != nil {
|
||||
return SaveResult{}, err
|
||||
}
|
||||
if _, err := archiveInDir(otherDir, duplicate.Name); err != nil {
|
||||
return SaveResult{}, err
|
||||
}
|
||||
if err := flushIndexIn(otherDir, lines); err != nil {
|
||||
if _, err := archiveMemoryInDir(otherDir, duplicate.Name); err != nil {
|
||||
return SaveResult{}, err
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user