package main import ( "flag" "fmt" go_lazy_quiter "git.swzry.com/zry/go-lazy-quiter" "git.swzry.com/zry/pathutils" "gopkg.in/natefinch/lumberjack.v2" "gopkg.in/yaml.v2" "io" "io/ioutil" "os" "os/exec" "sync" ) var ConfigData ConfigYAML var FrontendShellLogger io.Writer var BackendShellLogger io.Writer var mainWaitGroup sync.WaitGroup var showHelp bool var withDLV bool var dlvListenString string var dlvProcess *os.Process var noFrontEnd bool func main() { flag.BoolVar(&showHelp, "h", false, "Show this help") flag.BoolVar(&withDLV, "d", false, "Start backend with delve debugger") flag.StringVar(&dlvListenString, "l", "127.0.0.1:7827", "Set delve listening, default is '127.0.0.1:7827'") flag.BoolVar(&noFrontEnd, "no-front", false, "Not to start front end") flag.Parse() if showHelp { flag.PrintDefaults() return } fmt.Println("zDWSI Windows Test Enviroment Launcher Start.") LoadYAML() if !noFrontEnd { StartFrontend() } StartBackend() //fmt.Println("Launcher Sleeping.") //RoutineSleep() q := go_lazy_quiter.NewLazyQuiter() fmt.Println("Ctrl+C to quit.") _ = q.Wait() fmt.Println("Abort by user, quitting...") if dlvProcess != nil { err := dlvProcess.Kill() if err != nil { fmt.Println("failed kill delve:", err.Error()) } } fmt.Println("End.") os.Exit(0) } func LoadYAML() { fmt.Println("Load Config 'config.yaml'") jdata, err := ioutil.ReadFile("config.yaml") if err != nil { fmt.Println("failed read file 'config.yaml': ", err) Dead() } err = yaml.Unmarshal(jdata, &ConfigData) if err != nil { fmt.Println("failed parse 'config.yaml': ", err) Dead() } fmt.Println("Config Loaded.") } func Dead() { fmt.Println("Program Dead By Fatal Error. Please Restart.") FailureServer() } func RoutineSleep() { mainWaitGroup.Wait() fmt.Println("All GoRoutine Stopped. Please Restart.") FailureServer() } func InitLogger(cfg LumberjackLoggerYAML) io.Writer { ljl := &lumberjack.Logger{ Filename: cfg.FileName, MaxSize: cfg.MaxSize, MaxAge: cfg.MaxAge, MaxBackups: cfg.MaxBackups, LocalTime: cfg.UseLocalTime, Compress: cfg.Compress, } wra := []io.Writer{ljl, os.Stdout} mwr := io.MultiWriter(wra...) return mwr } func StartFrontend() { if !ConfigData.Frontend.Enable { fmt.Println("Frontend Not Enable.") return } pe, err := pathutils.PathExists(ConfigData.Frontend.EntryPoint) if err != nil || !pe { fmt.Println("frontend entrypoint not exists") return } FrontendShellLogger = InitLogger(ConfigData.Frontend.ShellLog) mainWaitGroup.Add(1) go func() { runenv := make([]string, 0) runenv = append(runenv, makeEnvMember("listen", ConfigData.Frontend.ListenAddr)) runenv = append(runenv, makeEnvMember("wwwroot", ConfigData.Frontend.WWWRoot)) runenv = append(runenv, makeEnvMember("backend_prefix", ConfigData.Frontend.BackendProxy.Prefix)) runenv = append(runenv, makeEnvMember("backend_target", ConfigData.Frontend.BackendProxy.ProxyTaret)) runenv = append(runenv, "is_win_test_env=yes") err = StartProcess(ConfigData.Frontend.EntryPoint, runenv, FrontendShellLogger) if err != nil { fmt.Println("failed start frontend or frontend exited with error: ", err) } mainWaitGroup.Done() }() } func makeEnvMember(key string, value string) string { return fmt.Sprintf("%s=%s", key, value) } func StartBackend() { if !ConfigData.Backend.Enable { fmt.Println("Backend Not Enable.") return } pe, err := pathutils.PathExists(ConfigData.Backend.EntryPoint) if err != nil || !pe { fmt.Println("backend entrypoint not exists") return } BackendShellLogger = InitLogger(ConfigData.Backend.ShellLog) mainWaitGroup.Add(1) go func() { runenv := make([]string, 0) runenv = append(runenv, makeEnvMember("listen", ConfigData.Backend.ListenAddr)) if withDLV { err = StartProcessWithDLV(ConfigData.Backend.EntryPoint, runenv, BackendShellLogger) } else { err = StartProcess(ConfigData.Backend.EntryPoint, runenv, BackendShellLogger) } if err != nil { fmt.Println("failed start backend or backend exited with error: ", err) } mainWaitGroup.Done() }() } func StartProcess(entry string, runenv []string, logger io.Writer) error { cmd := exec.Command(entry) cmd.Env = runenv pipe_r, pipe_w := io.Pipe() cmd.Stdout = pipe_w cmd.Stderr = pipe_w go func() { io.Copy(logger, pipe_r) }() err := cmd.Start() if err != nil { return err } err = cmd.Wait() return err } func StartProcessWithDLV(entry string, runenv []string, logger io.Writer) error { cmd := exec.Command("dlv") cmd.Args = []string{ "dlv", fmt.Sprintf("--listen=%s", dlvListenString), "--headless=true", "--api-version=2", "--accept-multiclient", "exec", entry, } cmd.Env = runenv pipe_r, pipe_w := io.Pipe() cmd.Stdout = pipe_w cmd.Stderr = pipe_w go func() { io.Copy(logger, pipe_r) }() err := cmd.Start() dlvProcess = cmd.Process if err != nil { return err } err = cmd.Wait() return err }