// Use of this source code is governed by MIT-style // license that can be found in the LICENSE file. package cmd import ( "fmt" "os" "os/exec" "os/signal" "path" "runtime" "syscall" "time" "github.com/spf13/cobra" ) var pid int // runCmd represents the run command var runCmdPro = &cobra.Command{ Use: "run:prod", Short: "Start the app in production mode", Long: `To Start the app in production mode the following command: goffee run:prod `, Run: func(cmd *cobra.Command, args []string) { startAppChan := make(chan bool, 1) pidChan := make(chan int, 1) termSigsChan := make(chan os.Signal, 1) startAppChan <- true go startServerJob(pidChan, startAppChan) signal.Notify(termSigsChan, syscall.SIGINT, syscall.SIGTERM) go func(termSigsChan chan os.Signal) { for { <-termSigsChan if pid == 0 { os.Exit(0) } else { pgid, err := syscall.Getpgid(pid) if err != nil { fmt.Println("error getting pgid: ", err) } err = syscall.Kill(-pgid, syscall.SIGKILL) if err != nil { fmt.Println("error stopping process: ", err) } os.Exit(0) } } }(termSigsChan) func() { time.Sleep(time.Second * 5) }() }, } func startServerJob(pidChan chan int, startAppChan chan bool) { for { shouldStartApp := <-startAppChan if shouldStartApp { fmt.Println("\n\nBuilding...") err := compileApp() if err != nil { fmt.Println("error building: ", err.Error()) go func() { pidChan <- 0 }() } else { fmt.Println("Starting...") pwd, _ := os.Getwd() if runtime.GOOS == "darwin" { execFile := pwd + "/tmp/" + path.Base(pwd) args := []string{execFile, "prod"} execSpec := &syscall.ProcAttr{ Dir: pwd, Env: os.Environ(), Files: []uintptr{os.Stdin.Fd(), os.Stdout.Fd(), os.Stderr.Fd()}, Sys: &syscall.SysProcAttr{ Setpgid: true, }, } pid, _, err = syscall.StartProcess(execFile, args, execSpec) if err != nil { fmt.Println("error starting process: ", err.Error()) go func() { pidChan <- 0 }() } else { go func() { pidChan <- pid }() } } else if runtime.GOOS == "linux" { execFile := pwd + "/tmp/" + path.Base(pwd) args := []string{execFile, "prod"} execSpec := &syscall.ProcAttr{ Dir: pwd, Env: os.Environ(), Files: []uintptr{os.Stdin.Fd(), os.Stdout.Fd(), os.Stderr.Fd()}, Sys: &syscall.SysProcAttr{ Setpgid: true, }, } pid, _, err = syscall.StartProcess(execFile, args, execSpec) if err != nil { fmt.Println("error starting process: ", err.Error()) go func() { pidChan <- 0 }() } else { go func() { pidChan <- pid }() } } else { fmt.Println("not implemented for os: ", runtime.GOOS) } } } } } func compileApp() error { pwd, _ := os.Getwd() var command *exec.Cmd command = exec.Command("/bin/sh", "-c", fmt.Sprintf("go build -o %v/tmp/", pwd)) command.Env = os.Environ() command.SysProcAttr = &syscall.SysProcAttr{ Setpgid: true, } command.Dir = pwd o, err := command.CombinedOutput() if string(o) != "" { fmt.Println(string(o)) } if err != nil { return err } return nil } func init() { rootCmd.AddCommand(runCmdPro) }