-
Notifications
You must be signed in to change notification settings - Fork 43
/
sysl.go
117 lines (103 loc) · 2.77 KB
/
sysl.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
package main
import (
"fmt"
"io"
"os"
"strings"
"github.com/anz-bank/sysl/pkg/arrai"
"github.com/anz-bank/sysl/pkg/cfg"
"github.com/anz-bank/sysl/pkg/syslutil"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/afero"
"gopkg.in/alecthomas/kingpin.v2"
)
// main3 is the real main function. It takes its output streams and command-line
// arguments as parameters to support testability.
func main3(args []string, fs afero.Fs, logger *logrus.Logger, stdin io.Reader) error {
flags, err := syslutil.PopulateCMDFlagsFromFile(args)
if err == nil && len(flags) > 0 {
// apply flags in file
args = flags
}
syslCmd := kingpin.New("sysl", "System Specification Language Toolkit")
syslCmd.Version(fmt.Sprintf("sysl %s %s", Version, BuildOS))
syslCmd.UsageTemplate(kingpin.SeparateOptionalFlagsUsageTemplate)
(&debugTypeData{}).add(syslCmd)
runner := cmdRunner{}
if err := runner.Configure(syslCmd); err != nil {
return err
}
selectedCommand, err := syslCmd.Parse(args[1:])
if err != nil {
return err
}
return runner.Run(selectedCommand, fs, logger, stdin)
}
type debugTypeData struct {
loglevel string
verbose bool
}
//nolint:unparam
func (d *debugTypeData) do(_ *kingpin.ParseContext) error {
if d.verbose {
d.loglevel = cfg.LogLevel
}
// Default info
syslutil.SetLogLevel(d.loglevel)
logrus.Debugf("Logging: %+v", *d)
return nil
}
func (d *debugTypeData) add(app *kingpin.Application) {
var levels []string
for l := range syslutil.LogLevels {
if l != "" {
levels = append(levels, l)
}
}
app.Flag("log", fmt.Sprintf("log level: [%s]", strings.Join(levels, ","))).
HintOptions(levels...).
Default("warn").
StringVar(&d.loglevel)
app.Flag("verbose", "enable verbose logging").Short('v').BoolVar(&d.verbose)
app.PreAction(d.do)
}
// main2 calls main3 and handles any errors it returns. It takes its output
// streams and command-line arguments and even main3 as parameters to support
// testability.
func main2(
args []string,
fs afero.Fs,
logger *logrus.Logger,
stdin io.Reader,
main3 func(args []string, fs afero.Fs, logger *logrus.Logger, stdin io.Reader) error,
) int {
if err := main3(args, fs, logger, stdin); err != nil {
arraiErr, ok := errors.Cause(err).(arrai.ExecutionError)
var exitCode = 1
if ok {
logger.Debugln(err)
logger.Errorln(arraiErr.ShortMsg)
} else {
if err, ok := err.(syslutil.Exit); ok {
exitCode = err.Code
}
switch exitCode {
case 0:
logger.Infoln(err.Error())
case 2:
logger.Warnln(err.Error())
default:
logger.Errorln(err.Error())
}
}
return exitCode
}
return 0
}
// main is as small as possible to minimise its no-coverage footprint.
func main() {
if rc := main2(os.Args, afero.NewOsFs(), logrus.StandardLogger(), os.Stdin, main3); rc != 0 {
os.Exit(rc)
}
}