Move progress into pkg

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
Michael Crosby
2018-05-22 13:20:11 -04:00
parent d1435e6e4d
commit ae4b78d1cc
9 changed files with 4 additions and 4 deletions

82
pkg/progress/bar.go Normal file
View File

@@ -0,0 +1,82 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package progress
import (
"bytes"
"fmt"
)
// TODO(stevvooe): We may want to support more interesting parameterization of
// the bar. For now, it is very simple.
// Bar provides a very simple progress bar implementation.
//
// Use with fmt.Printf and "r" to format the progress bar. A "-" flag makes it
// progress from right to left.
type Bar float64
var _ fmt.Formatter = Bar(1.0)
// Format the progress bar as output
func (h Bar) Format(state fmt.State, r rune) {
switch r {
case 'r':
default:
panic(fmt.Sprintf("%v: unexpected format character", float64(h)))
}
if h > 1.0 {
h = 1.0
}
if h < 0.0 {
h = 0.0
}
if state.Flag('-') {
h = 1.0 - h
}
width, ok := state.Width()
if !ok {
// default width of 40
width = 40
}
var pad int
extra := len([]byte(green)) + len([]byte(reset))
p := make([]byte, width+extra)
p[0], p[len(p)-1] = '|', '|'
pad += 2
positive := int(Bar(width-pad) * h)
negative := width - pad - positive
n := 1
n += copy(p[n:], []byte(green))
n += copy(p[n:], bytes.Repeat([]byte("+"), positive))
n += copy(p[n:], []byte(reset))
if negative > 0 {
copy(p[n:len(p)-1], bytes.Repeat([]byte("-"), negative))
}
state.Write(p)
}

18
pkg/progress/doc.go Normal file
View File

@@ -0,0 +1,18 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package progress assists in displaying human readable progress information.
package progress

24
pkg/progress/escape.go Normal file
View File

@@ -0,0 +1,24 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package progress
const (
escape = "\x1b"
reset = escape + "[0m"
red = escape + "[31m" // nolint: unused, varcheck
green = escape + "[32m"
)

45
pkg/progress/humaans.go Normal file
View File

@@ -0,0 +1,45 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package progress
import (
"fmt"
"time"
units "github.com/docker/go-units"
)
// Bytes converts a regular int64 to human readable type.
type Bytes int64
// String returns the string representation of bytes
func (b Bytes) String() string {
return units.CustomSize("%02.1f %s", float64(b), 1024.0, []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"})
}
// BytesPerSecond is the rate in seconds for byte operations
type BytesPerSecond int64
// NewBytesPerSecond returns the rate that n bytes were written in the provided duration
func NewBytesPerSecond(n int64, duration time.Duration) BytesPerSecond {
return BytesPerSecond(float64(n) / duration.Seconds())
}
// String returns the string representation of the rate
func (bps BytesPerSecond) String() string {
return fmt.Sprintf("%v/s", Bytes(bps))
}

115
pkg/progress/writer.go Normal file
View File

@@ -0,0 +1,115 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package progress
import (
"bytes"
"fmt"
"io"
"os"
"regexp"
"strings"
"github.com/containerd/console"
)
var (
regexCleanLine = regexp.MustCompile("\x1b\\[[0-9]+m[\x1b]?")
)
// Writer buffers writes until flush, at which time the last screen is cleared
// and the current buffer contents are written. This is useful for
// implementing progress displays, such as those implemented in docker and
// git.
type Writer struct {
buf bytes.Buffer
w io.Writer
lines int
}
// NewWriter returns a writer
func NewWriter(w io.Writer) *Writer {
return &Writer{
w: w,
}
}
// Write the provided bytes
func (w *Writer) Write(p []byte) (n int, err error) {
return w.buf.Write(p)
}
// Flush should be called when refreshing the current display.
func (w *Writer) Flush() error {
if w.buf.Len() == 0 {
return nil
}
if err := w.clearLines(); err != nil {
return err
}
w.lines = countLines(w.buf.String())
if _, err := w.w.Write(w.buf.Bytes()); err != nil {
return err
}
w.buf.Reset()
return nil
}
// TODO(stevvooe): The following are system specific. Break these out if we
// decide to build this package further.
func (w *Writer) clearLines() error {
for i := 0; i < w.lines; i++ {
if _, err := fmt.Fprintf(w.w, "\x1b[1A\x1b[2K\r"); err != nil {
return err
}
}
return nil
}
// countLines in the output. If a line is longer than the console width then
// an extra line is added to the count for each wrapped line. If the console
// width is undefined then 0 is returned so that no lines are cleared on the next
// flush.
func countLines(output string) int {
con, err := console.ConsoleFromFile(os.Stdin)
if err != nil {
return 0
}
ws, err := con.Size()
if err != nil {
return 0
}
width := int(ws.Width)
if width <= 0 {
return 0
}
strlines := strings.Split(output, "\n")
lines := -1
for _, line := range strlines {
lines += (len(stripLine(line))-1)/width + 1
}
return lines
}
func stripLine(line string) string {
return string(regexCleanLine.ReplaceAll([]byte(line), []byte{}))
}