-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.go
114 lines (101 loc) · 2.1 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package main
import (
"errors"
"fmt"
"os"
"os/exec"
"time"
"github.com/avast/retry-go/v4"
"github.com/spf13/pflag"
)
var (
version = "dev"
commit = "none"
date = "unknown"
)
func main() {
var opt = Option{}
cli := pflag.NewFlagSet("try", pflag.ContinueOnError)
cli.UintVar(&opt.Limit, "limit", 5, "max retry, set limit to 0 to disable limit")
cli.DurationVar(&opt.Delay, "delay", time.Millisecond*100, "retry delay")
cli.BoolVar(&opt.Quiet, "quiet", false, "hide command stdout/stderr")
flags, cmd := partitionCommand(os.Args[1:])
if len(cmd) == 0 {
if contains(flags, "--version") {
fmt.Printf("version: %s\n", version)
fmt.Printf("commit: %s\n", commit)
fmt.Printf("build at: %s\n", date)
os.Exit(0)
} else {
// handle help message
fmt.Println("Usage: try [flags] -- command")
fmt.Println("\nflags:")
cli.PrintDefaults()
os.Exit(1)
}
}
if err := cli.Parse(flags); err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
err := opt.Retry(cmd[0], cmd[1:])
if opt.Quiet {
fmt.Println()
}
if err != nil {
if errors.As(err, &retry.Error{}) {
fmt.Println("All attempts fail")
} else {
fmt.Println(err.Error())
}
os.Exit(2)
}
}
type Option struct {
Limit uint
Delay time.Duration
Quiet bool
}
func (o Option) Retry(cmd string, args []string) error {
return retry.Do(
func() error {
c := exec.Command(cmd, args...)
if !o.Quiet {
c.Stderr = os.Stderr
c.Stdout = os.Stdout
}
return c.Run()
},
retry.Attempts(o.Limit),
retry.Delay(o.Delay),
retry.DelayType(retry.FixedDelay),
retry.OnRetry(func(n uint, err error) {
if o.Quiet {
fmt.Print(".")
} else {
fmt.Printf("--- failed %d time(s), err: %s ---\n", n+1, err)
}
}),
)
}
func partitionCommand(args []string) ([]string, []string) {
var splitIndex = -1
for i, arg := range args {
if arg == "--" {
splitIndex = i
break
}
}
if splitIndex == -1 {
return args, []string{}
}
return args[:splitIndex], args[splitIndex+1:]
}
func contains(s []string, item string) bool {
for _, i := range s {
if i == item {
return true
}
}
return false
}