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}