From 0c8c5ddf0a9a63e871622c5f2da388c92d392610 Mon Sep 17 00:00:00 2001 From: Sebastian Schwarz Date: Fri, 13 Apr 2018 14:45:27 +0200 Subject: [PATCH 1/8] feat: only colorize output if stdout is a terminal --- go.mod | 7 ++++++- go.sum | 8 ++++++++ outlet.go | 16 ++++++++++------ start.go | 4 ++++ 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 5838515..c9f9c87 100644 --- a/go.mod +++ b/go.mod @@ -7,4 +7,9 @@ require ( github.com/subosito/gotenv v1.6.0 ) -require golang.org/x/text v0.12.0 // indirect +require ( + golang.org/x/crypto v0.17.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/term v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect +) diff --git a/go.sum b/go.sum index 6b94b91..1736433 100644 --- a/go.sum +++ b/go.sum @@ -10,6 +10,14 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/stretchr/testify v1.7.5 h1:s5PTfem8p8EbKQOctVV53k6jCJt3UX4IEJzwh+C324Q= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/outlet.go b/outlet.go index 596b98a..f740462 100644 --- a/outlet.go +++ b/outlet.go @@ -77,17 +77,21 @@ func (of *OutletFactory) WriteLine(left, right string, leftC, rightC ct.Color, i of.Lock() defer of.Unlock() - ct.ChangeColor(leftC, true, ct.None, false) + if colorize { + 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 colorize { + if isError { + ct.ChangeColor(rightC, true, ct.None, true) + } else { + ct.ResetColor() + } } fmt.Println(right) - if isError { + if colorize && isError { ct.ResetColor() } } diff --git a/start.go b/start.go index 70b77ce..a4722d7 100644 --- a/start.go +++ b/start.go @@ -11,6 +11,8 @@ import ( "sync" "syscall" "time" + + "golang.org/x/crypto/ssh/terminal" ) const defaultPort = 5000 @@ -21,6 +23,7 @@ var flagConcurrency string var flagRestart bool var flagShutdownGraceTime int var envs envFiles +var colorize bool var cmdStart = &Command{ Run: runStart, @@ -88,6 +91,7 @@ func init() { cmdStart.Flag.IntVar(&flagShutdownGraceTime, "t", defaultShutdownGraceTime, "shutdown grace time") err := readConfigFile(".forego", &flagProcfile, &flagPort, &flagConcurrency, &flagShutdownGraceTime) handleError(err) + colorize = terminal.IsTerminal(int(os.Stdout.Fd())) } func readConfigFile(config_path string, flagProcfile *string, flagPort *int, flagConcurrency *string, flagShutdownGraceTime *int) error { From 0b2ad7e4d7961ebbba7749f9ec572b75e14db0cd Mon Sep 17 00:00:00 2001 From: Sebastian Schwarz Date: Tue, 15 May 2018 14:30:37 +0200 Subject: [PATCH 2/8] feat: use /bin/sh instead of bash There are plenty of environments without BASH, but with sh. --- unix.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/unix.go b/unix.go index 6137364..f08e6cf 100644 --- a/unix.go +++ b/unix.go @@ -1,4 +1,4 @@ -// +build darwin freebsd linux netbsd openbsd +//go:build darwin || freebsd || linux || netbsd || openbsd package main @@ -7,7 +7,7 @@ import ( "syscall" ) -var osShell string = "bash" +var osShell string = "/bin/sh" const osHaveSigTerm = true @@ -16,7 +16,7 @@ func ShellInvocationCommand(interactive bool, root, command string) []string { if interactive { shellArgument = "-ic" } - shellCommand := fmt.Sprintf("cd \"%s\"; source .profile 2>/dev/null; exec %s", root, command) + shellCommand := fmt.Sprintf("cd \"%s\"; . ./.profile 2>/dev/null; exec %s", root, command) return []string{osShell, shellArgument, shellCommand} } From 51adabfe863ab733a3200c20b7093aeda4bdeb5d Mon Sep 17 00:00:00 2001 From: Sebastian Schwarz Date: Tue, 15 May 2018 14:43:59 +0200 Subject: [PATCH 3/8] feat: safeguard against shell characters in directory These could have caused problems: $!"\ --- unix.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unix.go b/unix.go index f08e6cf..3840411 100644 --- a/unix.go +++ b/unix.go @@ -16,8 +16,8 @@ func ShellInvocationCommand(interactive bool, root, command string) []string { if interactive { shellArgument = "-ic" } - shellCommand := fmt.Sprintf("cd \"%s\"; . ./.profile 2>/dev/null; exec %s", root, command) - return []string{osShell, shellArgument, shellCommand} + shellCommand := fmt.Sprintf("cd \"$1\"; . ./.profile 2>/dev/null; exec %s", command) + return []string{osShell, shellArgument, shellCommand, "sh", root} } func (p *Process) PlatformSpecificInit() { From 665c76ac61a7fb37df319d614c4fa3c42a326e27 Mon Sep 17 00:00:00 2001 From: Sebastian Schwarz Date: Tue, 15 May 2018 14:43:59 +0200 Subject: [PATCH 4/8] feat: improve error handling. - exit if directory doesn't exist - source .profile only if it exists - don't suppress stderr while doing that --- unix.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unix.go b/unix.go index 3840411..865c374 100644 --- a/unix.go +++ b/unix.go @@ -16,7 +16,7 @@ func ShellInvocationCommand(interactive bool, root, command string) []string { if interactive { shellArgument = "-ic" } - shellCommand := fmt.Sprintf("cd \"$1\"; . ./.profile 2>/dev/null; exec %s", command) + shellCommand := fmt.Sprintf("cd \"$1\" || exit 66; test -e .profile && . ./.profile; exec %s", command) return []string{osShell, shellArgument, shellCommand, "sh", root} } From b211c27f461a87859e1da6bba624b7643315e954 Mon Sep 17 00:00:00 2001 From: iain barnett Date: Sat, 21 Sep 2019 15:20:30 +0900 Subject: [PATCH 5/8] fix: the -f operator is a bit more specific. --- unix.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unix.go b/unix.go index 865c374..e6da367 100644 --- a/unix.go +++ b/unix.go @@ -16,7 +16,7 @@ func ShellInvocationCommand(interactive bool, root, command string) []string { if interactive { shellArgument = "-ic" } - shellCommand := fmt.Sprintf("cd \"$1\" || exit 66; test -e .profile && . ./.profile; exec %s", command) + shellCommand := fmt.Sprintf("cd \"$1\" || exit 66; test -f .profile && . ./.profile; exec %s", command) return []string{osShell, shellArgument, shellCommand, "sh", root} } From b412cee0927d51c795f0bab5b75af7fc480b6b8a Mon Sep 17 00:00:00 2001 From: Sehrope Sarkuni Date: Sun, 12 Apr 2020 09:32:04 -0400 Subject: [PATCH 6/8] feat: disable colored output if NO_COLOR is defined --- start.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/start.go b/start.go index a4722d7..4537d29 100644 --- a/start.go +++ b/start.go @@ -91,7 +91,7 @@ func init() { cmdStart.Flag.IntVar(&flagShutdownGraceTime, "t", defaultShutdownGraceTime, "shutdown grace time") err := readConfigFile(".forego", &flagProcfile, &flagPort, &flagConcurrency, &flagShutdownGraceTime) handleError(err) - colorize = terminal.IsTerminal(int(os.Stdout.Fd())) + colorize = os.Getenv("NO_COLOR") == "" && terminal.IsTerminal(int(os.Stdout.Fd())) } func readConfigFile(config_path string, flagProcfile *string, flagPort *int, flagConcurrency *string, flagShutdownGraceTime *int) error { From ae5cca35db15519917a6b4237754c04dcba38fbe Mon Sep 17 00:00:00 2001 From: Sehrope Sarkuni Date: Sun, 12 Apr 2020 10:05:15 -0400 Subject: [PATCH 7/8] refactor: create outlet formatter once rather than for each line The output padding is based upon the longest name of processes and thus never changes at runtime so we can optimize things a bit by only creating the output formatter pattern once at startup. --- outlet.go | 5 ++--- start.go | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/outlet.go b/outlet.go index f740462..4f699ed 100644 --- a/outlet.go +++ b/outlet.go @@ -12,7 +12,7 @@ import ( ) type OutletFactory struct { - Padding int + LeftFormatter string sync.Mutex } @@ -80,8 +80,7 @@ func (of *OutletFactory) WriteLine(left, right string, leftC, rightC ct.Color, i if colorize { ct.ChangeColor(leftC, true, ct.None, false) } - formatter := fmt.Sprintf("%%-%ds | ", of.Padding) - fmt.Printf(formatter, left) + fmt.Printf(of.LeftFormatter, left) if colorize { if isError { diff --git a/start.go b/start.go index 4537d29..d13af82 100644 --- a/start.go +++ b/start.go @@ -281,7 +281,7 @@ func runStart(cmd *Command, args []string) { handleError(err) of := NewOutletFactory() - of.Padding = pf.LongestProcessName(concurrency) + of.LeftFormatter = fmt.Sprintf("%%-%ds | ", pf.LongestProcessName(concurrency)) f := &Forego{ outletFactory: of, From b69ab4c10f9cc4635c001c0aed2ab79faf3b02d7 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sat, 23 Dec 2023 23:20:12 +0100 Subject: [PATCH 8/8] build: inject version into forego binary mirroring what's being done with docker-gen --- .github/workflows/build-publish.yml | 1 + Dockerfile.alpine | 9 +++++++-- Dockerfile.debian | 9 +++++++-- Makefile | 5 ++++- 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-publish.yml b/.github/workflows/build-publish.yml index 5778257..607cbcc 100644 --- a/.github/workflows/build-publish.yml +++ b/.github/workflows/build-publish.yml @@ -70,6 +70,7 @@ jobs: uses: docker/build-push-action@v5 with: context: . + build-args: FOREGO_VERSION=${{ steps.forego_version.outputs.VERSION }} platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x file: Dockerfile.${{ matrix.base }} sbom: true diff --git a/Dockerfile.alpine b/Dockerfile.alpine index e3ec1e3..3ff5ca4 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,9 +1,11 @@ +ARG FOREGO_VERSION=main + # Build forego FROM --platform=$BUILDPLATFORM golang:1.21.5-alpine as go-builder ENV CGO_ENABLED=0 -ARG TARGETOS TARGETARCH TARGETVARIANT +ARG FOREGO_VERSION TARGETOS TARGETARCH TARGETVARIANT ENV GOOS=$TARGETOS GOARCH=$TARGETARCH VARIANT=$TARGETVARIANT RUN apk add --no-cache musl-dev @@ -21,11 +23,14 @@ RUN set -eu; \ *) [ -z "$VARIANT" ] ;; \ esac; \ go env | grep -E 'OS=|ARCH=|ARM=|AMD64='; \ - go build -o forego .; \ + go build -ldflags "-X main.buildVersion=${FOREGO_VERSION}" -o forego .; \ go clean -cache FROM --platform=$TARGETPLATFORM alpine:3.19.0 +ARG FOREGO_VERSION +ENV FOREGO_VERSION=${FOREGO_VERSION} + RUN apk add --no-cache bash # Install Forego diff --git a/Dockerfile.debian b/Dockerfile.debian index 3c65e33..72eb099 100644 --- a/Dockerfile.debian +++ b/Dockerfile.debian @@ -1,9 +1,11 @@ +ARG FOREGO_VERSION=main + # Build forego FROM --platform=$BUILDPLATFORM golang:1.21.5 as go-builder ENV CGO_ENABLED=0 -ARG TARGETOS TARGETARCH TARGETVARIANT +ARG FOREGO_VERSION TARGETOS TARGETARCH TARGETVARIANT ENV GOOS=$TARGETOS GOARCH=$TARGETARCH VARIANT=$TARGETVARIANT WORKDIR /build @@ -19,11 +21,14 @@ RUN set -eu; \ *) [ -z "$VARIANT" ] ;; \ esac; \ go env | grep -E 'OS=|ARCH=|ARM=|AMD64='; \ - go build -o forego .; \ + go build -ldflags "-X main.buildVersion=${FOREGO_VERSION}" -o forego .; \ go clean -cache FROM --platform=$TARGETPLATFORM debian:12.4-slim +ARG FOREGO_VERSION +ENV FOREGO_VERSION=${FOREGO_VERSION} + # Install Forego COPY --from=go-builder /build/forego /usr/local/bin/forego diff --git a/Makefile b/Makefile index 51622f2..34ad512 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,9 @@ BIN = forego SRC = $(shell find . -name '*.go') +TAG:=`git describe --tags` +LDFLAGS:=-X main.buildVersion=$(TAG) + .PHONY: all build clean lint test all: build @@ -20,4 +23,4 @@ test: lint get-deps build go test -v -race -cover ./... $(BIN): $(SRC) - go build -o $@ + go build -ldflags "$(LDFLAGS)" -o $@