mirror of
https://github.com/zrepl/zrepl.git
synced 2024-11-22 16:34:32 +01:00
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:
parent
82d51cd0dc
commit
c60ed78bc5
139
client/status.go
139
client/status.go
@ -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 {
|
return
|
||||||
printFilesystem(fs, t, false, maxNameLength)
|
}
|
||||||
|
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)
|
||||||
|
} else {
|
||||||
|
nextStep = fmt.Sprintf("%s (full)", rep.Pending[0].To)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
status := fmt.Sprintf("%s (step %d/%d, %s/%s)",
|
||||||
|
rep.Status,
|
||||||
|
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()
|
t.newline()
|
||||||
t.addIndent(-1)
|
|
||||||
}
|
|
||||||
if versions && len(rep.Pending) > 0 {
|
|
||||||
v := rep.Pending[0]
|
|
||||||
t.drawBar(times(" ", snapshotIndent) + v.To, maxNameLength, StringStepState(v.Status), v.Bytes, v.ExpectedBytes)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ByteCountBinary(b int64) string {
|
func ByteCountBinary(b int64) string {
|
||||||
|
Loading…
Reference in New Issue
Block a user