GitRoot
craft your forge, build your project, grow your community freely
1// SPDX-FileCopyrightText: 2025 Romain Maneschi <romain@gitroot.dev>
2//
3// SPDX-License-Identifier: EUPL-1.2
4
5package main
6
7import (
8 "bytes"
9 "errors"
10 "fmt"
11 "io/fs"
12 "slices"
13 "strings"
14)
15
16type CacheLine struct {
17 fp string
18 toPath string
19 title string
20 selects []string
21}
22
23func (p *Plugin) extractCacheLines(fp string) ([]CacheLine, []CacheLine) {
24 res := []CacheLine{}
25 toDelete := []CacheLine{}
26 for _, conf := range p.config {
27 if conf.glob.Match(fp) {
28 content, err := fs.ReadFile(p.server.Worktree(), fp)
29 if err != nil {
30 p.server.Log("extractCacheLines ReadFile " + fp + " == " + err.Error())
31 continue
32 }
33 if bytes.Contains(content, []byte(conf.Where)) {
34 res = append(res, p.extractCacheLine(fp, conf, content))
35 } else {
36 toDelete = append(toDelete, CacheLine{fp: fp, toPath: conf.To})
37 }
38 }
39 }
40 return res, toDelete
41}
42func (p *Plugin) extractCacheLine(fp string, c conf, content []byte) CacheLine {
43 res := CacheLine{
44 fp: fp,
45 toPath: c.To,
46 title: findTitle(fp, content),
47 selects: make([]string, 0),
48 }
49 for _, selection := range c.selections {
50 t := selection.FindSubmatch(content)
51 if len(t) > 1 {
52 toAppend := ""
53 for _, a := range t[1:] {
54 if toAppend == "" {
55 toAppend = string(a)
56 } else {
57 toAppend = fmt.Sprintf("%s %s", toAppend, a)
58 }
59 }
60 res.selects = append(res.selects, toAppend)
61 } else {
62 res.selects = append(res.selects, " ")
63 }
64 }
65 return res
66}
67
68func (c CacheLine) Marshal() string {
69 return fmt.Sprintf("%s||%s||%s||%s", c.fp, c.toPath, c.title, strings.Join(c.selects, ";;"))
70}
71
72func Unmarshal(s string) CacheLine {
73 data := strings.Split(s, "||")
74 return CacheLine{
75 fp: data[0],
76 toPath: data[1],
77 title: data[2],
78 selects: slices.DeleteFunc(strings.Split(data[3], ";;"), func(s string) bool { return s == "" }),
79 }
80}
81
82func (p *Plugin) fromCache() []CacheLine {
83 cache, err := fs.ReadFile(p.server.Cache(), cachePath)
84 if err != nil && errors.Is(err, fs.ErrNotExist) {
85 p.server.Log("cache not existing")
86 return []CacheLine{}
87 } else if err != nil {
88 p.server.LogError("can't read cache in fromCache", err)
89 }
90 res := []CacheLine{}
91 for _, line := range bytes.Split(cache, []byte("\n")) {
92 if len(line) > 0 {
93 res = append(res, Unmarshal(string(line)))
94 }
95 }
96 return res
97}
98
99func (p *Plugin) toCache() string {
100 var buf bytes.Buffer
101 for _, cl := range p.cache {
102 buf.WriteString(cl.Marshal())
103 buf.WriteString("\n")
104 }
105 return buf.String()
106}
107
108func (p *Plugin) deleteInCache(fp string) {
109 res := make([]CacheLine, 0)
110 for _, cl := range p.cache {
111 if cl.fp != fp {
112 res = append(res, cl)
113 }
114 }
115 p.cache = res
116}
117
118func (p *Plugin) deleteInCacheConf(cacheLine CacheLine) {
119 res := make([]CacheLine, 0)
120 for _, cl := range p.cache {
121 if cl.fp != cacheLine.fp || cl.toPath != cacheLine.toPath {
122 res = append(res, cl)
123 }
124 }
125 p.cache = res
126}
127
128func (p *Plugin) appendInCache(cacheLine CacheLine) {
129 found := false // check if not already stored, in case inactive/active and wortree pass
130 for _, cl := range p.cache {
131 if cl.fp == cacheLine.fp && cl.toPath == cacheLine.toPath {
132 found = true
133 break
134 }
135 }
136 p.server.Log(fmt.Sprintf("fp %s is found %t with %s", cacheLine.fp, found, cacheLine.Marshal()))
137 if !found {
138 p.cache = append(p.cache, cacheLine)
139 } else {
140 p.modifyInCache(cacheLine.fp, cacheLine)
141 }
142}
143
144func (p *Plugin) modifyInCache(oldFp string, cacheLine CacheLine) {
145 res := make([]CacheLine, len(p.cache))
146 for i, cl := range p.cache {
147 if cl.fp == oldFp && cl.toPath == cacheLine.toPath {
148 res[i] = cacheLine
149 } else {
150 res[i] = cl
151 }
152 }
153 p.cache = res
154}