Cameradar 3.0.0: Uses ullaakut/nmap, runs faster, removed legacy code (#188)
Unit tests functional and coverage back to 100% Add more routes to dictionary, add more credentials, add default port 5554, rename cameradar logs ENV variable, improve unit test readability, remove tmp file
This commit is contained in:
committed by
GitHub
parent
878ca9f032
commit
5849898283
+3
@@ -0,0 +1,3 @@
|
||||
[submodule "cli-spinners"]
|
||||
path = cli-spinners
|
||||
url = https://github.com/sindresorhus/cli-spinners
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Geofrey Ernest
|
||||
|
||||
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.
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
|
||||
## wow
|
||||
[](https://godoc.org/github.com/gernest/wow)
|
||||
|
||||
Beautiful spinners for Go commandline apps
|
||||
|
||||

|
||||
|
||||
## Install
|
||||
go get -u github.com/gernest/wow
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/gernest/wow"
|
||||
"github.com/gernest/wow/spin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
w := wow.New(os.Stdout, spin.Get(spin.Dots), "Such Spins")
|
||||
w.Start()
|
||||
time.Sleep(2 * time.Second)
|
||||
w.Text("Very emojis").Spinner(spin.Get(spin.Hearts))
|
||||
time.Sleep(2 * time.Second)
|
||||
w.PersistWith(spin.Spinner{Frames: []string{"👍"}}, " Wow!")
|
||||
}
|
||||
```
|
||||
|
||||
## Available spinners
|
||||
|
||||
Name | What it looks like
|
||||
--------|---------------------
|
||||
`Star2` | 
|
||||
`GrowHorizontal` | 
|
||||
`Squish` | 
|
||||
`Toggle12` | 
|
||||
`Smiley` | 
|
||||
`Hearts` | 
|
||||
`Dots3` | 
|
||||
`Dots11` | 
|
||||
`Balloon` | 
|
||||
`Clock` | 
|
||||
`Dots4` | 
|
||||
`SquareCorners` | 
|
||||
`CircleHalves` | 
|
||||
`Star` | 
|
||||
`Arc` | 
|
||||
`Toggle13` | 
|
||||
`BoxBounce` | 
|
||||
`Line2` | 
|
||||
`Pipe` | 
|
||||
`Triangle` | 
|
||||
`Shark` | 
|
||||
`Line` | 
|
||||
`Arrow` | 
|
||||
`Earth` | 
|
||||
`Dots5` | 
|
||||
`Toggle11` | 
|
||||
`CircleQuarters` | 
|
||||
`Toggle9` | 
|
||||
`Dots9` | 
|
||||
`Bounce` | 
|
||||
`Toggle2` | 
|
||||
`Toggle7` | 
|
||||
`Arrow3` | 
|
||||
`Moon` | 
|
||||
`Dots6` | 
|
||||
`Christmas` | 
|
||||
`Dots10` | 
|
||||
`Hamburger` | 
|
||||
`BoxBounce2` | 
|
||||
`BouncingBar` | 
|
||||
`Flip` | 
|
||||
`Dots8` | 
|
||||
`Dots12` | 
|
||||
`Noise` | 
|
||||
`Toggle3` | 
|
||||
`Toggle6` | 
|
||||
`Runner` | 
|
||||
`Dqpb` | 
|
||||
`Dots` | 
|
||||
`Toggle4` | 
|
||||
`Monkey` | 
|
||||
`Dots7` | 
|
||||
`SimpleDots` | 
|
||||
`GrowVertical` | 
|
||||
`Circle` | 
|
||||
`Toggle` | 
|
||||
`Toggle5` | 
|
||||
`Arrow2` | 
|
||||
`Dots2` | 
|
||||
`Toggle8` | 
|
||||
`Toggle10` | 
|
||||
`BouncingBall` | 
|
||||
`SimpleDotsScrolling` | 
|
||||
`Pong` | 
|
||||
`Weather` | 
|
||||
`Balloon2` | 
|
||||
+228
@@ -0,0 +1,228 @@
|
||||
// +build mage
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/magefile/mage/sh"
|
||||
|
||||
"github.com/magefile/mage/mg"
|
||||
)
|
||||
|
||||
// Spinners generates easy/accessible Go types for spinners from
|
||||
// cli-spinners/spinners.json.
|
||||
func Spinners() error {
|
||||
pkg := "spin"
|
||||
mg.Deps(func() error {
|
||||
_, err := os.Stat(pkg)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return os.Mkdir(pkg, 0777)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
b, err := ioutil.ReadFile("cli-spinners/spinners.json")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o := make(map[string]interface{})
|
||||
err = json.Unmarshal(b, &o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tpl, err := template.New("spinner").Funcs(helpers()).Parse(spinnersTpl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
err = tpl.Execute(&buf, o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bo, err := format.Source(buf.Bytes())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(filepath.Join(pkg, "spinners.go"), bo, 0600)
|
||||
}
|
||||
|
||||
// ExampleAll generates example executable file to demo all spinners
|
||||
func ExampleAll() error {
|
||||
b, err := ioutil.ReadFile("cli-spinners/spinners.json")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o := make(map[string]interface{})
|
||||
err = json.Unmarshal(b, &o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Generate example/all/main.go
|
||||
tpl, err := template.New("example-all").Funcs(helpers()).Parse(exampleAllTpl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
err = tpl.Execute(&buf, o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bo, err := format.Source(buf.Bytes())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile("example/all/main.go", bo, 0600)
|
||||
}
|
||||
|
||||
func helpers() template.FuncMap {
|
||||
return template.FuncMap{
|
||||
"title": strings.Title,
|
||||
"stringify": func(a []interface{}) string {
|
||||
o := ""
|
||||
switch len(a) {
|
||||
case 0:
|
||||
return ""
|
||||
case 1:
|
||||
return fmt.Sprintf("\"%s\"", a[0])
|
||||
default:
|
||||
for k, v := range a {
|
||||
if k == 0 {
|
||||
o += fmt.Sprintf("`%s`", v)
|
||||
} else {
|
||||
if v == "`" {
|
||||
o += fmt.Sprintf(",\"%s\"", v)
|
||||
|
||||
} else {
|
||||
o += fmt.Sprintf(",`%s`", v)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("[]string{ %v }", o)
|
||||
}
|
||||
},
|
||||
"all": func(a map[string]interface{}) string {
|
||||
o := ""
|
||||
for k := range a {
|
||||
if o == "" {
|
||||
o += fmt.Sprintf("%s", strings.Title(k))
|
||||
} else {
|
||||
o += fmt.Sprintf(",%s", strings.Title(k))
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("[]Name{%s}", o)
|
||||
},
|
||||
"allwithpkg": func(a map[string]interface{}) string {
|
||||
o := ""
|
||||
for k := range a {
|
||||
if o == "" {
|
||||
o += fmt.Sprintf("spin.%s", strings.Title(k))
|
||||
} else {
|
||||
o += fmt.Sprintf(",spin.%s", strings.Title(k))
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("[]spin.Name{%s}", o)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const spinnersTpl = `//DO NOT EDIT : this file was automatically generated.
|
||||
package spin
|
||||
|
||||
// Spinner defines a spinner widget
|
||||
type Spinner struct{
|
||||
Name Name
|
||||
Interval int
|
||||
Frames []string
|
||||
}
|
||||
|
||||
// Name represents a name for a spinner item.
|
||||
type Name uint
|
||||
|
||||
// available spinners
|
||||
const(
|
||||
Unknown Name=iota
|
||||
{{range $k,$v:= .}}
|
||||
{{- $k|title}}
|
||||
{{end}}
|
||||
)
|
||||
|
||||
func (s Name)String()string{
|
||||
switch s{
|
||||
{{- range $k,$v:=.}}
|
||||
case {{$k|title}} :
|
||||
return "{{$k}}"
|
||||
{{- end}}
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func Get( name Name)Spinner{
|
||||
switch name{
|
||||
{{- range $k,$v:=.}}
|
||||
case {{$k|title}} :
|
||||
return Spinner{
|
||||
Name: {{$k|title}},
|
||||
Interval: {{$v.interval}},
|
||||
Frames: {{$v.frames|stringify }},
|
||||
}
|
||||
{{- end}}
|
||||
default:
|
||||
return Spinner{}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const exampleAllTpl = `//DO NOT EDIT : this file was automatically generated.
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/gernest/wow"
|
||||
"github.com/gernest/wow/spin"
|
||||
)
|
||||
|
||||
var all = {{allwithpkg .}}
|
||||
|
||||
func main() {
|
||||
for _, v := range all {
|
||||
w := wow.New(os.Stdout, spin.Get(v), " "+v.String())
|
||||
w.Start()
|
||||
time.Sleep(2)
|
||||
w.Persist()
|
||||
}
|
||||
}
|
||||
|
||||
`
|
||||
|
||||
// Update updates cli-spinners to get latest changes to the spinners.json file.
|
||||
func Update() error {
|
||||
return sh.Run("git", "submodule", "update", "--remote", "cli-spinners")
|
||||
}
|
||||
|
||||
//Setup prepares the project for local development.
|
||||
//
|
||||
// This runs git submodule init && git submodule update
|
||||
func Setup() error {
|
||||
err := sh.Run("git", "submodule", "init")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return sh.Run("git", "submodule", "update")
|
||||
}
|
||||
+625
@@ -0,0 +1,625 @@
|
||||
//DO NOT EDIT : this file was automatically generated.
|
||||
package spin
|
||||
|
||||
// Spinner defines a spinner widget
|
||||
type Spinner struct {
|
||||
Name Name
|
||||
Interval int
|
||||
Frames []string
|
||||
}
|
||||
|
||||
// Name represents a name for a spinner item.
|
||||
type Name uint
|
||||
|
||||
// available spinners
|
||||
const (
|
||||
Unknown Name = iota
|
||||
Arc
|
||||
Arrow
|
||||
Arrow2
|
||||
Arrow3
|
||||
Balloon
|
||||
Balloon2
|
||||
Bounce
|
||||
BouncingBall
|
||||
BouncingBar
|
||||
BoxBounce
|
||||
BoxBounce2
|
||||
Christmas
|
||||
Circle
|
||||
CircleHalves
|
||||
CircleQuarters
|
||||
Clock
|
||||
Dots
|
||||
Dots10
|
||||
Dots11
|
||||
Dots12
|
||||
Dots2
|
||||
Dots3
|
||||
Dots4
|
||||
Dots5
|
||||
Dots6
|
||||
Dots7
|
||||
Dots8
|
||||
Dots9
|
||||
Dqpb
|
||||
Earth
|
||||
Flip
|
||||
GrowHorizontal
|
||||
GrowVertical
|
||||
Hamburger
|
||||
Hearts
|
||||
Line
|
||||
Line2
|
||||
Monkey
|
||||
Moon
|
||||
Noise
|
||||
Pipe
|
||||
Pong
|
||||
Runner
|
||||
Shark
|
||||
SimpleDots
|
||||
SimpleDotsScrolling
|
||||
Smiley
|
||||
SquareCorners
|
||||
Squish
|
||||
Star
|
||||
Star2
|
||||
Toggle
|
||||
Toggle10
|
||||
Toggle11
|
||||
Toggle12
|
||||
Toggle13
|
||||
Toggle2
|
||||
Toggle3
|
||||
Toggle4
|
||||
Toggle5
|
||||
Toggle6
|
||||
Toggle7
|
||||
Toggle8
|
||||
Toggle9
|
||||
Triangle
|
||||
Weather
|
||||
)
|
||||
|
||||
func (s Name) String() string {
|
||||
switch s {
|
||||
case Arc:
|
||||
return "arc"
|
||||
case Arrow:
|
||||
return "arrow"
|
||||
case Arrow2:
|
||||
return "arrow2"
|
||||
case Arrow3:
|
||||
return "arrow3"
|
||||
case Balloon:
|
||||
return "balloon"
|
||||
case Balloon2:
|
||||
return "balloon2"
|
||||
case Bounce:
|
||||
return "bounce"
|
||||
case BouncingBall:
|
||||
return "bouncingBall"
|
||||
case BouncingBar:
|
||||
return "bouncingBar"
|
||||
case BoxBounce:
|
||||
return "boxBounce"
|
||||
case BoxBounce2:
|
||||
return "boxBounce2"
|
||||
case Christmas:
|
||||
return "christmas"
|
||||
case Circle:
|
||||
return "circle"
|
||||
case CircleHalves:
|
||||
return "circleHalves"
|
||||
case CircleQuarters:
|
||||
return "circleQuarters"
|
||||
case Clock:
|
||||
return "clock"
|
||||
case Dots:
|
||||
return "dots"
|
||||
case Dots10:
|
||||
return "dots10"
|
||||
case Dots11:
|
||||
return "dots11"
|
||||
case Dots12:
|
||||
return "dots12"
|
||||
case Dots2:
|
||||
return "dots2"
|
||||
case Dots3:
|
||||
return "dots3"
|
||||
case Dots4:
|
||||
return "dots4"
|
||||
case Dots5:
|
||||
return "dots5"
|
||||
case Dots6:
|
||||
return "dots6"
|
||||
case Dots7:
|
||||
return "dots7"
|
||||
case Dots8:
|
||||
return "dots8"
|
||||
case Dots9:
|
||||
return "dots9"
|
||||
case Dqpb:
|
||||
return "dqpb"
|
||||
case Earth:
|
||||
return "earth"
|
||||
case Flip:
|
||||
return "flip"
|
||||
case GrowHorizontal:
|
||||
return "growHorizontal"
|
||||
case GrowVertical:
|
||||
return "growVertical"
|
||||
case Hamburger:
|
||||
return "hamburger"
|
||||
case Hearts:
|
||||
return "hearts"
|
||||
case Line:
|
||||
return "line"
|
||||
case Line2:
|
||||
return "line2"
|
||||
case Monkey:
|
||||
return "monkey"
|
||||
case Moon:
|
||||
return "moon"
|
||||
case Noise:
|
||||
return "noise"
|
||||
case Pipe:
|
||||
return "pipe"
|
||||
case Pong:
|
||||
return "pong"
|
||||
case Runner:
|
||||
return "runner"
|
||||
case Shark:
|
||||
return "shark"
|
||||
case SimpleDots:
|
||||
return "simpleDots"
|
||||
case SimpleDotsScrolling:
|
||||
return "simpleDotsScrolling"
|
||||
case Smiley:
|
||||
return "smiley"
|
||||
case SquareCorners:
|
||||
return "squareCorners"
|
||||
case Squish:
|
||||
return "squish"
|
||||
case Star:
|
||||
return "star"
|
||||
case Star2:
|
||||
return "star2"
|
||||
case Toggle:
|
||||
return "toggle"
|
||||
case Toggle10:
|
||||
return "toggle10"
|
||||
case Toggle11:
|
||||
return "toggle11"
|
||||
case Toggle12:
|
||||
return "toggle12"
|
||||
case Toggle13:
|
||||
return "toggle13"
|
||||
case Toggle2:
|
||||
return "toggle2"
|
||||
case Toggle3:
|
||||
return "toggle3"
|
||||
case Toggle4:
|
||||
return "toggle4"
|
||||
case Toggle5:
|
||||
return "toggle5"
|
||||
case Toggle6:
|
||||
return "toggle6"
|
||||
case Toggle7:
|
||||
return "toggle7"
|
||||
case Toggle8:
|
||||
return "toggle8"
|
||||
case Toggle9:
|
||||
return "toggle9"
|
||||
case Triangle:
|
||||
return "triangle"
|
||||
case Weather:
|
||||
return "weather"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func Get(name Name) Spinner {
|
||||
switch name {
|
||||
case Arc:
|
||||
return Spinner{
|
||||
Name: Arc,
|
||||
Interval: 100,
|
||||
Frames: []string{`◜`, `◠`, `◝`, `◞`, `◡`, `◟`},
|
||||
}
|
||||
case Arrow:
|
||||
return Spinner{
|
||||
Name: Arrow,
|
||||
Interval: 100,
|
||||
Frames: []string{`←`, `↖`, `↑`, `↗`, `→`, `↘`, `↓`, `↙`},
|
||||
}
|
||||
case Arrow2:
|
||||
return Spinner{
|
||||
Name: Arrow2,
|
||||
Interval: 80,
|
||||
Frames: []string{`⬆️ `, `↗️ `, `➡️ `, `↘️ `, `⬇️ `, `↙️ `, `⬅️ `, `↖️ `},
|
||||
}
|
||||
case Arrow3:
|
||||
return Spinner{
|
||||
Name: Arrow3,
|
||||
Interval: 120,
|
||||
Frames: []string{`▹▹▹▹▹`, `▸▹▹▹▹`, `▹▸▹▹▹`, `▹▹▸▹▹`, `▹▹▹▸▹`, `▹▹▹▹▸`},
|
||||
}
|
||||
case Balloon:
|
||||
return Spinner{
|
||||
Name: Balloon,
|
||||
Interval: 140,
|
||||
Frames: []string{` `, `.`, `o`, `O`, `@`, `*`, ` `},
|
||||
}
|
||||
case Balloon2:
|
||||
return Spinner{
|
||||
Name: Balloon2,
|
||||
Interval: 120,
|
||||
Frames: []string{`.`, `o`, `O`, `°`, `O`, `o`, `.`},
|
||||
}
|
||||
case Bounce:
|
||||
return Spinner{
|
||||
Name: Bounce,
|
||||
Interval: 120,
|
||||
Frames: []string{`⠁`, `⠂`, `⠄`, `⠂`},
|
||||
}
|
||||
case BouncingBall:
|
||||
return Spinner{
|
||||
Name: BouncingBall,
|
||||
Interval: 80,
|
||||
Frames: []string{`( ● )`, `( ● )`, `( ● )`, `( ● )`, `( ●)`, `( ● )`, `( ● )`, `( ● )`, `( ● )`, `(● )`},
|
||||
}
|
||||
case BouncingBar:
|
||||
return Spinner{
|
||||
Name: BouncingBar,
|
||||
Interval: 80,
|
||||
Frames: []string{`[ ]`, `[= ]`, `[== ]`, `[=== ]`, `[ ===]`, `[ ==]`, `[ =]`, `[ ]`, `[ =]`, `[ ==]`, `[ ===]`, `[====]`, `[=== ]`, `[== ]`, `[= ]`},
|
||||
}
|
||||
case BoxBounce:
|
||||
return Spinner{
|
||||
Name: BoxBounce,
|
||||
Interval: 120,
|
||||
Frames: []string{`▖`, `▘`, `▝`, `▗`},
|
||||
}
|
||||
case BoxBounce2:
|
||||
return Spinner{
|
||||
Name: BoxBounce2,
|
||||
Interval: 100,
|
||||
Frames: []string{`▌`, `▀`, `▐`, `▄`},
|
||||
}
|
||||
case Christmas:
|
||||
return Spinner{
|
||||
Name: Christmas,
|
||||
Interval: 400,
|
||||
Frames: []string{`🌲`, `🎄`},
|
||||
}
|
||||
case Circle:
|
||||
return Spinner{
|
||||
Name: Circle,
|
||||
Interval: 120,
|
||||
Frames: []string{`◡`, `⊙`, `◠`},
|
||||
}
|
||||
case CircleHalves:
|
||||
return Spinner{
|
||||
Name: CircleHalves,
|
||||
Interval: 50,
|
||||
Frames: []string{`◐`, `◓`, `◑`, `◒`},
|
||||
}
|
||||
case CircleQuarters:
|
||||
return Spinner{
|
||||
Name: CircleQuarters,
|
||||
Interval: 120,
|
||||
Frames: []string{`◴`, `◷`, `◶`, `◵`},
|
||||
}
|
||||
case Clock:
|
||||
return Spinner{
|
||||
Name: Clock,
|
||||
Interval: 100,
|
||||
Frames: []string{`🕐 `, `🕑 `, `🕒 `, `🕓 `, `🕔 `, `🕕 `, `🕖 `, `🕗 `, `🕘 `, `🕙 `, `🕚 `},
|
||||
}
|
||||
case Dots:
|
||||
return Spinner{
|
||||
Name: Dots,
|
||||
Interval: 80,
|
||||
Frames: []string{`⠋`, `⠙`, `⠹`, `⠸`, `⠼`, `⠴`, `⠦`, `⠧`, `⠇`, `⠏`},
|
||||
}
|
||||
case Dots10:
|
||||
return Spinner{
|
||||
Name: Dots10,
|
||||
Interval: 80,
|
||||
Frames: []string{`⢄`, `⢂`, `⢁`, `⡁`, `⡈`, `⡐`, `⡠`},
|
||||
}
|
||||
case Dots11:
|
||||
return Spinner{
|
||||
Name: Dots11,
|
||||
Interval: 100,
|
||||
Frames: []string{`⠁`, `⠂`, `⠄`, `⡀`, `⢀`, `⠠`, `⠐`, `⠈`},
|
||||
}
|
||||
case Dots12:
|
||||
return Spinner{
|
||||
Name: Dots12,
|
||||
Interval: 80,
|
||||
Frames: []string{`⢀⠀`, `⡀⠀`, `⠄⠀`, `⢂⠀`, `⡂⠀`, `⠅⠀`, `⢃⠀`, `⡃⠀`, `⠍⠀`, `⢋⠀`, `⡋⠀`, `⠍⠁`, `⢋⠁`, `⡋⠁`, `⠍⠉`, `⠋⠉`, `⠋⠉`, `⠉⠙`, `⠉⠙`, `⠉⠩`, `⠈⢙`, `⠈⡙`, `⢈⠩`, `⡀⢙`, `⠄⡙`, `⢂⠩`, `⡂⢘`, `⠅⡘`, `⢃⠨`, `⡃⢐`, `⠍⡐`, `⢋⠠`, `⡋⢀`, `⠍⡁`, `⢋⠁`, `⡋⠁`, `⠍⠉`, `⠋⠉`, `⠋⠉`, `⠉⠙`, `⠉⠙`, `⠉⠩`, `⠈⢙`, `⠈⡙`, `⠈⠩`, `⠀⢙`, `⠀⡙`, `⠀⠩`, `⠀⢘`, `⠀⡘`, `⠀⠨`, `⠀⢐`, `⠀⡐`, `⠀⠠`, `⠀⢀`, `⠀⡀`},
|
||||
}
|
||||
case Dots2:
|
||||
return Spinner{
|
||||
Name: Dots2,
|
||||
Interval: 80,
|
||||
Frames: []string{`⣾`, `⣽`, `⣻`, `⢿`, `⡿`, `⣟`, `⣯`, `⣷`},
|
||||
}
|
||||
case Dots3:
|
||||
return Spinner{
|
||||
Name: Dots3,
|
||||
Interval: 80,
|
||||
Frames: []string{`⠋`, `⠙`, `⠚`, `⠞`, `⠖`, `⠦`, `⠴`, `⠲`, `⠳`, `⠓`},
|
||||
}
|
||||
case Dots4:
|
||||
return Spinner{
|
||||
Name: Dots4,
|
||||
Interval: 80,
|
||||
Frames: []string{`⠄`, `⠆`, `⠇`, `⠋`, `⠙`, `⠸`, `⠰`, `⠠`, `⠰`, `⠸`, `⠙`, `⠋`, `⠇`, `⠆`},
|
||||
}
|
||||
case Dots5:
|
||||
return Spinner{
|
||||
Name: Dots5,
|
||||
Interval: 80,
|
||||
Frames: []string{`⠋`, `⠙`, `⠚`, `⠒`, `⠂`, `⠂`, `⠒`, `⠲`, `⠴`, `⠦`, `⠖`, `⠒`, `⠐`, `⠐`, `⠒`, `⠓`, `⠋`},
|
||||
}
|
||||
case Dots6:
|
||||
return Spinner{
|
||||
Name: Dots6,
|
||||
Interval: 80,
|
||||
Frames: []string{`⠁`, `⠉`, `⠙`, `⠚`, `⠒`, `⠂`, `⠂`, `⠒`, `⠲`, `⠴`, `⠤`, `⠄`, `⠄`, `⠤`, `⠴`, `⠲`, `⠒`, `⠂`, `⠂`, `⠒`, `⠚`, `⠙`, `⠉`, `⠁`},
|
||||
}
|
||||
case Dots7:
|
||||
return Spinner{
|
||||
Name: Dots7,
|
||||
Interval: 80,
|
||||
Frames: []string{`⠈`, `⠉`, `⠋`, `⠓`, `⠒`, `⠐`, `⠐`, `⠒`, `⠖`, `⠦`, `⠤`, `⠠`, `⠠`, `⠤`, `⠦`, `⠖`, `⠒`, `⠐`, `⠐`, `⠒`, `⠓`, `⠋`, `⠉`, `⠈`},
|
||||
}
|
||||
case Dots8:
|
||||
return Spinner{
|
||||
Name: Dots8,
|
||||
Interval: 80,
|
||||
Frames: []string{`⠁`, `⠁`, `⠉`, `⠙`, `⠚`, `⠒`, `⠂`, `⠂`, `⠒`, `⠲`, `⠴`, `⠤`, `⠄`, `⠄`, `⠤`, `⠠`, `⠠`, `⠤`, `⠦`, `⠖`, `⠒`, `⠐`, `⠐`, `⠒`, `⠓`, `⠋`, `⠉`, `⠈`, `⠈`},
|
||||
}
|
||||
case Dots9:
|
||||
return Spinner{
|
||||
Name: Dots9,
|
||||
Interval: 80,
|
||||
Frames: []string{`⢹`, `⢺`, `⢼`, `⣸`, `⣇`, `⡧`, `⡗`, `⡏`},
|
||||
}
|
||||
case Dqpb:
|
||||
return Spinner{
|
||||
Name: Dqpb,
|
||||
Interval: 100,
|
||||
Frames: []string{`d`, `q`, `p`, `b`},
|
||||
}
|
||||
case Earth:
|
||||
return Spinner{
|
||||
Name: Earth,
|
||||
Interval: 180,
|
||||
Frames: []string{`🌍 `, `🌎 `, `🌏 `},
|
||||
}
|
||||
case Flip:
|
||||
return Spinner{
|
||||
Name: Flip,
|
||||
Interval: 70,
|
||||
Frames: []string{`_`, `_`, `_`, `-`, "`", "`", `'`, `´`, `-`, `_`, `_`, `_`},
|
||||
}
|
||||
case GrowHorizontal:
|
||||
return Spinner{
|
||||
Name: GrowHorizontal,
|
||||
Interval: 120,
|
||||
Frames: []string{`▏`, `▎`, `▍`, `▌`, `▋`, `▊`, `▉`, `▊`, `▋`, `▌`, `▍`, `▎`},
|
||||
}
|
||||
case GrowVertical:
|
||||
return Spinner{
|
||||
Name: GrowVertical,
|
||||
Interval: 120,
|
||||
Frames: []string{`▁`, `▃`, `▄`, `▅`, `▆`, `▇`, `▆`, `▅`, `▄`, `▃`},
|
||||
}
|
||||
case Hamburger:
|
||||
return Spinner{
|
||||
Name: Hamburger,
|
||||
Interval: 100,
|
||||
Frames: []string{`☱`, `☲`, `☴`},
|
||||
}
|
||||
case Hearts:
|
||||
return Spinner{
|
||||
Name: Hearts,
|
||||
Interval: 100,
|
||||
Frames: []string{`💛 `, `💙 `, `💜 `, `💚 `, `❤️ `},
|
||||
}
|
||||
case Line:
|
||||
return Spinner{
|
||||
Name: Line,
|
||||
Interval: 130,
|
||||
Frames: []string{`-`, `\`, `|`, `/`},
|
||||
}
|
||||
case Line2:
|
||||
return Spinner{
|
||||
Name: Line2,
|
||||
Interval: 100,
|
||||
Frames: []string{`⠂`, `-`, `–`, `—`, `–`, `-`},
|
||||
}
|
||||
case Monkey:
|
||||
return Spinner{
|
||||
Name: Monkey,
|
||||
Interval: 300,
|
||||
Frames: []string{`🙈 `, `🙈 `, `🙉 `, `🙊 `},
|
||||
}
|
||||
case Moon:
|
||||
return Spinner{
|
||||
Name: Moon,
|
||||
Interval: 80,
|
||||
Frames: []string{`🌑 `, `🌒 `, `🌓 `, `🌔 `, `🌕 `, `🌖 `, `🌗 `, `🌘 `},
|
||||
}
|
||||
case Noise:
|
||||
return Spinner{
|
||||
Name: Noise,
|
||||
Interval: 100,
|
||||
Frames: []string{`▓`, `▒`, `░`},
|
||||
}
|
||||
case Pipe:
|
||||
return Spinner{
|
||||
Name: Pipe,
|
||||
Interval: 100,
|
||||
Frames: []string{`┤`, `┘`, `┴`, `└`, `├`, `┌`, `┬`, `┐`},
|
||||
}
|
||||
case Pong:
|
||||
return Spinner{
|
||||
Name: Pong,
|
||||
Interval: 80,
|
||||
Frames: []string{`▐⠂ ▌`, `▐⠈ ▌`, `▐ ⠂ ▌`, `▐ ⠠ ▌`, `▐ ⡀ ▌`, `▐ ⠠ ▌`, `▐ ⠂ ▌`, `▐ ⠈ ▌`, `▐ ⠂ ▌`, `▐ ⠠ ▌`, `▐ ⡀ ▌`, `▐ ⠠ ▌`, `▐ ⠂ ▌`, `▐ ⠈ ▌`, `▐ ⠂▌`, `▐ ⠠▌`, `▐ ⡀▌`, `▐ ⠠ ▌`, `▐ ⠂ ▌`, `▐ ⠈ ▌`, `▐ ⠂ ▌`, `▐ ⠠ ▌`, `▐ ⡀ ▌`, `▐ ⠠ ▌`, `▐ ⠂ ▌`, `▐ ⠈ ▌`, `▐ ⠂ ▌`, `▐ ⠠ ▌`, `▐ ⡀ ▌`, `▐⠠ ▌`},
|
||||
}
|
||||
case Runner:
|
||||
return Spinner{
|
||||
Name: Runner,
|
||||
Interval: 140,
|
||||
Frames: []string{`🚶 `, `🏃 `},
|
||||
}
|
||||
case Shark:
|
||||
return Spinner{
|
||||
Name: Shark,
|
||||
Interval: 120,
|
||||
Frames: []string{`▐|\____________▌`, `▐_|\___________▌`, `▐__|\__________▌`, `▐___|\_________▌`, `▐____|\________▌`, `▐_____|\_______▌`, `▐______|\______▌`, `▐_______|\_____▌`, `▐________|\____▌`, `▐_________|\___▌`, `▐__________|\__▌`, `▐___________|\_▌`, `▐____________|\▌`, `▐____________/|▌`, `▐___________/|_▌`, `▐__________/|__▌`, `▐_________/|___▌`, `▐________/|____▌`, `▐_______/|_____▌`, `▐______/|______▌`, `▐_____/|_______▌`, `▐____/|________▌`, `▐___/|_________▌`, `▐__/|__________▌`, `▐_/|___________▌`, `▐/|____________▌`},
|
||||
}
|
||||
case SimpleDots:
|
||||
return Spinner{
|
||||
Name: SimpleDots,
|
||||
Interval: 400,
|
||||
Frames: []string{`. `, `.. `, `...`, ` `},
|
||||
}
|
||||
case SimpleDotsScrolling:
|
||||
return Spinner{
|
||||
Name: SimpleDotsScrolling,
|
||||
Interval: 200,
|
||||
Frames: []string{`. `, `.. `, `...`, ` ..`, ` .`, ` `},
|
||||
}
|
||||
case Smiley:
|
||||
return Spinner{
|
||||
Name: Smiley,
|
||||
Interval: 200,
|
||||
Frames: []string{`😄 `, `😝 `},
|
||||
}
|
||||
case SquareCorners:
|
||||
return Spinner{
|
||||
Name: SquareCorners,
|
||||
Interval: 180,
|
||||
Frames: []string{`◰`, `◳`, `◲`, `◱`},
|
||||
}
|
||||
case Squish:
|
||||
return Spinner{
|
||||
Name: Squish,
|
||||
Interval: 100,
|
||||
Frames: []string{`╫`, `╪`},
|
||||
}
|
||||
case Star:
|
||||
return Spinner{
|
||||
Name: Star,
|
||||
Interval: 70,
|
||||
Frames: []string{`✶`, `✸`, `✹`, `✺`, `✹`, `✷`},
|
||||
}
|
||||
case Star2:
|
||||
return Spinner{
|
||||
Name: Star2,
|
||||
Interval: 80,
|
||||
Frames: []string{`+`, `x`, `*`},
|
||||
}
|
||||
case Toggle:
|
||||
return Spinner{
|
||||
Name: Toggle,
|
||||
Interval: 250,
|
||||
Frames: []string{`⊶`, `⊷`},
|
||||
}
|
||||
case Toggle10:
|
||||
return Spinner{
|
||||
Name: Toggle10,
|
||||
Interval: 100,
|
||||
Frames: []string{`㊂`, `㊀`, `㊁`},
|
||||
}
|
||||
case Toggle11:
|
||||
return Spinner{
|
||||
Name: Toggle11,
|
||||
Interval: 50,
|
||||
Frames: []string{`⧇`, `⧆`},
|
||||
}
|
||||
case Toggle12:
|
||||
return Spinner{
|
||||
Name: Toggle12,
|
||||
Interval: 120,
|
||||
Frames: []string{`☗`, `☖`},
|
||||
}
|
||||
case Toggle13:
|
||||
return Spinner{
|
||||
Name: Toggle13,
|
||||
Interval: 80,
|
||||
Frames: []string{`=`, `*`, `-`},
|
||||
}
|
||||
case Toggle2:
|
||||
return Spinner{
|
||||
Name: Toggle2,
|
||||
Interval: 80,
|
||||
Frames: []string{`▫`, `▪`},
|
||||
}
|
||||
case Toggle3:
|
||||
return Spinner{
|
||||
Name: Toggle3,
|
||||
Interval: 120,
|
||||
Frames: []string{`□`, `■`},
|
||||
}
|
||||
case Toggle4:
|
||||
return Spinner{
|
||||
Name: Toggle4,
|
||||
Interval: 100,
|
||||
Frames: []string{`■`, `□`, `▪`, `▫`},
|
||||
}
|
||||
case Toggle5:
|
||||
return Spinner{
|
||||
Name: Toggle5,
|
||||
Interval: 100,
|
||||
Frames: []string{`▮`, `▯`},
|
||||
}
|
||||
case Toggle6:
|
||||
return Spinner{
|
||||
Name: Toggle6,
|
||||
Interval: 300,
|
||||
Frames: []string{`ဝ`, `၀`},
|
||||
}
|
||||
case Toggle7:
|
||||
return Spinner{
|
||||
Name: Toggle7,
|
||||
Interval: 80,
|
||||
Frames: []string{`⦾`, `⦿`},
|
||||
}
|
||||
case Toggle8:
|
||||
return Spinner{
|
||||
Name: Toggle8,
|
||||
Interval: 100,
|
||||
Frames: []string{`◍`, `◌`},
|
||||
}
|
||||
case Toggle9:
|
||||
return Spinner{
|
||||
Name: Toggle9,
|
||||
Interval: 100,
|
||||
Frames: []string{`◉`, `◎`},
|
||||
}
|
||||
case Triangle:
|
||||
return Spinner{
|
||||
Name: Triangle,
|
||||
Interval: 50,
|
||||
Frames: []string{`◢`, `◣`, `◤`, `◥`},
|
||||
}
|
||||
case Weather:
|
||||
return Spinner{
|
||||
Name: Weather,
|
||||
Interval: 100,
|
||||
Frames: []string{`☀️ `, `☀️ `, `☀️ `, `🌤 `, `⛅️ `, `🌥 `, `☁️ `, `🌧 `, `🌨 `, `🌧 `, `🌨 `, `🌧 `, `🌨 `, `⛈ `, `🌨 `, `🌧 `, `🌨 `, `☁️ `, `🌥 `, `⛅️ `, `🌤 `, `☀️ `, `☀️ `},
|
||||
}
|
||||
default:
|
||||
return Spinner{}
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package wow
|
||||
|
||||
import "runtime"
|
||||
|
||||
// LogSymbol is a log severity level
|
||||
type LogSymbol uint
|
||||
|
||||
// common log symbos
|
||||
const (
|
||||
INFO LogSymbol = iota
|
||||
SUCCESS
|
||||
WARNING
|
||||
ERROR
|
||||
)
|
||||
|
||||
func (s LogSymbol) String() string {
|
||||
if runtime.GOOS != "windows" {
|
||||
switch s {
|
||||
case INFO:
|
||||
return "ℹ"
|
||||
case SUCCESS:
|
||||
return "✔"
|
||||
case WARNING:
|
||||
return "⚠"
|
||||
case ERROR:
|
||||
return "✖"
|
||||
}
|
||||
} else {
|
||||
switch s {
|
||||
case INFO:
|
||||
return "i"
|
||||
case SUCCESS:
|
||||
return "v"
|
||||
case WARNING:
|
||||
return "!!"
|
||||
case ERROR:
|
||||
return "x"
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
package wow
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gernest/wow/spin"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
const erase = "\033[2K\r"
|
||||
|
||||
// Wow writes beautiful spinners on the terminal.
|
||||
type Wow struct {
|
||||
txt string
|
||||
s spin.Spinner
|
||||
out io.Writer
|
||||
running bool
|
||||
done func()
|
||||
mu sync.RWMutex
|
||||
IsTerminal bool
|
||||
}
|
||||
|
||||
// New creates a new wow instance ready to start spinning.
|
||||
func New(o io.Writer, s spin.Spinner, text string, options ...func(*Wow)) *Wow {
|
||||
isTerminal := terminal.IsTerminal(int(os.Stdout.Fd()))
|
||||
|
||||
wow := Wow{out: o, s: s, txt: text, IsTerminal: isTerminal}
|
||||
|
||||
for _, option := range options {
|
||||
option(&wow)
|
||||
}
|
||||
|
||||
return &wow
|
||||
}
|
||||
|
||||
// Start starts the spinner. The frames are written based on the spinner
|
||||
// interval.
|
||||
func (w *Wow) Start() {
|
||||
if !w.running {
|
||||
ctx, done := context.WithCancel(context.Background())
|
||||
t := time.NewTicker(time.Duration(w.s.Interval) * time.Millisecond)
|
||||
w.done = done
|
||||
w.running = true
|
||||
go func() {
|
||||
at := 0
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
t.Stop()
|
||||
break
|
||||
case <-t.C:
|
||||
txt := erase + w.s.Frames[at%len(w.s.Frames)] + w.txt
|
||||
if w.IsTerminal {
|
||||
fmt.Fprint(w.out, txt)
|
||||
}
|
||||
at++
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
// Stop stops the spinner
|
||||
func (w *Wow) Stop() {
|
||||
if w.done != nil {
|
||||
w.done()
|
||||
}
|
||||
w.running = false
|
||||
}
|
||||
|
||||
// Spinner sets s to the current spinner
|
||||
func (w *Wow) Spinner(s spin.Spinner) *Wow {
|
||||
w.Stop()
|
||||
w.s = s
|
||||
w.Start()
|
||||
return w
|
||||
}
|
||||
|
||||
// Text adds text to the current spinner
|
||||
func (w *Wow) Text(txt string) *Wow {
|
||||
w.mu.Lock()
|
||||
w.txt = txt
|
||||
w.mu.Unlock()
|
||||
return w
|
||||
}
|
||||
|
||||
// Persist writes the last character of the currect spinner frames together with
|
||||
// the text on stdout.
|
||||
//
|
||||
// A new line is added at the end to ensure the text stay that way.
|
||||
func (w *Wow) Persist() {
|
||||
w.Stop()
|
||||
at := len(w.s.Frames) - 1
|
||||
txt := erase + w.s.Frames[at] + w.txt + "\n"
|
||||
if w.IsTerminal {
|
||||
fmt.Fprint(w.out, txt)
|
||||
}
|
||||
}
|
||||
|
||||
// PersistWith writes the last frame of s together with text with a new line
|
||||
// added to make it stick.
|
||||
func (w *Wow) PersistWith(s spin.Spinner, text string) {
|
||||
w.Stop()
|
||||
var a string
|
||||
if len(s.Frames) > 0 {
|
||||
a = s.Frames[len(s.Frames)-1]
|
||||
}
|
||||
txt := erase + a + text + "\n"
|
||||
if w.IsTerminal {
|
||||
fmt.Fprint(w.out, txt)
|
||||
}
|
||||
}
|
||||
|
||||
// ForceOutput forces all output even if not not outputting directly to a terminal
|
||||
func ForceOutput(w *Wow) {
|
||||
w.IsTerminal = true
|
||||
}
|
||||
Reference in New Issue
Block a user