reveil/model/action.go

183 lines
3.7 KiB
Go

package reveil
import (
"bufio"
"crypto/sha512"
"errors"
"fmt"
"io/fs"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
"git.nemunai.re/nemunaire/reveil/config"
)
type Action struct {
Id Identifier `json:"id"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
Path string `json:"path"`
Enabled bool `json:"enabled"`
fullPath string
}
func loadAction(path string) (string, string, error) {
fd, err := os.Open(path)
if err != nil {
return "", "", err
}
defer fd.Close()
fileScanner := bufio.NewScanner(fd)
fileScanner.Split(bufio.ScanLines)
var (
shebang = false
name = ""
description = ""
)
for fileScanner.Scan() {
line := strings.TrimSpace(fileScanner.Text())
if !shebang {
if len(line) < 2 || line[0] != '#' || line[1] != '!' {
return name, description, errors.New("Not a valid action file (shebang not found).")
}
shebang = true
continue
}
if len(line) < 2 || line[0] != '#' {
if len(description) > 0 {
return name, strings.TrimSpace(description), nil
}
continue
}
if len(name) == 0 {
name = strings.TrimSpace(line[1:])
} else {
description += strings.TrimSpace(line[1:]) + "\n"
}
}
return name, description, nil
}
func LoadAction(cfg *config.Config, path string) (*Action, error) {
actionsDir, err := filepath.Abs(cfg.ActionsDir)
if err != nil {
return nil, err
}
path = filepath.Join(actionsDir, path)
d, err := os.Stat(path)
if err != nil {
return nil, err
}
if !d.Mode().IsRegular() {
return nil, fmt.Errorf("%q is not a file, it cannot be an action.", path)
}
hash := sha512.Sum512([]byte(path))
// Parse content
name, description, err := loadAction(path)
if err != nil {
return nil, fmt.Errorf("Invalid action file (trying to parse %s): %s", path, err.Error())
}
if apath, err := filepath.Abs(path); err == nil {
path = apath
}
return &Action{
Id: hash[:],
Name: name,
Description: description,
Path: strings.TrimPrefix(path, actionsDir+"/"),
Enabled: d.Mode().Perm()&0111 != 0,
fullPath: path,
}, nil
}
func LoadActions(cfg *config.Config) (actions []*Action, err error) {
actionsDir, err := filepath.Abs(cfg.ActionsDir)
if err != nil {
return nil, err
}
err = filepath.Walk(cfg.ActionsDir, func(path string, d fs.FileInfo, err error) error {
if d.Mode().IsRegular() {
hash := sha512.Sum512([]byte(path))
// Parse content
name, description, err := loadAction(path)
if err != nil {
log.Printf("Invalid action file (trying to parse %s): %s", path, err.Error())
// Ignore invalid files
return nil
}
if description == "" {
return nil
}
if apath, err := filepath.Abs(path); err == nil {
path = apath
}
actions = append(actions, &Action{
Id: hash[:],
Name: name,
Description: description,
Path: strings.TrimPrefix(path, actionsDir+"/"),
Enabled: d.Mode().Perm()&0111 != 0,
fullPath: path,
})
}
return nil
})
return
}
func (a *Action) Rename(name string) error {
return errors.New("Not implemeted")
}
func (a *Action) Enable() error {
fi, err := os.Stat(a.Path)
if err != nil {
return err
}
return os.Chmod(a.Path, fi.Mode().Perm()|0111)
}
func (a *Action) Disable() error {
fi, err := os.Stat(a.Path)
if err != nil {
return err
}
return os.Chmod(a.Path, fi.Mode().Perm()&0666)
}
func (a *Action) Remove() error {
return os.Remove(a.Path)
}
func (a *Action) Launch(settings *Settings) (cmd *exec.Cmd, err error) {
cmd = exec.Command(a.fullPath)
cmd.Env = append(cmd.Environ(), fmt.Sprintf("LANG=%s", settings.Language))
err = cmd.Start()
return
}