This repository has been archived by the owner on May 11, 2022. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
main.go
131 lines (116 loc) · 3.05 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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package main
import (
"bytes"
"flag"
"fmt"
"io"
"os"
"os/exec"
"strings"
"text/template"
"time"
"github.com/briandowns/spinner"
"github.com/fatih/color"
"github.com/kamilsk/breaker"
"github.com/kamilsk/retry/v4"
"github.com/pkg/errors"
_ "github.com/stretchr/testify/assert"
_ "go.octolab.org/toolkit/cli/cobra"
"go.octolab.org/unsafe"
)
const (
success = 0
failure = 1
)
var reportTpl = `
---
command: {{ .Name }}
error: {{ .Error }}
details: started at {{ .Start }}, finished at {{ .End }}, elapsed {{ .Elapsed }}
stdout:
{{ .Stdout }}
stderr:
{{ .Stderr }}
`
func main() { legacy{Args: os.Args, Stderr: os.Stderr, Stdout: os.Stdout, Shutdown: os.Exit}.Run() }
type legacy struct {
Args []string
Stderr, Stdout io.Writer
Shutdown func(code int)
}
// Run executes the tool logic.
func (app legacy) Run() {
var (
result, err = parse(app.Stderr, app.Args[0], app.Args[1:]...)
start, finish time.Time
shutdown, spin = app.Shutdown, spinner.New(spinner.CharSets[17], 100*time.Millisecond)
stderr, stdout = bytes.NewBuffer(nil), bytes.NewBuffer(nil)
report = template.Must(template.New("report").Parse(reportTpl))
)
if err != nil {
if err != flag.ErrHelp {
unsafe.DoSilent(color.New(color.FgRed).Fprintf(app.Stderr, "an error occurred: %v\n", err))
app.Shutdown(failure)
return
}
app.Shutdown(success)
return
}
command := result.Args[0]
if len(result.Args) > 1 {
command += strings.Join(result.Args[1:], " ")
}
{
spin.Prefix = fmt.Sprintf("process `%s`... ", command)
spin.Writer = app.Stderr
app.Shutdown = func(code int) {
finish = time.Now()
if result.Notify {
// TODO try to find or implement by myself
// - https://github.com/variadico/noti
// - https://github.com/jolicode/JoliNotif
unsafe.DoSilent(color.New(color.FgYellow).Fprintln(stderr, "notify component is not ready yet"))
}
unsafe.Ignore(report.Execute(app.Stdout, struct {
Name string
Error string
Start, End string
Elapsed time.Duration
Stdout string
Stderr string
}{
Name: command,
Error: fmt.Sprintf("an error occurred: %v\n", err),
Start: start.Format("2006-01-02 15:04:05.99"),
End: finish.Format("2006-01-02 15:04:05.99"),
Elapsed: finish.Sub(start),
Stdout: stdout.String(),
Stderr: stderr.String(),
}))
spin.Stop()
shutdown(code)
}
}
action := func(attempt uint) error {
if start.IsZero() {
spin.Start()
start = time.Now()
} else {
unsafe.Ignore(spin.Color("red"))
unsafe.DoSilent(color.New(color.FgYellow).Fprintf(stderr, "#%d attempt at %s... \n", attempt+1,
time.Since(start)))
}
cmd := exec.Command(result.Args[0], result.Args[1:]...)
cmd.Stderr, cmd.Stdout = stderr, stdout
return errors.WithStack(cmd.Run())
}
interrupter := breaker.MultiplexTwo(
breaker.BreakByTimeout(result.Timeout),
breaker.BreakBySignal(os.Interrupt),
)
if err = retry.Retry(interrupter, action, result.Strategies...); err != nil {
app.Shutdown(failure)
return
}
app.Shutdown(success)
}