Add actual file upload to Yandex with progress bar

This commit is contained in:
2019-03-30 07:00:15 +04:00
parent ff258dde2d
commit 1fbeb6c063
17 changed files with 1085 additions and 6 deletions

4
vendor/github.com/schollz/progressbar/v2/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,4 @@
language: go
go:
- tip

21
vendor/github.com/schollz/progressbar/v2/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Zack
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

122
vendor/github.com/schollz/progressbar/v2/README.md generated vendored Normal file
View File

@@ -0,0 +1,122 @@
# progressbar
[![travis](https://travis-ci.org/schollz/progressbar.svg?branch=master)](https://travis-ci.org/schollz/progressbar)
[![go report card](https://goreportcard.com/badge/github.com/schollz/progressbar)](https://goreportcard.com/report/github.com/schollz/progressbar)
[![coverage](https://img.shields.io/badge/coverage-84%25-brightgreen.svg)](https://gocover.io/github.com/schollz/progressbar)
[![godocs](https://godoc.org/github.com/schollz/progressbar?status.svg)](https://godoc.org/github.com/schollz/progressbar)
A very simple thread-safe progress bar which should work on every OS without problems. I needed a progressbar for [croc](https://github.com/schollz/croc) and everything I tried had problems, so I made another one.
![Example of progress bar](https://user-images.githubusercontent.com/6550035/32120326-5f420d42-bb15-11e7-89d4-c502864e78eb.gif)
## Install
```
go get -u github.com/schollz/progressbar
```
## Usage
### Basic usage
```golang
bar := progressbar.New(100)
for i := 0; i < 100; i++ {
bar.Add(1)
time.Sleep(10 * time.Millisecond)
}
```
which looks like:
```bash
100% |████████████████████████████████████████| [1s:0s]
```
The times at the end show the elapsed time and the remaining time, respectively.
### Long running processes
For long running processes, you might want to render from a 0% state.
```golang
// Renders the bar right on construction
bar := progressbar.NewOptions(100, progressbar.OptionSetRenderBlankState(true))
```
Alternatively, when you want to delay rendering, but still want to render a 0% state
```golang
bar := progressbar.NewOptions(100)
// Render the current state, which is 0% in this case
bar.RenderBlank()
// Emulate work
for i := 0; i < 10; i++ {
time.Sleep(10 * time.Minute)
bar.Add(10)
}
```
### Use a custom writer
The default writer is standard output (os.Stdout), but you can set it to whatever satisfies io.Writer.
```golang
bar := NewOptions(
10,
OptionSetTheme(Theme{Saucer: "#", SaucerPadding: "-", BarStart: ">", BarEnd: "<"}),
OptionSetWidth(10),
OptionSetWriter(&buf),
)
bar.Add(5)
result := strings.TrimSpace(buf.String())
// Result equals:
// 50% >#####-----< [0s:0s]
```
### Progress for I/O operations
The `progressbar` implements an `io.Writer` so it can automatically detect the number of bytes written to a stream, so you can use it as a progressbar for an `io.Reader`.
```golang
urlToGet := "https://github.com/schollz/croc/releases/download/v4.1.4/croc_v4.1.4_Windows-64bit_GUI.zip"
req, _ := http.NewRequest("GET", urlToGet, nil)
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
var out io.Writer
f, _ := os.OpenFile("croc_v4.1.4_Windows-64bit_GUI.zip", os.O_CREATE|os.O_WRONLY, 0644)
out = f
defer f.Close()
bar := progressbar.NewOptions(
int(resp.ContentLength),
progressbar.OptionSetBytes(int(resp.ContentLength)),
)
out = io.MultiWriter(out, bar)
io.Copy(out, resp.Body)
```
See the tests for another example.
## Contributing
Pull requests are welcome. Feel free to...
- Revise documentation
- Add new features
- Fix bugs
- Suggest improvements
## Thanks
Thanks [@Dynom](https://github.com/dynom) for massive improvements in version 2.0!
Thanks [@CrushedPixel](https://github.com/CrushedPixel) for adding descriptions and color code support!
## License
MIT

3
vendor/github.com/schollz/progressbar/v2/go.mod generated vendored Normal file
View File

@@ -0,0 +1,3 @@
module github.com/schollz/progressbar/v2
require github.com/mitchellh/colorstring v0.0.0-20150917214807-8631ce90f286

451
vendor/github.com/schollz/progressbar/v2/progressbar.go generated vendored Normal file
View File

@@ -0,0 +1,451 @@
package progressbar
import (
"errors"
"fmt"
"io"
"os"
"regexp"
"strings"
"sync"
"time"
"github.com/mitchellh/colorstring"
)
// ProgressBar is a thread-safe, simple
// progress bar
type ProgressBar struct {
state state
config config
lock sync.Mutex
}
// State is the basic properties of the bar
type State struct {
CurrentPercent float64
CurrentBytes float64
MaxBytes int64
SecondsSince float64
SecondsLeft float64
KBsPerSecond float64
}
type state struct {
currentNum int64
currentPercent int
lastPercent int
currentSaucerSize int
lastShown time.Time
startTime time.Time
maxLineWidth int
currentBytes float64
}
type config struct {
max int64 // max number of the counter
width int
writer io.Writer
theme Theme
renderWithBlankState bool
description string
// whether the output is expected to contain color codes
colorCodes bool
maxBytes int64
// show the iterations per second
showIterationsPerSecond bool
showIterationsCount bool
// minimum time to wait in between updates
throttleDuration time.Duration
}
// Theme defines the elements of the bar
type Theme struct {
Saucer string
SaucerHead string
SaucerPadding string
BarStart string
BarEnd string
}
// Option is the type all options need to adhere to
type Option func(p *ProgressBar)
// OptionSetWidth sets the width of the bar
func OptionSetWidth(s int) Option {
return func(p *ProgressBar) {
p.config.width = s
}
}
// OptionSetTheme sets the elements the bar is constructed of
func OptionSetTheme(t Theme) Option {
return func(p *ProgressBar) {
p.config.theme = t
}
}
// OptionSetWriter sets the output writer (defaults to os.StdOut)
func OptionSetWriter(w io.Writer) Option {
return func(p *ProgressBar) {
p.config.writer = w
}
}
// OptionSetRenderBlankState sets whether or not to render a 0% bar on construction
func OptionSetRenderBlankState(r bool) Option {
return func(p *ProgressBar) {
p.config.renderWithBlankState = r
}
}
// OptionSetDescription sets the description of the bar to render in front of it
func OptionSetDescription(description string) Option {
return func(p *ProgressBar) {
p.config.description = description
}
}
// OptionEnableColorCodes enables or disables support for color codes
// using mitchellh/colorstring
func OptionEnableColorCodes(colorCodes bool) Option {
return func(p *ProgressBar) {
p.config.colorCodes = colorCodes
}
}
// OptionSetBytes will also print the bytes/second
func OptionSetBytes(maxBytes int) Option {
return OptionSetBytes64(int64(maxBytes))
}
// OptionSetBytes64 will also print the bytes/second
func OptionSetBytes64(maxBytes int64) Option {
return func(p *ProgressBar) {
p.config.maxBytes = maxBytes
}
}
// OptionShowCount will also print current count out of total
func OptionShowCount() Option {
return func(p *ProgressBar) {
p.config.showIterationsCount = true
}
}
// OptionShowIts will also print the iterations/second
func OptionShowIts() Option {
return func(p *ProgressBar) {
p.config.showIterationsPerSecond = true
}
}
// OptionThrottle will wait the specified duration before updating again. The default
// duration is 0 seconds.
func OptionThrottle(duration time.Duration) Option {
return func(p *ProgressBar) {
p.config.throttleDuration = duration
}
}
var defaultTheme = Theme{Saucer: "█", SaucerPadding: " ", BarStart: "|", BarEnd: "|"}
// NewOptions constructs a new instance of ProgressBar, with any options you specify
func NewOptions(max int, options ...Option) *ProgressBar {
return NewOptions64(int64(max), options...)
}
// NewOptions64 constructs a new instance of ProgressBar, with any options you specify
func NewOptions64(max int64, options ...Option) *ProgressBar {
b := ProgressBar{
state: getBlankState(),
config: config{
writer: os.Stdout,
theme: defaultTheme,
width: 40,
max: max,
throttleDuration: 0 * time.Nanosecond,
},
}
for _, o := range options {
o(&b)
}
if b.config.renderWithBlankState {
b.RenderBlank()
}
return &b
}
func getBlankState() state {
now := time.Now()
return state{
startTime: now,
lastShown: now,
}
}
// New returns a new ProgressBar
// with the specified maximum
func New(max int) *ProgressBar {
return NewOptions(max)
}
// RenderBlank renders the current bar state, you can use this to render a 0% state
func (p *ProgressBar) RenderBlank() error {
return p.render()
}
// Reset will reset the clock that is used
// to calculate current time and the time left.
func (p *ProgressBar) Reset() {
p.lock.Lock()
defer p.lock.Unlock()
p.state = getBlankState()
}
// Finish will fill the bar to full
func (p *ProgressBar) Finish() error {
p.lock.Lock()
p.state.currentNum = p.config.max
p.lock.Unlock()
return p.Add(0)
}
// Add with increase the current count on the progress bar
func (p *ProgressBar) Set(num int) error {
return p.Set64(int64(num))
}
// Add with increase the current count on the progress bar
func (p *ProgressBar) Set64(num int64) error {
p.lock.Lock()
defer p.lock.Unlock()
if p.config.max == 0 {
return errors.New("max must be greater than 0")
}
p.state.currentNum = num
percent := float64(p.state.currentNum) / float64(p.config.max)
p.state.currentSaucerSize = int(percent * float64(p.config.width))
p.state.currentPercent = int(percent * 100)
updateBar := p.state.currentPercent != p.state.lastPercent && p.state.currentPercent > 0
p.state.currentBytes = float64(percent) * float64(p.config.maxBytes)
p.state.lastPercent = p.state.currentPercent
if p.state.currentNum > p.config.max {
return errors.New("current number exceeds max")
}
// always update if show bytes/second or its/second
if updateBar || p.config.showIterationsPerSecond || p.config.maxBytes > 0 {
return p.render()
}
return nil
}
func (p *ProgressBar) Add(num int) error {
return p.Add64(int64(num))
}
func (p *ProgressBar) Add64(num int64) error {
return p.Set64(p.state.currentNum + num)
}
// Clear erases the progress bar from the current line
func (p *ProgressBar) Clear() error {
return clearProgressBar(p.config, p.state)
}
// Describe will change the description shown before the progress, which
// can be changed on the fly (as for a slow running process).
func (p *ProgressBar) Describe(description string) {
p.config.description = description
}
// render renders the progress bar, updating the maximum
// rendered line width. this function is not thread-safe,
// so it must be called with an acquired lock.
func (p *ProgressBar) render() error {
// make sure that the rendering is not happening too quickly
// but always show if the currentNum reaches the max
if time.Since(p.state.lastShown).Nanoseconds() < p.config.throttleDuration.Nanoseconds() &&
p.state.currentNum < p.config.max {
return nil
}
// first, clear the existing progress bar
err := clearProgressBar(p.config, p.state)
if err != nil {
return err
}
// then, re-render the current progress bar
w, err := renderProgressBar(p.config, p.state)
if err != nil {
return err
}
if w > p.state.maxLineWidth {
p.state.maxLineWidth = w
}
p.state.lastShown = time.Now()
return nil
}
// State returns the current state
func (p *ProgressBar) State() State {
p.lock.Lock()
defer p.lock.Unlock()
s := State{}
s.CurrentPercent = float64(p.state.currentNum) / float64(p.config.max)
s.CurrentBytes = p.state.currentBytes
s.MaxBytes = p.config.maxBytes
s.SecondsSince = time.Since(p.state.startTime).Seconds()
if p.state.currentNum > 0 {
s.SecondsLeft = s.SecondsSince / float64(p.state.currentNum) * (float64(p.config.max) - float64(p.state.currentNum))
}
s.KBsPerSecond = float64(p.state.currentBytes) / 1000.0 / s.SecondsSince
return s
}
// regex matching ansi escape codes
var ansiRegex = regexp.MustCompile(`\x1b\[[0-9;]*[a-zA-Z]`)
func renderProgressBar(c config, s state) (int, error) {
var leftTime float64
if s.currentNum > 0 {
leftTime = time.Since(s.startTime).Seconds() / float64(s.currentNum) * (float64(c.max) - float64(s.currentNum))
}
var saucer string
if s.currentSaucerSize > 0 {
saucer = strings.Repeat(c.theme.Saucer, s.currentSaucerSize-1)
saucerHead := c.theme.SaucerHead
if saucerHead == "" || s.currentSaucerSize == c.width {
// use the saucer for the saucer head if it hasn't been set
// to preserve backwards compatibility
saucerHead = c.theme.Saucer
}
saucer += saucerHead
}
// add on bytes string if max bytes option was set
kbPerSecond := float64(s.currentBytes) / 1000.0 / time.Since(s.startTime).Seconds()
bytesString := ""
if kbPerSecond > 1000.0 {
bytesString = fmt.Sprintf("(%2.1f MB/s)", kbPerSecond/1000.0)
} else if kbPerSecond > 0 {
bytesString = fmt.Sprintf("(%2.1f kB/s)", kbPerSecond)
}
if c.showIterationsPerSecond && !c.showIterationsCount {
// replace bytesString if used
bytesString = fmt.Sprintf("(%2.0f it/s)", float64(s.currentNum)/time.Since(s.startTime).Seconds())
} else if !c.showIterationsPerSecond && c.showIterationsCount {
bytesString = fmt.Sprintf("(%d/%d)", s.currentNum, c.max)
} else if c.showIterationsPerSecond && c.showIterationsCount {
bytesString = fmt.Sprintf("(%d/%d, %2.0f it/s)", s.currentNum, c.max, float64(s.currentNum)/time.Since(s.startTime).Seconds())
}
str := fmt.Sprintf("\r%s%4d%% %s%s%s%s %s [%s:%s]",
c.description,
s.currentPercent,
c.theme.BarStart,
saucer,
strings.Repeat(c.theme.SaucerPadding, c.width-s.currentSaucerSize),
c.theme.BarEnd,
bytesString,
(time.Duration(time.Since(s.startTime).Seconds()) * time.Second).String(),
(time.Duration(leftTime) * time.Second).String(),
)
if c.colorCodes {
// convert any color codes in the progress bar into the respective ANSI codes
str = colorstring.Color(str)
}
// the width of the string, if printed to the console
// does not include the carriage return character
cleanString := strings.Replace(str, "\r", "", -1)
if c.colorCodes {
// the ANSI codes for the colors do not take up space in the console output,
// so they do not count towards the output string width
cleanString = ansiRegex.ReplaceAllString(cleanString, "")
}
// get the amount of runes in the string instead of the
// character count of the string, as some runes span multiple characters.
// see https://stackoverflow.com/a/12668840/2733724
stringWidth := len([]rune(cleanString))
return stringWidth, writeString(c, str)
}
func clearProgressBar(c config, s state) error {
// fill the current line with enough spaces
// to overwrite the progress bar and jump
// back to the beginning of the line
str := fmt.Sprintf("\r%s\r", strings.Repeat(" ", s.maxLineWidth))
return writeString(c, str)
}
func writeString(c config, str string) error {
if _, err := io.WriteString(c.writer, str); err != nil {
return err
}
if f, ok := c.writer.(*os.File); ok {
// ignore any errors in Sync(), as stdout
// can't be synced on some operating systems
// like Debian 9 (Stretch)
f.Sync()
}
return nil
}
// Reader is the progressbar io.Reader struct
type Reader struct {
io.Reader
bar *ProgressBar
}
func (r *Reader) Read(p []byte) (n int, err error) {
n, err = r.Reader.Read(p)
r.bar.Add(n)
return
}
// Close the reader when it implements io.Closer
func (r *Reader) Close() (err error) {
if closer, ok := r.Reader.(io.Closer); ok {
return closer.Close()
}
return
}
// Write implement io.Writer
func (p *ProgressBar) Write(b []byte) (n int, err error) {
n = len(b)
p.Add(n)
return
}
// Read implement io.Reader
func (p *ProgressBar) Read(b []byte) (n int, err error) {
n = len(b)
p.Add(n)
return
}