Skip to content

Commit 13a1680

Browse files
authored
Kong to Cobra Migration (#208)
1 parent d754626 commit 13a1680

File tree

9 files changed

+327
-113
lines changed

9 files changed

+327
-113
lines changed

.vscode/launch.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
"request": "launch",
2525
"mode" : "auto",
2626
"program": "${workspaceFolder}/cmd/modern",
27-
"args" : ["-Q", "EXIT(select net_transport from sys.dm_exec_connections)"],
27+
"args" : ["-Q", "EXIT(select net_transport from sys.dm_exec_connections)"],
2828
},
2929
{
3030
"name" : "Run file query",

.vscode/settings.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"go.lintTool": "golangci-lint",
3+
"go.lintOnSave": "workspace"
4+
}

cmd/sqlcmd/sqlcmd.go

Lines changed: 220 additions & 51 deletions
Large diffs are not rendered by default.

cmd/sqlcmd/sqlcmd_test.go

Lines changed: 72 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,30 +10,14 @@ import (
1010
"strings"
1111
"testing"
1212

13-
"github.com/alecthomas/kong"
1413
"github.com/microsoft/go-mssqldb/azuread"
1514
"github.com/microsoft/go-sqlcmd/pkg/sqlcmd"
15+
"github.com/spf13/cobra"
1616
"github.com/stretchr/testify/assert"
17-
"github.com/stretchr/testify/require"
1817
)
1918

2019
const oneRowAffected = "(1 row affected)"
2120

22-
func newKong(t *testing.T, cli interface{}, options ...kong.Option) *kong.Kong {
23-
t.Helper()
24-
options = append([]kong.Option{
25-
kong.Name("test"),
26-
kong.NoDefaultHelp(),
27-
kong.Exit(func(int) {
28-
t.Helper()
29-
assert.Fail(t, "unexpected exit()")
30-
}),
31-
}, options...)
32-
parser, err := kong.New(cli, options...)
33-
require.NoError(t, err)
34-
return parser
35-
}
36-
3721
func TestValidCommandLineToArgsConversion(t *testing.T) {
3822
type cmdLineTest struct {
3923
commandLine []string
@@ -90,15 +74,34 @@ func TestValidCommandLineToArgsConversion(t *testing.T) {
9074
{[]string{"--version"}, func(args SQLCmdArguments) bool {
9175
return args.Version
9276
}},
77+
{[]string{}, func(args SQLCmdArguments) bool {
78+
return args.ScreenWidth == nil
79+
}},
80+
{[]string{"-w", "10"}, func(args SQLCmdArguments) bool {
81+
return args.ScreenWidth != nil && *args.ScreenWidth == 10
82+
}},
9383
{[]string{"-s", "|", "-w", "10", "-W"}, func(args SQLCmdArguments) bool {
9484
return args.TrimSpaces && args.ColumnSeparator == "|" && *args.ScreenWidth == 10
9585
}},
9686
}
9787

9888
for _, test := range commands {
9989
arguments := &SQLCmdArguments{}
100-
parser := newKong(t, arguments)
101-
_, err := parser.Parse(test.commandLine)
90+
cmd := &cobra.Command{
91+
Use: "testCommand",
92+
Short: "A brief description of my command",
93+
Long: "A long description of my command",
94+
PreRunE: func(cmd *cobra.Command, argss []string) error {
95+
SetScreenWidthFlag(arguments, cmd)
96+
return arguments.Validate()
97+
},
98+
Run: func(cmd *cobra.Command, argss []string) {
99+
// Command logic goes here
100+
},
101+
}
102+
setFlags(cmd, arguments)
103+
cmd.SetArgs(test.commandLine)
104+
err := cmd.Execute()
102105
msg := ""
103106
if err != nil {
104107
msg = err.Error()
@@ -116,19 +119,61 @@ func TestInvalidCommandLine(t *testing.T) {
116119
}
117120

118121
commands := []cmdLineTest{
119-
{[]string{"-E", "-U", "someuser"}, "--use-trusted-connection and --user-name can't be used together"},
120-
// the test prefix is a kong artifact https://github.com/alecthomas/kong/issues/221
121-
{[]string{"-a", "100"}, "test: '-a 100': Packet size has to be a number between 512 and 32767."},
122+
// Issue:341 https://github.com/microsoft/go-sqlcmd/issues/341
123+
//{[]string{"-E", "-U", "someuser"}, "--use-trusted-connection and --user-name can't be used together"},
122124
{[]string{"-F", "what"}, "--format must be one of \"horiz\",\"horizontal\",\"vert\",\"vertical\" but got \"what\""},
123-
{[]string{"-r", "5"}, `--errors-to-stderr must be one of "-1","0","1" but got '\x05'`},
124-
{[]string{"-h-4"}, "test: '-h -4': header value must be either -1 or a value between 1 and 2147483647"},
125-
{[]string{"-w", "6"}, "test: '-w 6': value must be greater than 8 and less than 65536."},
125+
{[]string{"-r", "5"}, `--errors-to-stderr must be one of "-1","0","1" but got "5"`},
126126
}
127127

128128
for _, test := range commands {
129129
arguments := &SQLCmdArguments{}
130-
parser := newKong(t, arguments)
131-
_, err := parser.Parse(test.commandLine)
130+
cmd := &cobra.Command{
131+
Use: "testCommand",
132+
Short: "A brief description of my command",
133+
Long: "A long description of my command",
134+
PreRunE: func(cmd *cobra.Command, argss []string) error {
135+
return normalizeFlags(cmd)
136+
},
137+
Run: func(cmd *cobra.Command, argss []string) {
138+
},
139+
}
140+
setFlags(cmd, arguments)
141+
cmd.SetArgs(test.commandLine)
142+
err := cmd.Execute()
143+
assert.EqualError(t, err, test.errorMessage, "Command line:%v", test.commandLine)
144+
}
145+
}
146+
147+
func TestValidateFlags(t *testing.T) {
148+
type cmdLineTest struct {
149+
commandLine []string
150+
errorMessage string
151+
}
152+
153+
commands := []cmdLineTest{
154+
{[]string{"-a", "100"}, "'-a 100': Packet size has to be a number between 512 and 32767."},
155+
{[]string{"-h-4"}, "'-h -4': header value must be either -1 or a value between 1 and 2147483647"},
156+
{[]string{"-w", "6"}, "'-w 6': value must be greater than 8 and less than 65536."},
157+
}
158+
159+
for _, test := range commands {
160+
arguments := &SQLCmdArguments{}
161+
//var screenWidth *int
162+
cmd := &cobra.Command{
163+
Use: "testCommand",
164+
Short: "A brief description of my command",
165+
Long: "A long description of my command",
166+
PreRunE: func(cmd *cobra.Command, argss []string) error {
167+
SetScreenWidthFlag(arguments, cmd)
168+
return arguments.Validate()
169+
},
170+
Run: func(cmd *cobra.Command, argss []string) {
171+
},
172+
}
173+
174+
setFlags(cmd, arguments)
175+
cmd.SetArgs(test.commandLine)
176+
err := cmd.Execute()
132177
assert.EqualError(t, err, test.errorMessage, "Command line:%v", test.commandLine)
133178
}
134179
}

cmd/sqlcmd/testdata/select100.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
select 100
1+
select 100

go.mod

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ go 1.18
44

55
require (
66
github.com/alecthomas/chroma/v2 v2.5.0
7-
github.com/alecthomas/kong v0.6.2-0.20220922001058-c62bf25854a0
87
github.com/billgraziano/dpapi v0.4.0
98
github.com/docker/distribution v2.8.2+incompatible
109
github.com/docker/docker v20.10.24+incompatible
@@ -16,6 +15,7 @@ require (
1615
github.com/peterh/liner v1.2.2
1716
github.com/pkg/errors v0.9.1
1817
github.com/spf13/cobra v1.6.1
18+
github.com/spf13/pflag v1.0.5
1919
github.com/spf13/viper v1.14.0
2020
github.com/stretchr/testify v1.8.1
2121
golang.org/x/sys v0.5.0
@@ -65,7 +65,6 @@ require (
6565
github.com/spf13/afero v1.9.2 // indirect
6666
github.com/spf13/cast v1.5.0 // indirect
6767
github.com/spf13/jwalterweatherman v1.1.0 // indirect
68-
github.com/spf13/pflag v1.0.5 // indirect
6968
github.com/subosito/gotenv v1.4.1 // indirect
7069
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect
7170
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect

go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,6 @@ github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2B
5353
github.com/alecthomas/assert/v2 v2.2.1 h1:XivOgYcduV98QCahG8T5XTezV5bylXe+lBxLG2K2ink=
5454
github.com/alecthomas/chroma/v2 v2.5.0 h1:CQCdj1BiBV17sD4Bd32b/Bzuiq/EqoNTrnIhyQAZ+Rk=
5555
github.com/alecthomas/chroma/v2 v2.5.0/go.mod h1:yrkMI9807G1ROx13fhe1v6PN2DDeaR73L3d+1nmYQtw=
56-
github.com/alecthomas/kong v0.6.2-0.20220922001058-c62bf25854a0 h1:HQ3WlFsqBcr4qsiHtfA7UdFSrChglOcQa8q/tbXJFBI=
57-
github.com/alecthomas/kong v0.6.2-0.20220922001058-c62bf25854a0/go.mod h1:n1iCIO2xS46oE8ZfYCNDqdR0b0wZNrXAIAqro/2132U=
5856
github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
5957
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
6058
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=

pkg/sqlcmd-linter/imports.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ var ImportsAnalyzer = &analysis.Analyzer{
2121
}
2222

2323
var AllowedImports = map[string][]string{
24-
`"github.com/alecthomas/kong`: {`cmd/sqlcmd`, `pkg/sqlcmd`},
2524
`"github.com/golang-sql/sqlexp`: {`pkg/sqlcmd`},
2625
`"github.com/google/uuid`: {},
2726
`"github.com/peterh/liner`: {`pkg/console`},

pkg/sqlcmd/commands.go

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
package sqlcmd
55

66
import (
7+
"flag"
78
"fmt"
89
"os"
910
"regexp"
1011
"sort"
1112
"strconv"
1213
"strings"
1314

14-
"github.com/alecthomas/kong"
1515
"github.com/microsoft/go-sqlcmd/internal/color"
1616
"golang.org/x/text/encoding/unicode"
1717
"golang.org/x/text/transform"
@@ -398,41 +398,33 @@ func listCommand(s *Sqlcmd, args []string, line uint) (err error) {
398398
return
399399
}
400400

401-
type connectData struct {
402-
Server string `arg:""`
403-
Database string `short:"D"`
404-
Username string `short:"U"`
405-
Password string `short:"P"`
406-
LoginTimeout string `short:"l"`
407-
AuthenticationMethod string `short:"G"`
408-
}
409-
410401
func connectCommand(s *Sqlcmd, args []string, line uint) error {
411-
412402
if len(args) == 0 {
413403
return InvalidCommandError("CONNECT", line)
414404
}
415-
cmdLine := strings.TrimSpace(args[0])
416-
if cmdLine == "" {
417-
return InvalidCommandError("CONNECT", line)
418-
}
419-
arguments := &connectData{}
420-
parser, err := kong.New(arguments)
421-
if err != nil {
422-
return InvalidCommandError("CONNECT", line)
423-
}
424405

425-
// Fields removes extra whitespace.
426-
// Note :connect doesn't support passwords with spaces
427-
if _, err = parser.Parse(strings.Fields(cmdLine)); err != nil {
406+
commandArgs := strings.Fields(args[0])
407+
408+
// Parse flags
409+
flags := flag.NewFlagSet("connect", flag.ContinueOnError)
410+
database := flags.String("D", "", "database name")
411+
username := flags.String("U", "", "user name")
412+
password := flags.String("P", "", "password")
413+
loginTimeout := flags.String("l", "", "login timeout")
414+
authenticationMethod := flags.String("G", "", "authentication method")
415+
416+
err := flags.Parse(commandArgs[1:])
417+
//err := flags.Parse(args[1:])
418+
if err != nil {
428419
return InvalidCommandError("CONNECT", line)
429420
}
430421

431422
connect := *s.Connect
432-
connect.UserName, _ = resolveArgumentVariables(s, []rune(arguments.Username), false)
433-
connect.Password, _ = resolveArgumentVariables(s, []rune(arguments.Password), false)
434-
connect.ServerName, _ = resolveArgumentVariables(s, []rune(arguments.Server), false)
435-
timeout, _ := resolveArgumentVariables(s, []rune(arguments.LoginTimeout), false)
423+
connect.UserName, _ = resolveArgumentVariables(s, []rune(*username), false)
424+
connect.Password, _ = resolveArgumentVariables(s, []rune(*password), false)
425+
connect.Database, _ = resolveArgumentVariables(s, []rune(*database), false)
426+
427+
timeout, _ := resolveArgumentVariables(s, []rune(*loginTimeout), false)
436428
if timeout != "" {
437429
if timeoutSeconds, err := strconv.ParseInt(timeout, 10, 32); err == nil {
438430
if timeoutSeconds < 0 {
@@ -441,9 +433,17 @@ func connectCommand(s *Sqlcmd, args []string, line uint) error {
441433
connect.LoginTimeoutSeconds = int(timeoutSeconds)
442434
}
443435
}
444-
connect.AuthenticationMethod = arguments.AuthenticationMethod
436+
437+
connect.AuthenticationMethod = *authenticationMethod
438+
439+
// Set server name as the first positional argument
440+
if len(commandArgs) > 0 {
441+
connect.ServerName, _ = resolveArgumentVariables(s, []rune(commandArgs[0]), false)
442+
}
443+
445444
// If no user name is provided we switch to integrated auth
446445
_ = s.ConnectDb(&connect, s.lineIo == nil)
446+
447447
// ConnectDb prints connection errors already, and failure to connect is not fatal even with -b option
448448
return nil
449449
}

0 commit comments

Comments
 (0)