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 }