4
4
package console
5
5
6
6
import (
7
+ "bufio"
7
8
"os"
8
9
9
10
"github.com/microsoft/go-sqlcmd/pkg/sqlcmd"
10
11
"github.com/peterh/liner"
11
12
)
12
13
13
14
type console struct {
14
- impl * liner.State
15
- historyFile string
16
- prompt string
15
+ impl * liner.State
16
+ historyFile string
17
+ prompt string
18
+ stdinRedirected bool
19
+ stdinReader * bufio.Reader
17
20
}
18
21
19
22
// NewConsole creates a sqlcmdConsole implementation that provides these features:
20
23
// - Storage of input history to a local file. History can be scrolled through using the up and down arrow keys.
21
24
// - Simple tab key completion of SQL keywords
22
25
func NewConsole (historyFile string ) sqlcmd.Console {
23
26
c := & console {
24
- impl : liner .NewLiner (),
25
- historyFile : historyFile ,
27
+ impl : liner .NewLiner (),
28
+ historyFile : historyFile ,
29
+ stdinRedirected : isStdinRedirected (),
26
30
}
27
- c .impl .SetCtrlCAborts (true )
28
- c .impl .SetCompleter (CompleteLine )
29
- if c .historyFile != "" {
30
- if f , err := os .Open (historyFile ); err == nil {
31
- _ , _ = c .impl .ReadHistory (f )
32
- f .Close ()
31
+
32
+ if c .stdinRedirected {
33
+ c .stdinReader = bufio .NewReader (os .Stdin )
34
+ } else {
35
+ c .impl .SetCtrlCAborts (true )
36
+ c .impl .SetCompleter (CompleteLine )
37
+ if c .historyFile != "" {
38
+ if f , err := os .Open (historyFile ); err == nil {
39
+ _ , _ = c .impl .ReadHistory (f )
40
+ f .Close ()
41
+ }
33
42
}
34
43
}
35
44
return c
36
45
}
37
46
38
47
// Close writes out the history data to disk and closes the console buffers
39
48
func (c * console ) Close () {
40
- if c .historyFile != "" {
49
+ if ! c . stdinRedirected && c .historyFile != "" {
41
50
if f , err := os .Create (c .historyFile ); err == nil {
42
51
_ , _ = c .impl .WriteHistory (f )
43
52
f .Close ()
44
53
}
45
54
}
46
- c .impl .Close ()
55
+
56
+ if ! c .stdinRedirected {
57
+ c .impl .Close ()
58
+ }
47
59
}
48
60
49
61
// Readline displays the current prompt and returns a line of text entered by the user.
50
62
// It appends the returned line to the history buffer.
51
63
// If the user presses Ctrl-C the error returned is sqlcmd.ErrCtrlC
64
+ // If stdin is redirected, it reads directly from stdin without displaying prompts
52
65
func (c * console ) Readline () (string , error ) {
66
+ // Handle redirected stdin without displaying prompts
67
+ if c .stdinRedirected {
68
+ line , err := c .stdinReader .ReadString ('\n' )
69
+ if err != nil {
70
+ return "" , err
71
+ }
72
+ // Trim the trailing newline
73
+ if len (line ) > 0 && line [len (line )- 1 ] == '\n' {
74
+ line = line [:len (line )- 1 ]
75
+ // Also trim carriage return if present
76
+ if len (line ) > 0 && line [len (line )- 1 ] == '\r' {
77
+ line = line [:len (line )- 1 ]
78
+ }
79
+ }
80
+ return line , nil
81
+ }
82
+
83
+ // Interactive terminal mode with prompts
53
84
s , err := c .impl .Prompt (c .prompt )
54
85
if err == liner .ErrPromptAborted {
55
86
return "" , sqlcmd .ErrCtrlC
@@ -61,6 +92,8 @@ func (c *console) Readline() (string, error) {
61
92
// ReadPassword displays the given prompt and returns the password entered by the user.
62
93
// If the user presses Ctrl-C the error returned is sqlcmd.ErrCtrlC
63
94
func (c * console ) ReadPassword (prompt string ) ([]byte , error ) {
95
+ // Even when stdin is redirected, we need to use the prompt for passwords
96
+ // since they should not be read from the redirected input
64
97
b , err := c .impl .PasswordPrompt (prompt )
65
98
if err == liner .ErrPromptAborted {
66
99
return []byte {}, sqlcmd .ErrCtrlC
0 commit comments