status subcommand: only draw one big progress bar of the entire replication

more details on progress per step in text form
This commit is contained in:
Christian Schwarz 2018-09-06 11:05:32 -07:00
parent 82d51cd0dc
commit c60ed78bc5

View File

@ -169,50 +169,74 @@ func (t *tui) draw() {
t.newline() t.newline()
continue continue
} }
all := make([]*fsrep.Report, 0, len(rep.Completed)+len(rep.Pending) + 1)
all = append(all, rep.Completed...)
all = append(all, rep.Pending...)
if rep.Active != nil {
all = append(all, rep.Active)
}
sort.Slice(all, func(i, j int) bool {
return all[i].Filesystem < all[j].Filesystem
})
t.printf("Status: %s", rep.Status) t.printf("Status: %s", rep.Status)
t.newline() t.newline()
if rep.Problem != "" { if rep.Problem != "" {
t.printf("Problem: %s", rep.Problem) t.printf("Problem: %s", rep.Problem)
t.newline() t.newline()
} }
{ // Progress: [---------------]
maxNameLength := calculateMaxFilesystemAndVersionNameLength(&rep) sumUpFSRep := func(rep *fsrep.Report) (transferred, total int64) {
for _, s := range rep.Pending {
for _, fs := range rep.Completed { transferred += s.Bytes
printFilesystem(fs, t, false, maxNameLength) total += s.ExpectedBytes
} }
if rep.Active != nil { for _, s := range rep.Completed {
printFilesystem(rep.Active, t, true, maxNameLength) transferred += s.Bytes
} total += s.ExpectedBytes
for _, fs := range rep.Pending { }
printFilesystem(fs, t, false, maxNameLength) return
}
var transferred, total int64
for _, fs := range all {
fstx, fstotal := sumUpFSRep(fs)
transferred += fstx
total += fstotal
}
t.write("Progress: ")
t.drawBar(80, transferred, total)
t.write(fmt.Sprintf(" %s / %s", ByteCountBinary(transferred), ByteCountBinary(total)))
t.newline()
} }
maxFS, maxStatus := calculateMaxFilesystemAndVersionNameLength(all)
for _, fs := range all {
printFilesystemStatus(fs, t, fs == rep.Active, maxFS, maxStatus)
}
} }
} }
termbox.Flush() termbox.Flush()
} }
const snapshotIndent = 1 const snapshotIndent = 1
func calculateMaxFilesystemAndVersionNameLength(report *replication.Report) int { func calculateMaxFilesystemAndVersionNameLength(all []*fsrep.Report) (maxFS, maxStatus int) {
all := append(report.Completed, report.Active)
all = append(all, report.Pending...)
maxLen := 0
for _, e := range all { for _, e := range all {
if e == nil { //active can be nil if len(e.Filesystem) > maxFS {
continue maxFS = len(e.Filesystem)
} }
if len(e.Filesystem) > maxLen { all2 := make([]*fsrep.StepReport, 0, len(e.Pending) + len(e.Completed))
maxLen = len(e.Filesystem) all2 = append(all2, e.Pending...)
} all2 = append(all2, e.Completed...)
all2 := append(e.Pending, e.Completed...)
for _, e2 := range all2 { for _, e2 := range all2 {
if len(e2.To) + snapshotIndent > maxLen { elen := len(e2.Problem) + len(e2.From) + len(e2.To) + 60 // random spacing, units, labels, etc
maxLen = len(e2.To) + snapshotIndent if elen > maxStatus {
maxStatus = elen
} }
} }
} }
return maxLen return
} }
func times(str string, n int) (out string) { func times(str string, n int) (out string) {
@ -229,13 +253,15 @@ func rightPad(str string, length int, pad string) string {
return str + times(pad, length-len(str)) return str + times(pad, length-len(str))
} }
func (t *tui) drawBar(name string, maxNameLength int, status string, bytes int64, totalBytes int64) {
t.write(rightPad(name, maxNameLength + 1, " "))
t.write(" ")
t.write(rightPad(status, 14, " "))
t.write(" ")
length := 50 func leftPad(str string, length int, pad string) string {
if len(str) > length {
return str[len(str)-length:]
}
return times(pad, length-len(str)) + str
}
func (t *tui) drawBar(length int, bytes, totalBytes int64) {
var completedLength int var completedLength int
if totalBytes > 0 { if totalBytes > 0 {
completedLength = int(int64(length) * bytes / totalBytes) completedLength = int(int64(length) * bytes / totalBytes)
@ -249,15 +275,6 @@ func (t *tui) drawBar(name string, maxNameLength int, status string, bytes int64
t.write(">") t.write(">")
t.write(times("-", length-completedLength)) t.write(times("-", length-completedLength))
t.write("]") t.write("]")
t.write(" ")
totalBytesStr := ByteCountBinary(totalBytes)
if totalBytes == 0 {
totalBytesStr = "??? B"
}
t.write(rightPad(ByteCountBinary(bytes)+"/"+totalBytesStr, 20, " "))
t.newline()
} }
func StringStepState(s fsrep.StepState) string { func StringStepState(s fsrep.StepState) string {
@ -273,9 +290,9 @@ func StringStepState(s fsrep.StepState) string {
} }
} }
func printFilesystem(rep *fsrep.Report, t *tui, versions bool, maxNameLength int) { func filesystemStatusString(rep *fsrep.Report, active bool, maxFS, maxStatus int) (totalStatus string, bytes, totalBytes int64) {
bytes := int64(0) bytes = int64(0)
totalBytes := int64(0) totalBytes = int64(0)
for _, s := range rep.Pending { for _, s := range rep.Pending {
bytes += s.Bytes bytes += s.Bytes
totalBytes += s.ExpectedBytes totalBytes += s.ExpectedBytes
@ -285,17 +302,39 @@ func printFilesystem(rep *fsrep.Report, t *tui, versions bool, maxNameLength int
totalBytes += s.ExpectedBytes totalBytes += s.ExpectedBytes
} }
t.drawBar(rep.Filesystem, maxNameLength, rep.Status, bytes, totalBytes) nextStep := ""
if rep.Problem != "" { if len(rep.Pending) > 0 {
t.addIndent(1) if rep.Pending[0].From != "" {
t.printf("Problem: %s", rep.Problem) nextStep = fmt.Sprintf("%s => %s", rep.Pending[0].From, rep.Pending[0].To)
t.newline() } else {
t.addIndent(-1) nextStep = fmt.Sprintf("%s (full)", rep.Pending[0].To)
}
} }
if versions && len(rep.Pending) > 0 { status := fmt.Sprintf("%s (step %d/%d, %s/%s)",
v := rep.Pending[0] rep.Status,
t.drawBar(times(" ", snapshotIndent) + v.To, maxNameLength, StringStepState(v.Status), v.Bytes, v.ExpectedBytes) len(rep.Completed), len(rep.Pending) + len(rep.Completed),
ByteCountBinary(bytes), ByteCountBinary(totalBytes),
)
if rep.Problem == "" && nextStep != "" {
status += fmt.Sprintf(" next: %s", nextStep)
} else if rep.Problem != "" {
status += fmt.Sprintf(" problem: %s", rep.Problem)
} }
activeIndicator := " "
if active {
activeIndicator = "*"
}
totalStatus = fmt.Sprintf("%s %s %s",
activeIndicator,
rightPad(rep.Filesystem, maxFS, " "),
rightPad(status, maxStatus, " "))
return totalStatus, bytes, totalBytes
}
func printFilesystemStatus(rep *fsrep.Report, t *tui, active bool, maxFS, maxTotal int) {
totalStatus, _, _ := filesystemStatusString(rep, active, maxFS, maxTotal)
t.write(totalStatus)
t.newline()
} }
func ByteCountBinary(b int64) string { func ByteCountBinary(b int64) string {