First commit
This commit is contained in:
commit
8200c2bc87
17 files changed
+2592
No files matched your search
@@ -0,0 +1,151 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Tag colore un mot-clé dans les messages affichés.
|
||||
type Tag struct {
|
||||
ID string `json:"id"`
|
||||
Pattern string `json:"pattern"`
|
||||
Color string `json:"color"`
|
||||
WholeWord bool `json:"wholeWord"`
|
||||
CaseSensitive bool `json:"caseSensitive"`
|
||||
Regex bool `json:"regex"`
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
func defaultTags() []Tag {
|
||||
return []Tag{
|
||||
{ID: "warning", Pattern: "warning", Color: "#f59e0b", WholeWord: true, Enabled: true},
|
||||
{ID: "error", Pattern: "error", Color: "#ef4444", WholeWord: true, Enabled: true},
|
||||
{ID: "ok", Pattern: "ok", Color: "#22c55e", WholeWord: true, Enabled: true},
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
errTagNotFound = errors.New("tag introuvable")
|
||||
colorRe = regexp.MustCompile(`^#[0-9a-fA-F]{6}$`)
|
||||
)
|
||||
|
||||
func (t *Tag) validate() error {
|
||||
t.Pattern = strings.TrimSpace(t.Pattern)
|
||||
if t.Pattern == "" {
|
||||
return errors.New("le mot-clé est obligatoire")
|
||||
}
|
||||
if !colorRe.MatchString(t.Color) {
|
||||
return errors.New("couleur invalide (format #rrggbb attendu)")
|
||||
}
|
||||
if t.Regex {
|
||||
if _, err := regexp.Compile(t.Pattern); err != nil {
|
||||
return fmt.Errorf("expression régulière invalide : %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TagStore conserve les tags dans un fichier JSON (volume /data).
|
||||
type TagStore struct {
|
||||
mu sync.Mutex
|
||||
path string
|
||||
tags []Tag
|
||||
}
|
||||
|
||||
func LoadTagStore(path string) (*TagStore, error) {
|
||||
s := &TagStore{path: path}
|
||||
b, err := os.ReadFile(path)
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
s.tags = defaultTags()
|
||||
return s, s.save()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := json.Unmarshal(b, &s.tags); err != nil {
|
||||
return nil, fmt.Errorf("%s : %w", path, err)
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// save écrit le fichier de façon atomique ; l'appelant détient le verrou.
|
||||
func (s *TagStore) save() error {
|
||||
b, err := json.MarshalIndent(s.tags, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(s.path), 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
tmp := s.path + ".tmp"
|
||||
if err := os.WriteFile(tmp, b, 0o644); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.Rename(tmp, s.path)
|
||||
}
|
||||
|
||||
func (s *TagStore) List() []Tag {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return append([]Tag(nil), s.tags...)
|
||||
}
|
||||
|
||||
func (s *TagStore) Create(t Tag) (Tag, error) {
|
||||
if err := t.validate(); err != nil {
|
||||
return t, err
|
||||
}
|
||||
t.ID = newID()
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.tags = append(s.tags, t)
|
||||
return t, s.save()
|
||||
}
|
||||
|
||||
func (s *TagStore) Update(id string, t Tag) (Tag, error) {
|
||||
if err := t.validate(); err != nil {
|
||||
return t, err
|
||||
}
|
||||
t.ID = id
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
for i := range s.tags {
|
||||
if s.tags[i].ID == id {
|
||||
s.tags[i] = t
|
||||
return t, s.save()
|
||||
}
|
||||
}
|
||||
return t, errTagNotFound
|
||||
}
|
||||
|
||||
func (s *TagStore) Delete(id string) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
for i := range s.tags {
|
||||
if s.tags[i].ID == id {
|
||||
s.tags = append(s.tags[:i], s.tags[i+1:]...)
|
||||
return s.save()
|
||||
}
|
||||
}
|
||||
return errTagNotFound
|
||||
}
|
||||
|
||||
func (s *TagStore) Reset() ([]Tag, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.tags = defaultTags()
|
||||
return append([]Tag(nil), s.tags...), s.save()
|
||||
}
|
||||
|
||||
func newID() string {
|
||||
b := make([]byte, 6)
|
||||
_, _ = rand.Read(b)
|
||||
return hex.EncodeToString(b)
|
||||
}
|
||||
Reference in new issue
Block a user