178 lines
3 KiB
Go
178 lines
3 KiB
Go
|
|
package storage
|
||
|
|
|
||
|
|
import (
|
||
|
|
"encoding/json"
|
||
|
|
"fmt"
|
||
|
|
"os"
|
||
|
|
"path/filepath"
|
||
|
|
"sync"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
const configDir = ".tolo"
|
||
|
|
const dbFile = "tolo.db.json"
|
||
|
|
|
||
|
|
type Alias struct {
|
||
|
|
Name string `json:"name"`
|
||
|
|
Command string `json:"command"`
|
||
|
|
CreatedAt string `json:"created_at"`
|
||
|
|
}
|
||
|
|
|
||
|
|
type Data struct {
|
||
|
|
Aliases []Alias `json:"aliases"`
|
||
|
|
mu sync.RWMutex
|
||
|
|
}
|
||
|
|
|
||
|
|
var data *Data
|
||
|
|
var dataFile string
|
||
|
|
|
||
|
|
func init() {
|
||
|
|
homeDir, err := os.UserHomeDir()
|
||
|
|
if err != nil {
|
||
|
|
panic(err)
|
||
|
|
}
|
||
|
|
dataFile = filepath.Join(homeDir, configDir, dbFile)
|
||
|
|
data = &Data{}
|
||
|
|
load()
|
||
|
|
}
|
||
|
|
|
||
|
|
func load() error {
|
||
|
|
data.mu.Lock()
|
||
|
|
defer data.mu.Unlock()
|
||
|
|
|
||
|
|
if err := os.MkdirAll(filepath.Dir(dataFile), 0755); err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
content, err := os.ReadFile(dataFile)
|
||
|
|
if err != nil {
|
||
|
|
if os.IsNotExist(err) {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(content) == 0 {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
return json.Unmarshal(content, data)
|
||
|
|
}
|
||
|
|
|
||
|
|
func saveLocked() error {
|
||
|
|
content, err := json.MarshalIndent(data, "", " ")
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
return os.WriteFile(dataFile, content, 0644)
|
||
|
|
}
|
||
|
|
|
||
|
|
func save() error {
|
||
|
|
data.mu.Lock()
|
||
|
|
defer data.mu.Unlock()
|
||
|
|
return saveLocked()
|
||
|
|
}
|
||
|
|
|
||
|
|
func AddAlias(name, command string) error {
|
||
|
|
data.mu.Lock()
|
||
|
|
defer data.mu.Unlock()
|
||
|
|
|
||
|
|
for _, a := range data.Aliases {
|
||
|
|
if a.Name == name {
|
||
|
|
return fmt.Errorf("alias '%s' already exists", name)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
data.Aliases = append(data.Aliases, Alias{
|
||
|
|
Name: name,
|
||
|
|
Command: command,
|
||
|
|
CreatedAt: time.Now().Format(time.RFC3339),
|
||
|
|
})
|
||
|
|
|
||
|
|
return saveLocked()
|
||
|
|
}
|
||
|
|
|
||
|
|
func GetAlias(name string) (Alias, bool) {
|
||
|
|
data.mu.RLock()
|
||
|
|
defer data.mu.RUnlock()
|
||
|
|
|
||
|
|
for _, a := range data.Aliases {
|
||
|
|
if a.Name == name {
|
||
|
|
return a, true
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return Alias{}, false
|
||
|
|
}
|
||
|
|
|
||
|
|
func UpdateAlias(name, command string) error {
|
||
|
|
data.mu.Lock()
|
||
|
|
defer data.mu.Unlock()
|
||
|
|
|
||
|
|
for i, a := range data.Aliases {
|
||
|
|
if a.Name == name {
|
||
|
|
data.Aliases[i].Command = command
|
||
|
|
return saveLocked()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return fmt.Errorf("alias '%s' not found", name)
|
||
|
|
}
|
||
|
|
|
||
|
|
func DeleteAlias(name string) error {
|
||
|
|
data.mu.Lock()
|
||
|
|
defer data.mu.Unlock()
|
||
|
|
|
||
|
|
for i, a := range data.Aliases {
|
||
|
|
if a.Name == name {
|
||
|
|
data.Aliases = append(data.Aliases[:i], data.Aliases[i+1:]...)
|
||
|
|
return saveLocked()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return fmt.Errorf("alias '%s' not found", name)
|
||
|
|
}
|
||
|
|
|
||
|
|
func ListAliases() []Alias {
|
||
|
|
data.mu.RLock()
|
||
|
|
defer data.mu.RUnlock()
|
||
|
|
|
||
|
|
return data.Aliases
|
||
|
|
}
|
||
|
|
|
||
|
|
func ShowAlias(name string) (Alias, bool) {
|
||
|
|
data.mu.RLock()
|
||
|
|
defer data.mu.RUnlock()
|
||
|
|
|
||
|
|
for _, a := range data.Aliases {
|
||
|
|
if a.Name == name {
|
||
|
|
return a, true
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return Alias{}, false
|
||
|
|
}
|
||
|
|
|
||
|
|
func SearchAliases(query string) []Alias {
|
||
|
|
data.mu.RLock()
|
||
|
|
defer data.mu.RUnlock()
|
||
|
|
|
||
|
|
var results []Alias
|
||
|
|
for _, a := range data.Aliases {
|
||
|
|
if contains(a.Name, query) || contains(a.Command, query) {
|
||
|
|
results = append(results, a)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return results
|
||
|
|
}
|
||
|
|
|
||
|
|
func contains(s, substr string) bool {
|
||
|
|
return len(s) >= len(substr) && (s == substr || findSubstring(s, substr))
|
||
|
|
}
|
||
|
|
|
||
|
|
func findSubstring(s, substr string) bool {
|
||
|
|
for i := 0; i <= len(s)-len(substr); i++ {
|
||
|
|
if s[i:i+len(substr)] == substr {
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return false
|
||
|
|
}
|