diff --git a/daemon.go b/daemon.go new file mode 100644 index 0000000..88955f4 --- /dev/null +++ b/daemon.go @@ -0,0 +1,39 @@ +package main + +import ( + "github.com/go-ini/ini" +) + +type ScreenInfo struct { + Name string `ini:"name"` +} + +type ExecutionInfo struct { + Command string `ini:"command"` +} + +type DaemonInfo struct { + Enabled bool `ini:"enabled"` +} + +type DaemonConfig struct { + ScreenInfo `ini:"Screen"` + ExecutionInfo `ini:"Execution"` + DaemonInfo `ini:"Daemon"` +} + +func loadDaemon(cfgPath string) (*DaemonConfig, error) { + + cfg, err := ini.LoadSources(ini.LoadOptions{ + IgnoreInlineComment: true, + UnescapeValueCommentSymbols: true, + }, cfgPath) + + daemonConfig := new(DaemonConfig) + err = cfg.MapTo(daemonConfig) + if err != nil { + return daemonConfig, err + } + + return daemonConfig, nil +} diff --git a/daemons/test.ini b/daemons/test.ini new file mode 100644 index 0000000..40c4b8b --- /dev/null +++ b/daemons/test.ini @@ -0,0 +1,8 @@ +[Screen] +name = testgit + +[Execution] +command = bash + +[Daemon] +enabled = true \ No newline at end of file diff --git a/main.go b/main.go new file mode 100644 index 0000000..703ac73 --- /dev/null +++ b/main.go @@ -0,0 +1,75 @@ +package main + +import ( + "log" + "os/exec" + "path/filepath" + "strconv" + "time" +) + +func executeCommand(args ...string) (string, error) { + + baseCmd := args[0] + cmdArgs := args[1:] + + cmd := exec.Command(baseCmd, cmdArgs...) + out, err := cmd.Output() + if err != nil { + return string(out), err + } + + return string(out), nil +} + +func main() { + + files, err := filepath.Glob("daemons/*.ini") + if err != nil { + log.Fatal("Failed to find daemons: ", err) + return + } + + var daemons []DaemonConfig + for _, cfgPath := range files { + + cfg, err := loadDaemon(cfgPath) + if err != nil { + log.Fatal("Failed load ", cfgPath, err) + continue + } + + daemons = append(daemons, *cfg) + } + + firstRun := true + + for { + for _, daemon := range daemons { + + if !daemon.Enabled { + continue + } + + command := daemon.Command + name := daemon.Name + + screen, err := runScreen(name, command) + if err != nil { + if err.Error() == "SCREEN_ALREADY_EXISTS" { + if firstRun { + log.Print("(", name, ") WARNING: skipped, screen already exists") + } + } else { + log.Fatal("(", name, ") FAILED: ", command, " [", err, "]") + } + continue + } + + log.Print("(" + strconv.Itoa(screen.id) + ", " + screen.name + ") STARTED: " + command) + } + + firstRun = false + time.Sleep(5 * time.Second) + } +} diff --git a/screen.go b/screen.go new file mode 100644 index 0000000..efb66d2 --- /dev/null +++ b/screen.go @@ -0,0 +1,109 @@ +package main + +import ( + "github.com/pkg/errors" + "strconv" + "strings" +) + +type Screen struct { + id int + name string +} + +func runScreen(screenName string, command string) (Screen, error) { + + exists, err := doesScreenExists(screenName) + if err != nil { + return Screen{}, err + } + + if exists { + return Screen{}, errors.New("SCREEN_ALREADY_EXISTS") + } + + args := []string{"screen", "-dmS", screenName} + args = append(args, strings.Split(command, " ")...) + + _, err = executeCommand(args...) + if err != nil { + if err.Error() == "exit status 1" { + return Screen{}, errors.New("exit status 1: check command") + } + return Screen{}, err + } + + screen, err := getScreenByName(screenName) + if err != nil { + if err.Error() == "SCREEN_NOT_FOUND" { + return Screen{}, errors.New("Screen " + screenName + " not present after creation") + } + return Screen{}, err + } + + return screen, nil +} + +func getRunningScreens() ([]Screen, error) { + + output, err := executeCommand("screen", "-ls") + if err != nil { + if !strings.HasPrefix(output, "No Sockets found in") { + return []Screen{}, err + } + return []Screen{}, nil + } + + var screens []Screen + lines := strings.Split(output, "\n") + for _, line := range lines { + + if !strings.HasPrefix(line, "\t") { + continue + } + + lineParts := strings.Split(line, "\t") + fullScreenName := lineParts[1] + fullNameParts := strings.Split(fullScreenName, ".") + + name := strings.Join(fullNameParts[1:], ".") + id, err := strconv.Atoi(fullNameParts[0]) + if err != nil { + return []Screen{}, err + } + + screens = append(screens, Screen{id, name}) + } + + return screens, nil +} + +func doesScreenExists(screenName string) (bool, error) { + + _, err := getScreenByName(screenName) + if err != nil { + if err.Error() == "SCREEN_NOT_FOUND" { + return false, nil + } + return false, err + } + + return true, nil +} + +func getScreenByName(screenName string) (Screen, error) { + + screens, err := getRunningScreens() + if err != nil { + return Screen{}, err + } + + for _, screen := range screens { + if screen.name != screenName { + continue + } + return screen, nil + } + + return Screen{}, errors.New("SCREEN_NOT_FOUND") +}