-
Notifications
You must be signed in to change notification settings - Fork 69
Show current worker goroutine status below progress bar #338
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
27 commits
Select commit
Hold shift + click to select a range
8589aed
First try to add progress with status bars
mrnugget 1196b37
Refactoring and renaming
mrnugget 7e01f56
Tiny step and refactoring
mrnugget d53fbae
Get ProgressWithStatusBars working
mrnugget bbbff3d
Change API of progressWithStatusbars
mrnugget d863ac4
Refactor StatusBar printing
mrnugget 488f932
Embed ProgressTTY in ProgressWithStatusBarsTTY
mrnugget a88257b
More merging of progressTTY and progressWithStatusbarsTTY
mrnugget 44d8678
Add simple progress with status bars
mrnugget b9062e8
Move demo of progress with bars to _examples
mrnugget 8b73335
Restore overwritten methods
mrnugget 58ee488
Restore more overwritten methods
mrnugget f2dd25b
Restore another overwritten method
mrnugget e2b03e8
WIP: Wire up status bars with executor
mrnugget 5ef4682
Print status bars below progress bar and add ASCII box characters
mrnugget fb40ebd
WIP1: Introduce campaign progress printer
mrnugget e924abd
WIP2: More refactoring of campaign status printing
mrnugget e40066d
More cleanup and refactoring
mrnugget 1d74968
Change styling of progress bar with status
mrnugget ecdeded
Add time to StatusBar and display right-aligned
mrnugget 644f6d2
Use a const
mrnugget 5dacfdd
Add CHANGELOG entry
mrnugget fbd4e63
Ignore invisible characters for text length in progress bar
mrnugget c3aec3f
Update CHANGELOG.md
mrnugget 0f78474
Erase previous content with spaces on blank line
mrnugget 90a7c3e
Thin box drawing lines
mrnugget 7240453
Improve non-TTY output for progress indicators with status bars.
LawnGnome 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
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
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,188 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "strings" | ||
|
|
||
| "github.com/sourcegraph/go-diff/diff" | ||
| "github.com/sourcegraph/src-cli/internal/campaigns" | ||
| "github.com/sourcegraph/src-cli/internal/output" | ||
| ) | ||
|
|
||
| func newCampaignProgressPrinter(out *output.Output, numParallelism int) *campaignProgressPrinter { | ||
| return &campaignProgressPrinter{ | ||
| out: out, | ||
|
|
||
| numParallelism: numParallelism, | ||
|
|
||
| completedTasks: map[string]bool{}, | ||
| runningTasks: map[string]*campaigns.TaskStatus{}, | ||
|
|
||
| repoStatusBar: map[string]int{}, | ||
| statusBarRepo: map[int]string{}, | ||
| } | ||
| } | ||
|
|
||
| type campaignProgressPrinter struct { | ||
| out *output.Output | ||
| progress output.ProgressWithStatusBars | ||
|
|
||
| maxRepoName int | ||
| numParallelism int | ||
|
|
||
| completedTasks map[string]bool | ||
| runningTasks map[string]*campaigns.TaskStatus | ||
|
|
||
| repoStatusBar map[string]int | ||
| statusBarRepo map[int]string | ||
| } | ||
|
|
||
| func (p *campaignProgressPrinter) initProgressBar(statuses []*campaigns.TaskStatus) { | ||
| statusBars := []*output.StatusBar{} | ||
| for i := 0; i < p.numParallelism; i++ { | ||
| statusBars = append(statusBars, output.NewStatusBarWithLabel("Starting worker...")) | ||
| } | ||
|
|
||
| p.progress = p.out.ProgressWithStatusBars([]output.ProgressBar{{ | ||
| Label: fmt.Sprintf("Executing steps in %d repositories", len(statuses)), | ||
| Max: float64(len(statuses)), | ||
| }}, statusBars, nil) | ||
| } | ||
|
|
||
| func (p *campaignProgressPrinter) Complete() { | ||
| if p.progress != nil { | ||
| p.progress.Complete() | ||
| } | ||
| } | ||
|
|
||
| func (p *campaignProgressPrinter) PrintStatuses(statuses []*campaigns.TaskStatus) { | ||
| if p.progress == nil { | ||
| p.initProgressBar(statuses) | ||
| } | ||
|
|
||
| newlyCompleted := []*campaigns.TaskStatus{} | ||
| currentlyRunning := []*campaigns.TaskStatus{} | ||
|
|
||
| for _, ts := range statuses { | ||
| if len(ts.RepoName) > p.maxRepoName { | ||
| p.maxRepoName = len(ts.RepoName) | ||
| } | ||
|
|
||
| if ts.IsCompleted() { | ||
| if !p.completedTasks[ts.RepoName] { | ||
| p.completedTasks[ts.RepoName] = true | ||
| newlyCompleted = append(newlyCompleted, ts) | ||
| } | ||
|
|
||
| if _, ok := p.runningTasks[ts.RepoName]; ok { | ||
| delete(p.runningTasks, ts.RepoName) | ||
|
|
||
| // Free slot | ||
| idx := p.repoStatusBar[ts.RepoName] | ||
| delete(p.statusBarRepo, idx) | ||
| } | ||
| } | ||
|
|
||
| if ts.IsRunning() { | ||
| currentlyRunning = append(currentlyRunning, ts) | ||
| } | ||
|
|
||
| } | ||
|
|
||
| p.progress.SetValue(0, float64(len(p.completedTasks))) | ||
|
|
||
| newlyStarted := map[string]*campaigns.TaskStatus{} | ||
| statusBarIndex := 0 | ||
| for _, ts := range currentlyRunning { | ||
| if _, ok := p.runningTasks[ts.RepoName]; ok { | ||
| continue | ||
| } | ||
|
|
||
| newlyStarted[ts.RepoName] = ts | ||
| p.runningTasks[ts.RepoName] = ts | ||
|
|
||
| // Find free slot | ||
| _, ok := p.statusBarRepo[statusBarIndex] | ||
| for ok { | ||
| statusBarIndex += 1 | ||
| _, ok = p.statusBarRepo[statusBarIndex] | ||
| } | ||
|
|
||
| p.statusBarRepo[statusBarIndex] = ts.RepoName | ||
| p.repoStatusBar[ts.RepoName] = statusBarIndex | ||
| } | ||
|
|
||
| for _, ts := range newlyCompleted { | ||
| statusText, err := taskStatusText(ts) | ||
| if err != nil { | ||
| p.progress.Verbosef("%-*s failed to display status: %s", p.maxRepoName, ts.RepoName, err) | ||
| continue | ||
| } | ||
|
|
||
| p.progress.Verbosef("%-*s %s", p.maxRepoName, ts.RepoName, statusText) | ||
|
|
||
| if idx, ok := p.repoStatusBar[ts.RepoName]; ok { | ||
| // Log that this task completed, but only if there is no | ||
| // currently executing one in this bar, to avoid flicker. | ||
| if _, ok := p.statusBarRepo[idx]; !ok { | ||
| p.progress.StatusBarCompletef(idx, statusText) | ||
| } | ||
| delete(p.repoStatusBar, ts.RepoName) | ||
| } | ||
| } | ||
|
|
||
| for statusBar, repo := range p.statusBarRepo { | ||
| ts, ok := p.runningTasks[repo] | ||
| if !ok { | ||
| // This should not happen | ||
| continue | ||
| } | ||
|
|
||
| statusText, err := taskStatusText(ts) | ||
| if err != nil { | ||
| p.progress.Verbosef("%-*s failed to display status: %s", p.maxRepoName, ts.RepoName, err) | ||
| continue | ||
| } | ||
|
|
||
| if _, ok := newlyStarted[repo]; ok { | ||
| p.progress.StatusBarResetf(statusBar, ts.RepoName, statusText) | ||
| } else { | ||
| p.progress.StatusBarUpdatef(statusBar, statusText) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| func taskStatusText(ts *campaigns.TaskStatus) (string, error) { | ||
| var statusText string | ||
|
|
||
| if ts.IsCompleted() { | ||
| if ts.ChangesetSpec == nil { | ||
| statusText = "No changes" | ||
| } else { | ||
| fileDiffs, err := diff.ParseMultiFileDiff([]byte(ts.ChangesetSpec.Commits[0].Diff)) | ||
| if err != nil { | ||
| return "", err | ||
| } | ||
|
|
||
| statusText = diffStatDescription(fileDiffs) + " " + diffStatDiagram(sumDiffStats(fileDiffs)) | ||
| } | ||
|
|
||
| if ts.Cached { | ||
| statusText += " (cached)" | ||
| } | ||
| } else if ts.IsRunning() { | ||
| if ts.CurrentlyExecuting != "" { | ||
| lines := strings.Split(ts.CurrentlyExecuting, "\n") | ||
| escapedLine := strings.ReplaceAll(lines[0], "%", "%%") | ||
| if len(lines) > 1 { | ||
| statusText = fmt.Sprintf("%s ...", escapedLine) | ||
| } else { | ||
| statusText = fmt.Sprintf("%s", escapedLine) | ||
| } | ||
| } else { | ||
| statusText = fmt.Sprintf("...") | ||
| } | ||
| } | ||
|
|
||
| return statusText, nil | ||
| } |
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
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
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.
is this todo comment related to the newly added line? If not, I'd add a newline here to avoid confusion
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.
I'll let @LawnGnome decide. He added the TODO and I wasn't sure whether he had something else in mind, like
or something like that.
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.
That was my intention, but I think it's unnecessary now with the work that you've done since I wrote that, so we could remove the TODO.