44package console
55
66import (
7+ "bufio"
78 "os"
89
910 "github.com/microsoft/go-sqlcmd/pkg/sqlcmd"
1011 "github.com/peterh/liner"
1112)
1213
1314type 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
1720}
1821
1922// NewConsole creates a sqlcmdConsole implementation that provides these features:
2023// - Storage of input history to a local file. History can be scrolled through using the up and down arrow keys.
2124// - Simple tab key completion of SQL keywords
2225func NewConsole (historyFile string ) sqlcmd.Console {
2326 c := & console {
24- impl : liner .NewLiner (),
25- historyFile : historyFile ,
27+ impl : liner .NewLiner (),
28+ historyFile : historyFile ,
29+ stdinRedirected : isStdinRedirected (),
2630 }
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+ }
3342 }
3443 }
3544 return c
3645}
3746
3847// Close writes out the history data to disk and closes the console buffers
3948func (c * console ) Close () {
40- if c .historyFile != "" {
49+ if ! c . stdinRedirected && c .historyFile != "" {
4150 if f , err := os .Create (c .historyFile ); err == nil {
4251 _ , _ = c .impl .WriteHistory (f )
4352 f .Close ()
4453 }
4554 }
46- c .impl .Close ()
55+
56+ if ! c .stdinRedirected {
57+ c .impl .Close ()
58+ }
4759}
4860
4961// Readline displays the current prompt and returns a line of text entered by the user.
5062// It appends the returned line to the history buffer.
5163// 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
5265func (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
5384 s , err := c .impl .Prompt (c .prompt )
5485 if err == liner .ErrPromptAborted {
5586 return "" , sqlcmd .ErrCtrlC
@@ -61,6 +92,8 @@ func (c *console) Readline() (string, error) {
6192// ReadPassword displays the given prompt and returns the password entered by the user.
6293// If the user presses Ctrl-C the error returned is sqlcmd.ErrCtrlC
6394func (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
6497 b , err := c .impl .PasswordPrompt (prompt )
6598 if err == liner .ErrPromptAborted {
6699 return []byte {}, sqlcmd .ErrCtrlC
0 commit comments