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 return []CacheLine{}
90 }
91 res := []CacheLine{}
92 for _, line := range bytes.Split(cache, []byte("\n")) {
93 if len(line) > 0 {
94 res = append(res, Unmarshal(string(line)))
95 }
96 }
97 return res
98}
99
100func (p *Plugin) toCache() string {
101 var buf bytes.Buffer
102 for _, cl := range p.cache {
103 buf.WriteString(cl.Marshal())
104 buf.WriteString("\n")
105 }
106 return buf.String()
107}
108
109func (p *Plugin) deleteInCache(fp string) {
110 res := make([]CacheLine, 0)
111 for _, cl := range p.cache {
112 if cl.fp != fp {
113 res = append(res, cl)
114 }
115 }
116 p.cache = res
117}
118
119func (p *Plugin) deleteInCacheConf(cacheLine CacheLine) {
120 res := make([]CacheLine, 0)
121 for _, cl := range p.cache {
122 if cl.fp != cacheLine.fp || cl.toPath != cacheLine.toPath {
123 res = append(res, cl)
124 }
125 }
126 p.cache = res
127}
128
129func (p *Plugin) appendInCache(cacheLine CacheLine) {
130 found := false // check if not already stored, in case inactive/active and wortree pass
131 for _, cl := range p.cache {
132 if cl.fp == cacheLine.fp && cl.toPath == cacheLine.toPath {
133 found = true
134 break
135 }
136 }
137 p.server.Log(fmt.Sprintf("fp %s is found %t with %s", cacheLine.fp, found, cacheLine.Marshal()))
138 if !found {
139 p.cache = append(p.cache, cacheLine)
140 } else {
141 p.modifyInCache(cacheLine.fp, cacheLine)
142 }
143}
144
145func (p *Plugin) modifyInCache(oldFp string, cacheLine CacheLine) {
146 res := make([]CacheLine, len(p.cache))
147 for i, cl := range p.cache {
148 if cl.fp == oldFp && cl.toPath == cacheLine.toPath {
149 res[i] = cacheLine
150 } else {
151 res[i] = cl
152 }
153 }
154 p.cache = res
155}