• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / progressbar / 1691291161

27 Feb 2025 09:46AM UTC coverage: 57.471% (-42.5%) from 100.0%
1691291161

push

gitlab-ci

web-flow
Merge pull request #9 from lluiscampos/MEN-8127-fix-last-tick

MEN-8127: Fix "overflow" on the reported percentage

4 of 4 new or added lines in 1 file covered. (100.0%)

1 existing line in 1 file now uncovered.

50 of 87 relevant lines covered (57.47%)

3.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

57.47
/progress.go
1
// Copyright 2021 Northern.tech AS
2
//
3
//        Licensed under the Apache License, Version 2.0 (the "License");
4
//        you may not use this file except in compliance with the License.
5
//        You may obtain a copy of the License at
6
//
7
//            http://www.apache.org/licenses/LICENSE-2.0
8
//
9
//        Unless required by applicable law or agreed to in writing, software
10
//        distributed under the License is distributed on an "AS IS" BASIS,
11
//        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//        See the License for the specific language governing permissions and
13
//        limitations under the License.
14
package progressbar
15

16
// TODO -- Add terminal width respect
17

18
import (
19
        "fmt"
20
        "io"
21
        "os"
22
        "strings"
23

24
        "github.com/mattn/go-isatty"
25
        // "golang.org/x/sys/unix" - Do not add for now (split into minimal and not (?))
26
)
27

28
type Renderer interface {
29
        Render(int) // Write the progressbar
30
}
31

32
type Bar struct {
33
        Size         int64
34
        currentCount int64
35
        Renderer
36
        Percentage int
37
}
38

39
func New(size int64) *Bar {
×
40
        if isatty.IsTerminal(os.Stderr.Fd()) {
×
41
                return &Bar{
×
42
                        Renderer: &TTYRenderer{
×
43
                                Out:            os.Stderr,
×
44
                                ProgressMarker: ".",
×
45
                                terminalWidth:  70,
×
46
                        },
×
47
                        Size: size,
×
48
                }
×
49
        } else {
×
50
                return &Bar{
×
51
                        Renderer: &NoTTYRenderer{
×
52
                                Out:            os.Stderr,
×
53
                                ProgressMarker: ".",
×
54
                                terminalWidth:  70,
×
55
                        },
×
56
                        Size: size,
×
57
                }
×
58
        }
×
59
}
60

61
func (b *Bar) Tick(n int64) {
14✔
62
        b.currentCount += n
14✔
63
        // The last tick may be bigger than the remaining size
14✔
64
        if b.currentCount > b.Size {
17✔
65
                b.currentCount = b.Size
3✔
66
        }
3✔
67
        if b.Size > 0 {
28✔
68
                percentage := int((float64(b.currentCount) / float64(b.Size)) * 100)
14✔
69
                b.Percentage = percentage
14✔
70
                b.Renderer.Render(percentage)
14✔
71
        }
14✔
72
}
73

74
func (b *Bar) Reset() {
×
75
        b.currentCount = 0
×
76
        b.Renderer.Render(0)
×
77
}
×
78

79
func (b *Bar) Finish() {
×
80
        b.Renderer.Render(100)
×
81
}
×
82

83
type TTYRenderer struct {
84
        Out            io.Writer // Output device
85
        ProgressMarker string
86
        terminalWidth  int
87
        lastPercentage int
88
}
89

90
func (p *TTYRenderer) Render(percentage int) {
8✔
91
        if percentage <= p.lastPercentage {
9✔
92
                return
1✔
93
        }
1✔
94
        suffix := fmt.Sprintf(" - %3d %%", percentage)
7✔
95
        widthAvailable := p.terminalWidth - len(suffix)
7✔
96
        number_of_dots := int((float64(widthAvailable) * float64(percentage)) / 100)
7✔
97
        number_of_fillers := widthAvailable - number_of_dots
7✔
98
        if percentage < 0 {
7✔
UNCOV
99
                return
×
100
        }
×
101
        if number_of_dots < 0 {
7✔
102
                return
×
103
        }
×
104
        if number_of_fillers < 0 {
7✔
105
                return
×
106
        }
×
107
        p.lastPercentage = percentage
7✔
108
        fmt.Fprintf(p.Out, "\r%s%s%s",
7✔
109
                strings.Repeat(p.ProgressMarker, number_of_dots),
7✔
110
                strings.Repeat(" ", number_of_fillers),
7✔
111
                suffix)
7✔
112
        if percentage == 100 {
9✔
113
                fmt.Fprintln(p.Out)
2✔
114
        }
2✔
115
}
116

117
type NoTTYRenderer struct {
118
        Out              io.Writer // Output device
119
        ProgressMarker   string
120
        lastNumberOfDots int
121
        terminalWidth    int
122
        headerPrinted    bool
123
}
124

125
func (p *NoTTYRenderer) Render(percentage int) {
6✔
126
        if p.lastNumberOfDots >= p.terminalWidth {
7✔
127
                return
1✔
128
        }
1✔
129
        if !p.headerPrinted {
6✔
130
                // width, evenly distributed in half, taken away the characters
1✔
131
                // 0%,50% & 100%
1✔
132
                w := (p.terminalWidth - 2 - 3 - 4) / 2
1✔
133
                fmt.Fprintf(p.Out, "0%%%[1]*s50%%%[1]*[2]s100%%\n", w, " ")
1✔
134
                fmt.Fprintf(p.Out, "|%s|%[1]s|\n", strings.Repeat("-", (p.terminalWidth-3)/2))
1✔
135
                p.headerPrinted = true
1✔
136
        }
1✔
137
        slope := float64(p.terminalWidth) / 100
5✔
138
        fx := slope * float64(percentage)
5✔
139
        if int(fx) > p.lastNumberOfDots {
10✔
140
                numberOfDots := int(fx) - p.lastNumberOfDots
5✔
141
                str := strings.Repeat(p.ProgressMarker, numberOfDots)
5✔
142
                if numberOfDots+p.lastNumberOfDots > p.terminalWidth {
5✔
143
                        // Print only the difference
×
144
                        str = strings.Repeat(p.ProgressMarker, p.terminalWidth-p.lastNumberOfDots)
×
145
                        numberOfDots = p.terminalWidth - p.lastNumberOfDots
×
146
                }
×
147
                p.lastNumberOfDots += numberOfDots
5✔
148
                fmt.Fprintf(p.Out, str)
5✔
149
        }
150
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc