😄 progress
TYPES
type Progress struct {
Steps []*Step `json:"steps,omitempty"`
CreatedAt time.Time `json:"created_at,omitempty"`
// Has unexported fields.
}
Progress is the top-level object of the 'progress' library.
func New() *Progress
New creates and returns a new Progress.
func (p *Progress) AddStep(id string) *Step
AddStep creates and returns a new Step with the provided 'id'. A non-empty,
unique 'id' is required, else it will panic.
func (p *Progress) Get(id string) *Step
Get retrieves a Step by its 'id'. A non-empty 'id' is required, else it will
panic. If 'id' does not match an existing step, nil is returned.
func (p *Progress) MarshalJSON() ([]byte, error)
MarshalJSON is a custom JSON marshaler that automatically computes and
append the current snapshot.
func (p *Progress) Percent() float64
Percent returns the current completion percentage, it's a faster alternative
to Progress.Snapshot().Percent.
func (p *Progress) SafeAddStep(id string) (*Step, error)
SafeAddStep is equivalent to AddStep with but returns error instead of
panicking.
func (p *Progress) Snapshot() Snapshot
Snapshot computes and returns the current stats of the Progress.
func (p *Progress) Subscribe(subscriber chan *Step)
Subscribe register a provided chan as a target called each time a step is
changed.
type Snapshot struct {
State State `json:"state,omitempty"`
Doing string `json:"doing,omitempty"`
NotStarted int `json:"not_started,omitempty"`
InProgress int `json:"in_progress,omitempty"`
Completed int `json:"completed,omitempty"`
Total int `json:"total,omitempty"`
Percent float64 `json:"percent,omitempty"`
TotalDuration time.Duration `json:"total_duration,omitempty"`
StepDuration time.Duration `json:"step_duration,omitempty"`
CompletionEstimate time.Duration `json:"completion_estimate,omitempty"`
DoneAt *time.Time `json:"done_at,omitempty"`
StartedAt *time.Time `json:"started_at,omitempty"`
}
Snapshot represents info and stats about a progress at a given time.
type State string
const (
StateNotStarted State = "not started"
StateInProgress State = "in progress"
StateDone State = "done"
)
type Step struct {
ID string `json:"id,omitempty"`
Description string `json:"description,omitempty"`
StartedAt *time.Time `json:"started_at,omitempty"`
DoneAt *time.Time `json:"done_at,omitempty"`
State State `json:"state,omitempty"`
Data interface{} `json:"data,omitempty"`
// Has unexported fields.
}
Step represents a progress step. It always have an 'id' and can be
customized using helpers.
func (s *Step) Done()
Done marks a step as done. If the step was already done, it panics.
func (s *Step) Duration() time.Duration
Duration computes the step duration.
func (s *Step) MarshalJSON() ([]byte, error)
MarshalJSON is a custom JSON marshaler that automatically computes and
append some runtime metadata.
func (s *Step) SetAsCurrent()
SetAsCurrent stops all in-progress steps and start this one.
func (s *Step) SetData(data interface{}) *Step
SetData sets a custom step data. It returns itself (*Step) for chaining.
func (s *Step) SetDescription(desc string) *Step
SetDescription sets a custom step description. It returns itself (*Step) for
chaining.
func (s *Step) Start()
Start marks a step as started. If a step was already InProgress or Done, it
panics.
import (
"fmt"
"time"
"moul.io/progress"
"moul.io/u"
)
func Example() {
// initialize a new progress.Progress
prog := progress.New()
prog.AddStep("init").SetDescription("initialize")
prog.AddStep("step1").SetDescription("step 1")
prog.AddStep("step2").SetData([]string{"hello", "world"}).SetDescription("step 2")
prog.AddStep("step3")
prog.AddStep("finish")
// automatically mark the last step as done when the function quit
defer prog.Get("finish").Done()
// mark init as Done
prog.Get("init").Done()
// mark step1 as started
prog.Get("step1").SetData(42).Start()
// then, mark it as done + attach custom data
prog.Get("step1").SetData(1337).Done()
// mark step2 as started
prog.Get("step2").Start()
fmt.Println(u.PrettyJSON(prog))
// outputs something like this:
// {
// "steps": [
// {
// "id": "init",
// "description": "initialize",
// "started_at": "2020-12-22T20:26:05.717427484+01:00",
// "done_at": "2020-12-22T20:26:05.717427484+01:00",
// "state": "done"
// },
// {
// "id": "step1",
// "description": "step 1",
// "started_at": "2020-12-22T20:26:05.71742797+01:00",
// "done_at": "2020-12-22T20:26:05.717428258+01:00",
// "state": "done",
// "data": 1337,
// "duration": 286
// },
// {
// "id": "step2",
// "description": "step 2",
// "started_at": "2020-12-22T20:26:05.71742865+01:00",
// "state": "in progress",
// "data": [
// "hello",
// "world"
// ],
// "duration": 496251
// },
// {
// "id": "step3"
// },
// {
// "id": "finish"
// }
// ],
// "created_at": "2020-12-22T20:26:05.717423018+01:00",
// "snapshot": {
// "state": "in progress",
// "doing": "step 2",
// "not_started": 2,
// "in_progress": 1,
// "completed": 2,
// "total": 5,
// "percent": 50,
// "total_duration": 25935,
// "started_at": "2020-12-22T20:26:05.717427484+01:00"
// }
//}
}
func ExampleProgressSubscribe() {
prog := progress.New()
done := make(chan bool)
ch := make(chan *progress.Step, 0)
prog.Subscribe(ch)
go func() {
idx := 0
for step := range ch {
if step == nil {
break
}
fmt.Println(idx, step.ID, step.State)
idx++
}
done <- true
}()
time.Sleep(10 * time.Millisecond)
prog.AddStep("step1").SetDescription("hello")
prog.AddStep("step2")
prog.Get("step1").Start()
prog.Get("step2").Done()
prog.AddStep("step3")
prog.Get("step3").Start()
prog.Get("step1").Done()
prog.Get("step3").Done()
// fmt.Println(u.PrettyJSON(prog))
<-done
close(ch)
// Output:
// 0 step1 not started
// 1 step1 not started
// 2 step2 not started
// 3 step1 in progress
// 4 step2 done
// 5 step3 not started
// 6 step3 in progress
// 7 step1 done
// 8 step3 done
}
go get moul.io/progress
I really welcome contributions. Your input is the most precious material. I'm well aware of that and I thank you in advance. Everyone is encouraged to look at what they can do on their own scale; no effort is too small.
Everything on contribution is sum up here: CONTRIBUTING.md
Thanks goes to these wonderful people (emoji key):
Manfred Touron 🚧 📖 |
moul-bot 🚧 |
This project follows the all-contributors specification. Contributions of any kind welcome!
© 2020 Manfred Touron
Licensed under the Apache License, Version 2.0
(LICENSE-APACHE
) or the MIT license
(LICENSE-MIT
), at your option.
See the COPYRIGHT
file for more details.
SPDX-License-Identifier: (Apache-2.0 OR MIT)