You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by pc...@apache.org on 2022/11/02 08:29:00 UTC
[camel-k] branch main updated: feat(build): parse cmd execution for errors
This is an automated email from the ASF dual-hosted git repository.
pcongiusti pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-k.git
The following commit(s) were added to refs/heads/main by this push:
new 4e0ca2c01 feat(build): parse cmd execution for errors
4e0ca2c01 is described below
commit 4e0ca2c013174a96db8acabf2bcfb44eafed4b21
Author: Pasquale Congiusti <pa...@gmail.com>
AuthorDate: Mon Oct 31 10:43:34 2022 +0100
feat(build): parse cmd execution for errors
Closes #3779
---
pkg/util/command.go | 57 ++++++++++++++++++++++++--------------
pkg/util/command_test.go | 60 ++++++++++++++++++++++++++++++++++++++++
pkg/util/jvm/keystore.go | 4 +--
pkg/util/maven/maven_log.go | 19 +++++++++++--
pkg/util/maven/maven_log_test.go | 35 +++++++++++++++++++++++
5 files changed, 150 insertions(+), 25 deletions(-)
diff --git a/pkg/util/command.go b/pkg/util/command.go
index a3de8522d..37d3262de 100644
--- a/pkg/util/command.go
+++ b/pkg/util/command.go
@@ -21,14 +21,18 @@ import (
"bufio"
"context"
"fmt"
+ "io"
"os/exec"
+ "github.com/pkg/errors"
"golang.org/x/sync/errgroup"
)
// RunAndLog starts the provided command, scans its standard and error outputs line by line,
// to feed the provided handlers, and waits until the scans complete and the command returns.
-func RunAndLog(ctx context.Context, cmd *exec.Cmd, stdOutF func(string), stdErrF func(string)) error {
+func RunAndLog(ctx context.Context, cmd *exec.Cmd, stdOutF func(string) string, stdErrF func(string) string) error {
+ scanOutMsg := ""
+ scanErrMsg := ""
stdOutF(fmt.Sprintf("Executed command: %s", cmd.String()))
stdOut, err := cmd.StdoutPipe()
@@ -40,38 +44,51 @@ func RunAndLog(ctx context.Context, cmd *exec.Cmd, stdOutF func(string), stdErrF
return err
}
err = cmd.Start()
+ // if the command is in error, we try to figure it out why also by parsing the log
if err != nil {
- scanOut := bufio.NewScanner(stdOut)
- for scanOut.Scan() {
- stdOutF(scanOut.Text())
- }
- scanErr := bufio.NewScanner(stdErr)
- for scanErr.Scan() {
- stdOutF(scanErr.Text())
- }
- return err
+ scanOutMsg = scan(stdOut, stdOutF)
+ scanErrMsg = scan(stdErr, stdErrF)
+
+ return errors.Wrapf(err, formatErr(scanOutMsg, scanErrMsg))
}
g, _ := errgroup.WithContext(ctx)
g.Go(func() error {
- scanner := bufio.NewScanner(stdOut)
- for scanner.Scan() {
- stdOutF(scanner.Text())
- }
+ scanOutMsg = scan(stdOut, stdOutF)
return nil
})
g.Go(func() error {
- scanner := bufio.NewScanner(stdErr)
- for scanner.Scan() {
- stdErrF(scanner.Text())
- }
+ scanErrMsg = scan(stdErr, stdErrF)
return nil
})
if err = g.Wait(); err != nil {
- return err
+ return errors.Wrapf(err, formatErr(scanOutMsg, scanErrMsg))
}
if err = cmd.Wait(); err != nil {
- return err
+ return errors.Wrapf(err, formatErr(scanOutMsg, scanErrMsg))
}
return nil
}
+
+func scan(stdOut io.ReadCloser, stdOutF func(string) string) string {
+ scanError := ""
+ scanner := bufio.NewScanner(stdOut)
+ for scanner.Scan() {
+ errMsg := stdOutF(scanner.Text())
+ if errMsg != "" && scanError == "" {
+ scanError = errMsg
+ }
+ }
+
+ return scanError
+}
+
+func formatErr(stdout, stderr string) string {
+ if stderr == "" {
+ return stdout
+ }
+ if stdout == "" {
+ return stderr
+ }
+ return fmt.Sprintf("stdout: %s, stderr: %s", stdout, stderr)
+}
diff --git a/pkg/util/command_test.go b/pkg/util/command_test.go
new file mode 100644
index 000000000..0831b2286
--- /dev/null
+++ b/pkg/util/command_test.go
@@ -0,0 +1,60 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package util
+
+import (
+ "context"
+ "fmt"
+ "os/exec"
+ "strings"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+var (
+ loggerInfo = func(s string) string {
+ fmt.Println("OUT:", s)
+ if strings.Contains(s, "invalid") {
+ return s
+ }
+ return ""
+ }
+ loggerError = func(s string) string {
+ fmt.Println("ERR:", s)
+ if strings.Contains(s, "invalid") {
+ return s
+ }
+ return ""
+ }
+)
+
+func TestRunAndLog(t *testing.T) {
+ cmd := exec.CommandContext(context.Background(), "/usr/bin/date")
+ err := RunAndLog(context.Background(), cmd, loggerInfo, loggerError)
+
+ assert.Nil(t, err)
+}
+
+func TestRunAndLogInvalid(t *testing.T) {
+ cmd := exec.CommandContext(context.Background(), "/usr/bin/date", "-dsa")
+ err := RunAndLog(context.Background(), cmd, loggerInfo, loggerError)
+
+ assert.NotNil(t, err)
+ assert.Equal(t, "/usr/bin/date: invalid date ‘sa’: exit status 1", err.Error())
+}
diff --git a/pkg/util/jvm/keystore.go b/pkg/util/jvm/keystore.go
index 600a23f1a..9788fa362 100644
--- a/pkg/util/jvm/keystore.go
+++ b/pkg/util/jvm/keystore.go
@@ -33,8 +33,8 @@ import (
var (
logger = log.WithName("keytool")
- loggerInfo = func(s string) { logger.Info(s) }
- loggerError = func(s string) { logger.Error(nil, s) }
+ loggerInfo = func(s string) string { logger.Info(s); return "" }
+ loggerError = func(s string) string { logger.Error(nil, s); return "" }
)
func GenerateKeystore(ctx context.Context, keystoreDir, keystoreName, keystorePass string, data [][]byte) error {
diff --git a/pkg/util/maven/maven_log.go b/pkg/util/maven/maven_log.go
index 1c1c4ab02..21f9ec889 100644
--- a/pkg/util/maven/maven_log.go
+++ b/pkg/util/maven/maven_log.go
@@ -19,6 +19,7 @@ package maven
import (
"encoding/json"
+ "strings"
"github.com/apache/camel-k/pkg/util/log"
)
@@ -47,7 +48,7 @@ const (
var mavenLogger = log.WithName("maven.build")
-func mavenLogHandler(s string) {
+func mavenLogHandler(s string) string {
mavenLog, parseError := parseLog(s)
if parseError == nil {
normalizeLog(mavenLog)
@@ -57,6 +58,13 @@ func mavenLogHandler(s string) {
// etc). The build may still have succeeded, though.
nonNormalizedLog(s)
}
+
+ // Return the error message according to maven log
+ if strings.HasPrefix(s, "[ERROR]") {
+ return s
+ }
+
+ return ""
}
func parseLog(line string) (mavenLog, error) {
@@ -72,10 +80,15 @@ func normalizeLog(mavenLog mavenLog) {
case INFO, WARN:
mavenLogger.Info(mavenLog.Msg)
case ERROR, FATAL:
- mavenLogger.Errorf(nil, mavenLog.Msg)
+ mavenLogger.Error(nil, mavenLog.Msg)
}
}
func nonNormalizedLog(rawLog string) {
- mavenLogger.Info(rawLog)
+ // Distinguish an error message from the rest
+ if strings.HasPrefix(rawLog, "[ERROR]") {
+ mavenLogger.Error(nil, rawLog)
+ } else {
+ mavenLogger.Info(rawLog)
+ }
}
diff --git a/pkg/util/maven/maven_log_test.go b/pkg/util/maven/maven_log_test.go
new file mode 100644
index 000000000..86f27c0f3
--- /dev/null
+++ b/pkg/util/maven/maven_log_test.go
@@ -0,0 +1,35 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package maven
+
+import (
+ "context"
+ "os/exec"
+ "testing"
+
+ "github.com/apache/camel-k/pkg/util"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestRunAndLogErrorMvn(t *testing.T) {
+ cmd := exec.CommandContext(context.Background(), "/usr/bin/mvn", "package")
+ err := util.RunAndLog(context.Background(), cmd, mavenLogHandler, mavenLogHandler)
+
+ assert.NotNil(t, err)
+ assert.ErrorContains(t, err, "[ERROR] The goal you specified requires a project to execute but there is no POM in this directory")
+}