From a36dfbcffd0c6d34cca3f08fbd1d313ae7ab01ab Mon Sep 17 00:00:00 2001 From: "Brian W. Wolter" Date: Fri, 2 Jun 2017 10:53:50 -0400 Subject: [PATCH 01/27] Suppress color --- outlet.go | 20 ++++++++++++-------- start.go | 9 +++++++-- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/outlet.go b/outlet.go index 596b98a..e312c30 100644 --- a/outlet.go +++ b/outlet.go @@ -13,7 +13,7 @@ import ( type OutletFactory struct { Padding int - + Color bool sync.Mutex } @@ -76,18 +76,22 @@ func (of *OutletFactory) ErrorOutput(str string) { func (of *OutletFactory) WriteLine(left, right string, leftC, rightC ct.Color, isError bool) { of.Lock() defer of.Unlock() - - ct.ChangeColor(leftC, true, ct.None, false) + + if of.Color { + ct.ChangeColor(leftC, true, ct.None, false) + } formatter := fmt.Sprintf("%%-%ds | ", of.Padding) fmt.Printf(formatter, left) - if isError { - ct.ChangeColor(ct.Red, true, ct.None, true) - } else { - ct.ResetColor() + if of.Color { + if isError { + ct.ChangeColor(ct.Red, true, ct.None, true) + } else { + ct.ResetColor() + } } fmt.Println(right) - if isError { + if of.Color && isError { ct.ResetColor() } } diff --git a/start.go b/start.go index 59f5e47..c77b8ba 100644 --- a/start.go +++ b/start.go @@ -19,12 +19,13 @@ const defaultShutdownGraceTime = 3 var flagPort int var flagConcurrency string var flagRestart bool +var flagNoColor bool var flagShutdownGraceTime int var envs envFiles var cmdStart = &Command{ Run: runStart, - Usage: "start [process name] [-f procfile] [-e env] [-p port] [-c concurrency] [-r] [-t shutdown_grace_time]", + Usage: "start [process name] [-f procfile] [-e env] [-p port] [-c concurrency] [-r] [-t shutdown_grace_time] [-n]", Short: "Start the application", Long: ` Start the application specified by a Procfile. The directory containing the @@ -58,6 +59,8 @@ The following options are available: being asked to stop. Once this grace time expires, the process is forcibly terminated. By default, it is 3 seconds. + -n Do not colorize output. + If there is a file named .forego in the current directory, it will be read in the same way as an environment file, and the values of variables procfile, port, concurrency, and shutdown_grace_time used to change the corresponding default @@ -85,6 +88,7 @@ func init() { cmdStart.Flag.IntVar(&flagPort, "p", defaultPort, "port") cmdStart.Flag.StringVar(&flagConcurrency, "c", "", "concurrency") cmdStart.Flag.BoolVar(&flagRestart, "r", false, "restart") + cmdStart.Flag.BoolVar(&flagNoColor, "n", false, "suppress color in output") cmdStart.Flag.IntVar(&flagShutdownGraceTime, "t", defaultShutdownGraceTime, "shutdown grace time") err := readConfigFile(".forego", &flagProcfile, &flagPort, &flagConcurrency, &flagShutdownGraceTime) handleError(err) @@ -276,7 +280,8 @@ func runStart(cmd *Command, args []string) { of := NewOutletFactory() of.Padding = pf.LongestProcessName(concurrency) - + of.Color = !flagNoColor + f := &Forego{ outletFactory: of, } From d19d4cbdb1ddba021ef58cc62ee04362f6491761 Mon Sep 17 00:00:00 2001 From: "Brian W. Wolter" Date: Fri, 2 Jun 2017 10:55:13 -0400 Subject: [PATCH 02/27] Spaces --- start.go | 486 +++++++++++++++++++++++++++---------------------------- 1 file changed, 243 insertions(+), 243 deletions(-) diff --git a/start.go b/start.go index c77b8ba..a103efa 100644 --- a/start.go +++ b/start.go @@ -1,16 +1,16 @@ package main import ( - "errors" - "fmt" - "os" - "os/signal" - "path/filepath" - "strconv" - "strings" - "sync" - "syscall" - "time" + "errors" + "fmt" + "os" + "os/signal" + "path/filepath" + "strconv" + "strings" + "sync" + "syscall" + "time" ) const defaultPort = 5000 @@ -24,10 +24,10 @@ var flagShutdownGraceTime int var envs envFiles var cmdStart = &Command{ - Run: runStart, - Usage: "start [process name] [-f procfile] [-e env] [-p port] [-c concurrency] [-r] [-t shutdown_grace_time] [-n]", - Short: "Start the application", - Long: ` + Run: runStart, + Usage: "start [process name] [-f procfile] [-e env] [-p port] [-c concurrency] [-r] [-t shutdown_grace_time] [-n]", + Short: "Start the application", + Long: ` Start the application specified by a Procfile. The directory containing the Procfile is used as the working directory. @@ -59,7 +59,7 @@ The following options are available: being asked to stop. Once this grace time expires, the process is forcibly terminated. By default, it is 3 seconds. - -n Do not colorize output. + -n Do not colorize output. If there is a file named .forego in the current directory, it will be read in the same way as an environment file, and the values of variables procfile, port, @@ -83,255 +83,255 @@ Examples: } func init() { - cmdStart.Flag.StringVar(&flagProcfile, "f", "Procfile", "procfile") - cmdStart.Flag.Var(&envs, "e", "env") - cmdStart.Flag.IntVar(&flagPort, "p", defaultPort, "port") - cmdStart.Flag.StringVar(&flagConcurrency, "c", "", "concurrency") - cmdStart.Flag.BoolVar(&flagRestart, "r", false, "restart") - cmdStart.Flag.BoolVar(&flagNoColor, "n", false, "suppress color in output") - cmdStart.Flag.IntVar(&flagShutdownGraceTime, "t", defaultShutdownGraceTime, "shutdown grace time") - err := readConfigFile(".forego", &flagProcfile, &flagPort, &flagConcurrency, &flagShutdownGraceTime) - handleError(err) + cmdStart.Flag.StringVar(&flagProcfile, "f", "Procfile", "procfile") + cmdStart.Flag.Var(&envs, "e", "env") + cmdStart.Flag.IntVar(&flagPort, "p", defaultPort, "port") + cmdStart.Flag.StringVar(&flagConcurrency, "c", "", "concurrency") + cmdStart.Flag.BoolVar(&flagRestart, "r", false, "restart") + cmdStart.Flag.BoolVar(&flagNoColor, "n", false, "suppress color in output") + cmdStart.Flag.IntVar(&flagShutdownGraceTime, "t", defaultShutdownGraceTime, "shutdown grace time") + err := readConfigFile(".forego", &flagProcfile, &flagPort, &flagConcurrency, &flagShutdownGraceTime) + handleError(err) } func readConfigFile(config_path string, flagProcfile *string, flagPort *int, flagConcurrency *string, flagShutdownGraceTime *int) error { - config, err := ReadConfig(config_path) - - if config["procfile"] != "" { - *flagProcfile = config["procfile"] - } else { - *flagProcfile = "Procfile" - } - if config["port"] != "" { - *flagPort, err = strconv.Atoi(config["port"]) - } else { - *flagPort = defaultPort - } - if config["shutdown_grace_time"] != "" { - *flagShutdownGraceTime, err = strconv.Atoi(config["shutdown_grace_time"]) - } else { - *flagShutdownGraceTime = defaultShutdownGraceTime - } - *flagConcurrency = config["concurrency"] - return err + config, err := ReadConfig(config_path) + + if config["procfile"] != "" { + *flagProcfile = config["procfile"] + } else { + *flagProcfile = "Procfile" + } + if config["port"] != "" { + *flagPort, err = strconv.Atoi(config["port"]) + } else { + *flagPort = defaultPort + } + if config["shutdown_grace_time"] != "" { + *flagShutdownGraceTime, err = strconv.Atoi(config["shutdown_grace_time"]) + } else { + *flagShutdownGraceTime = defaultShutdownGraceTime + } + *flagConcurrency = config["concurrency"] + return err } func parseConcurrency(value string) (map[string]int, error) { - concurrency := map[string]int{} - if strings.TrimSpace(value) == "" { - return concurrency, nil - } - - parts := strings.Split(value, ",") - for _, part := range parts { - if !strings.Contains(part, "=") { - return concurrency, errors.New("Concurrency should be in the format: foo=1,bar=2") - } - - nameValue := strings.Split(part, "=") - n, v := strings.TrimSpace(nameValue[0]), strings.TrimSpace(nameValue[1]) - if n == "" || v == "" { - return concurrency, errors.New("Concurrency should be in the format: foo=1,bar=2") - } - - numProcs, err := strconv.ParseInt(v, 10, 16) - if err != nil { - return concurrency, err - } - - concurrency[n] = int(numProcs) - } - return concurrency, nil + concurrency := map[string]int{} + if strings.TrimSpace(value) == "" { + return concurrency, nil + } + + parts := strings.Split(value, ",") + for _, part := range parts { + if !strings.Contains(part, "=") { + return concurrency, errors.New("Concurrency should be in the format: foo=1,bar=2") + } + + nameValue := strings.Split(part, "=") + n, v := strings.TrimSpace(nameValue[0]), strings.TrimSpace(nameValue[1]) + if n == "" || v == "" { + return concurrency, errors.New("Concurrency should be in the format: foo=1,bar=2") + } + + numProcs, err := strconv.ParseInt(v, 10, 16) + if err != nil { + return concurrency, err + } + + concurrency[n] = int(numProcs) + } + return concurrency, nil } type Forego struct { - outletFactory *OutletFactory + outletFactory *OutletFactory - teardown, teardownNow Barrier // signal shutting down + teardown, teardownNow Barrier // signal shutting down - wg sync.WaitGroup + wg sync.WaitGroup } func (f *Forego) monitorInterrupt() { - handler := make(chan os.Signal, 1) - signal.Notify(handler, syscall.SIGALRM, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM) - - first := true - - for sig := range handler { - switch sig { - case syscall.SIGINT: - fmt.Println(" | ctrl-c detected") - fallthrough - default: - f.teardown.Fall() - if !first { - f.teardownNow.Fall() - } - first = false - } - } + handler := make(chan os.Signal, 1) + signal.Notify(handler, syscall.SIGALRM, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM) + + first := true + + for sig := range handler { + switch sig { + case syscall.SIGINT: + fmt.Println(" | ctrl-c detected") + fallthrough + default: + f.teardown.Fall() + if !first { + f.teardownNow.Fall() + } + first = false + } + } } func basePort(env Env) (int, error) { - if flagPort != defaultPort { - return flagPort, nil - } else if env["PORT"] != "" { - return strconv.Atoi(env["PORT"]) - } else if os.Getenv("PORT") != "" { - return strconv.Atoi(os.Getenv("PORT")) - } - return defaultPort, nil + if flagPort != defaultPort { + return flagPort, nil + } else if env["PORT"] != "" { + return strconv.Atoi(env["PORT"]) + } else if os.Getenv("PORT") != "" { + return strconv.Atoi(os.Getenv("PORT")) + } + return defaultPort, nil } func (f *Forego) startProcess(idx, procNum int, proc ProcfileEntry, env Env, of *OutletFactory) { - port, err := basePort(env) - if err != nil { - panic(err) - } - - port = port + (idx * 100) - - const interactive = false - workDir := filepath.Dir(flagProcfile) - ps := NewProcess(workDir, proc.Command, env, interactive) - procName := fmt.Sprint(proc.Name, ".", procNum+1) - ps.Env["PORT"] = strconv.Itoa(port) - - ps.Stdin = nil - - stdout, err := ps.StdoutPipe() - if err != nil { - panic(err) - } - stderr, err := ps.StderrPipe() - if err != nil { - panic(err) - } - - pipeWait := new(sync.WaitGroup) - pipeWait.Add(2) - go of.LineReader(pipeWait, procName, idx, stdout, false) - go of.LineReader(pipeWait, procName, idx, stderr, true) - - of.SystemOutput(fmt.Sprintf("starting %s on port %d", procName, port)) - - finished := make(chan struct{}) // closed on process exit - - err = ps.Start() - if err != nil { - f.teardown.Fall() - of.SystemOutput(fmt.Sprint("Failed to start ", procName, ": ", err)) - return - } - - f.wg.Add(1) - go func() { - defer f.wg.Done() - defer close(finished) - pipeWait.Wait() - ps.Wait() - }() - - f.wg.Add(1) - go func() { - defer f.wg.Done() - - select { - case <-finished: - if flagRestart { - f.startProcess(idx, procNum, proc, env, of) - } else { - f.teardown.Fall() - } - - case <-f.teardown.Barrier(): - // Forego tearing down - - if !osHaveSigTerm { - of.SystemOutput(fmt.Sprintf("Killing %s", procName)) - ps.Process.Kill() - return - } - - of.SystemOutput(fmt.Sprintf("sending SIGTERM to %s", procName)) - ps.SendSigTerm() - - // Give the process a chance to exit, otherwise kill it. - select { - case <-f.teardownNow.Barrier(): - of.SystemOutput(fmt.Sprintf("Killing %s", procName)) - ps.SendSigKill() - case <-finished: - } - } - }() + port, err := basePort(env) + if err != nil { + panic(err) + } + + port = port + (idx * 100) + + const interactive = false + workDir := filepath.Dir(flagProcfile) + ps := NewProcess(workDir, proc.Command, env, interactive) + procName := fmt.Sprint(proc.Name, ".", procNum+1) + ps.Env["PORT"] = strconv.Itoa(port) + + ps.Stdin = nil + + stdout, err := ps.StdoutPipe() + if err != nil { + panic(err) + } + stderr, err := ps.StderrPipe() + if err != nil { + panic(err) + } + + pipeWait := new(sync.WaitGroup) + pipeWait.Add(2) + go of.LineReader(pipeWait, procName, idx, stdout, false) + go of.LineReader(pipeWait, procName, idx, stderr, true) + + of.SystemOutput(fmt.Sprintf("starting %s on port %d", procName, port)) + + finished := make(chan struct{}) // closed on process exit + + err = ps.Start() + if err != nil { + f.teardown.Fall() + of.SystemOutput(fmt.Sprint("Failed to start ", procName, ": ", err)) + return + } + + f.wg.Add(1) + go func() { + defer f.wg.Done() + defer close(finished) + pipeWait.Wait() + ps.Wait() + }() + + f.wg.Add(1) + go func() { + defer f.wg.Done() + + select { + case <-finished: + if flagRestart { + f.startProcess(idx, procNum, proc, env, of) + } else { + f.teardown.Fall() + } + + case <-f.teardown.Barrier(): + // Forego tearing down + + if !osHaveSigTerm { + of.SystemOutput(fmt.Sprintf("Killing %s", procName)) + ps.Process.Kill() + return + } + + of.SystemOutput(fmt.Sprintf("sending SIGTERM to %s", procName)) + ps.SendSigTerm() + + // Give the process a chance to exit, otherwise kill it. + select { + case <-f.teardownNow.Barrier(): + of.SystemOutput(fmt.Sprintf("Killing %s", procName)) + ps.SendSigKill() + case <-finished: + } + } + }() } func runStart(cmd *Command, args []string) { - pf, err := ReadProcfile(flagProcfile) - handleError(err) - - concurrency, err := parseConcurrency(flagConcurrency) - handleError(err) - - env, err := loadEnvs(envs) - handleError(err) - - of := NewOutletFactory() - of.Padding = pf.LongestProcessName(concurrency) - of.Color = !flagNoColor - - f := &Forego{ - outletFactory: of, - } - - go f.monitorInterrupt() - - // When teardown fires, start the grace timer - f.teardown.FallHook = func() { - go func() { - time.Sleep(time.Duration(flagShutdownGraceTime) * time.Second) - of.SystemOutput("Grace time expired") - f.teardownNow.Fall() - }() - } - - var singleton string = "" - if len(args) > 0 { - singleton = args[0] - if !pf.HasProcess(singleton) { - of.ErrorOutput(fmt.Sprintf("no such process: %s", singleton)) - } - } - - defaultConcurrency := 1 - - var all bool - for name, num := range concurrency { - if name == "all" { - defaultConcurrency = num - all = true - } - } - - for idx, proc := range pf.Entries { - numProcs := defaultConcurrency - if len(concurrency) > 0 { - if value, ok := concurrency[proc.Name]; ok { - numProcs = value - } else if !all { - continue - } - } - for i := 0; i < numProcs; i++ { - if (singleton == "") || (singleton == proc.Name) { - f.startProcess(idx, i, proc, env, of) - } - } - } - - <-f.teardown.Barrier() - - f.wg.Wait() + pf, err := ReadProcfile(flagProcfile) + handleError(err) + + concurrency, err := parseConcurrency(flagConcurrency) + handleError(err) + + env, err := loadEnvs(envs) + handleError(err) + + of := NewOutletFactory() + of.Padding = pf.LongestProcessName(concurrency) + of.Color = !flagNoColor + + f := &Forego{ + outletFactory: of, + } + + go f.monitorInterrupt() + + // When teardown fires, start the grace timer + f.teardown.FallHook = func() { + go func() { + time.Sleep(time.Duration(flagShutdownGraceTime) * time.Second) + of.SystemOutput("Grace time expired") + f.teardownNow.Fall() + }() + } + + var singleton string = "" + if len(args) > 0 { + singleton = args[0] + if !pf.HasProcess(singleton) { + of.ErrorOutput(fmt.Sprintf("no such process: %s", singleton)) + } + } + + defaultConcurrency := 1 + + var all bool + for name, num := range concurrency { + if name == "all" { + defaultConcurrency = num + all = true + } + } + + for idx, proc := range pf.Entries { + numProcs := defaultConcurrency + if len(concurrency) > 0 { + if value, ok := concurrency[proc.Name]; ok { + numProcs = value + } else if !all { + continue + } + } + for i := 0; i < numProcs; i++ { + if (singleton == "") || (singleton == proc.Name) { + f.startProcess(idx, i, proc, env, of) + } + } + } + + <-f.teardown.Barrier() + + f.wg.Wait() } From d9f48d694396f48401ab78b6b9b3915fd56df08f Mon Sep 17 00:00:00 2001 From: "Brian W. Wolter" Date: Wed, 3 Apr 2019 14:44:36 -0400 Subject: [PATCH 03/27] Add support for exiting when an error status (specified by -s). The error status is used when any of the managed processes exit with an error status. --- start.go | 524 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 272 insertions(+), 252 deletions(-) diff --git a/start.go b/start.go index a103efa..53d3f8f 100644 --- a/start.go +++ b/start.go @@ -1,33 +1,38 @@ package main import ( - "errors" - "fmt" - "os" - "os/signal" - "path/filepath" - "strconv" - "strings" - "sync" - "syscall" - "time" + "errors" + "fmt" + "os" + "os/signal" + "path/filepath" + "strconv" + "strings" + "sync" + "syscall" + "time" ) -const defaultPort = 5000 -const defaultShutdownGraceTime = 3 +const ( + defaultPort = 5000 + defaultShutdownGraceTime = 3 +) -var flagPort int -var flagConcurrency string -var flagRestart bool -var flagNoColor bool -var flagShutdownGraceTime int -var envs envFiles +var ( + flagPort int + flagConcurrency string + flagRestart bool + flagNoColor bool + flagExitStatusOnError int + flagShutdownGraceTime int + envs envFiles +) var cmdStart = &Command{ - Run: runStart, - Usage: "start [process name] [-f procfile] [-e env] [-p port] [-c concurrency] [-r] [-t shutdown_grace_time] [-n]", - Short: "Start the application", - Long: ` + Run: runStart, + Usage: "start [process name] [-f procfile] [-e env] [-p port] [-c concurrency] [-r] [-t shutdown_grace_time] [-n]", + Short: "Start the application", + Long: ` Start the application specified by a Procfile. The directory containing the Procfile is used as the working directory. @@ -60,6 +65,9 @@ The following options are available: forcibly terminated. By default, it is 3 seconds. -n Do not colorize output. + + -s status When non-zero, exit with the provided status when a managed process + exits with an error status. If there is a file named .forego in the current directory, it will be read in the same way as an environment file, and the values of variables procfile, port, @@ -83,255 +91,267 @@ Examples: } func init() { - cmdStart.Flag.StringVar(&flagProcfile, "f", "Procfile", "procfile") - cmdStart.Flag.Var(&envs, "e", "env") - cmdStart.Flag.IntVar(&flagPort, "p", defaultPort, "port") - cmdStart.Flag.StringVar(&flagConcurrency, "c", "", "concurrency") - cmdStart.Flag.BoolVar(&flagRestart, "r", false, "restart") - cmdStart.Flag.BoolVar(&flagNoColor, "n", false, "suppress color in output") - cmdStart.Flag.IntVar(&flagShutdownGraceTime, "t", defaultShutdownGraceTime, "shutdown grace time") - err := readConfigFile(".forego", &flagProcfile, &flagPort, &flagConcurrency, &flagShutdownGraceTime) - handleError(err) + cmdStart.Flag.StringVar(&flagProcfile, "f", "Procfile", "procfile") + cmdStart.Flag.Var(&envs, "e", "env") + cmdStart.Flag.IntVar(&flagPort, "p", defaultPort, "port") + cmdStart.Flag.StringVar(&flagConcurrency, "c", "", "concurrency") + cmdStart.Flag.BoolVar(&flagRestart, "r", false, "restart") + cmdStart.Flag.BoolVar(&flagNoColor, "n", false, "suppress") + cmdStart.Flag.IntVar(&flagExitStatusOnError, "s", 0, "status") + cmdStart.Flag.IntVar(&flagShutdownGraceTime, "t", defaultShutdownGraceTime, "shutdown grace time") + err := readConfigFile(".forego", &flagProcfile, &flagPort, &flagConcurrency, &flagShutdownGraceTime) + handleError(err) } func readConfigFile(config_path string, flagProcfile *string, flagPort *int, flagConcurrency *string, flagShutdownGraceTime *int) error { - config, err := ReadConfig(config_path) - - if config["procfile"] != "" { - *flagProcfile = config["procfile"] - } else { - *flagProcfile = "Procfile" - } - if config["port"] != "" { - *flagPort, err = strconv.Atoi(config["port"]) - } else { - *flagPort = defaultPort - } - if config["shutdown_grace_time"] != "" { - *flagShutdownGraceTime, err = strconv.Atoi(config["shutdown_grace_time"]) - } else { - *flagShutdownGraceTime = defaultShutdownGraceTime - } - *flagConcurrency = config["concurrency"] - return err + config, err := ReadConfig(config_path) + + if config["procfile"] != "" { + *flagProcfile = config["procfile"] + } else { + *flagProcfile = "Procfile" + } + if config["port"] != "" { + *flagPort, err = strconv.Atoi(config["port"]) + } else { + *flagPort = defaultPort + } + if config["shutdown_grace_time"] != "" { + *flagShutdownGraceTime, err = strconv.Atoi(config["shutdown_grace_time"]) + } else { + *flagShutdownGraceTime = defaultShutdownGraceTime + } + *flagConcurrency = config["concurrency"] + return err } func parseConcurrency(value string) (map[string]int, error) { - concurrency := map[string]int{} - if strings.TrimSpace(value) == "" { - return concurrency, nil - } - - parts := strings.Split(value, ",") - for _, part := range parts { - if !strings.Contains(part, "=") { - return concurrency, errors.New("Concurrency should be in the format: foo=1,bar=2") - } - - nameValue := strings.Split(part, "=") - n, v := strings.TrimSpace(nameValue[0]), strings.TrimSpace(nameValue[1]) - if n == "" || v == "" { - return concurrency, errors.New("Concurrency should be in the format: foo=1,bar=2") - } - - numProcs, err := strconv.ParseInt(v, 10, 16) - if err != nil { - return concurrency, err - } - - concurrency[n] = int(numProcs) - } - return concurrency, nil + concurrency := map[string]int{} + if strings.TrimSpace(value) == "" { + return concurrency, nil + } + + parts := strings.Split(value, ",") + for _, part := range parts { + if !strings.Contains(part, "=") { + return concurrency, errors.New("Concurrency should be in the format: foo=1,bar=2") + } + + nameValue := strings.Split(part, "=") + n, v := strings.TrimSpace(nameValue[0]), strings.TrimSpace(nameValue[1]) + if n == "" || v == "" { + return concurrency, errors.New("Concurrency should be in the format: foo=1,bar=2") + } + + numProcs, err := strconv.ParseInt(v, 10, 16) + if err != nil { + return concurrency, err + } + + concurrency[n] = int(numProcs) + } + return concurrency, nil } type Forego struct { - outletFactory *OutletFactory - - teardown, teardownNow Barrier // signal shutting down - - wg sync.WaitGroup + sync.Mutex + outletFactory *OutletFactory + teardown, teardownNow Barrier // signal shutting down + wg sync.WaitGroup + status int } func (f *Forego) monitorInterrupt() { - handler := make(chan os.Signal, 1) - signal.Notify(handler, syscall.SIGALRM, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM) - - first := true - - for sig := range handler { - switch sig { - case syscall.SIGINT: - fmt.Println(" | ctrl-c detected") - fallthrough - default: - f.teardown.Fall() - if !first { - f.teardownNow.Fall() - } - first = false - } - } + handler := make(chan os.Signal, 1) + signal.Notify(handler, syscall.SIGALRM, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM) + + first := true + + for sig := range handler { + switch sig { + case syscall.SIGINT: + fmt.Println(" | ctrl-c detected") + fallthrough + default: + f.teardown.Fall() + if !first { + f.teardownNow.Fall() + } + first = false + } + } } func basePort(env Env) (int, error) { - if flagPort != defaultPort { - return flagPort, nil - } else if env["PORT"] != "" { - return strconv.Atoi(env["PORT"]) - } else if os.Getenv("PORT") != "" { - return strconv.Atoi(os.Getenv("PORT")) - } - return defaultPort, nil + if flagPort != defaultPort { + return flagPort, nil + } else if env["PORT"] != "" { + return strconv.Atoi(env["PORT"]) + } else if os.Getenv("PORT") != "" { + return strconv.Atoi(os.Getenv("PORT")) + } + return defaultPort, nil } func (f *Forego) startProcess(idx, procNum int, proc ProcfileEntry, env Env, of *OutletFactory) { - port, err := basePort(env) - if err != nil { - panic(err) - } - - port = port + (idx * 100) - - const interactive = false - workDir := filepath.Dir(flagProcfile) - ps := NewProcess(workDir, proc.Command, env, interactive) - procName := fmt.Sprint(proc.Name, ".", procNum+1) - ps.Env["PORT"] = strconv.Itoa(port) - - ps.Stdin = nil - - stdout, err := ps.StdoutPipe() - if err != nil { - panic(err) - } - stderr, err := ps.StderrPipe() - if err != nil { - panic(err) - } - - pipeWait := new(sync.WaitGroup) - pipeWait.Add(2) - go of.LineReader(pipeWait, procName, idx, stdout, false) - go of.LineReader(pipeWait, procName, idx, stderr, true) - - of.SystemOutput(fmt.Sprintf("starting %s on port %d", procName, port)) - - finished := make(chan struct{}) // closed on process exit - - err = ps.Start() - if err != nil { - f.teardown.Fall() - of.SystemOutput(fmt.Sprint("Failed to start ", procName, ": ", err)) - return - } - - f.wg.Add(1) - go func() { - defer f.wg.Done() - defer close(finished) - pipeWait.Wait() - ps.Wait() - }() - - f.wg.Add(1) - go func() { - defer f.wg.Done() - - select { - case <-finished: - if flagRestart { - f.startProcess(idx, procNum, proc, env, of) - } else { - f.teardown.Fall() - } - - case <-f.teardown.Barrier(): - // Forego tearing down - - if !osHaveSigTerm { - of.SystemOutput(fmt.Sprintf("Killing %s", procName)) - ps.Process.Kill() - return - } - - of.SystemOutput(fmt.Sprintf("sending SIGTERM to %s", procName)) - ps.SendSigTerm() - - // Give the process a chance to exit, otherwise kill it. - select { - case <-f.teardownNow.Barrier(): - of.SystemOutput(fmt.Sprintf("Killing %s", procName)) - ps.SendSigKill() - case <-finished: - } - } - }() + port, err := basePort(env) + if err != nil { + panic(err) + } + + port = port + (idx * 100) + + const interactive = false + workDir := filepath.Dir(flagProcfile) + ps := NewProcess(workDir, proc.Command, env, interactive) + procName := fmt.Sprint(proc.Name, ".", procNum+1) + ps.Env["PORT"] = strconv.Itoa(port) + + ps.Stdin = nil + + stdout, err := ps.StdoutPipe() + if err != nil { + panic(err) + } + stderr, err := ps.StderrPipe() + if err != nil { + panic(err) + } + + pipeWait := new(sync.WaitGroup) + pipeWait.Add(2) + go of.LineReader(pipeWait, procName, idx, stdout, false) + go of.LineReader(pipeWait, procName, idx, stderr, true) + + of.SystemOutput(fmt.Sprintf("starting %s on port %d", procName, port)) + + finished := make(chan struct{}) // closed on process exit + + err = ps.Start() + if err != nil { + f.teardown.Fall() + of.SystemOutput(fmt.Sprint("Failed to start ", procName, ": ", err)) + return + } + + f.wg.Add(1) + go func() { + defer f.wg.Done() + defer close(finished) + pipeWait.Wait() + err := ps.Wait() + if err != nil { + f.Lock() + if flagExitStatusOnError > 0 { + f.status = flagExitStatusOnError + } + f.Unlock() + } + }() + + f.wg.Add(1) + go func() { + defer f.wg.Done() + + select { + case <-finished: + if flagRestart { + f.startProcess(idx, procNum, proc, env, of) + } else { + f.teardown.Fall() + } + + case <-f.teardown.Barrier(): + // Forego tearing down + + if !osHaveSigTerm { + of.SystemOutput(fmt.Sprintf("Killing %s", procName)) + ps.Process.Kill() + return + } + + of.SystemOutput(fmt.Sprintf("sending SIGTERM to %s", procName)) + ps.SendSigTerm() + + // Give the process a chance to exit, otherwise kill it. + select { + case <-f.teardownNow.Barrier(): + of.SystemOutput(fmt.Sprintf("Killing %s", procName)) + ps.SendSigKill() + case <-finished: + } + } + }() } func runStart(cmd *Command, args []string) { - pf, err := ReadProcfile(flagProcfile) - handleError(err) - - concurrency, err := parseConcurrency(flagConcurrency) - handleError(err) - - env, err := loadEnvs(envs) - handleError(err) - - of := NewOutletFactory() - of.Padding = pf.LongestProcessName(concurrency) - of.Color = !flagNoColor - - f := &Forego{ - outletFactory: of, - } - - go f.monitorInterrupt() - - // When teardown fires, start the grace timer - f.teardown.FallHook = func() { - go func() { - time.Sleep(time.Duration(flagShutdownGraceTime) * time.Second) - of.SystemOutput("Grace time expired") - f.teardownNow.Fall() - }() - } - - var singleton string = "" - if len(args) > 0 { - singleton = args[0] - if !pf.HasProcess(singleton) { - of.ErrorOutput(fmt.Sprintf("no such process: %s", singleton)) - } - } - - defaultConcurrency := 1 - - var all bool - for name, num := range concurrency { - if name == "all" { - defaultConcurrency = num - all = true - } - } - - for idx, proc := range pf.Entries { - numProcs := defaultConcurrency - if len(concurrency) > 0 { - if value, ok := concurrency[proc.Name]; ok { - numProcs = value - } else if !all { - continue - } - } - for i := 0; i < numProcs; i++ { - if (singleton == "") || (singleton == proc.Name) { - f.startProcess(idx, i, proc, env, of) - } - } - } - - <-f.teardown.Barrier() - - f.wg.Wait() + pf, err := ReadProcfile(flagProcfile) + handleError(err) + + concurrency, err := parseConcurrency(flagConcurrency) + handleError(err) + + env, err := loadEnvs(envs) + handleError(err) + + of := NewOutletFactory() + of.Padding = pf.LongestProcessName(concurrency) + of.Color = !flagNoColor + + f := &Forego{ + outletFactory: of, + } + + go f.monitorInterrupt() + + // When teardown fires, start the grace timer + f.teardown.FallHook = func() { + go func() { + time.Sleep(time.Duration(flagShutdownGraceTime) * time.Second) + of.SystemOutput("Grace time expired") + f.teardownNow.Fall() + }() + } + + var singleton string = "" + if len(args) > 0 { + singleton = args[0] + if !pf.HasProcess(singleton) { + of.ErrorOutput(fmt.Sprintf("no such process: %s", singleton)) + } + } + + defaultConcurrency := 1 + + var all bool + for name, num := range concurrency { + if name == "all" { + defaultConcurrency = num + all = true + } + } + + for idx, proc := range pf.Entries { + numProcs := defaultConcurrency + if len(concurrency) > 0 { + if value, ok := concurrency[proc.Name]; ok { + numProcs = value + } else if !all { + continue + } + } + for i := 0; i < numProcs; i++ { + if (singleton == "") || (singleton == proc.Name) { + f.startProcess(idx, i, proc, env, of) + } + } + } + + <-f.teardown.Barrier() + f.wg.Wait() + + // all other routines have completed; no need for locking + if f.status > 0 { + os.Exit(f.status) + } } From 5228145255f081031c3725512bca4946a09309c2 Mon Sep 17 00:00:00 2001 From: "Brian W. Wolter" Date: Wed, 3 Apr 2019 14:55:32 -0400 Subject: [PATCH 04/27] Ignore error statuses resulting from being signaled --- start.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/start.go b/start.go index 53d3f8f..4ba6a56 100644 --- a/start.go +++ b/start.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "os" + "os/exec" "os/signal" "path/filepath" "strconv" @@ -242,8 +243,13 @@ func (f *Forego) startProcess(idx, procNum int, proc ProcfileEntry, env Env, of err := ps.Wait() if err != nil { f.Lock() - if flagExitStatusOnError > 0 { - f.status = flagExitStatusOnError + if e, ok := err.(*exec.ExitError); ok && !e.ProcessState.Success() { + s := e.ProcessState.Sys() + if u, ok := s.(syscall.WaitStatus); ok { + if !u.Signaled() && flagExitStatusOnError > 0 { + f.status = flagExitStatusOnError + } + } } f.Unlock() } From fef93de0f557b3cb503e370899532f42d33cd8fe Mon Sep 17 00:00:00 2001 From: "Brian W. Wolter" Date: Wed, 3 Apr 2019 17:56:17 -0400 Subject: [PATCH 05/27] Help update --- start.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/start.go b/start.go index 4ba6a56..c8a9935 100644 --- a/start.go +++ b/start.go @@ -31,7 +31,7 @@ var ( var cmdStart = &Command{ Run: runStart, - Usage: "start [process name] [-f procfile] [-e env] [-p port] [-c concurrency] [-r] [-t shutdown_grace_time] [-n]", + Usage: "start [process name] [-f procfile] [-e env] [-p port] [-c concurrency] [-r] [-t shutdown_grace_time] [-n] [-s status]", Short: "Start the application", Long: ` Start the application specified by a Procfile. The directory containing the From e689ff1a29302994af7112e03b40a2864237d6ec Mon Sep 17 00:00:00 2001 From: "Brian W. Wolter" Date: Wed, 3 Apr 2019 17:57:30 -0400 Subject: [PATCH 06/27] Use Fatalf when we expect formatting --- start_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/start_test.go b/start_test.go index b57ca5f..8982588 100644 --- a/start_test.go +++ b/start_test.go @@ -123,7 +123,7 @@ func TestPortFromEnv(t *testing.T) { os.Setenv("PORT", "4000") port, err = basePort(env) if err != nil { - t.Fatal("Can not get port: %s", err) + t.Fatalf("Can not get port: %s", err) } if port != 4000 { t.Fatal("Base port should be 4000") @@ -162,14 +162,14 @@ func TestConfigBeOverrideByForegoFile(t *testing.T) { } if port != 15000 { - t.Fatal("port should be 15000, got %d", port) + t.Fatalf("port should be 15000, got %d", port) } if concurrency != "foo=2,bar=3" { - t.Fatal("concurrency should be 'foo=2,bar=3', got %s", concurrency) + t.Fatalf("concurrency should be 'foo=2,bar=3', got %s", concurrency) } if gracetime != 30 { - t.Fatal("gracetime should be 3, got %d", gracetime) + t.Fatalf("gracetime should be 3, got %d", gracetime) } } From 921a82b7376031e9fc28b300108a0f4c68ca9953 Mon Sep 17 00:00:00 2001 From: "Brian W. Wolter" Date: Fri, 5 Apr 2019 14:06:58 -0400 Subject: [PATCH 07/27] Restructure --- Makefile | 65 +++++++++++++++---- barrier.go => src/barrier.go | 0 command.go => src/command.go | 0 config.go => src/config.go | 0 config_test.go => src/config_test.go | 0 env.go => src/env.go | 0 env_test.go => src/env_test.go | 2 +- error.go => src/error.go | 0 help.go => src/help.go | 0 main.go => src/main.go | 5 ++ outlet.go => src/outlet.go | 0 process.go => src/process.go | 0 procfile.go => src/procfile.go | 0 run.go => src/run.go | 0 start.go => src/start.go | 0 start_test.go => src/start_test.go | 2 +- unix.go => src/unix.go | 0 update.go => src/update.go | 0 util.go => src/util.go | 0 .../daviddengcn/go-colortext/.gitignore | 0 .../daviddengcn/go-colortext/LICENSE | 0 .../daviddengcn/go-colortext/README.md | 0 .../github.com/daviddengcn/go-colortext/ct.go | 0 .../daviddengcn/go-colortext/ct_ansi.go | 0 .../daviddengcn/go-colortext/ct_win.go | 0 .../github.com/subosito/gotenv/.gitignore | 0 .../github.com/subosito/gotenv/LICENSE | 0 .../github.com/subosito/gotenv/README.md | 0 .../github.com/subosito/gotenv/gotenv.go | 0 version.go => src/version.go | 0 version_test.go => src/version_test.go | 0 windows.go => src/windows.go | 0 {bin => tools}/release | 0 vendor/github.com/subosito/gotenv/.env | 1 - 34 files changed, 58 insertions(+), 17 deletions(-) rename barrier.go => src/barrier.go (100%) rename command.go => src/command.go (100%) rename config.go => src/config.go (100%) rename config_test.go => src/config_test.go (100%) rename env.go => src/env.go (100%) rename env_test.go => src/env_test.go (82%) rename error.go => src/error.go (100%) rename help.go => src/help.go (100%) rename main.go => src/main.go (86%) rename outlet.go => src/outlet.go (100%) rename process.go => src/process.go (100%) rename procfile.go => src/procfile.go (100%) rename run.go => src/run.go (100%) rename start.go => src/start.go (100%) rename start_test.go => src/start_test.go (97%) rename unix.go => src/unix.go (100%) rename update.go => src/update.go (100%) rename util.go => src/util.go (100%) rename {vendor => src/vendor}/github.com/daviddengcn/go-colortext/.gitignore (100%) rename {vendor => src/vendor}/github.com/daviddengcn/go-colortext/LICENSE (100%) rename {vendor => src/vendor}/github.com/daviddengcn/go-colortext/README.md (100%) rename {vendor => src/vendor}/github.com/daviddengcn/go-colortext/ct.go (100%) rename {vendor => src/vendor}/github.com/daviddengcn/go-colortext/ct_ansi.go (100%) rename {vendor => src/vendor}/github.com/daviddengcn/go-colortext/ct_win.go (100%) rename {vendor => src/vendor}/github.com/subosito/gotenv/.gitignore (100%) rename {vendor => src/vendor}/github.com/subosito/gotenv/LICENSE (100%) rename {vendor => src/vendor}/github.com/subosito/gotenv/README.md (100%) rename {vendor => src/vendor}/github.com/subosito/gotenv/gotenv.go (100%) rename version.go => src/version.go (100%) rename version_test.go => src/version_test.go (100%) rename windows.go => src/windows.go (100%) rename {bin => tools}/release (100%) delete mode 100644 vendor/github.com/subosito/gotenv/.env diff --git a/Makefile b/Makefile index a69d6f5..21439c5 100644 --- a/Makefile +++ b/Makefile @@ -1,23 +1,60 @@ -BIN = forego -SRC = $(shell find . -name '*.go' -not -path './vendor/*') -.PHONY: all build clean lint release test +# the product we're building +NAME := forego +# the product's main package +MAIN := ./src +# fix our gopath +GOPATH := $(GOPATH):$(PWD) + +# build and packaging +TARGETS := $(PWD)/bin +PRODUCT := $(TARGETS)/$(NAME) + +# build and packaging for release +GITHASH := $(shell git log --pretty=format:'%h' -n 1) +VERSION ?= $(GITHASH) +RELEASE_TARGETS = $(PWD)/target/$(GOOS)_$(GOARCH) +RELEASE_PRODUCT = $(NAME)-$(VERSION) +RELEASE_ARCHIVE = $(RELEASE_PRODUCT)-$(GOOS)-$(GOARCH).tgz +RELEASE_PACKAGE = $(RELEASE_TARGETS)/$(RELEASE_ARCHIVE) +RELEASE_BINARY = $(RELEASE_TARGETS)/$(RELEASE_PRODUCT)/bin/$(NAME) + +# build and install +PREFIX ?= /usr/local + +# sources +SRC = $(shell find src -name \*.go -not -path ./src/vendor -print) + +.PHONY: all test clean install release build build_release build_formula all: build -build: $(BIN) +$(PRODUCT): $(SRC) + go build -ldflags="-X main.version=$(VERSION) -X main.githash=$(GITHASH)" -o $@ $(MAIN) + +build: $(PRODUCT) ## Build the product + +$(RELEASE_BINARY): $(SRC) + go build -ldflags="-X main.version=$(VERSION) -X main.githash=$(GITHASH)" -o $(RELEASE_BINARY) $(MAIN) + +$(RELEASE_PACKAGE): $(RELEASE_BINARY) + (cd $(RELEASE_TARGETS) && tar -zcf $(RELEASE_ARCHIVE) $(RELEASE_PRODUCT)) + +build_release: $(RELEASE_PACKAGE) -clean: - rm -f $(BIN) +build_formula: build_release + $(PWD)/tools/update-formula -v $(VERSION) -o $(PWD)/formula/instaunit.rb $(RELEASE_PACKAGE) -lint: $(SRC) - go fmt +release: test ## Build for all supported architectures + make build_release GOOS=linux GOARCH=amd64 + make build_release GOOS=freebsd GOARCH=amd64 + make build_formula GOOS=darwin GOARCH=amd64 -release: - bin/release +install: build ## Build and install + install -m 0755 $(PRODUCT) $(PREFIX)/bin/ -test: lint build - go test -v -race -cover ./... +test: ## Run tests + go test ./src/... -$(BIN): $(SRC) - go build -o $@ +clean: ## Delete the built product and any generated files + rm -rf $(TARGETS) diff --git a/barrier.go b/src/barrier.go similarity index 100% rename from barrier.go rename to src/barrier.go diff --git a/command.go b/src/command.go similarity index 100% rename from command.go rename to src/command.go diff --git a/config.go b/src/config.go similarity index 100% rename from config.go rename to src/config.go diff --git a/config_test.go b/src/config_test.go similarity index 100% rename from config_test.go rename to src/config_test.go diff --git a/env.go b/src/env.go similarity index 100% rename from env.go rename to src/env.go diff --git a/env_test.go b/src/env_test.go similarity index 82% rename from env_test.go rename to src/env_test.go index b52f44b..b8cb424 100644 --- a/env_test.go +++ b/src/env_test.go @@ -3,7 +3,7 @@ package main import "testing" func TestMultipleEnvironmentFiles(t *testing.T) { - envs := []string{"fixtures/envs/.env1", "fixtures/envs/.env2"} + envs := []string{"../fixtures/envs/.env1", "../fixtures/envs/.env2"} env, err := loadEnvs(envs) if err != nil { diff --git a/error.go b/src/error.go similarity index 100% rename from error.go rename to src/error.go diff --git a/help.go b/src/help.go similarity index 100% rename from help.go rename to src/help.go diff --git a/main.go b/src/main.go similarity index 86% rename from main.go rename to src/main.go index 8fe5078..c6e3d67 100644 --- a/main.go +++ b/src/main.go @@ -2,6 +2,11 @@ package main import "os" +var ( // set at compile time via the linker + version = "v0.0.0" + githash = "000000" +) + var commands = []*Command{ cmdStart, cmdRun, diff --git a/outlet.go b/src/outlet.go similarity index 100% rename from outlet.go rename to src/outlet.go diff --git a/process.go b/src/process.go similarity index 100% rename from process.go rename to src/process.go diff --git a/procfile.go b/src/procfile.go similarity index 100% rename from procfile.go rename to src/procfile.go diff --git a/run.go b/src/run.go similarity index 100% rename from run.go rename to src/run.go diff --git a/start.go b/src/start.go similarity index 100% rename from start.go rename to src/start.go diff --git a/start_test.go b/src/start_test.go similarity index 97% rename from start_test.go rename to src/start_test.go index 8982588..15a687c 100644 --- a/start_test.go +++ b/src/start_test.go @@ -151,7 +151,7 @@ func TestConfigBeOverrideByForegoFile(t *testing.T) { var port = 5000 var concurrency string = "web=2" var gracetime int = 3 - err := readConfigFile("./fixtures/configs/.forego", &procfile, &port, &concurrency, &gracetime) + err := readConfigFile("../fixtures/configs/.forego", &procfile, &port, &concurrency, &gracetime) if err != nil { t.Fatalf("Cannot set default values from forego config file") diff --git a/unix.go b/src/unix.go similarity index 100% rename from unix.go rename to src/unix.go diff --git a/update.go b/src/update.go similarity index 100% rename from update.go rename to src/update.go diff --git a/util.go b/src/util.go similarity index 100% rename from util.go rename to src/util.go diff --git a/vendor/github.com/daviddengcn/go-colortext/.gitignore b/src/vendor/github.com/daviddengcn/go-colortext/.gitignore similarity index 100% rename from vendor/github.com/daviddengcn/go-colortext/.gitignore rename to src/vendor/github.com/daviddengcn/go-colortext/.gitignore diff --git a/vendor/github.com/daviddengcn/go-colortext/LICENSE b/src/vendor/github.com/daviddengcn/go-colortext/LICENSE similarity index 100% rename from vendor/github.com/daviddengcn/go-colortext/LICENSE rename to src/vendor/github.com/daviddengcn/go-colortext/LICENSE diff --git a/vendor/github.com/daviddengcn/go-colortext/README.md b/src/vendor/github.com/daviddengcn/go-colortext/README.md similarity index 100% rename from vendor/github.com/daviddengcn/go-colortext/README.md rename to src/vendor/github.com/daviddengcn/go-colortext/README.md diff --git a/vendor/github.com/daviddengcn/go-colortext/ct.go b/src/vendor/github.com/daviddengcn/go-colortext/ct.go similarity index 100% rename from vendor/github.com/daviddengcn/go-colortext/ct.go rename to src/vendor/github.com/daviddengcn/go-colortext/ct.go diff --git a/vendor/github.com/daviddengcn/go-colortext/ct_ansi.go b/src/vendor/github.com/daviddengcn/go-colortext/ct_ansi.go similarity index 100% rename from vendor/github.com/daviddengcn/go-colortext/ct_ansi.go rename to src/vendor/github.com/daviddengcn/go-colortext/ct_ansi.go diff --git a/vendor/github.com/daviddengcn/go-colortext/ct_win.go b/src/vendor/github.com/daviddengcn/go-colortext/ct_win.go similarity index 100% rename from vendor/github.com/daviddengcn/go-colortext/ct_win.go rename to src/vendor/github.com/daviddengcn/go-colortext/ct_win.go diff --git a/vendor/github.com/subosito/gotenv/.gitignore b/src/vendor/github.com/subosito/gotenv/.gitignore similarity index 100% rename from vendor/github.com/subosito/gotenv/.gitignore rename to src/vendor/github.com/subosito/gotenv/.gitignore diff --git a/vendor/github.com/subosito/gotenv/LICENSE b/src/vendor/github.com/subosito/gotenv/LICENSE similarity index 100% rename from vendor/github.com/subosito/gotenv/LICENSE rename to src/vendor/github.com/subosito/gotenv/LICENSE diff --git a/vendor/github.com/subosito/gotenv/README.md b/src/vendor/github.com/subosito/gotenv/README.md similarity index 100% rename from vendor/github.com/subosito/gotenv/README.md rename to src/vendor/github.com/subosito/gotenv/README.md diff --git a/vendor/github.com/subosito/gotenv/gotenv.go b/src/vendor/github.com/subosito/gotenv/gotenv.go similarity index 100% rename from vendor/github.com/subosito/gotenv/gotenv.go rename to src/vendor/github.com/subosito/gotenv/gotenv.go diff --git a/version.go b/src/version.go similarity index 100% rename from version.go rename to src/version.go diff --git a/version_test.go b/src/version_test.go similarity index 100% rename from version_test.go rename to src/version_test.go diff --git a/windows.go b/src/windows.go similarity index 100% rename from windows.go rename to src/windows.go diff --git a/bin/release b/tools/release similarity index 100% rename from bin/release rename to tools/release diff --git a/vendor/github.com/subosito/gotenv/.env b/vendor/github.com/subosito/gotenv/.env deleted file mode 100644 index 6405eca..0000000 --- a/vendor/github.com/subosito/gotenv/.env +++ /dev/null @@ -1 +0,0 @@ -HELLO=world From 6e45f1fe98ce35c93ad38bc1d667adf9bde0143a Mon Sep 17 00:00:00 2001 From: "Brian W. Wolter" Date: Fri, 5 Apr 2019 14:24:30 -0400 Subject: [PATCH 08/27] Build, release --- .gitignore | 4 ++++ Makefile | 34 +++++++++++++++++++-------- build/.DS_Store | Bin 0 -> 6148 bytes build/update-formula | 53 +++++++++++++++++++++++++++++++++++++++++++ tools/release | 12 ---------- 5 files changed, 82 insertions(+), 21 deletions(-) create mode 100644 build/.DS_Store create mode 100755 build/update-formula delete mode 100755 tools/release diff --git a/.gitignore b/.gitignore index c2cf70d..e6a9897 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,6 @@ .env +.DS_Store /forego + +target/ +bin/ diff --git a/Makefile b/Makefile index 21439c5..819cdbd 100644 --- a/Makefile +++ b/Makefile @@ -3,8 +3,11 @@ NAME := forego # the product's main package MAIN := ./src + # fix our gopath GOPATH := $(GOPATH):$(PWD) +GOOS ?= $(shell go env GOOS) +GOARCH ?= $(shell go env GOARCH) # build and packaging TARGETS := $(PWD)/bin @@ -12,20 +15,23 @@ PRODUCT := $(TARGETS)/$(NAME) # build and packaging for release GITHASH := $(shell git log --pretty=format:'%h' -n 1) +BRANCH := $(shell git rev-parse --abbrev-ref HEAD) VERSION ?= $(GITHASH) RELEASE_TARGETS = $(PWD)/target/$(GOOS)_$(GOARCH) RELEASE_PRODUCT = $(NAME)-$(VERSION) +RELEASE_BUILD = $(RELEASE_TARGETS)/$(RELEASE_PRODUCT) +RELEASE_BINARY = $(RELEASE_BUILD)/bin/$(NAME) RELEASE_ARCHIVE = $(RELEASE_PRODUCT)-$(GOOS)-$(GOARCH).tgz RELEASE_PACKAGE = $(RELEASE_TARGETS)/$(RELEASE_ARCHIVE) -RELEASE_BINARY = $(RELEASE_TARGETS)/$(RELEASE_PRODUCT)/bin/$(NAME) # build and install PREFIX ?= /usr/local +LATEST ?= latest # sources SRC = $(shell find src -name \*.go -not -path ./src/vendor -print) -.PHONY: all test clean install release build build_release build_formula +.PHONY: all test clean install release build archive publish release formula all: build @@ -40,15 +46,25 @@ $(RELEASE_BINARY): $(SRC) $(RELEASE_PACKAGE): $(RELEASE_BINARY) (cd $(RELEASE_TARGETS) && tar -zcf $(RELEASE_ARCHIVE) $(RELEASE_PRODUCT)) -build_release: $(RELEASE_PACKAGE) +archive: $(RELEASE_PACKAGE) + +publish: archive + aws s3 cp --acl public-read $(RELEASE_PACKAGE) s3://bww-artifacts/forego/$(VERSION)/$(RELEASE_ARCHIVE) + +formula: archive + mkdir -p $(RELEASE_BUILD)/formula && $(PWD)/build/update-formula -v $(VERSION) -o $(RELEASE_BUILD)/formula/forego.rb $(RELEASE_PACKAGE) + aws s3 cp --acl public-read $(RELEASE_BUILD)/formula/forego.rb s3://bww-artifacts/forego/$(LATEST)/forego.rb + aws s3 cp --acl public-read $(RELEASE_BUILD)/formula/forego.rb s3://bww-artifacts/forego/$(VERSION)/forego.rb -build_formula: build_release - $(PWD)/tools/update-formula -v $(VERSION) -o $(PWD)/formula/instaunit.rb $(RELEASE_PACKAGE) +gate: + @echo && echo "AWS Profile: $(AWS_PROFILE)" && echo " Version: $(VERSION)" && echo " Branch: $(BRANCH)" + @echo && read -p "Release version $(VERSION)? [y/N] " -r continue && echo && [ "$${continue:-N}" = "y" ] -release: test ## Build for all supported architectures - make build_release GOOS=linux GOARCH=amd64 - make build_release GOOS=freebsd GOARCH=amd64 - make build_formula GOOS=darwin GOARCH=amd64 +release: gate test ## Build for all supported architectures + make publish GOOS=linux GOARCH=amd64 + make publish GOOS=freebsd GOARCH=amd64 + make publish formula GOOS=darwin GOARCH=amd64 + @echo && echo "Tag this release:\n\t$ git commit -a -m \"Version $(VERSION)\" && git tag $(VERSION)" && echo install: build ## Build and install install -m 0755 $(PRODUCT) $(PREFIX)/bin/ diff --git a/build/.DS_Store b/build/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0)" + exit -1 +fi + +# archive +if [ ! -f "$1" ]; then + echo "No archive provided" + exit -1 +fi + +sha256=$(openssl dgst -sha256 "$1") +sha256=${sha256#* } + +cat < "$formula_path" + +class Forego < Formula + homepage "https://github.com/bww/forego" + url "http://bww-artifacts.s3.amazonaws.com/forego/${release_version}/forego-${release_version}-${OS}-${ARCH}.tgz" + sha256 "${sha256}" + version "${release_version}" + + def install + bin.install "bin/forego" + end +end +FORMULA \ No newline at end of file diff --git a/tools/release b/tools/release deleted file mode 100755 index 84aa1fa..0000000 --- a/tools/release +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -version=$(date +%Y%m%d%H%M%S) - -curl -s ${GITHUB_KEY_URL} -o /tmp/github.key -chmod 0400 /tmp/github.key -git tag ${version} -GIT_SSH_COMMAND='ssh -i /tmp/github.key' git push origin ${version} - -curl -s https://bin.equinox.io/c/mBWdkfai63v/release-tool-stable-linux-amd64.tgz | sudo tar xz -C /usr/local/bin -curl -s ${EQUINOX_KEY_URL} -o /tmp/equinox.key -equinox release --version=${version} --platforms="darwin_386 darwin_amd64 linux_386 linux_amd64 linux_arm linux_arm64 windows_386 windows_amd64" --channel=stable --signing-key=/tmp/equinox.key --app=${EQUINOX_APP} --token=${EQUINOX_TOKEN} From 420f12c16a5365a7590d3970adaf3f2b662c526c Mon Sep 17 00:00:00 2001 From: "Brian W. Wolter" Date: Fri, 5 Apr 2019 14:30:39 -0400 Subject: [PATCH 09/27] Docs --- README.md | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index cafe174..409bdf6 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,28 @@ -## forego - - - - +## Forego [Foreman](https://github.com/ddollar/foreman) in Go. -### Installation +## Installing + +For your convenience, Forego can be installed via Homebrew. However you cannot install it along side the original Forego, from which this was forked. + +Install the latest version thusly: + +``` +$ brew install 'http://bww-artifacts.s3.amazonaws.com/forego/latest/forego.rb' +``` + +Upgrade (or uninstall) it as follows: -[Downloads](https://dl.equinox.io/ddollar/forego/stable) +``` +$ brew upgrade 'http://bww-artifacts.s3.amazonaws.com/forego/latest/forego.rb' +``` -##### Compile from Source +Uninstall as follows: - $ go get -u github.com/ddollar/forego +``` +$ brew uninstall forego +``` ### Usage @@ -29,4 +39,4 @@ Use `forego help` to get a list of available commands, and `forego help ### License -Apache 2.0 © 2015 David Dollar +Apache 2.0 © 2015 David Dollar, 2018 Brian W. Wolter From ec86935c3fd07ba517b58e93062fc2dc5a2d9f3f Mon Sep 17 00:00:00 2001 From: "Brian W. Wolter" Date: Tue, 13 Oct 2020 12:46:27 -0400 Subject: [PATCH 10/27] Migrating to modules --- Godeps/Godeps.json | 19 --- Godeps/Readme | 5 - {src => cmd}/barrier.go | 0 {src => cmd}/command.go | 0 {src => cmd}/config.go | 0 {src => cmd}/config_test.go | 0 {src => cmd}/env.go | 0 {src => cmd}/env_test.go | 0 {src => cmd}/error.go | 0 {src => cmd}/help.go | 0 {src => cmd}/main.go | 0 {src => cmd}/outlet.go | 0 {src => cmd}/process.go | 0 {src => cmd}/procfile.go | 0 {src => cmd}/run.go | 0 {src => cmd}/start.go | 0 {src => cmd}/start_test.go | 0 {src => cmd}/unix.go | 0 {src => cmd}/update.go | 0 {src => cmd}/util.go | 0 {src => cmd}/version.go | 0 {src => cmd}/version_test.go | 0 {src => cmd}/windows.go | 0 go.mod | 8 + go.sum | 8 + .../daviddengcn/go-colortext/.gitignore | 22 --- .../daviddengcn/go-colortext/LICENSE | 27 ---- .../daviddengcn/go-colortext/README.md | 21 --- .../github.com/daviddengcn/go-colortext/ct.go | 47 ------ .../daviddengcn/go-colortext/ct_ansi.go | 35 ----- .../daviddengcn/go-colortext/ct_win.go | 139 ------------------ .../github.com/subosito/gotenv/.gitignore | 2 - src/vendor/github.com/subosito/gotenv/LICENSE | 21 --- .../github.com/subosito/gotenv/README.md | 102 ------------- .../github.com/subosito/gotenv/gotenv.go | 119 --------------- 35 files changed, 16 insertions(+), 559 deletions(-) delete mode 100644 Godeps/Godeps.json delete mode 100644 Godeps/Readme rename {src => cmd}/barrier.go (100%) rename {src => cmd}/command.go (100%) rename {src => cmd}/config.go (100%) rename {src => cmd}/config_test.go (100%) rename {src => cmd}/env.go (100%) rename {src => cmd}/env_test.go (100%) rename {src => cmd}/error.go (100%) rename {src => cmd}/help.go (100%) rename {src => cmd}/main.go (100%) rename {src => cmd}/outlet.go (100%) rename {src => cmd}/process.go (100%) rename {src => cmd}/procfile.go (100%) rename {src => cmd}/run.go (100%) rename {src => cmd}/start.go (100%) rename {src => cmd}/start_test.go (100%) rename {src => cmd}/unix.go (100%) rename {src => cmd}/update.go (100%) rename {src => cmd}/util.go (100%) rename {src => cmd}/version.go (100%) rename {src => cmd}/version_test.go (100%) rename {src => cmd}/windows.go (100%) create mode 100644 go.mod create mode 100644 go.sum delete mode 100644 src/vendor/github.com/daviddengcn/go-colortext/.gitignore delete mode 100644 src/vendor/github.com/daviddengcn/go-colortext/LICENSE delete mode 100644 src/vendor/github.com/daviddengcn/go-colortext/README.md delete mode 100644 src/vendor/github.com/daviddengcn/go-colortext/ct.go delete mode 100644 src/vendor/github.com/daviddengcn/go-colortext/ct_ansi.go delete mode 100644 src/vendor/github.com/daviddengcn/go-colortext/ct_win.go delete mode 100644 src/vendor/github.com/subosito/gotenv/.gitignore delete mode 100644 src/vendor/github.com/subosito/gotenv/LICENSE delete mode 100644 src/vendor/github.com/subosito/gotenv/README.md delete mode 100644 src/vendor/github.com/subosito/gotenv/gotenv.go diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json deleted file mode 100644 index 1cc516a..0000000 --- a/Godeps/Godeps.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "ImportPath": "github.com/ddollar/forego", - "GoVersion": "go1.6", - "GodepVersion": "v61", - "Packages": [ - "./..." - ], - "Deps": [ - { - "ImportPath": "github.com/daviddengcn/go-colortext", - "Rev": "3b18c8575a432453d41fdafb340099fff5bba2f7" - }, - { - "ImportPath": "github.com/subosito/gotenv", - "Comment": "v0.1.0", - "Rev": "a37a0e8fb3298354bf97daad07b38feb2d0fa263" - } - ] -} diff --git a/Godeps/Readme b/Godeps/Readme deleted file mode 100644 index 4cdaa53..0000000 --- a/Godeps/Readme +++ /dev/null @@ -1,5 +0,0 @@ -This directory tree is generated automatically by godep. - -Please do not edit. - -See https://github.com/tools/godep for more information. diff --git a/src/barrier.go b/cmd/barrier.go similarity index 100% rename from src/barrier.go rename to cmd/barrier.go diff --git a/src/command.go b/cmd/command.go similarity index 100% rename from src/command.go rename to cmd/command.go diff --git a/src/config.go b/cmd/config.go similarity index 100% rename from src/config.go rename to cmd/config.go diff --git a/src/config_test.go b/cmd/config_test.go similarity index 100% rename from src/config_test.go rename to cmd/config_test.go diff --git a/src/env.go b/cmd/env.go similarity index 100% rename from src/env.go rename to cmd/env.go diff --git a/src/env_test.go b/cmd/env_test.go similarity index 100% rename from src/env_test.go rename to cmd/env_test.go diff --git a/src/error.go b/cmd/error.go similarity index 100% rename from src/error.go rename to cmd/error.go diff --git a/src/help.go b/cmd/help.go similarity index 100% rename from src/help.go rename to cmd/help.go diff --git a/src/main.go b/cmd/main.go similarity index 100% rename from src/main.go rename to cmd/main.go diff --git a/src/outlet.go b/cmd/outlet.go similarity index 100% rename from src/outlet.go rename to cmd/outlet.go diff --git a/src/process.go b/cmd/process.go similarity index 100% rename from src/process.go rename to cmd/process.go diff --git a/src/procfile.go b/cmd/procfile.go similarity index 100% rename from src/procfile.go rename to cmd/procfile.go diff --git a/src/run.go b/cmd/run.go similarity index 100% rename from src/run.go rename to cmd/run.go diff --git a/src/start.go b/cmd/start.go similarity index 100% rename from src/start.go rename to cmd/start.go diff --git a/src/start_test.go b/cmd/start_test.go similarity index 100% rename from src/start_test.go rename to cmd/start_test.go diff --git a/src/unix.go b/cmd/unix.go similarity index 100% rename from src/unix.go rename to cmd/unix.go diff --git a/src/update.go b/cmd/update.go similarity index 100% rename from src/update.go rename to cmd/update.go diff --git a/src/util.go b/cmd/util.go similarity index 100% rename from src/util.go rename to cmd/util.go diff --git a/src/version.go b/cmd/version.go similarity index 100% rename from src/version.go rename to cmd/version.go diff --git a/src/version_test.go b/cmd/version_test.go similarity index 100% rename from src/version_test.go rename to cmd/version_test.go diff --git a/src/windows.go b/cmd/windows.go similarity index 100% rename from src/windows.go rename to cmd/windows.go diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..c129923 --- /dev/null +++ b/go.mod @@ -0,0 +1,8 @@ +module github.com/bww/forego + +go 1.15 + +require ( + github.com/daviddengcn/go-colortext v1.0.0 + github.com/subosito/gotenv v1.2.0 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..99e0bd4 --- /dev/null +++ b/go.sum @@ -0,0 +1,8 @@ +github.com/daviddengcn/go-colortext v1.0.0 h1:ANqDyC0ys6qCSvuEK7l3g5RaehL/Xck9EX8ATG8oKsE= +github.com/daviddengcn/go-colortext v1.0.0/go.mod h1:zDqEI5NVUop5QPpVJUxE9UO10hRnmkD5G4Pmri9+m4c= +github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho= +github.com/golangplus/bytes v1.0.0/go.mod h1:AdRaCFwmc/00ZzELMWb01soso6W1R/++O1XL80yAn+A= +github.com/golangplus/fmt v1.0.0/go.mod h1:zpM0OfbMCjPtd2qkTD/jX2MgiFCqklhSUFyDW44gVQE= +github.com/golangplus/testing v1.0.0/go.mod h1:ZDreixUV3YzhoVraIDyOzHrr76p6NUh6k/pPg/Q3gYA= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= diff --git a/src/vendor/github.com/daviddengcn/go-colortext/.gitignore b/src/vendor/github.com/daviddengcn/go-colortext/.gitignore deleted file mode 100644 index 0026861..0000000 --- a/src/vendor/github.com/daviddengcn/go-colortext/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe diff --git a/src/vendor/github.com/daviddengcn/go-colortext/LICENSE b/src/vendor/github.com/daviddengcn/go-colortext/LICENSE deleted file mode 100644 index 974ec42..0000000 --- a/src/vendor/github.com/daviddengcn/go-colortext/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2015, David Deng -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of go-colortext nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/vendor/github.com/daviddengcn/go-colortext/README.md b/src/vendor/github.com/daviddengcn/go-colortext/README.md deleted file mode 100644 index 6e140f1..0000000 --- a/src/vendor/github.com/daviddengcn/go-colortext/README.md +++ /dev/null @@ -1,21 +0,0 @@ -go-colortext package [![GoSearch](http://go-search.org/badge?id=github.com%2Fdaviddengcn%2Fgo-colortext)](http://go-search.org/view?id=github.com%2Fdaviddengcn%2Fgo-colortext) -==================== - -This is a package to change the color of the text and background in the console, working both under Windows and other systems. - -Under Windows, the console APIs are used. Otherwise, ANSI texts are output. - -Docs: http://godoc.org/github.com/daviddengcn/go-colortext ([packages that import ct](http://go-search.org/view?id=github.com%2fdaviddengcn%2fgo-colortext)) - -Usage: -```go -Foreground(Green, false) -fmt.Println("Green text starts here...") -ChangeColor(Red, true, White, false) -fmt.Println(...) -ResetColor() -``` - -LICENSE -======= -BSD license diff --git a/src/vendor/github.com/daviddengcn/go-colortext/ct.go b/src/vendor/github.com/daviddengcn/go-colortext/ct.go deleted file mode 100644 index 4acfaac..0000000 --- a/src/vendor/github.com/daviddengcn/go-colortext/ct.go +++ /dev/null @@ -1,47 +0,0 @@ -/* -ct package provides functions to change the color of console text. - -Under windows platform, the Console api is used. Under other systems, ANSI text mode is used. -*/ -package ct - -// Color is the type of color to be set. -type Color int - -const ( - // No change of color - None = Color(iota) - Black - Red - Green - Yellow - Blue - Magenta - Cyan - White -) - -/* -ResetColor resets the foreground and background to original colors -*/ -func ResetColor() { - resetColor() -} - -// ChangeColor sets the foreground and background colors. If the value of the color is None, -// the corresponding color keeps unchanged. -// If fgBright or bgBright is set true, corresponding color use bright color. bgBright may be -// ignored in some OS environment. -func ChangeColor(fg Color, fgBright bool, bg Color, bgBright bool) { - changeColor(fg, fgBright, bg, bgBright) -} - -// Foreground changes the foreground color. -func Foreground(cl Color, bright bool) { - ChangeColor(cl, bright, None, false) -} - -// Background changes the background color. -func Background(cl Color, bright bool) { - ChangeColor(None, false, cl, bright) -} diff --git a/src/vendor/github.com/daviddengcn/go-colortext/ct_ansi.go b/src/vendor/github.com/daviddengcn/go-colortext/ct_ansi.go deleted file mode 100644 index 6b0c5bc..0000000 --- a/src/vendor/github.com/daviddengcn/go-colortext/ct_ansi.go +++ /dev/null @@ -1,35 +0,0 @@ -// +build !windows - -package ct - -import ( - "fmt" -) - -func resetColor() { - fmt.Print("\x1b[0m") -} - -func changeColor(fg Color, fgBright bool, bg Color, bgBright bool) { - if fg == None && bg == None { - return - } // if - - s := "" - if fg != None { - s = fmt.Sprintf("%s%d", s, 30+(int)(fg-Black)) - if fgBright { - s += ";1" - } // if - } // if - - if bg != None { - if s != "" { - s += ";" - } // if - s = fmt.Sprintf("%s%d", s, 40+(int)(bg-Black)) - } // if - - s = "\x1b[0;" + s + "m" - fmt.Print(s) -} diff --git a/src/vendor/github.com/daviddengcn/go-colortext/ct_win.go b/src/vendor/github.com/daviddengcn/go-colortext/ct_win.go deleted file mode 100644 index 6b41644..0000000 --- a/src/vendor/github.com/daviddengcn/go-colortext/ct_win.go +++ /dev/null @@ -1,139 +0,0 @@ -// +build windows - -package ct - -import ( - "syscall" - "unsafe" -) - -var fg_colors = []uint16{ - 0, - 0, - foreground_red, - foreground_green, - foreground_red | foreground_green, - foreground_blue, - foreground_red | foreground_blue, - foreground_green | foreground_blue, - foreground_red | foreground_green | foreground_blue} - -var bg_colors = []uint16{ - 0, - 0, - background_red, - background_green, - background_red | background_green, - background_blue, - background_red | background_blue, - background_green | background_blue, - background_red | background_green | background_blue} - -const ( - foreground_blue = uint16(0x0001) - foreground_green = uint16(0x0002) - foreground_red = uint16(0x0004) - foreground_intensity = uint16(0x0008) - background_blue = uint16(0x0010) - background_green = uint16(0x0020) - background_red = uint16(0x0040) - background_intensity = uint16(0x0080) - - foreground_mask = foreground_blue | foreground_green | foreground_red | foreground_intensity - background_mask = background_blue | background_green | background_red | background_intensity -) - -var ( - kernel32 = syscall.NewLazyDLL("kernel32.dll") - - procGetStdHandle = kernel32.NewProc("GetStdHandle") - procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute") - procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") - - hStdout uintptr - initScreenInfo *console_screen_buffer_info -) - -func setConsoleTextAttribute(hConsoleOutput uintptr, wAttributes uint16) bool { - ret, _, _ := procSetConsoleTextAttribute.Call( - hConsoleOutput, - uintptr(wAttributes)) - return ret != 0 -} - -type coord struct { - X, Y int16 -} - -type small_rect struct { - Left, Top, Right, Bottom int16 -} - -type console_screen_buffer_info struct { - DwSize coord - DwCursorPosition coord - WAttributes uint16 - SrWindow small_rect - DwMaximumWindowSize coord -} - -func getConsoleScreenBufferInfo(hConsoleOutput uintptr) *console_screen_buffer_info { - var csbi console_screen_buffer_info - ret, _, _ := procGetConsoleScreenBufferInfo.Call( - hConsoleOutput, - uintptr(unsafe.Pointer(&csbi))) - if ret == 0 { - return nil - } - return &csbi -} - -const ( - std_output_handle = uint32(-11 & 0xFFFFFFFF) -) - -func init() { - kernel32 := syscall.NewLazyDLL("kernel32.dll") - - procGetStdHandle = kernel32.NewProc("GetStdHandle") - - hStdout, _, _ = procGetStdHandle.Call(uintptr(std_output_handle)) - - initScreenInfo = getConsoleScreenBufferInfo(hStdout) - - syscall.LoadDLL("") -} - -func resetColor() { - if initScreenInfo == nil { // No console info - Ex: stdout redirection - return - } - setConsoleTextAttribute(hStdout, initScreenInfo.WAttributes) -} - -func changeColor(fg Color, fgBright bool, bg Color, bgBright bool) { - attr := uint16(0) - if fg == None || bg == None { - cbufinfo := getConsoleScreenBufferInfo(hStdout) - if cbufinfo == nil { // No console info - Ex: stdout redirection - return - } - attr = getConsoleScreenBufferInfo(hStdout).WAttributes - } // if - - if fg != None { - attr = attr & ^foreground_mask | fg_colors[fg] - if fgBright { - attr |= foreground_intensity - } // if - } // if - - if bg != None { - attr = attr & ^background_mask | bg_colors[bg] - if bgBright { - attr |= background_intensity - } // if - } // if - - setConsoleTextAttribute(hStdout, attr) -} diff --git a/src/vendor/github.com/subosito/gotenv/.gitignore b/src/vendor/github.com/subosito/gotenv/.gitignore deleted file mode 100644 index 7c7dff2..0000000 --- a/src/vendor/github.com/subosito/gotenv/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.test -annotate.json diff --git a/src/vendor/github.com/subosito/gotenv/LICENSE b/src/vendor/github.com/subosito/gotenv/LICENSE deleted file mode 100644 index f64ccae..0000000 --- a/src/vendor/github.com/subosito/gotenv/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013 Alif Rachmawadi - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/src/vendor/github.com/subosito/gotenv/README.md b/src/vendor/github.com/subosito/gotenv/README.md deleted file mode 100644 index 196683f..0000000 --- a/src/vendor/github.com/subosito/gotenv/README.md +++ /dev/null @@ -1,102 +0,0 @@ -# gotenv - -Load environment variables dynamically in Go. - -|- | - | -|---------------|----------------------------------------------------| -| Build Status | [![Build Status][drone-img]][drone-url] | -| Coverage | [![Coverage Status][coveralls-img]][coveralls-url] | -| Documentation | http://godoc.org/github.com/subosito/gotenv | - -## Installation - -```bash -$ go get github.com/subosito/gotenv -``` - -## Usage - -Store your configuration to `.env` file on your root directory of your project: - -``` -APP_ID=1234567 -APP_SECRET=abcdef -``` - -Put the gotenv package on your `import` statement: - -```go -import "github.com/subosito/gotenv" -``` - -Then somewhere on your application code, put: - -```go -gotenv.Load() -``` - -Behind the scene it will then load `.env` file and export the valid variables to the environment variables. Make sure you call the method as soon as possible to ensure all variables are loaded, say, put it on `init()` function. - -Once loaded you can use `os.Getenv()` to get the value of the variable. - -Here's the final example: - -```go -package main - -import ( - "github.com/subosito/gotenv" - "log" - "os" -) - -func init() { - gotenv.Load() -} - -func main() { - log.Println(os.Getenv("APP_ID")) // "1234567" - log.Println(os.Getenv("APP_SECRET")) // "abcdef" -} -``` - -You can also load other than `.env` file if you wish. Just supply filenames when calling `Load()`: - -```go -gotenv.Load(".env.production", "credentials") -``` - -That's it :) - -### Another Scenario - -Just in case you want to parse environment variables from any `io.Reader`, gotenv keeps its `Parse()` function as public API so you can utilize that. - -```go -// import "strings" - -pairs := gotenv.Parse(strings.NewReader("FOO=test\nBAR=$FOO")) -// gotenv.Env{"FOO": "test", "BAR": "test"} - -pairs = gotenv.Parse(strings.NewReader(`FOO="bar"`)) -// gotenv.Env{"FOO": "bar"} -``` - -Parse ignores invalid lines and returns `Env` of valid environment variables. - -### Formats - -The gotenv supports various format for defining environment variables. You can see more about it on: - -- [fixtures](./fixtures) -- [gotenv_test.go](./gotenv_test.go) - -## Notes - -The gotenv package is a Go port of [`dotenv`](https://github.com/bkeepers/dotenv) project. Most logic and regexp pattern is taken from there and aims will be compatible as close as possible. - -[drone-img]: https://drone.io/github.com/subosito/gotenv/status.png -[drone-url]: https://drone.io/github.com/subosito/gotenv/latest -[coveralls-img]: https://coveralls.io/repos/subosito/gotenv/badge.png?branch=master -[coveralls-url]: https://coveralls.io/r/subosito/gotenv?branch=master - diff --git a/src/vendor/github.com/subosito/gotenv/gotenv.go b/src/vendor/github.com/subosito/gotenv/gotenv.go deleted file mode 100644 index c7a7b09..0000000 --- a/src/vendor/github.com/subosito/gotenv/gotenv.go +++ /dev/null @@ -1,119 +0,0 @@ -// Package gotenv provides functionality to dynamically load the environment variables -package gotenv - -import ( - "bufio" - "io" - "os" - "regexp" - "strings" -) - -const ( - // Pattern for detecting valid line format - linePattern = `\A(?:export\s+)?([\w\.]+)(?:\s*=\s*|:\s+?)('(?:\'|[^'])*'|"(?:\"|[^"])*"|[^#\n]+)?(?:\s*\#.*)?\z` - - // Pattern for detecting valid variable within a value - variablePattern = `(\\)?(\$)(\{?([A-Z0-9_]+)\}?)` -) - -// Holds key/value pair of valid environment variable -type Env map[string]string - -/* -Load is function to load a file or multiple files and then export the valid variables which found into environment variables. -When it's called with no argument, it will load `.env` file on the current path and set the environment variables. -Otherwise, it will loop over the filenames parameter and set the proper environment variables. - - // processing `.env` - gotenv.Load() - - // processing multiple files - gotenv.Load("production.env", "credentials") - -*/ -func Load(filenames ...string) error { - if len(filenames) == 0 { - filenames = []string{".env"} - } - - for _, filename := range filenames { - f, err := os.Open(filename) - if err != nil { - return err - } - defer f.Close() - - // set environment - env := Parse(f) - for key, val := range env { - os.Setenv(key, val) - } - } - - return nil -} - -// Parse if a function to parse line by line any io.Reader supplied and returns the valid Env key/value pair of valid variables. -// It expands the value of a variable from environment variable, but does not set the value to the environment itself. -// This function is skipping any invalid lines and only processing the valid one. -func Parse(r io.Reader) Env { - env := make(Env) - scanner := bufio.NewScanner(r) - - for scanner.Scan() { - parseLine(scanner.Text(), env) - } - - return env -} - -func parseLine(s string, env Env) { - r := regexp.MustCompile(linePattern) - matches := r.FindStringSubmatch(s) - if len(matches) == 0 { - return - } - - key := matches[1] - val := matches[2] - - // determine if string has quote prefix - hq := strings.HasPrefix(val, `"`) - - // trim whitespace - val = strings.Trim(val, " ") - - // remove quotes '' or "" - rq := regexp.MustCompile(`\A(['"])(.*)(['"])\z`) - val = rq.ReplaceAllString(val, "$2") - - if hq { - val = strings.Replace(val, `\n`, "\n", -1) - // Unescape all characters except $ so variables can be escaped properly - re := regexp.MustCompile(`\\([^$])`) - val = re.ReplaceAllString(val, "$1") - } - - rv := regexp.MustCompile(variablePattern) - xv := rv.FindStringSubmatch(val) - - if len(xv) > 0 { - var replace string - var ok bool - - if xv[1] == "\\" { - replace = strings.Join(xv[2:4], "") - } else { - replace, ok = env[xv[4]] - if !ok { - replace = os.Getenv(xv[4]) - } - } - - val = strings.Replace(val, strings.Join(xv[0:1], ""), replace, -1) - } - - env[key] = val - return -} From 0f44327c0d961cdaadb2732b5d674a540628f04a Mon Sep 17 00:00:00 2001 From: "Brian W. Wolter" Date: Tue, 13 Oct 2020 12:48:51 -0400 Subject: [PATCH 11/27] Renaming --- .gitignore | 1 - {cmd => forego}/barrier.go | 0 {cmd => forego}/command.go | 0 {cmd => forego}/config.go | 0 {cmd => forego}/config_test.go | 0 {cmd => forego}/env.go | 0 {cmd => forego}/env_test.go | 0 {cmd => forego}/error.go | 0 {cmd => forego}/help.go | 0 {cmd => forego}/main.go | 0 {cmd => forego}/outlet.go | 0 {cmd => forego}/process.go | 0 {cmd => forego}/procfile.go | 0 {cmd => forego}/run.go | 0 {cmd => forego}/start.go | 0 {cmd => forego}/start_test.go | 0 {cmd => forego}/unix.go | 0 {cmd => forego}/update.go | 0 {cmd => forego}/util.go | 0 {cmd => forego}/version.go | 0 {cmd => forego}/version_test.go | 0 {cmd => forego}/windows.go | 0 22 files changed, 1 deletion(-) rename {cmd => forego}/barrier.go (100%) rename {cmd => forego}/command.go (100%) rename {cmd => forego}/config.go (100%) rename {cmd => forego}/config_test.go (100%) rename {cmd => forego}/env.go (100%) rename {cmd => forego}/env_test.go (100%) rename {cmd => forego}/error.go (100%) rename {cmd => forego}/help.go (100%) rename {cmd => forego}/main.go (100%) rename {cmd => forego}/outlet.go (100%) rename {cmd => forego}/process.go (100%) rename {cmd => forego}/procfile.go (100%) rename {cmd => forego}/run.go (100%) rename {cmd => forego}/start.go (100%) rename {cmd => forego}/start_test.go (100%) rename {cmd => forego}/unix.go (100%) rename {cmd => forego}/update.go (100%) rename {cmd => forego}/util.go (100%) rename {cmd => forego}/version.go (100%) rename {cmd => forego}/version_test.go (100%) rename {cmd => forego}/windows.go (100%) diff --git a/.gitignore b/.gitignore index e6a9897..7f8a427 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ .env .DS_Store -/forego target/ bin/ diff --git a/cmd/barrier.go b/forego/barrier.go similarity index 100% rename from cmd/barrier.go rename to forego/barrier.go diff --git a/cmd/command.go b/forego/command.go similarity index 100% rename from cmd/command.go rename to forego/command.go diff --git a/cmd/config.go b/forego/config.go similarity index 100% rename from cmd/config.go rename to forego/config.go diff --git a/cmd/config_test.go b/forego/config_test.go similarity index 100% rename from cmd/config_test.go rename to forego/config_test.go diff --git a/cmd/env.go b/forego/env.go similarity index 100% rename from cmd/env.go rename to forego/env.go diff --git a/cmd/env_test.go b/forego/env_test.go similarity index 100% rename from cmd/env_test.go rename to forego/env_test.go diff --git a/cmd/error.go b/forego/error.go similarity index 100% rename from cmd/error.go rename to forego/error.go diff --git a/cmd/help.go b/forego/help.go similarity index 100% rename from cmd/help.go rename to forego/help.go diff --git a/cmd/main.go b/forego/main.go similarity index 100% rename from cmd/main.go rename to forego/main.go diff --git a/cmd/outlet.go b/forego/outlet.go similarity index 100% rename from cmd/outlet.go rename to forego/outlet.go diff --git a/cmd/process.go b/forego/process.go similarity index 100% rename from cmd/process.go rename to forego/process.go diff --git a/cmd/procfile.go b/forego/procfile.go similarity index 100% rename from cmd/procfile.go rename to forego/procfile.go diff --git a/cmd/run.go b/forego/run.go similarity index 100% rename from cmd/run.go rename to forego/run.go diff --git a/cmd/start.go b/forego/start.go similarity index 100% rename from cmd/start.go rename to forego/start.go diff --git a/cmd/start_test.go b/forego/start_test.go similarity index 100% rename from cmd/start_test.go rename to forego/start_test.go diff --git a/cmd/unix.go b/forego/unix.go similarity index 100% rename from cmd/unix.go rename to forego/unix.go diff --git a/cmd/update.go b/forego/update.go similarity index 100% rename from cmd/update.go rename to forego/update.go diff --git a/cmd/util.go b/forego/util.go similarity index 100% rename from cmd/util.go rename to forego/util.go diff --git a/cmd/version.go b/forego/version.go similarity index 100% rename from cmd/version.go rename to forego/version.go diff --git a/cmd/version_test.go b/forego/version_test.go similarity index 100% rename from cmd/version_test.go rename to forego/version_test.go diff --git a/cmd/windows.go b/forego/windows.go similarity index 100% rename from cmd/windows.go rename to forego/windows.go From da5438edcaca994d7751647cef1fa360f8742c39 Mon Sep 17 00:00:00 2001 From: "Brian W. Wolter" Date: Wed, 10 Feb 2021 22:10:48 -0500 Subject: [PATCH 12/27] Initial workflow --- .github/workflows/release.yml | 25 +++++++++++++++++++++++++ build/update-formula | 10 ++++++---- 2 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..c3b06b5 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,25 @@ +name: Release + +on: [push] +# on: +# push: +# tags: # Sequence of patterns matched against refs/tags +# - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 + +jobs: + build: + name: Create Release + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v2 + - name: Create Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + release_name: Release ${{ github.ref }} + draft: true + prerelease: false diff --git a/build/update-formula b/build/update-formula index f9167b4..93f9b2e 100755 --- a/build/update-formula +++ b/build/update-formula @@ -1,7 +1,9 @@ #!/usr/bin/env bash +# meta +product="forego" # defaults -formula_path="./forego.rb" +formula_path="./${product}.rb" # arguments while [[ $# -gt 1 ]]; do @@ -41,13 +43,13 @@ sha256=${sha256#* } cat < "$formula_path" class Forego < Formula - homepage "https://github.com/bww/forego" - url "http://bww-artifacts.s3.amazonaws.com/forego/${release_version}/forego-${release_version}-${OS}-${ARCH}.tgz" + homepage "https://github.com/bww/${product}" + url "http://bww-artifacts.s3.amazonaws.com/${product}/${release_version}/${product}-${release_version}-${OS}-${ARCH}.tgz" sha256 "${sha256}" version "${release_version}" def install - bin.install "bin/forego" + bin.install "bin/${product}" end end FORMULA \ No newline at end of file From 28b610f6fa08ba22c6894092869f4d4856a765fe Mon Sep 17 00:00:00 2001 From: "Brian W. Wolter" Date: Wed, 10 Feb 2021 22:25:35 -0500 Subject: [PATCH 13/27] ... --- .github/workflows/release.yml | 40 ++++++++++++++++++++++++++++++++++- Makefile | 8 +++---- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c3b06b5..a51a83b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,7 +13,15 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v2 - - name: Create Release + - name: Build + run: | + make archive GOOS=linux GOARCH=amd64 + make archive GOOS=freebsd GOARCH=amd64 + make archive GOOS=darwin GOARCH=amd64 + - name: Setup variables + id: vars + run: echo "::set-output name=githash::$(git rev-parse --short HEAD)" + - name: Create release id: create_release uses: actions/create-release@v1 env: @@ -23,3 +31,33 @@ jobs: release_name: Release ${{ github.ref }} draft: true prerelease: false + - name: Upload artifact + id: upload-artifact-linux-amd64 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./target/linux_amd64/forego-${{ steps.vars.outputs.sha_short }}-linux-amd64.tgz + asset_name: forego-${{ steps.vars.outputs.sha_short }}-linux-amd64.tgz + asset_content_type: application/x-tgz + - name: Upload artifact + id: upload-artifact-freebsd-amd64 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./target/freebsd_amd64/forego-${{ steps.vars.outputs.sha_short }}-freebsd-amd64.tgz + asset_name: forego-${{ steps.vars.outputs.sha_short }}-freebsd-amd64.tgz + asset_content_type: application/x-tgz + - name: Upload artifact + id: upload-artifact-darwin-amd64 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./target/darwin_amd64/forego-${{ steps.vars.outputs.sha_short }}-darwin-amd64.tgz + asset_name: forego-${{ steps.vars.outputs.sha_short }}-darwin-amd64.tgz + asset_content_type: application/x-tgz diff --git a/Makefile b/Makefile index 819cdbd..09592e1 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ # the product we're building NAME := forego # the product's main package -MAIN := ./src +MAIN := ./forego # fix our gopath GOPATH := $(GOPATH):$(PWD) @@ -29,7 +29,7 @@ PREFIX ?= /usr/local LATEST ?= latest # sources -SRC = $(shell find src -name \*.go -not -path ./src/vendor -print) +SRC = $(shell find $(MAIN) -name \*.go) .PHONY: all test clean install release build archive publish release formula @@ -63,14 +63,14 @@ gate: release: gate test ## Build for all supported architectures make publish GOOS=linux GOARCH=amd64 make publish GOOS=freebsd GOARCH=amd64 - make publish formula GOOS=darwin GOARCH=amd64 + make public formula GOOS=darwin GOARCH=amd64 @echo && echo "Tag this release:\n\t$ git commit -a -m \"Version $(VERSION)\" && git tag $(VERSION)" && echo install: build ## Build and install install -m 0755 $(PRODUCT) $(PREFIX)/bin/ test: ## Run tests - go test ./src/... + go test $(MAIN)/... clean: ## Delete the built product and any generated files rm -rf $(TARGETS) From 28e870e450f6fc3622f1c246ac13ff5f72ac338b Mon Sep 17 00:00:00 2001 From: "Brian W. Wolter" Date: Wed, 10 Feb 2021 22:27:02 -0500 Subject: [PATCH 14/27] ... --- .github/workflows/release.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a51a83b..7dfa9af 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -38,8 +38,8 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./target/linux_amd64/forego-${{ steps.vars.outputs.sha_short }}-linux-amd64.tgz - asset_name: forego-${{ steps.vars.outputs.sha_short }}-linux-amd64.tgz + asset_path: ./target/linux_amd64/forego-${{ steps.vars.outputs.githash }}-linux-amd64.tgz + asset_name: forego-${{ steps.vars.outputs.githash }}-linux-amd64.tgz asset_content_type: application/x-tgz - name: Upload artifact id: upload-artifact-freebsd-amd64 @@ -48,8 +48,8 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./target/freebsd_amd64/forego-${{ steps.vars.outputs.sha_short }}-freebsd-amd64.tgz - asset_name: forego-${{ steps.vars.outputs.sha_short }}-freebsd-amd64.tgz + asset_path: ./target/freebsd_amd64/forego-${{ steps.vars.outputs.githash }}-freebsd-amd64.tgz + asset_name: forego-${{ steps.vars.outputs.githash }}-freebsd-amd64.tgz asset_content_type: application/x-tgz - name: Upload artifact id: upload-artifact-darwin-amd64 @@ -58,6 +58,6 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./target/darwin_amd64/forego-${{ steps.vars.outputs.sha_short }}-darwin-amd64.tgz - asset_name: forego-${{ steps.vars.outputs.sha_short }}-darwin-amd64.tgz + asset_path: ./target/darwin_amd64/forego-${{ steps.vars.outputs.githash }}-darwin-amd64.tgz + asset_name: forego-${{ steps.vars.outputs.githash }}-darwin-amd64.tgz asset_content_type: application/x-tgz From 99b81353947e7bef14808e346b22593e128f25d2 Mon Sep 17 00:00:00 2001 From: "Brian W. Wolter" Date: Wed, 10 Feb 2021 22:32:24 -0500 Subject: [PATCH 15/27] ... --- Makefile | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/Makefile b/Makefile index 09592e1..6031daf 100644 --- a/Makefile +++ b/Makefile @@ -48,24 +48,11 @@ $(RELEASE_PACKAGE): $(RELEASE_BINARY) archive: $(RELEASE_PACKAGE) -publish: archive - aws s3 cp --acl public-read $(RELEASE_PACKAGE) s3://bww-artifacts/forego/$(VERSION)/$(RELEASE_ARCHIVE) - formula: archive mkdir -p $(RELEASE_BUILD)/formula && $(PWD)/build/update-formula -v $(VERSION) -o $(RELEASE_BUILD)/formula/forego.rb $(RELEASE_PACKAGE) aws s3 cp --acl public-read $(RELEASE_BUILD)/formula/forego.rb s3://bww-artifacts/forego/$(LATEST)/forego.rb aws s3 cp --acl public-read $(RELEASE_BUILD)/formula/forego.rb s3://bww-artifacts/forego/$(VERSION)/forego.rb -gate: - @echo && echo "AWS Profile: $(AWS_PROFILE)" && echo " Version: $(VERSION)" && echo " Branch: $(BRANCH)" - @echo && read -p "Release version $(VERSION)? [y/N] " -r continue && echo && [ "$${continue:-N}" = "y" ] - -release: gate test ## Build for all supported architectures - make publish GOOS=linux GOARCH=amd64 - make publish GOOS=freebsd GOARCH=amd64 - make public formula GOOS=darwin GOARCH=amd64 - @echo && echo "Tag this release:\n\t$ git commit -a -m \"Version $(VERSION)\" && git tag $(VERSION)" && echo - install: build ## Build and install install -m 0755 $(PRODUCT) $(PREFIX)/bin/ From 8f5604da1a5b0553e73f23355835b9481938fa67 Mon Sep 17 00:00:00 2001 From: "Brian W. Wolter" Date: Wed, 10 Feb 2021 22:37:41 -0500 Subject: [PATCH 16/27] ... --- .github/workflows/release.yml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7dfa9af..d23b110 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,10 +1,9 @@ name: Release -on: [push] -# on: -# push: -# tags: # Sequence of patterns matched against refs/tags -# - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 +on: + push: + tags: # Sequence of patterns matched against refs/tags + - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 jobs: build: @@ -20,7 +19,9 @@ jobs: make archive GOOS=darwin GOARCH=amd64 - name: Setup variables id: vars - run: echo "::set-output name=githash::$(git rev-parse --short HEAD)" + run: + - echo "::set-output name=githash::$(git rev-parse --short HEAD)" + - echo "::set-output name=message::$(git log -1 --pretty=%B)" - name: Create release id: create_release uses: actions/create-release@v1 @@ -29,6 +30,7 @@ jobs: with: tag_name: ${{ github.ref }} release_name: Release ${{ github.ref }} + body: ${{ steps.vars.outputs.message }} draft: true prerelease: false - name: Upload artifact From 07da1097aef3de18bac61d80ae69c61016f0e28b Mon Sep 17 00:00:00 2001 From: "Brian W. Wolter" Date: Wed, 10 Feb 2021 22:38:57 -0500 Subject: [PATCH 17/27] ... --- .github/workflows/release.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d23b110..9988084 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,9 +19,7 @@ jobs: make archive GOOS=darwin GOARCH=amd64 - name: Setup variables id: vars - run: - - echo "::set-output name=githash::$(git rev-parse --short HEAD)" - - echo "::set-output name=message::$(git log -1 --pretty=%B)" + run: echo "::set-output name=githash::$(git rev-parse --short HEAD)" - name: Create release id: create_release uses: actions/create-release@v1 @@ -30,7 +28,6 @@ jobs: with: tag_name: ${{ github.ref }} release_name: Release ${{ github.ref }} - body: ${{ steps.vars.outputs.message }} draft: true prerelease: false - name: Upload artifact From 0e4df3036f200f5511840ccb0a7d4c2e43b015bd Mon Sep 17 00:00:00 2001 From: "Brian W. Wolter" Date: Thu, 11 Feb 2021 20:07:14 -0500 Subject: [PATCH 18/27] ... --- .github/workflows/release.yml | 8 ++--- Makefile | 5 ---- build/.DS_Store | Bin 6148 -> 0 bytes build/update-formula | 55 ---------------------------------- 4 files changed, 4 insertions(+), 64 deletions(-) delete mode 100644 build/.DS_Store delete mode 100755 build/update-formula diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9988084..91c9bb2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,10 +28,10 @@ jobs: with: tag_name: ${{ github.ref }} release_name: Release ${{ github.ref }} - draft: true + draft: false prerelease: false - name: Upload artifact - id: upload-artifact-linux-amd64 + id: upload_artifact_linux_amd64 uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -41,7 +41,7 @@ jobs: asset_name: forego-${{ steps.vars.outputs.githash }}-linux-amd64.tgz asset_content_type: application/x-tgz - name: Upload artifact - id: upload-artifact-freebsd-amd64 + id: upload_artifact_freebsd_amd64 uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -51,7 +51,7 @@ jobs: asset_name: forego-${{ steps.vars.outputs.githash }}-freebsd-amd64.tgz asset_content_type: application/x-tgz - name: Upload artifact - id: upload-artifact-darwin-amd64 + id: upload_artifact_darwin_amd64 uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/Makefile b/Makefile index 6031daf..73431f4 100644 --- a/Makefile +++ b/Makefile @@ -48,11 +48,6 @@ $(RELEASE_PACKAGE): $(RELEASE_BINARY) archive: $(RELEASE_PACKAGE) -formula: archive - mkdir -p $(RELEASE_BUILD)/formula && $(PWD)/build/update-formula -v $(VERSION) -o $(RELEASE_BUILD)/formula/forego.rb $(RELEASE_PACKAGE) - aws s3 cp --acl public-read $(RELEASE_BUILD)/formula/forego.rb s3://bww-artifacts/forego/$(LATEST)/forego.rb - aws s3 cp --acl public-read $(RELEASE_BUILD)/formula/forego.rb s3://bww-artifacts/forego/$(VERSION)/forego.rb - install: build ## Build and install install -m 0755 $(PRODUCT) $(PREFIX)/bin/ diff --git a/build/.DS_Store b/build/.DS_Store deleted file mode 100644 index 5008ddfcf53c02e82d7eee2e57c38e5672ef89f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0)" - exit -1 -fi - -# archive -if [ ! -f "$1" ]; then - echo "No archive provided" - exit -1 -fi - -sha256=$(openssl dgst -sha256 "$1") -sha256=${sha256#* } - -cat < "$formula_path" - -class Forego < Formula - homepage "https://github.com/bww/${product}" - url "http://bww-artifacts.s3.amazonaws.com/${product}/${release_version}/${product}-${release_version}-${OS}-${ARCH}.tgz" - sha256 "${sha256}" - version "${release_version}" - - def install - bin.install "bin/${product}" - end -end -FORMULA \ No newline at end of file From 727342ff6aed9373f46462628038e1a4f9e97d1e Mon Sep 17 00:00:00 2001 From: "Brian W. Wolter" Date: Thu, 11 Feb 2021 21:38:42 -0500 Subject: [PATCH 19/27] ... --- Makefile | 2 +- README.md | 11 +++-------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 73431f4..20be3f3 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ LATEST ?= latest # sources SRC = $(shell find $(MAIN) -name \*.go) -.PHONY: all test clean install release build archive publish release formula +.PHONY: all test clean install build archive all: build diff --git a/README.md b/README.md index 409bdf6..f91e9ce 100644 --- a/README.md +++ b/README.md @@ -6,16 +6,11 @@ For your convenience, Forego can be installed via Homebrew. However you cannot install it along side the original Forego, from which this was forked. -Install the latest version thusly: +Install or upgrade the latest version thusly: ``` -$ brew install 'http://bww-artifacts.s3.amazonaws.com/forego/latest/forego.rb' -``` - -Upgrade (or uninstall) it as follows: - -``` -$ brew upgrade 'http://bww-artifacts.s3.amazonaws.com/forego/latest/forego.rb' +$ brew install bww/stable/forego +$ brew upgrade bww/stable/forego ``` Uninstall as follows: From f5206cde53fdffdac273c98d919bab0b76f74cf2 Mon Sep 17 00:00:00 2001 From: "Brian W. Wolter" Date: Thu, 11 Feb 2021 22:17:09 -0500 Subject: [PATCH 20/27] ... --- .github/workflows/release.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 91c9bb2..acb8819 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,9 +14,9 @@ jobs: uses: actions/checkout@v2 - name: Build run: | - make archive GOOS=linux GOARCH=amd64 - make archive GOOS=freebsd GOARCH=amd64 - make archive GOOS=darwin GOARCH=amd64 + make archive VERSION=${{ github.ref }} GOOS=linux GOARCH=amd64 + make archive VERSION=${{ github.ref }} GOOS=freebsd GOARCH=amd64 + make archive VERSION=${{ github.ref }} GOOS=darwin GOARCH=amd64 - name: Setup variables id: vars run: echo "::set-output name=githash::$(git rev-parse --short HEAD)" From 72d3181f19d665d78af438e3989ae54f49ccf19f Mon Sep 17 00:00:00 2001 From: "Brian W. Wolter" Date: Fri, 26 May 2023 18:47:23 -0400 Subject: [PATCH 21/27] ... --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 20be3f3..e20fd2a 100644 --- a/Makefile +++ b/Makefile @@ -49,7 +49,8 @@ $(RELEASE_PACKAGE): $(RELEASE_BINARY) archive: $(RELEASE_PACKAGE) install: build ## Build and install - install -m 0755 $(PRODUCT) $(PREFIX)/bin/ + @echo "Using sudo to install; you may be prompted for a password..." + sudo install -m 0755 $(PRODUCT) $(PREFIX)/bin/ test: ## Run tests go test $(MAIN)/... From f90c26fa5649d3d00dd9331da43e1b0ad35c3b11 Mon Sep 17 00:00:00 2001 From: "Brian W. Wolter" Date: Sat, 27 May 2023 18:36:05 -0400 Subject: [PATCH 22/27] Add packaging for Arm64 via matrices --- .github/workflows/release.yml | 73 ++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index acb8819..9f972d4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,20 +6,12 @@ on: - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 jobs: - build: + release: name: Create Release runs-on: ubuntu-latest + outputs: + artifact_upload_url: ${{ steps.create_release.outputs.upload_url }} steps: - - name: Checkout repository - uses: actions/checkout@v2 - - name: Build - run: | - make archive VERSION=${{ github.ref }} GOOS=linux GOARCH=amd64 - make archive VERSION=${{ github.ref }} GOOS=freebsd GOARCH=amd64 - make archive VERSION=${{ github.ref }} GOOS=darwin GOARCH=amd64 - - name: Setup variables - id: vars - run: echo "::set-output name=githash::$(git rev-parse --short HEAD)" - name: Create release id: create_release uses: actions/create-release@v1 @@ -27,36 +19,45 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: tag_name: ${{ github.ref }} - release_name: Release ${{ github.ref }} - draft: false + release_name: ${{ github.ref }} + draft: true prerelease: false - - name: Upload artifact - id: upload_artifact_linux_amd64 - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./target/linux_amd64/forego-${{ steps.vars.outputs.githash }}-linux-amd64.tgz - asset_name: forego-${{ steps.vars.outputs.githash }}-linux-amd64.tgz - asset_content_type: application/x-tgz - - name: Upload artifact - id: upload_artifact_freebsd_amd64 - uses: actions/upload-release-asset@v1 + + artifacts: + needs: [ release ] + name: Build Artifacts + strategy: + matrix: + include: + - target: linux + arch: amd64 + os: ubuntu-latest + - target: freebsd + arch: amd64 + os: ubuntu-latest + - target: darwin + arch: amd64 + os: macos-latest + - target: darwin + arch: arm64 + os: macos-latest + runs-on: ${{ matrix.os }} + steps: + - name: Checkout repository + uses: actions/checkout@v2 + - name: Build env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./target/freebsd_amd64/forego-${{ steps.vars.outputs.githash }}-freebsd-amd64.tgz - asset_name: forego-${{ steps.vars.outputs.githash }}-freebsd-amd64.tgz - asset_content_type: application/x-tgz + GOOS: ${{ matrix.target }} + GOARCH: ${{ matrix.arch }} + run: | + make package VERSION=${{ github.ref }} PRODUCT=forego-${GITHUB_SHA}-${{ matrix.target }}-${{ matrix.arch }} - name: Upload artifact - id: upload_artifact_darwin_amd64 + id: upload_artifact_linux_amd64 uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./target/darwin_amd64/forego-${{ steps.vars.outputs.githash }}-darwin-amd64.tgz - asset_name: forego-${{ steps.vars.outputs.githash }}-darwin-amd64.tgz + upload_url: ${{ needs.release.outputs.artifact_upload_url }} + asset_path: ./target/forego-${{ github.sha }}-${{ matrix.target }}-${{ matrix.arch }}.tgz + asset_name: forego-${{ github.sha }}-${{ matrix.target }}-${{ matrix.arch }}.tgz asset_content_type: application/x-tgz From d53d87fa7c118532e7f2a9bc75cd8f66c251aa6b Mon Sep 17 00:00:00 2001 From: "Brian W. Wolter" Date: Sat, 27 May 2023 18:38:28 -0400 Subject: [PATCH 23/27] ... --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9f972d4..8644d80 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -50,7 +50,7 @@ jobs: GOOS: ${{ matrix.target }} GOARCH: ${{ matrix.arch }} run: | - make package VERSION=${{ github.ref }} PRODUCT=forego-${GITHUB_SHA}-${{ matrix.target }}-${{ matrix.arch }} + make archive VERSION=${{ github.ref }} - name: Upload artifact id: upload_artifact_linux_amd64 uses: actions/upload-release-asset@v1 From 66eb3ccffb9c1471c21cb38395b8b912971403c2 Mon Sep 17 00:00:00 2001 From: "Brian W. Wolter" Date: Sat, 27 May 2023 18:41:15 -0400 Subject: [PATCH 24/27] ... --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8644d80..575e201 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -58,6 +58,6 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ needs.release.outputs.artifact_upload_url }} - asset_path: ./target/forego-${{ github.sha }}-${{ matrix.target }}-${{ matrix.arch }}.tgz + asset_path: ./target/${{ matrix.target }}_${{ matrix.arch }}/forego-${{ github.sha }}-${{ matrix.target }}-${{ matrix.arch }}.tgz asset_name: forego-${{ github.sha }}-${{ matrix.target }}-${{ matrix.arch }}.tgz asset_content_type: application/x-tgz From d86398e957e60b3a19e2ff0cf4306339806776be Mon Sep 17 00:00:00 2001 From: "Brian W. Wolter" Date: Sat, 27 May 2023 18:43:36 -0400 Subject: [PATCH 25/27] ... --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 575e201..c35748a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -50,7 +50,7 @@ jobs: GOOS: ${{ matrix.target }} GOARCH: ${{ matrix.arch }} run: | - make archive VERSION=${{ github.ref }} + make archive GITHASH=${{ github.ref }} - name: Upload artifact id: upload_artifact_linux_amd64 uses: actions/upload-release-asset@v1 From c392427c1f91339f655043d98fdf98e0db8f4aa0 Mon Sep 17 00:00:00 2001 From: "Brian W. Wolter" Date: Sat, 27 May 2023 18:45:53 -0400 Subject: [PATCH 26/27] ... --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c35748a..52b4911 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -50,7 +50,7 @@ jobs: GOOS: ${{ matrix.target }} GOARCH: ${{ matrix.arch }} run: | - make archive GITHASH=${{ github.ref }} + make archive GITHASH=${{ github.sha }} - name: Upload artifact id: upload_artifact_linux_amd64 uses: actions/upload-release-asset@v1 From 24f5ba8267df62158e3cc8dfc7c95ca10b3e137e Mon Sep 17 00:00:00 2001 From: "Brian W. Wolter" Date: Sat, 27 May 2023 18:55:18 -0400 Subject: [PATCH 27/27] Package with ref name in path --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 52b4911..ffa23fe 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -59,5 +59,5 @@ jobs: with: upload_url: ${{ needs.release.outputs.artifact_upload_url }} asset_path: ./target/${{ matrix.target }}_${{ matrix.arch }}/forego-${{ github.sha }}-${{ matrix.target }}-${{ matrix.arch }}.tgz - asset_name: forego-${{ github.sha }}-${{ matrix.target }}-${{ matrix.arch }}.tgz + asset_name: forego-${{ github.ref_name }}-${{ matrix.target }}-${{ matrix.arch }}.tgz asset_content_type: application/x-tgz