fix: loading print panic
This commit is contained in:
parent
8235631d4f
commit
16c018abbd
123
nft/loading/loading.go
Normal file
123
nft/loading/loading.go
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
package loading
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Type int
|
||||||
|
|
||||||
|
const (
|
||||||
|
TypeProcessing Type = iota
|
||||||
|
TypeInfo
|
||||||
|
TypeSuccess
|
||||||
|
TypeWarning
|
||||||
|
TypeError
|
||||||
|
)
|
||||||
|
|
||||||
|
func (t Type) Symbol() string {
|
||||||
|
switch t {
|
||||||
|
case TypeSuccess:
|
||||||
|
return "✔️ "
|
||||||
|
case TypeWarning:
|
||||||
|
return "❗ "
|
||||||
|
case TypeError:
|
||||||
|
return "❌ "
|
||||||
|
case TypeInfo:
|
||||||
|
return "❕ "
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type _msg struct {
|
||||||
|
msg string
|
||||||
|
t Type
|
||||||
|
}
|
||||||
|
|
||||||
|
var frames = []string{"|", "/", "-", "\\"}
|
||||||
|
|
||||||
|
func Do(ctx context.Context, fn func(ctx context.Context, print func(msg string, types ...Type)) error) (err error) {
|
||||||
|
start := time.Now()
|
||||||
|
ch := make(chan *_msg)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
fmt.Printf("\r\033[K")
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
var (
|
||||||
|
m *_msg
|
||||||
|
ok bool
|
||||||
|
processing string
|
||||||
|
)
|
||||||
|
|
||||||
|
for {
|
||||||
|
for _, frame := range frames {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case m, ok = <-ch:
|
||||||
|
if !ok || m == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch m.t {
|
||||||
|
case TypeProcessing:
|
||||||
|
if m.msg != "" {
|
||||||
|
processing = m.msg
|
||||||
|
}
|
||||||
|
case TypeInfo,
|
||||||
|
TypeSuccess,
|
||||||
|
TypeWarning,
|
||||||
|
TypeError:
|
||||||
|
// Clear the loading animation
|
||||||
|
fmt.Printf("\r\033[K")
|
||||||
|
fmt.Printf("%s%s\n", m.t.Symbol(), m.msg)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
elapsed := time.Since(start).Seconds()
|
||||||
|
if processing != "" {
|
||||||
|
fmt.Printf("\r\033[K%s %s (%.2fs)", frame, processing, elapsed)
|
||||||
|
}
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
printFn := func(msg string, types ...Type) {
|
||||||
|
if msg == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
m := &_msg{
|
||||||
|
msg: msg,
|
||||||
|
t: TypeProcessing,
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(types) > 0 {
|
||||||
|
m.t = types[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
ch <- m
|
||||||
|
}
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
if err = fn(ctx, printFn); err != nil {
|
||||||
|
ch <- &_msg{msg: err.Error(), t: TypeError}
|
||||||
|
}
|
||||||
|
|
||||||
|
close(ch)
|
||||||
|
done <- struct{}{}
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
case <-done:
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
25
nft/loading/loading_test.go
Normal file
25
nft/loading/loading_test.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package loading
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLoadingPrint(t *testing.T) {
|
||||||
|
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
Do(ctx, func(ctx context.Context, print func(msg string, types ...Type)) error {
|
||||||
|
print("start task 1...")
|
||||||
|
time.Sleep(3 * time.Second)
|
||||||
|
|
||||||
|
print("warning...1", TypeWarning)
|
||||||
|
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
@ -3,6 +3,7 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
@ -11,9 +12,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
|
"github.com/loveuer/nf/nft/loading"
|
||||||
"github.com/loveuer/nf/nft/log"
|
"github.com/loveuer/nf/nft/log"
|
||||||
"github.com/loveuer/nf/nft/nfctl/internal/opt"
|
"github.com/loveuer/nf/nft/nfctl/internal/opt"
|
||||||
"github.com/loveuer/nf/nft/nfctl/pkg/loading"
|
|
||||||
"github.com/loveuer/nf/nft/tool"
|
"github.com/loveuer/nf/nft/tool"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
@ -32,7 +33,7 @@ func initNew() *cobra.Command {
|
|||||||
return newCmd
|
return newCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func doNew(cmd *cobra.Command, args []string) error {
|
func doNew(cmd *cobra.Command, args []string) (err error) {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
return errors.New("必须提供 project 名称")
|
return errors.New("必须提供 project 名称")
|
||||||
}
|
}
|
||||||
@ -46,15 +47,11 @@ func doNew(cmd *cobra.Command, args []string) error {
|
|||||||
return errors.New("project 名称不能以 . 开头")
|
return errors.New("project 名称不能以 . 开头")
|
||||||
}
|
}
|
||||||
|
|
||||||
ch := make(chan *loading.Loading)
|
return loading.Do(cmd.Context(), func(ctx context.Context, print func(msg string, types ...loading.Type)) error {
|
||||||
defer close(ch)
|
print("开始新建项目: "+args[0], loading.TypeInfo)
|
||||||
|
|
||||||
go loading.Print(cmd.Context(), ch)
|
|
||||||
ch <- &loading.Loading{Content: "开始新建项目: " + args[0], Type: loading.TypeInfo}
|
|
||||||
|
|
||||||
pwd, err := os.Getwd()
|
pwd, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ch <- &loading.Loading{Content: err.Error(), Type: loading.TypeError}
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +60,7 @@ func doNew(cmd *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
log.Debug("cmd.new: new project, pwd = %s, name = %s, template = %s", pwd, moduleName, opt.Cfg.New.Template)
|
log.Debug("cmd.new: new project, pwd = %s, name = %s, template = %s", pwd, moduleName, opt.Cfg.New.Template)
|
||||||
|
|
||||||
ch <- &loading.Loading{Content: "开始下载模板: " + opt.Cfg.New.Template, Type: loading.TypeProcessing}
|
print("开始下载模板: "+opt.Cfg.New.Template, loading.TypeProcessing)
|
||||||
|
|
||||||
repo := opt.Cfg.New.Template
|
repo := opt.Cfg.New.Template
|
||||||
if v, ok := opt.TemplateMap[repo]; ok {
|
if v, ok := opt.TemplateMap[repo]; ok {
|
||||||
@ -71,17 +68,16 @@ func doNew(cmd *cobra.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err = tool.Clone(pwd, repo); err != nil {
|
if err = tool.Clone(pwd, repo); err != nil {
|
||||||
ch <- &loading.Loading{Content: err.Error(), Type: loading.TypeError}
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ch <- &loading.Loading{Content: "下载模板完成: " + opt.Cfg.New.Template, Type: loading.TypeSuccess}
|
print("下载模板完成: "+opt.Cfg.New.Template, loading.TypeSuccess)
|
||||||
|
|
||||||
if err = os.RemoveAll(path.Join(pwd, ".git")); err != nil {
|
if err = os.RemoveAll(path.Join(pwd, ".git")); err != nil {
|
||||||
ch <- &loading.Loading{Content: err.Error(), Type: loading.TypeWarning}
|
print(err.Error(), loading.TypeWarning)
|
||||||
}
|
}
|
||||||
|
|
||||||
ch <- &loading.Loading{Content: "开始初始化项目: " + args[0], Type: loading.TypeProcessing}
|
print("开始初始化项目: "+args[0], loading.TypeProcessing)
|
||||||
|
|
||||||
if err = filepath.Walk(pwd, func(path string, info os.FileInfo, err error) error {
|
if err = filepath.Walk(pwd, func(path string, info os.FileInfo, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -95,8 +91,8 @@ func doNew(cmd *cobra.Command, args []string) error {
|
|||||||
if strings.HasSuffix(path, ".go") || strings.HasSuffix(path, "go.mod") {
|
if strings.HasSuffix(path, ".go") || strings.HasSuffix(path, "go.mod") {
|
||||||
var content []byte
|
var content []byte
|
||||||
if content, err = os.ReadFile(path); err != nil {
|
if content, err = os.ReadFile(path); err != nil {
|
||||||
ch <- &loading.Loading{Content: "初始化文件失败: " + err.Error(), Type: loading.TypeWarning}
|
print("初始化文件失败: "+err.Error(), loading.TypeWarning)
|
||||||
ch <- &loading.Loading{Content: "开始初始化项目: " + args[0], Type: loading.TypeProcessing}
|
print("开始初始化项目: "+args[0], loading.TypeProcessing)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,7 +113,6 @@ func doNew(cmd *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
ch <- &loading.Loading{Content: "初始化文件失败: " + err.Error(), Type: loading.TypeWarning}
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,13 +123,13 @@ func doNew(cmd *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
if render, err = template.New(base).Parse(opt.README); err != nil {
|
if render, err = template.New(base).Parse(opt.README); err != nil {
|
||||||
log.Debug("cmd.new: new text template err, err = %s", err.Error())
|
log.Debug("cmd.new: new text template err, err = %s", err.Error())
|
||||||
ch <- &loading.Loading{Content: "生成 readme 失败", Type: loading.TypeWarning}
|
print("生成 readme 失败", loading.TypeWarning)
|
||||||
goto END
|
goto END
|
||||||
}
|
}
|
||||||
|
|
||||||
if rf, err = os.OpenFile(path.Join(pwd, "readme.md"), os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0o644); err != nil {
|
if rf, err = os.OpenFile(path.Join(pwd, "readme.md"), os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0o644); err != nil {
|
||||||
log.Debug("cmd.new: new readme file err, err = %s", err.Error())
|
log.Debug("cmd.new: new readme file err, err = %s", err.Error())
|
||||||
ch <- &loading.Loading{Content: "生成 readme 失败", Type: loading.TypeWarning}
|
print("生成 readme 失败", loading.TypeWarning)
|
||||||
goto END
|
goto END
|
||||||
}
|
}
|
||||||
defer rf.Close()
|
defer rf.Close()
|
||||||
@ -143,11 +138,12 @@ func doNew(cmd *cobra.Command, args []string) error {
|
|||||||
"project_name": base,
|
"project_name": base,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
log.Debug("cmd.new: template execute err, err = %s", err.Error())
|
log.Debug("cmd.new: template execute err, err = %s", err.Error())
|
||||||
ch <- &loading.Loading{Content: "生成 readme 失败", Type: loading.TypeWarning}
|
print("生成 readme 失败", loading.TypeWarning)
|
||||||
}
|
}
|
||||||
|
|
||||||
END:
|
END:
|
||||||
ch <- &loading.Loading{Content: fmt.Sprintf("项目: %s 初始化成功", args[0]), Type: loading.TypeSuccess}
|
print(fmt.Sprintf("项目: %s 初始化成功", args[0]), loading.TypeSuccess)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -9,16 +9,19 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
resty "github.com/go-resty/resty/v2"
|
resty "github.com/go-resty/resty/v2"
|
||||||
|
"github.com/loveuer/nf/nft/loading"
|
||||||
"github.com/loveuer/nf/nft/log"
|
"github.com/loveuer/nf/nft/log"
|
||||||
"github.com/loveuer/nf/nft/nfctl/internal/opt"
|
"github.com/loveuer/nf/nft/nfctl/internal/opt"
|
||||||
"github.com/loveuer/nf/nft/nfctl/pkg/loading"
|
"github.com/loveuer/nf/nft/tool"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
var updateCmd = &cobra.Command{
|
var updateCmd = &cobra.Command{
|
||||||
Use: "update",
|
Use: "update",
|
||||||
Short: "update nfctl self",
|
Short: "update nfctl self",
|
||||||
RunE: func(cmd *cobra.Command, args []string) error { return nil },
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func initUpdate() *cobra.Command {
|
func initUpdate() *cobra.Command {
|
||||||
@ -26,15 +29,9 @@ func initUpdate() *cobra.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func doUpdate(ctx context.Context) (err error) {
|
func doUpdate(ctx context.Context) (err error) {
|
||||||
ch := make(chan *loading.Loading)
|
return loading.Do(tool.TimeoutCtx(ctx, 30), func(ctx context.Context, print func(msg string, types ...loading.Type)) error {
|
||||||
defer close(ch)
|
print("正在检查更新...")
|
||||||
|
tip := "❗ 请尝试手动更新: go install github.com/loveuer/nf/nft/nfctl@master"
|
||||||
go func() {
|
|
||||||
loading.Print(ctx, ch)
|
|
||||||
}()
|
|
||||||
|
|
||||||
ch <- &loading.Loading{Content: "正在检查更新...", Type: loading.TypeProcessing}
|
|
||||||
tip := "❗ 请尝试手动更新: go install github.com/loveuer/nf/nft/nfctl@latest"
|
|
||||||
version := ""
|
version := ""
|
||||||
|
|
||||||
var rr *resty.Response
|
var rr *resty.Response
|
||||||
@ -42,7 +39,6 @@ func doUpdate(ctx context.Context) (err error) {
|
|||||||
SetContext(ctx).
|
SetContext(ctx).
|
||||||
Get(opt.VersionURL); err != nil {
|
Get(opt.VersionURL); err != nil {
|
||||||
err = fmt.Errorf("检查更新失败: %s\n%s", err.Error(), tip)
|
err = fmt.Errorf("检查更新失败: %s\n%s", err.Error(), tip)
|
||||||
ch <- &loading.Loading{Content: err.Error(), Type: loading.TypeError}
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,8 +46,7 @@ func doUpdate(ctx context.Context) (err error) {
|
|||||||
|
|
||||||
if rr.StatusCode() != 200 {
|
if rr.StatusCode() != 200 {
|
||||||
err = fmt.Errorf("检查更新失败: %s\n%s", rr.Status(), tip)
|
err = fmt.Errorf("检查更新失败: %s\n%s", rr.Status(), tip)
|
||||||
ch <- &loading.Loading{Content: err.Error(), Type: loading.TypeError}
|
return err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reg := regexp.MustCompile(`const Version = "v\d{2}\.\d{2}\.\d{2}-r\d{1,2}"`)
|
reg := regexp.MustCompile(`const Version = "v\d{2}\.\d{2}\.\d{2}-r\d{1,2}"`)
|
||||||
@ -65,22 +60,24 @@ func doUpdate(ctx context.Context) (err error) {
|
|||||||
|
|
||||||
if version == "" {
|
if version == "" {
|
||||||
err = fmt.Errorf("检查更新失败: 未找到版本信息\n%s", tip)
|
err = fmt.Errorf("检查更新失败: 未找到版本信息\n%s", tip)
|
||||||
ch <- &loading.Loading{Content: err.Error(), Type: loading.TypeError}
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug("cmd.update: find version = %s, now_version = %s", version, opt.Version)
|
log.Debug("cmd.update: find version = %s, now_version = %s", version, opt.Version)
|
||||||
|
|
||||||
if version <= opt.Version {
|
if version <= opt.Version {
|
||||||
ch <- &loading.Loading{Content: fmt.Sprintf("已是最新版本: %s", opt.Version), Type: loading.TypeSuccess}
|
print(fmt.Sprintf("已是最新版本: %s", opt.Version), loading.TypeSuccess)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ch <- &loading.Loading{Content: fmt.Sprintf("发现新版本: %s", version), Type: loading.TypeInfo}
|
print(fmt.Sprintf("发现新版本: %s", version), loading.TypeInfo)
|
||||||
|
|
||||||
ch <- &loading.Loading{Content: fmt.Sprintf("正在更新到 %s ...", version)}
|
print(fmt.Sprintf("正在更新到 %s ...", version))
|
||||||
|
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
ch <- &loading.Loading{Content: "暂时无法自动更新, 请尝试手动更新: go install github.com/loveuer/nf/nft/nfctl@latest", Type: loading.TypeWarning}
|
|
||||||
|
print("暂时无法自动更新, 请尝试手动更新: go install github.com/loveuer/nf/nft/nfctl@master", loading.TypeWarning)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package opt
|
package opt
|
||||||
|
|
||||||
const Version = "v24.12.27-r02"
|
const Version = "v24.12.27-r03"
|
||||||
|
|
||||||
// const VersionURL = "https://github.com/loveuer/nf/nft/nfctl/internal/opt/version.go"
|
// const VersionURL = "https://github.com/loveuer/nf/nft/nfctl/internal/opt/version.go"
|
||||||
|
|
||||||
const VersionURL = "https://raw.githubusercontent.com/loveuer/nf/refs/heads/master/nft/nfctl/internal/opt/version.go"
|
const VersionURL = "https://gitea.loveuer.com/loveuer/nf/raw/branch/master/nft/nfctl/internal/opt/version.go"
|
||||||
|
|
||||||
const Banner = ` ___ __ __
|
const Banner = ` ___ __ __
|
||||||
___ / _/___/ /_/ /
|
___ / _/___/ /_/ /
|
||||||
|
@ -1,81 +0,0 @@
|
|||||||
package loading
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Type int
|
|
||||||
|
|
||||||
const (
|
|
||||||
TypeProcessing Type = iota
|
|
||||||
TypeInfo
|
|
||||||
TypeSuccess
|
|
||||||
TypeWarning
|
|
||||||
TypeError
|
|
||||||
)
|
|
||||||
|
|
||||||
func (t Type) Symbol() string {
|
|
||||||
switch t {
|
|
||||||
case TypeSuccess:
|
|
||||||
return "✔️ "
|
|
||||||
case TypeWarning:
|
|
||||||
return "❗ "
|
|
||||||
case TypeError:
|
|
||||||
return "❌ "
|
|
||||||
case TypeInfo:
|
|
||||||
return "❕ "
|
|
||||||
default:
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type Loading struct {
|
|
||||||
Content string
|
|
||||||
Type Type
|
|
||||||
}
|
|
||||||
|
|
||||||
func Print(ctx context.Context, ch <-chan *Loading) {
|
|
||||||
var (
|
|
||||||
ok bool
|
|
||||||
frames = []string{"|", "/", "-", "\\"}
|
|
||||||
start = time.Now()
|
|
||||||
loading = &Loading{}
|
|
||||||
)
|
|
||||||
|
|
||||||
for {
|
|
||||||
for _, frame := range frames {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return
|
|
||||||
case loading, ok = <-ch:
|
|
||||||
if !ok || loading == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if loading.Content == "" {
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
switch loading.Type {
|
|
||||||
case TypeInfo,
|
|
||||||
TypeSuccess,
|
|
||||||
TypeWarning,
|
|
||||||
TypeError:
|
|
||||||
// Clear the loading animation
|
|
||||||
fmt.Printf("\r\033[K")
|
|
||||||
fmt.Printf("%s%s\n", loading.Type.Symbol(), loading.Content)
|
|
||||||
loading.Content = ""
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
elapsed := time.Since(start).Seconds()
|
|
||||||
if loading.Content != "" {
|
|
||||||
fmt.Printf("\r\033[K%s %s (%.2fs)", frame, loading.Content, elapsed)
|
|
||||||
}
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
package loading
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestLoadingPrint(t *testing.T) {
|
|
||||||
ch := make(chan *Loading)
|
|
||||||
|
|
||||||
Print(context.TODO(), ch)
|
|
||||||
ch <- &Loading{Content: "处理中(1)..."}
|
|
||||||
|
|
||||||
time.Sleep(3 * time.Second)
|
|
||||||
|
|
||||||
ch <- &Loading{Content: "处理完成(1)", Type: TypeSuccess}
|
|
||||||
|
|
||||||
ch <- &Loading{Content: "处理中(2)..."}
|
|
||||||
|
|
||||||
time.Sleep(4 * time.Second)
|
|
||||||
|
|
||||||
ch <- &Loading{Content: "处理失败(2)", Type: TypeError}
|
|
||||||
|
|
||||||
time.Sleep(2 * time.Second)
|
|
||||||
close(ch)
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user