Skip to content

Commit 5abb51e

Browse files
author
Federico Fissore
committed
External processes output is printed on stdout/stderr in a synchronized way.
Thus we are sure that those outputs do not interfere with our own output, otherwise leading to wrongly formatted log messages. Fixes arduino#17 Signed-off-by: Federico Fissore <f.fissore@arduino.cc>
1 parent 1887d56 commit 5abb51e

File tree

5 files changed

+84
-20
lines changed

5 files changed

+84
-20
lines changed

src/arduino.cc/builder/builder_utils/utils.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ import (
3333
"arduino.cc/builder/constants"
3434
"arduino.cc/builder/i18n"
3535
"arduino.cc/builder/props"
36+
"arduino.cc/builder/types"
3637
"arduino.cc/builder/utils"
3738
"bytes"
38-
"fmt"
3939
"os"
4040
"os/exec"
4141
"path/filepath"
@@ -319,10 +319,18 @@ func ExecRecipe(properties map[string]string, recipe string, removeUnsetProperti
319319
}
320320

321321
if echoOutput {
322-
command.Stdout = os.Stdout
322+
printToStdOut := func(s string) {
323+
logger.UnformattedFprintln(os.Stdout, s)
324+
}
325+
stdout := &types.BufferedUntilNewLineWriter{PrintFunc: printToStdOut, Buffer: bytes.Buffer{}}
326+
command.Stdout = stdout
323327
}
324328

325-
command.Stderr = os.Stderr
329+
printToStdErr := func(s string) {
330+
logger.UnformattedFprintln(os.Stderr, s)
331+
}
332+
stderr := &types.BufferedUntilNewLineWriter{PrintFunc: printToStdErr, Buffer: bytes.Buffer{}}
333+
command.Stderr = stderr
326334

327335
if echoOutput {
328336
err := command.Run()
@@ -354,7 +362,7 @@ func PrepareCommandForRecipe(properties map[string]string, recipe string, remove
354362
}
355363

356364
if echoCommandLine {
357-
fmt.Println(commandLine)
365+
logger.UnformattedFprintln(os.Stdout, commandLine)
358366
}
359367

360368
return command, nil

src/arduino.cc/builder/coan_runner.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import (
3434
"arduino.cc/builder/i18n"
3535
"arduino.cc/builder/props"
3636
"arduino.cc/builder/utils"
37-
"fmt"
37+
"os"
3838
"path/filepath"
3939
"regexp"
4040
)
@@ -74,7 +74,7 @@ func (s *CoanRunner) Run(context map[string]interface{}) error {
7474
command, err := utils.PrepareCommandFilteredArgs(commandLine, filterAllowedArg, logger)
7575

7676
if verbose {
77-
fmt.Println(commandLine)
77+
logger.UnformattedFprintln(os.Stdout, commandLine)
7878
}
7979

8080
sourceBytes, _ := command.Output()

src/arduino.cc/builder/ctags_runner.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import (
3434
"arduino.cc/builder/i18n"
3535
"arduino.cc/builder/props"
3636
"arduino.cc/builder/utils"
37-
"fmt"
37+
"os"
3838
)
3939

4040
type CTagsRunner struct{}
@@ -60,7 +60,7 @@ func (s *CTagsRunner) Run(context map[string]interface{}) error {
6060

6161
verbose := context[constants.CTX_VERBOSE].(bool)
6262
if verbose {
63-
fmt.Println(commandLine)
63+
logger.UnformattedFprintln(os.Stdout, commandLine)
6464
}
6565

6666
sourceBytes, err := command.Output()

src/arduino.cc/builder/i18n/i18n.go

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,14 @@ import (
3838
"regexp"
3939
"strconv"
4040
"strings"
41+
"sync"
4142
)
4243

4344
var PLACEHOLDER = regexp.MustCompile("{(\\d)}")
4445

4546
type Logger interface {
4647
Fprintln(w io.Writer, level string, format string, a ...interface{})
48+
UnformattedFprintln(w io.Writer, s string)
4749
Println(level string, format string, a ...interface{})
4850
Name() string
4951
}
@@ -52,6 +54,8 @@ type NoopLogger struct{}
5254

5355
func (s NoopLogger) Fprintln(w io.Writer, level string, format string, a ...interface{}) {}
5456

57+
func (s NoopLogger) UnformattedFprintln(w io.Writer, str string) {}
58+
5559
func (s NoopLogger) Println(level string, format string, a ...interface{}) {}
5660

5761
func (s NoopLogger) Name() string {
@@ -61,10 +65,14 @@ func (s NoopLogger) Name() string {
6165
type HumanLogger struct{}
6266

6367
func (s HumanLogger) Fprintln(w io.Writer, level string, format string, a ...interface{}) {
64-
fmt.Fprintln(w, Format(format, a...))
68+
fprintln(w, Format(format, a...))
69+
}
70+
71+
func (s HumanLogger) UnformattedFprintln(w io.Writer, str string) {
72+
fprintln(w, str)
6573
}
6674

67-
func (s HumanLogger) Println(level string, format string, a ...interface{}) {
75+
func (s HumanLogger) Println(format string, level string, a ...interface{}) {
6876
s.Fprintln(os.Stdout, level, Format(format, a...))
6977
}
7078

@@ -74,28 +82,45 @@ func (s HumanLogger) Name() string {
7482

7583
type MachineLogger struct{}
7684

77-
func (s MachineLogger) printWithoutFormatting(w io.Writer, level string, format string, a []interface{}) {
85+
func (s MachineLogger) Fprintln(w io.Writer, level string, format string, a ...interface{}) {
86+
printMachineFormattedLogLine(w, level, format, a)
87+
}
88+
89+
func (s MachineLogger) Println(level string, format string, a ...interface{}) {
90+
printMachineFormattedLogLine(os.Stdout, level, format, a)
91+
}
92+
93+
func (s MachineLogger) UnformattedFprintln(w io.Writer, str string) {
94+
fprintln(w, str)
95+
}
96+
97+
func (s MachineLogger) Name() string {
98+
return "machine"
99+
}
100+
101+
func printMachineFormattedLogLine(w io.Writer, level string, format string, a []interface{}) {
78102
a = append([]interface{}(nil), a...)
79103
for idx, value := range a {
80104
typeof := reflect.Indirect(reflect.ValueOf(value)).Kind()
81105
if typeof == reflect.String {
82106
a[idx] = url.QueryEscape(value.(string))
83107
}
84108
}
85-
fmt.Fprintf(w, "===%s ||| %s ||| %s", level, format, a)
86-
fmt.Fprintln(w)
109+
fprintf(w, "===%s ||| %s ||| %s\n", level, format, a)
87110
}
88111

89-
func (s MachineLogger) Fprintln(w io.Writer, level string, format string, a ...interface{}) {
90-
s.printWithoutFormatting(w, level, format, a)
91-
}
112+
var lock sync.Mutex
92113

93-
func (s MachineLogger) Println(level string, format string, a ...interface{}) {
94-
s.printWithoutFormatting(os.Stdout, level, format, a)
114+
func fprintln(w io.Writer, s string) {
115+
lock.Lock()
116+
defer lock.Unlock()
117+
fmt.Fprintln(w, s)
95118
}
96119

97-
func (s MachineLogger) Name() string {
98-
return "machine"
120+
func fprintf(w io.Writer, format string, a ...interface{}) {
121+
lock.Lock()
122+
defer lock.Unlock()
123+
fmt.Fprintf(w, format, a...)
99124
}
100125

101126
func FromJavaToGoSyntax(s string) string {

src/arduino.cc/builder/types/accessories.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@
2929

3030
package types
3131

32+
import (
33+
"bytes"
34+
"sync"
35+
)
36+
3237
type UniqueStringQueue []string
3338

3439
func (queue UniqueStringQueue) Len() int { return len(queue) }
@@ -74,3 +79,29 @@ func (queue *UniqueSourceFolderQueue) Pop() interface{} {
7479
func (queue *UniqueSourceFolderQueue) Empty() bool {
7580
return queue.Len() == 0
7681
}
82+
83+
type BufferedUntilNewLineWriter struct {
84+
PrintFunc PrintFunc
85+
Buffer bytes.Buffer
86+
lock sync.Mutex
87+
}
88+
89+
type PrintFunc func(string)
90+
91+
func (w *BufferedUntilNewLineWriter) Write(p []byte) (n int, err error) {
92+
w.lock.Lock()
93+
defer w.lock.Unlock()
94+
95+
writtenToBuffer, err := w.Buffer.Write(p)
96+
if err != nil {
97+
return writtenToBuffer, err
98+
}
99+
100+
bytesUntilNewLine, err := w.Buffer.ReadBytes('\n')
101+
if err != nil && len(bytesUntilNewLine) > 0 {
102+
bytesUntilNewLine = bytesUntilNewLine[:len(bytesUntilNewLine)-1]
103+
w.PrintFunc(string(bytesUntilNewLine))
104+
}
105+
106+
return writtenToBuffer, err
107+
}

0 commit comments

Comments
 (0)