summaryrefslogtreecommitdiff
path: root/cache/cache.go
diff options
context:
space:
mode:
Diffstat (limited to 'cache/cache.go')
-rw-r--r--cache/cache.go113
1 files changed, 113 insertions, 0 deletions
diff --git a/cache/cache.go b/cache/cache.go
new file mode 100644
index 0000000..b57d8b8
--- /dev/null
+++ b/cache/cache.go
@@ -0,0 +1,113 @@
+package cache
+
+import (
+ "bufio"
+ "errors"
+ "io"
+ "io/fs"
+ "os"
+ "path"
+ "pik/model"
+ "pik/paths"
+ "strings"
+)
+
+type Cache struct {
+ Entries []Entry
+}
+
+func (c Cache) Merge(other Cache) Cache {
+ mp := make(map[string]string)
+ for _, e := range append(c.Entries, other.Entries...) {
+ mp[e.Path] = e.Label
+ }
+ result := Cache{}
+ for p, l := range mp {
+ result.Entries = append(result.Entries, Entry{Label: l, Path: p})
+ }
+ return result
+}
+
+type Entry struct {
+ Path string
+ Label string
+}
+
+var Path = path.Join(paths.Cache, "contexts")
+
+var UnexpectedEntryError = errors.New("unexpected cache entry")
+
+func Load() (Cache, error) {
+ fd, err := os.Open(Path)
+ if errors.Is(err, os.ErrNotExist) {
+ return Cache{}, nil
+ } else if err != nil {
+ return Cache{}, err
+ }
+ defer fd.Close()
+ return FromReader(fd)
+}
+
+func FromReader(r io.Reader) (Cache, error) {
+ c := Cache{}
+ scanner := bufio.NewScanner(r)
+ for scanner.Scan() {
+ line := strings.TrimSpace(scanner.Text())
+ if line == "" || line[0] == '#' || line[0:2] == "//" {
+ continue
+ }
+
+ entry := &Entry{}
+ parts := strings.SplitN(line, "#", 2)
+ switch len(parts) {
+ case 2:
+ entry.Label = strings.TrimSpace(parts[1])
+ fallthrough
+ case 1:
+ entry.Path = strings.TrimSpace(parts[0])
+ default:
+ return c, UnexpectedEntryError
+ }
+ c.Entries = append(c.Entries, *entry)
+ }
+ return c, nil
+}
+
+func (c Cache) String() string {
+ b := strings.Builder{}
+ for _, e := range c.Entries {
+ b.WriteString(e.Path)
+ b.WriteString(" # ")
+ b.WriteString(e.Label)
+ b.WriteString("\n")
+ }
+ return b.String()
+}
+
+func New(st *model.State) Cache {
+ c := &Cache{}
+ for _, s := range st.Sources {
+ c.Entries = append(c.Entries, Entry{
+ Path: s.Path,
+ Label: s.Label(),
+ })
+ }
+ return *c
+}
+
+func Save(s *model.State) error {
+ ld, err := Load()
+ if err != nil {
+ return err
+ }
+ c := New(s).Merge(ld)
+ return os.WriteFile(Path, []byte(c.String()), os.ModePerm)
+}
+
+func LoadState(f fs.FS, cache Cache, indexers []model.Indexer, runners []model.Runner) (*model.State, error) {
+ var locs []string
+ for _, e := range cache.Entries {
+ locs = append(locs, e.Path)
+ }
+ return model.NewState(f, locs, indexers, runners)
+}