diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 0000000..7c4d9ff --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,84 @@ +package main + +import ( + "fmt" + "os" + "os/user" + "strings" + + "gogs.bullercodeworks.com/brian/gosyphus" +) + +func main() { + var proc string + if len(os.Args) > 1 { + // The first argument is the executable that we want to serve + proc = os.Args[1] + } + cwd, err := os.Getwd() + wd := cwd + wd = requestParam("Working Directory", wd, true) + for !checkFileExists(proc) { + if len(proc) > 0 { + fmt.Println("Couldn't find file: " + proc) + } + proc = requestParam("Process", proc, true) + } + if !strings.HasPrefix(proc, "/") { + proc = cwd + "/" + proc + } + var userName string + user, err := user.Current() + if err == nil { + userName = user.Name + } + userName = requestParam("Username", userName, true) + groupName := requestParam("Group Name", userName, true) + //desc := requestParam("Description", "", false) + outFile := requestParam("Output File", "", true) + if !strings.HasSuffix(outFile, ".service") { + outFile = outFile + ".service" + } + // TODO: Request Environment + /* + environ := os.Environ() + for i := range environ { + fmt.Println(environ[i]) + } + */ + g := gosyphus.NewService(wd, proc, userName, groupName) + //g.Describe(desc) + g.GenerateFile(outFile) +} + +func requestParam(label, def string, req bool) string { + var firstRun = true + var newVal string + for firstRun || (req && len(newVal) == 0) { + fmt.Print(label) + fmt.Print(" [") + outDef := def + if len(outDef) == 0 { + outDef = "No default" + } + fmt.Print(outDef) + fmt.Print("]: ") + fmt.Scanf("%s", &newVal) + if len(newVal) == 0 { + newVal = def + } + firstRun = false + } + return newVal +} + +func checkFileExists(fn string) bool { + _, err := os.Stat(fn) + if err == nil { + return true + } + if os.IsNotExist(err) { + return false + } + return true +} diff --git a/gosyphus.go b/gosyphus.go new file mode 100644 index 0000000..1288503 --- /dev/null +++ b/gosyphus.go @@ -0,0 +1,123 @@ +package gosyphus + +import ( + "os" + "strings" +) + +// Gosyphus represents a Systemd service +type Gosyphus struct { + servType string + description string + user string + group string + directory string + process string + restart bool + needNetwork bool + environment map[string]string + wantedBy string +} + +// NewService creates a service +func NewService(wd, proc, usr, grp string) *Gosyphus { + g := &Gosyphus{ + servType: "simple", + directory: wd, + process: proc, + user: usr, + group: grp, + restart: true, + needNetwork: true, + wantedBy: "multi-user.target", + } + g.environment = make(map[string]string) + return g +} + +// Describe sets the description of the service +func (g *Gosyphus) Describe(desc string) { + g.description = desc +} + +// DisableNetwork removes the network requirement from the service +func (g *Gosyphus) DisableNetwork() { + g.needNetwork = false +} + +// EnableNetwork adds the network requirement to the service +func (g *Gosyphus) EnableNetwork() { + g.needNetwork = true +} + +// DisableRestart sets the 'Restart' flag to 'never' +func (g *Gosyphus) DisableRestart() { + g.restart = false +} + +// EnableRestart sets the 'Restart' flag to 'always' +func (g *Gosyphus) EnableRestart() { + g.restart = true +} + +// AddToEnvironment adds a new line to the service environment +func (g *Gosyphus) AddToEnvironment(k, v string) { + g.environment[k] = v +} + +// SetEnvironmentToCurrent copies the active environment into the service +func (g *Gosyphus) SetEnvironmentToCurrent() { + for _, env := range os.Environ() { + vars := strings.Split(env, "=") + if len(vars) == 2 { + g.AddToEnvironment(vars[0], vars[1]) + } + } +} + +// GenerateFile generates the .service file in the current directory +func (g *Gosyphus) GenerateFile(filename string) error { + // For now, we force the USER and HOME environment variables + // TODO: make this dynamic + g.AddToEnvironment("USER", g.user) + g.AddToEnvironment("HOME", "/home/"+g.user) + + f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY, 0664) + if err != nil { + return err + } + f.WriteString("[Unit]\n") + f.WriteString("Description=" + g.description + "\n") + f.WriteString("After=syslog.target\n") + if g.needNetwork { + f.WriteString("After=network.target\n") + } + f.WriteString("\n") + f.WriteString("[Service]\n") + f.WriteString("Type=simple\n") + f.WriteString("User=" + g.user + "\n") + f.WriteString("Group=" + g.group + "\n") + f.WriteString("WorkingDirectory=" + g.directory + "\n") + f.WriteString("ExecStart=" + g.process + "\n") + if g.restart { + f.WriteString("Restart=always\n") + } else { + f.WriteString("Restart=no\n") + } + if len(g.environment) > 0 { + f.WriteString("Environment=") + } + var envString string + for k, v := range g.environment { + envString += ",\"" + k + "=" + v + "\"" + } + if len(envString) > 0 { + envString = envString[1:] + } + f.WriteString(envString) + f.WriteString("\n") + f.WriteString("[Install]\n") + f.WriteString("WantedBy=" + g.wantedBy + "\n") + f.Close() + return nil +} \ No newline at end of file