-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcli.go
More file actions
130 lines (112 loc) · 2.96 KB
/
cli.go
File metadata and controls
130 lines (112 loc) · 2.96 KB
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
package main
import (
"os"
"github.com/alecthomas/kong"
)
type InputMode uint8
const (
InputScript InputMode = iota
InputInline
)
type Action uint8
const (
ActionRun Action = iota
ActionBuild
ActionMigrate
ActionExplain
ActionClearCache
)
type Config struct {
Input InputMode
Action Action
ScriptPath string
Args []string
InlineCode string
OutputPath string
MigrateDir string
FieldSep string
Parallel int
Regex string
NoCache bool
}
type cliArgs struct {
FieldSep string `short:"F" help:"Field separator for f/fields in pipe mode (default: whitespace split)."`
Out string `short:"o" help:"Build output path."`
Mig string `short:"m" help:"Migrate script to a Go module directory."`
Parallel int `short:"j" help:"Run pipe loop concurrently with N goroutines." default:"0"`
Regex string `short:"r" help:"Regex pattern for pipe mode: exposes r, m, n, sub(), suball(); skips non-matching lines."`
Explain bool `help:"Print generated Go source without compiling."`
NoCache bool `help:"Skip cache lookup; always recompile."`
ClearCache bool `help:"Delete the goscript cache directory and exit."`
Script string `arg:"" optional:"" help:"Inline Go code snippet or path to a Go script."`
Args []string `arg:"" optional:"" help:"Args passed to the script."`
}
var cli cliArgs
func ParseArgs(argv []string) Config {
ctx := kong.Parse(&cli, kong.Name("goscript"))
ok, errst := validate(cli)
if !ok {
ctx.Errorf("%s", errst)
ctx.PrintUsage(false)
os.Exit(1)
}
cfg := Config{
Args: cli.Args,
OutputPath: cli.Out,
MigrateDir: cli.Mig,
FieldSep: cli.FieldSep,
Parallel: cli.Parallel,
Regex: cli.Regex,
NoCache: cli.NoCache,
}
if isFilePath(cli.Script) {
cfg.Input = InputScript
cfg.ScriptPath = cli.Script
} else {
cfg.Input = InputInline
cfg.InlineCode = cli.Script
}
if cli.FieldSep != "" && cfg.Input != InputInline {
ctx.Errorf("-F only applies to inline mode")
os.Exit(1)
}
if cli.Parallel > 0 && cfg.Input != InputInline {
ctx.Errorf("-j only applies to inline mode")
os.Exit(1)
}
if cli.Regex != "" && cfg.Input != InputInline {
ctx.Errorf("-r only applies to inline mode")
os.Exit(1)
}
switch {
case cli.ClearCache:
cfg.Action = ActionClearCache
case cli.Explain:
cfg.Action = ActionExplain
case cli.Mig != "":
cfg.Action = ActionMigrate
case cli.Out != "":
cfg.Action = ActionBuild
default:
cfg.Action = ActionRun
}
return cfg
}
func validate(cli cliArgs) (bool, string) {
if cli.ClearCache {
return true, ""
}
if cli.Script == "" {
return false, "provide an inline code snippet or a script path"
}
if cli.Out != "" && cli.Mig != "" {
return false, "can't have both output bin and migrate targets"
}
return true, ""
}
// isFilePath reports whether s refers to an existing file on disk.
// Used to distinguish inline code snippets from script paths.
func isFilePath(s string) bool {
_, err := os.Stat(s)
return err == nil
}