Files
snapd/progress/export_test.go
Maciej Borzecki 476810b31c progress: fix progress bar with multibyte duration units
Some languages may use multibyte characters for duration. In such case, the
width of the progress bar would be incorrectly calculated, making the displayed
label too short.

At runtime this would randomly cause a panic with the translation used a
multibyte characters:

panic: runtime error: slice bounds out of range [80:79] [recovered]
 panic: runtime error: slice bounds out of range [80:79]

goroutine 1 [running]:
main.main.func1()
 github.com/snapcore/snapd/cmd/snap/main.go:477 +0x95
panic(0x561d5f7fac80, 0xc000144280)
 runtime/panic.go:679 +0x1b6
github.com/snapcore/snapd/progress.(*ANSIMeter).Set(0xc000214eb0, 0x41a891a000000000)
 github.com/snapcore/snapd/progress/ansimeter.go:152 +0xa1b
main.waitMixin.wait(0xc0002e42a0, 0x561d5f3e0000, 0xc0001e4488, 0x2, 0x0, 0x0, 0x0)
 github.com/snapcore/snapd/cmd/snap/wait.go:130 +0x700
main.(*cmdInstall).installOne(0xc000359040, 0x7ffcf44c33e4, 0xb, 0x0, 0x0, 0xc00036cba0, 0x561d5f805060, 0x561d5f8693a0)
 github.com/snapcore/snapd/cmd/snap/cmd_snap_op.go:491 +0x316
main.(*cmdInstall).Execute(0xc000359040, 0xc0003787a0, 0x0, 0x2, 0xc000359040, 0x1)
 github.com/snapcore/snapd/cmd/snap/cmd_snap_op.go:596 +0x3d7
github.com/snapcore/snapd/vendor/github.com/jessevdk/go-flags.(*Parser).ParseArgs(0xc000316bd0, 0xc000032190, 0x2, 0x2, 0xc000330330, 0xc0002a5cd0, 0x561d5ee49fbd, 0x561d5f7d08a0, 0xc000330330)
 github.com/snapcore/snapd/vendor/github.com/jessevdk/go-flags/parser.go:333 +0x8e7
github.com/snapcore/snapd/vendor/github.com/jessevdk/go-flags.(*Parser).Parse(...)
 github.com/snapcore/snapd/vendor/github.com/jessevdk/go-flags/parser.go:190
main.run(0xc0002a5de0, 0xe)
 github.com/snapcore/snapd/cmd/snap/main.go:515 +0xa7
main.main()
 github.com/snapcore/snapd/cmd/snap/main.go:482 +0x371

Since we are assuming that terminal can display up to the column number of
runes, fix the length calculation to use slices of runes for all
components (keep in mind that len(string) >= len([]rune)).

Fixes: https://bugs.launchpad.net/ubuntu/+source/snapd/+bug/1876583

Signed-off-by: Maciej Borzecki <maciej.zenon.borzecki@canonical.com>
2020-05-06 13:34:21 +02:00

111 lines
2.3 KiB
Go

// -*- Mode: Go; indent-tabs-mode: t -*-
/*
* Copyright (C) 2017 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package progress
import (
"io"
)
var (
ClrEOL = clrEOL
CursorInvisible = cursorInvisible
CursorVisible = cursorVisible
EnterReverseMode = enterReverseMode
ExitAttributeMode = exitAttributeMode
)
func MockEmptyEscapes() func() {
clrEOL = ""
cursorInvisible = ""
cursorVisible = ""
enterReverseMode = ""
exitAttributeMode = ""
return func() {
clrEOL = ClrEOL
cursorInvisible = CursorInvisible
cursorVisible = CursorVisible
enterReverseMode = EnterReverseMode
exitAttributeMode = ExitAttributeMode
}
}
func MockSimpleEscapes() func() {
// set them to the tcap name (in all caps)
clrEOL = "<CE>"
cursorInvisible = "<VI>"
cursorVisible = "<VS>"
enterReverseMode = "<MR>"
exitAttributeMode = "<ME>"
return func() {
clrEOL = ClrEOL
cursorInvisible = CursorInvisible
cursorVisible = CursorVisible
enterReverseMode = EnterReverseMode
exitAttributeMode = ExitAttributeMode
}
}
func (p *ANSIMeter) Percent() string {
return p.percent()
}
func (p *ANSIMeter) SetWritten(written float64) {
p.written = written
}
func (p *ANSIMeter) GetWritten() float64 {
return p.written
}
func (p *ANSIMeter) GetTotal() float64 {
return p.total
}
func MockTermWidth(f func() int) func() {
origTermWidth := termWidth
termWidth = f
return func() {
termWidth = origTermWidth
}
}
func MockStdout(w io.Writer) func() {
origStdout := stdout
stdout = w
return func() {
stdout = origStdout
}
}
func MockFormatDuration(m func(f float64) string) (restore func()) {
old := formatDuration
formatDuration = m
return func() {
formatDuration = old
}
}
var (
Norm = norm
Spinner = spinner
)