-
Notifications
You must be signed in to change notification settings - Fork 531
capture go build / go mod tidy output to outputcapture #2540
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,8 +3,7 @@ version: 2 | |
| linters: | ||
| disable: | ||
| - unused | ||
| - unusedfunc | ||
| - unusedparams | ||
|
|
||
| issues: | ||
| exclude-rules: | ||
| - linters: | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,18 +30,42 @@ const MinSupportedGoMinorVersion = 22 | |
| const TsunamiUIImportPath = "github.com/wavetermdev/waveterm/tsunami/ui" | ||
|
|
||
| type OutputCapture struct { | ||
| lock sync.Mutex | ||
| lines []string | ||
| lock sync.Mutex | ||
| lines []string | ||
| lineWriter *util.LineWriter | ||
| } | ||
|
|
||
| func MakeOutputCapture() *OutputCapture { | ||
| return &OutputCapture{ | ||
| oc := &OutputCapture{ | ||
| lines: make([]string, 0), | ||
| } | ||
| oc.lineWriter = util.NewLineWriter(func(line []byte) { | ||
| // synchronized via the Write/Flush functions | ||
| oc.lines = append(oc.lines, string(line)) | ||
| }) | ||
| return oc | ||
| } | ||
|
|
||
| func (oc *OutputCapture) Printf(format string, args ...interface{}) { | ||
| func (oc *OutputCapture) Write(p []byte) (n int, err error) { | ||
| if oc == nil { | ||
| return os.Stdout.Write(p) | ||
| } | ||
| oc.lock.Lock() | ||
| defer oc.lock.Unlock() | ||
| return oc.lineWriter.Write(p) | ||
| } | ||
|
|
||
| func (oc *OutputCapture) Flush() { | ||
| if oc == nil || oc.lineWriter == nil { | ||
| return | ||
| } | ||
| oc.lock.Lock() | ||
| defer oc.lock.Unlock() | ||
| oc.lineWriter.Flush() | ||
| } | ||
|
|
||
| func (oc *OutputCapture) Printf(format string, args ...interface{}) { | ||
| if oc == nil || oc.lineWriter == nil { | ||
| log.Printf(format, args...) | ||
| return | ||
| } | ||
|
|
@@ -319,15 +343,16 @@ func createGoMod(tempDir, appName, goVersion string, opts BuildOpts, verbose boo | |
| tidyCmd := exec.Command("go", "mod", "tidy") | ||
| tidyCmd.Dir = tempDir | ||
|
|
||
| if verbose { | ||
| if oc != nil || verbose { | ||
| oc.Printf("Running go mod tidy") | ||
| tidyCmd.Stdout = os.Stdout | ||
| tidyCmd.Stderr = os.Stderr | ||
| tidyCmd.Stdout = oc | ||
| tidyCmd.Stderr = oc | ||
| } | ||
|
|
||
| if err := tidyCmd.Run(); err != nil { | ||
| return fmt.Errorf("failed to run go mod tidy: %w", err) | ||
| } | ||
| oc.Flush() | ||
|
|
||
| if verbose { | ||
| oc.Printf("Successfully ran go mod tidy") | ||
|
|
@@ -651,15 +676,16 @@ func runGoBuild(tempDir string, opts BuildOpts) error { | |
| buildCmd := exec.Command("go", args...) | ||
| buildCmd.Dir = tempDir | ||
|
|
||
| if opts.Verbose { | ||
| if oc != nil || opts.Verbose { | ||
| oc.Printf("Running: %s", strings.Join(buildCmd.Args, " ")) | ||
| buildCmd.Stdout = os.Stdout | ||
| buildCmd.Stderr = os.Stderr | ||
| buildCmd.Stdout = oc | ||
| buildCmd.Stderr = oc | ||
| } | ||
|
|
||
| if err := buildCmd.Run(); err != nil { | ||
| return fmt.Errorf("failed to build application: %w", err) | ||
| } | ||
| oc.Flush() | ||
|
Comment on lines
+679
to
+688
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical: Incorrect logic causes panic when Same issue as in Apply this fix: - if oc != nil || opts.Verbose {
+ if oc != nil {
oc.Printf("Running: %s", strings.Join(buildCmd.Args, " "))
buildCmd.Stdout = oc
buildCmd.Stderr = oc
+ } else if opts.Verbose {
+ buildCmd.Stdout = os.Stdout
+ buildCmd.Stderr = os.Stderr
}
if err := buildCmd.Run(); err != nil {
return fmt.Errorf("failed to build application: %w", err)
}
- oc.Flush()
+ if oc != nil {
+ oc.Flush()
+ }🤖 Prompt for AI Agents |
||
|
|
||
| if opts.Verbose { | ||
| if opts.OutputFile != "" { | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| // Copyright 2025, Command Line Inc. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| package util | ||
|
|
||
| import ( | ||
| "bytes" | ||
| "context" | ||
| "io" | ||
| "time" | ||
| ) | ||
|
|
||
| type LineOutput struct { | ||
| Line string | ||
| Error error | ||
| } | ||
|
|
||
| type lineBuf struct { | ||
| buf []byte | ||
| inLongLine bool | ||
| } | ||
|
|
||
| const maxLineLength = 128 * 1024 | ||
|
|
||
| func ReadLineWithTimeout(ch chan LineOutput, timeout time.Duration) (string, error) { | ||
| select { | ||
| case output := <-ch: | ||
| if output.Error != nil { | ||
| return "", output.Error | ||
| } | ||
| return output.Line, nil | ||
| case <-time.After(timeout): | ||
| return "", context.DeadlineExceeded | ||
| } | ||
| } | ||
|
|
||
| func streamToLines_processBuf(lineBuf *lineBuf, readBuf []byte, lineFn func([]byte)) { | ||
| for len(readBuf) > 0 { | ||
| nlIdx := bytes.IndexByte(readBuf, '\n') | ||
| if nlIdx == -1 { | ||
| if lineBuf.inLongLine || len(lineBuf.buf)+len(readBuf) > maxLineLength { | ||
| lineBuf.buf = nil | ||
| lineBuf.inLongLine = true | ||
| return | ||
| } | ||
| lineBuf.buf = append(lineBuf.buf, readBuf...) | ||
| return | ||
| } | ||
| if !lineBuf.inLongLine && len(lineBuf.buf)+nlIdx <= maxLineLength { | ||
| line := append(lineBuf.buf, readBuf[:nlIdx]...) | ||
| lineFn(line) | ||
| } | ||
| lineBuf.buf = nil | ||
| lineBuf.inLongLine = false | ||
| readBuf = readBuf[nlIdx+1:] | ||
| } | ||
| } | ||
|
|
||
| func StreamToLines(input io.Reader, lineFn func([]byte)) error { | ||
| var lineBuf lineBuf | ||
| readBuf := make([]byte, 64*1024) | ||
| for { | ||
| n, err := input.Read(readBuf) | ||
| streamToLines_processBuf(&lineBuf, readBuf[:n], lineFn) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // starts a goroutine to drive the channel | ||
| // line output does not include the trailing newline | ||
| func StreamToLinesChan(input io.Reader) chan LineOutput { | ||
| ch := make(chan LineOutput) | ||
| go func() { | ||
| defer close(ch) | ||
| err := StreamToLines(input, func(line []byte) { | ||
| ch <- LineOutput{Line: string(line)} | ||
| }) | ||
| if err != nil && err != io.EOF { | ||
| ch <- LineOutput{Error: err} | ||
| } | ||
| }() | ||
| return ch | ||
| } | ||
|
|
||
| // LineWriter is an io.Writer that processes data line-by-line via a callback. | ||
| // Lines do not include the trailing newline. Lines longer than maxLineLength are dropped. | ||
| type LineWriter struct { | ||
| lineBuf lineBuf | ||
| lineFn func([]byte) | ||
| } | ||
|
|
||
| // NewLineWriter creates a new LineWriter with the given callback function. | ||
| func NewLineWriter(lineFn func([]byte)) *LineWriter { | ||
| return &LineWriter{ | ||
| lineFn: lineFn, | ||
| } | ||
| } | ||
|
|
||
| // Write implements io.Writer, processing the data and calling the callback for each complete line. | ||
| func (lw *LineWriter) Write(p []byte) (n int, err error) { | ||
| streamToLines_processBuf(&lw.lineBuf, p, lw.lineFn) | ||
| return len(p), nil | ||
| } | ||
|
|
||
| // Flush outputs any remaining buffered data as a final line. | ||
| // Should be called when the input stream is complete (e.g., at EOF). | ||
| func (lw *LineWriter) Flush() { | ||
| if len(lw.lineBuf.buf) > 0 && !lw.lineBuf.inLongLine { | ||
| lw.lineFn(lw.lineBuf.buf) | ||
| lw.lineBuf.buf = nil | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guard utilfn.LineWriter with a mutex.
This copy of
LineWriteris hit by the same concurrentStdout/Stderrwrites. Without locking, sharedlineBufis racy and corrupts captured lines. Please add the same synchronization as suggested in the util package version so both stay in sync.Apply the identical mutex changes shown on the util version (import
sync, add a mutex field, and lock inWrite/Flush).🤖 Prompt for AI Agents