Skip to content

Commit

Permalink
feat: pipe stdout and err via logger
Browse files Browse the repository at this point in the history
  • Loading branch information
Viktor Voltaire authored and viktorvoltaire committed Jan 29, 2022
1 parent 2a02125 commit 5dfd5af
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 10 deletions.
57 changes: 53 additions & 4 deletions sg/exec.go
@@ -1,26 +1,75 @@
package sg

import (
"bufio"
"bytes"
"context"
"fmt"
"io"
"log"
"os"
"os/exec"
"strings"
)

// Command should be used when returning exec.Cmd from tools to set opinionated standard fields.
func Command(_ context.Context, path string, args ...string) *exec.Cmd {
func Command(ctx context.Context, path string, args ...string) *exec.Cmd {
// TODO: use exec.CommandContext when we have determined there are no side-effects.
cmd := exec.Command(path)
cmd.Args = append(cmd.Args, args...)
cmd.Dir = FromGitRoot(".")
cmd.Env = prependPath(os.Environ(), FromBinDir())
// TODO: Pipe stdout/stderr through the current context logger to get tagged output.
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
cmd.Stderr = newLogWriter(ctx, os.Stderr)
cmd.Stdout = newLogWriter(ctx, os.Stdout)
return cmd
}

func newLogWriter(ctx context.Context, out io.Writer) *logWriter {
logger := log.New(out, Logger(ctx).Prefix(), 0)
return &logWriter{logger: logger, out: out}
}

type logWriter struct {
logger *log.Logger
out io.Writer
hasFileReferences bool
}

func (l *logWriter) Write(p []byte) (n int, err error) {
in := bufio.NewScanner(bytes.NewReader(p))
for in.Scan() {
line := in.Text()
if !l.hasFileReferences {
l.hasFileReferences = hasFileReferences(line)
}
if l.hasFileReferences {
// Don't prefix output from processes that print file references (e.g. lint errors).
// Instead prefix on the line above, these lines can be multiline hence the conditional.
// This enables GitHub to autodetect the file references and print them in the PR review.
if hasFileReferences(line) {
_, _ = fmt.Fprintln(l.out, l.logger.Prefix(), "\n", line)
} else {
_, _ = fmt.Fprintln(l.out, line)
}
} else {
l.logger.Print(line)
}
}
if err := in.Err(); err != nil {
l.logger.Fatal(err)
}
return len(p), nil
}

func hasFileReferences(line string) bool {
if i := strings.IndexByte(line, ':'); i > 0 {
if _, err := os.Lstat(line[:i]); err == nil {
return true
}
}
return false
}

// Output runs the given command, and returns all output from stdout in a neatly, trimmed manner,
// panicking if an error occurs.
func Output(cmd *exec.Cmd) string {
Expand Down
3 changes: 1 addition & 2 deletions sg/generate.go
Expand Up @@ -102,8 +102,7 @@ func genMakefiles(ctx context.Context, mks ...Makefile) {
mk := codegen.NewMakefile(codegen.FileConfig{
GeneratedBy: "go.einride.tech/sage",
})

if err := generateMakefile(mk, pkg, v, mks...); err != nil {
if err := generateMakefile(ctx, mk, pkg, v, mks...); err != nil {
panic(err)
}
// Remove trailing whitespace with len
Expand Down
4 changes: 2 additions & 2 deletions sg/logger.go
Expand Up @@ -29,8 +29,8 @@ func WithLogger(ctx context.Context, logger *log.Logger) context.Context {

// Logger returns the log.Logger attached to ctx, or a default logger.
func Logger(ctx context.Context) *log.Logger {
if logger := ctx.Value(loggerContextKey{}).(*log.Logger); logger != nil {
return logger
if value := ctx.Value(loggerContextKey{}); value != nil {
return value.(*log.Logger)
}
return NewLogger("sage")
}
3 changes: 1 addition & 2 deletions sg/makefile.go
Expand Up @@ -13,7 +13,7 @@ import (
"go.einride.tech/sage/internal/strcase"
)

func generateMakefile(g *codegen.File, pkg *doc.Package, mk Makefile, mks ...Makefile) error {
func generateMakefile(ctx context.Context, g *codegen.File, pkg *doc.Package, mk Makefile, mks ...Makefile) error {
includePath, err := filepath.Rel(filepath.Dir(mk.Path), FromSageDir())
if err != nil {
return err
Expand All @@ -28,7 +28,6 @@ func generateMakefile(g *codegen.File, pkg *doc.Package, mk Makefile, mks ...Mak
if strings.TrimSpace(b.String()) == "go.einride.tech/sage" {
dependencies = fmt.Sprintf("%s/go.mod $(shell find %s/.. -type f -name '*.go')", includePath, includePath)
}

g.P("# To learn more, see ", includePath, "/sagefile.go and https://github.com/einride/sage.")
g.P()
if len(mk.defaultTargetName()) != 0 {
Expand Down

0 comments on commit 5dfd5af

Please sign in to comment.