@@ -12,11 +12,6 @@ import (
12
12
"unicode"
13
13
)
14
14
15
- const (
16
- plainColumnSep = ":"
17
- smartColumnSep = "@"
18
- )
19
-
20
15
var (
21
16
noExistsClauseFlag = flag .Bool ("no-exists-clause" , false , "Omit IF NOT EXISTS in CREATE TABLE statements" )
22
17
idColumnFlag = flag .String ("id-column" , "id" , "Name of the column that identifies a row" )
@@ -25,41 +20,84 @@ var (
25
20
onlyFlag = flag .String ("only" , "" , "Limit output to 'schema' or 'queries'" )
26
21
)
27
22
23
+ const (
24
+ plainColumnSep = ":"
25
+ smartColumnSep = "@"
26
+ )
27
+
28
+ const (
29
+ exitCodeBadArgument = 1
30
+ exitCodeInternalError = 2
31
+ )
32
+
28
33
var (
29
34
errBadArgument = errors .New ("bad argument" )
30
35
errInvalidSmartColumn = fmt .Errorf ("%w: invalid <smart-column>" , errBadArgument )
31
36
)
32
37
33
- func main () {
34
- flag .CommandLine .SetOutput (os .Stdout )
35
- flag .Usage = printUsage
36
- flag .Parse ()
38
+ // usage contains the inline documentation for sqlcup.
39
+ //go:embed usage.txt
40
+ var usage string
37
41
38
- if err := run (); err != nil {
39
- _ , _ = fmt .Fprintf (os .Stderr , "%s: %s\n " , os .Args [0 ], err )
40
- if errors .Is (err , errBadArgument ) {
41
- flag .Usage ()
42
+ func main () {
43
+ // Suppress error logs from flag package while parsing flags.
44
+ flag .CommandLine .SetOutput (io .Discard )
45
+ // With flag.ContinueOnError we prevent Parse from calling os.Exit on error and instead show our own error message.
46
+ flag .CommandLine .Init (os .Args [0 ], flag .ContinueOnError )
47
+ if err := flag .CommandLine .Parse (os .Args [1 :]); err != nil {
48
+ if err == flag .ErrHelp {
49
+ printHelp ()
50
+ os .Exit (0 )
42
51
}
43
- os .Exit (1 )
52
+ fatalUsageError (err )
53
+ }
54
+
55
+ sca , err := parseScaffoldCommandArgs (flag .CommandLine .Args ())
56
+ if err != nil {
57
+ exitWithError (err )
58
+ }
59
+
60
+ err = scaffoldCommand (sca )
61
+ if err != nil {
62
+ exitWithError (err )
44
63
}
45
64
}
46
65
47
- //go:embed usage.txt
48
- var usage string
66
+ // fatalUsageError writes the inline help to os.Stdout and the err to os.Stderr, then calls os.Exit(1).
67
+ //goland:noinspection GoUnhandledErrorResult
68
+ func fatalUsageError (err error ) {
69
+ printHelp ()
70
+
71
+ // Write error message to stderr.
72
+ fmt .Fprintf (os .Stderr , "%s: %s\n " , os .Args [0 ], err )
73
+
74
+ // Exit process with non-zero status code to indicate failure to the calling process.
75
+ os .Exit (exitCodeBadArgument )
76
+ }
49
77
50
78
//goland:noinspection GoUnhandledErrorResult
51
- func printUsage () {
52
- w := flag .CommandLine .Output ()
53
- fmt .Fprintln (w , usage )
54
- flag .PrintDefaults ()
79
+ func printHelp () {
80
+ // Write usage documentation for sqlcup to stdout.
81
+ fmt .Fprintln (os .Stdout , usage )
82
+
83
+ // Write flag documentation and defaults to stdout.
84
+ flag .CommandLine .SetOutput (os .Stdout )
85
+ flag .CommandLine .PrintDefaults ()
86
+ flag .CommandLine .SetOutput (io .Discard )
87
+ fmt .Fprintln (os .Stdout )
55
88
}
56
89
57
- func run () error {
58
- sca , err := parseScaffoldCommandArgs (flag .Args ())
59
- if err != nil {
60
- return err
90
+ // exitWithError prints err to os.Stderr and calls os.Exit.
91
+ // If err is (or wraps) errBadArgument, inline documentation is written to os.Stdout.
92
+ //goland:noinspection GoUnhandledErrorResult
93
+ func exitWithError (err error ) {
94
+ if errors .Is (err , errBadArgument ) {
95
+ fatalUsageError (err )
96
+ } else {
97
+ // This is not a user error, so we don't write inline help.
98
+ fmt .Fprintf (os .Stderr , "%s: %s\n " , os .Args [0 ], err )
99
+ os .Exit (exitCodeInternalError )
61
100
}
62
- return scaffoldCommand (sca )
63
101
}
64
102
65
103
type column struct {
@@ -152,7 +190,7 @@ func parseSmartColumnDefinition(s string) (column, error) {
152
190
case "blob" :
153
191
colType = "BLOB"
154
192
default :
155
- return column {}, fmt .Errorf ("%w: '%s': unknown <tag> #%s" , errInvalidSmartColumn , s , tag )
193
+ return column {}, fmt .Errorf ("%w: '%s', unknown <tag> #%s" , errInvalidSmartColumn , s , tag )
156
194
}
157
195
}
158
196
if id {
@@ -176,7 +214,7 @@ func parseSmartColumnDefinition(s string) (column, error) {
176
214
}
177
215
178
216
if colType == "" {
179
- return column {}, fmt .Errorf ("%w: '%s' missing column type" , errInvalidSmartColumn , s )
217
+ return column {}, fmt .Errorf ("%w: '%s', missing column type" , errInvalidSmartColumn , s )
180
218
}
181
219
constraint := ""
182
220
if ! null {
@@ -195,8 +233,8 @@ func parseSmartColumnDefinition(s string) (column, error) {
195
233
196
234
func parsePlainColumnDefinition (s string ) (column , error ) {
197
235
parts := strings .Split (s , ":" )
198
- if len (parts ) < 2 || len (parts ) > 3 {
199
- return column {}, fmt .Errorf ("%w: invalid <plain-column>: '%s', expected '<name>:<type>' or '<name>:<type>:< constraint>'" , errBadArgument , s )
236
+ if len (parts ) < 2 || len (parts ) > 3 || parts [ 0 ] == "" {
237
+ return column {}, fmt .Errorf ("%w: invalid <plain-column>: '%s', expected '<name>:<type>[:< constraint>] '" , errBadArgument , s )
200
238
}
201
239
col := column {
202
240
ID : strings .ToLower (parts [0 ]) == * idColumnFlag ,
@@ -331,14 +369,14 @@ func writeSchema(w io.Writer, args *scaffoldCommandArgs) {
331
369
fmt .Fprintf (w , ");" )
332
370
}
333
371
334
- //goland:noinspection GoUnhandledErrorResult
372
+ //goland:noinspection GoUnhandledErrorResult,SqlNoDataSourceInspection
335
373
func writeGetQuery (w io.Writer , args * scaffoldCommandArgs ) {
336
374
fmt .Fprintf (w , "-- name: Get%s :one\n " , args .SingularEntity )
337
375
fmt .Fprintf (w , "SELECT * FROM %s\n " , args .Table )
338
376
fmt .Fprintf (w , "WHERE %s = ? LIMIT 1;" , args .IDColumn .Name )
339
377
}
340
378
341
- //goland:noinspection GoUnhandledErrorResult
379
+ //goland:noinspection GoUnhandledErrorResult,SqlNoDataSourceInspection
342
380
func writeListQuery (w io.Writer , args * scaffoldCommandArgs ) {
343
381
fmt .Fprintf (w , "-- name: List%s :many\n " , args .PluralEntity )
344
382
fmt .Fprintf (w , "SELECT * FROM %s" , args .Table )
@@ -349,7 +387,7 @@ func writeListQuery(w io.Writer, args *scaffoldCommandArgs) {
349
387
}
350
388
}
351
389
352
- //goland:noinspection GoUnhandledErrorResult
390
+ //goland:noinspection GoUnhandledErrorResult,SqlNoDataSourceInspection
353
391
func writeCreateQuery (w io.Writer , args * scaffoldCommandArgs ) {
354
392
fmt .Fprintf (w , "-- name: Create%s :one\n " , args .SingularEntity )
355
393
fmt .Fprintf (w , "INSERT INTO %s (\n " , args .Table )
@@ -375,7 +413,7 @@ func writeCreateQuery(w io.Writer, args *scaffoldCommandArgs) {
375
413
fmt .Fprintf (w , "RETURNING *;" )
376
414
}
377
415
378
- //goland:noinspection GoUnhandledErrorResult
416
+ //goland:noinspection GoUnhandledErrorResult,SqlNoDataSourceInspection
379
417
func writeDeleteQuery (w io.Writer , args * scaffoldCommandArgs ) {
380
418
fmt .Fprintf (w , "-- name: Delete%s :exec\n " , args .SingularEntity )
381
419
fmt .Fprintf (w , "DELETE FROM %s\n " , args .Table )
0 commit comments