huge refactoring

This commit is contained in:
Julien Neuhart
2019-07-23 13:57:18 +02:00
parent f6b357691c
commit 7bfbda4490
105 changed files with 4051 additions and 2667 deletions

View File

@@ -0,0 +1,8 @@
/*
Package xexec helps creating exec.Cmd
with logging.
All functions return our standard xerror.Error
in case of error.
*/
package xexec

View File

@@ -0,0 +1,99 @@
package xexec
import (
"bufio"
"context"
"fmt"
"io"
"os/exec"
"strings"
"github.com/thecodingmachine/gotenberg/internal/pkg/xerror"
"github.com/thecodingmachine/gotenberg/internal/pkg/xlog"
)
/*
Command is a wrapper around exec.Command.
If given xlog.Logger has a xlog.DebugLevel,
also logs the output from the command.
*/
func Command(logger xlog.Logger, binary string, args ...string) (*exec.Cmd, error) {
const op string = "xexec.Command"
cmd := exec.Command(binary, args...)
if err := pipe(logger, cmd); err != nil {
return nil, xerror.New(op, err)
}
return cmd, nil
}
/*
CommandContext is a wrapper around exec.CommandContext.
If given xlog.Logger has a xlog.DebugLevel,
also logs the output from the command.
*/
func CommandContext(ctx context.Context, logger xlog.Logger, binary string, args ...string) (*exec.Cmd, error) {
const op string = "xexec.CommandContext"
cmd := exec.CommandContext(ctx, binary, args...)
if err := pipe(logger, cmd); err != nil {
return nil, xerror.New(op, err)
}
return cmd, nil
}
// LogBeforeExecute logs a command before its execution.
func LogBeforeExecute(logger xlog.Logger, cmd *exec.Cmd) {
const op string = "xexec.LogBeforeExecute"
logger.DebugfOp(op, "executing command: %s", strings.Join(cmd.Args, " "))
}
func pipe(logger xlog.Logger, cmd *exec.Cmd) error {
const op string = "xexec.pipe"
if logger.Level() != xlog.DebugLevel {
return nil
}
// if xlog.DebugLevel, log the output
// from the command.
resolver := func() error {
stdout, err := cmd.StdoutPipe()
if err != nil {
return err
}
stderr, err := cmd.StderrPipe()
if err != nil {
return err
}
go logCommandOutput(logger, stdout, "stdout", cmd)
go logCommandOutput(logger, stderr, "stderr", cmd)
return nil
}
if err := resolver(); err != nil {
return xerror.New(op, err)
}
return nil
}
func logCommandOutput(logger xlog.Logger, reader io.ReadCloser, outputType string, cmd *exec.Cmd) {
var op string
if len(cmd.Args) >= 2 {
op = fmt.Sprintf("%s.%s.%s", cmd.Args[0], cmd.Args[1], outputType)
} else {
// len(cmd.Args) should always be >= 1.
op = fmt.Sprintf("%s.%s", cmd.Args[0], outputType)
}
r := bufio.NewReader(reader)
defer reader.Close() // nolint: errcheck
for {
line, _, err := r.ReadLine()
if err != nil {
if err != io.EOF {
logger.ErrorOp(op, err)
}
break
}
if len(line) != 0 {
logger.DebugOp(op, string(line))
}
}
}

View File

@@ -0,0 +1,39 @@
package xexec
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/thecodingmachine/gotenberg/test/internalpkg/xlogtest"
)
func TestCommand(t *testing.T) {
logger := xlogtest.DebugLogger()
// should pipe command output as
// xlog.Logger has a xlog.DebugLevel.
cmd, err := Command(logger, "echo", "Hello", "World")
assert.Nil(t, err)
LogBeforeExecute(logger, cmd)
// should not pipe command output as
// xlog.Logger has a xlog.InfoLevel.
logger = xlogtest.InfoLogger()
cmd, err = Command(logger, "echo", "Hello", "World")
LogBeforeExecute(logger, cmd)
assert.Nil(t, err)
}
func TestCommandContext(t *testing.T) {
logger := xlogtest.DebugLogger()
// should pipe command output as
// xlog.Logger has a xlog.DebugLevel.
cmd, err := CommandContext(context.Background(), logger, "echo")
assert.Nil(t, err)
LogBeforeExecute(logger, cmd)
// should not pipe command output as
// xlog.Logger has a xlog.InfoLevel.
logger = xlogtest.InfoLogger()
cmd, err = CommandContext(context.Background(), logger, "echo", "Hello", "World")
LogBeforeExecute(logger, cmd)
assert.Nil(t, err)
}