55import org .neo4j .shell .build .Build ;
66import org .neo4j .shell .cli .CliArgHelper ;
77import org .neo4j .shell .cli .CliArgs ;
8- import org .neo4j .shell .cli .Format ;
98import org .neo4j .shell .commands .CommandHelper ;
109import org .neo4j .shell .exception .CommandException ;
1110import org .neo4j .shell .log .AnsiLogger ;
1514import javax .annotation .Nonnull ;
1615import javax .annotation .Nullable ;
1716import java .io .InputStream ;
17+ import java .io .OutputStream ;
1818import java .io .PrintStream ;
1919
2020import static org .neo4j .shell .ShellRunner .isInputInteractive ;
21+ import static org .neo4j .shell .ShellRunner .isOutputInteractive ;
2122
2223public class Main {
2324 static final String NEO_CLIENT_ERROR_SECURITY_UNAUTHORIZED = "Neo.ClientError.Security.Unauthorized" ;
@@ -72,7 +73,7 @@ void startShell(@Nonnull CliArgs cliArgs) {
7273 try {
7374 CypherShell shell = new CypherShell (logger , prettyConfig );
7475 // Can only prompt for password if input has not been redirected
75- connectMaybeInteractively (shell , connectionConfig , isInputInteractive ());
76+ connectMaybeInteractively (shell , connectionConfig , isInputInteractive (), isOutputInteractive () );
7677
7778 // Construct shellrunner after connecting, due to interrupt handling
7879 ShellRunner shellRunner = ShellRunner .getShellRunner (cliArgs , shell , logger , connectionConfig );
@@ -92,9 +93,20 @@ void startShell(@Nonnull CliArgs cliArgs) {
9293 /**
9394 * Connect the shell to the server, and try to handle missing passwords and such
9495 */
95- void connectMaybeInteractively (@ Nonnull CypherShell shell , @ Nonnull ConnectionConfig connectionConfig ,
96- boolean interactively )
96+ void connectMaybeInteractively (@ Nonnull CypherShell shell ,
97+ @ Nonnull ConnectionConfig connectionConfig ,
98+ boolean inputInteractive ,
99+ boolean outputInteractive )
97100 throws Exception {
101+
102+ OutputStream outputStream = outputInteractive ? out : new ThrowawayOutputStream ();
103+
104+ ConsoleReader consoleReader = new ConsoleReader (in , outputStream );
105+ // Disable expansion of bangs: !
106+ consoleReader .setExpandEvents (false );
107+ // Ensure Reader does not handle user input for ctrl+C behaviour
108+ consoleReader .setHandleUserInterrupt (false );
109+
98110 try {
99111 shell .connect (connectionConfig );
100112 } catch (AuthenticationException e ) {
@@ -103,19 +115,24 @@ void connectMaybeInteractively(@Nonnull CypherShell shell, @Nonnull ConnectionCo
103115 throw e ;
104116 }
105117 // else need to prompt for username and password
106- if (interactively ) {
118+ if (inputInteractive ) {
107119 if (connectionConfig .username ().isEmpty ()) {
108- connectionConfig .setUsername (promptForNonEmptyText ("username" , null ));
120+ String username = outputInteractive ?
121+ promptForNonEmptyText ("username" , consoleReader , null ) :
122+ promptForText ("username" , consoleReader , null );
123+ connectionConfig .setUsername (username );
109124 }
110125 if (connectionConfig .password ().isEmpty ()) {
111- connectionConfig .setPassword (promptForText ("password" , '*' ));
126+ connectionConfig .setPassword (promptForText ("password" , consoleReader , '*' ));
112127 }
113128 // try again
114129 shell .connect (connectionConfig );
115130 } else {
116131 // Can't prompt because input has been redirected
117132 throw e ;
118133 }
134+ } finally {
135+ consoleReader .close ();
119136 }
120137 }
121138
@@ -129,40 +146,41 @@ void connectMaybeInteractively(@Nonnull CypherShell shell, @Nonnull ConnectionCo
129146 * in case of errors
130147 */
131148 @ Nonnull
132- private String promptForNonEmptyText (@ Nonnull String prompt , @ Nullable Character mask ) throws Exception {
133- String text = promptForText (prompt , mask );
149+ private String promptForNonEmptyText (@ Nonnull String prompt , @ Nonnull ConsoleReader consoleReader , @ Nullable Character mask ) throws Exception {
150+ String text = promptForText (prompt , consoleReader , mask );
134151 if (!text .isEmpty ()) {
135152 return text ;
136153 }
137- out .println (prompt + " cannot be empty" );
138- out .println ();
139- return promptForNonEmptyText (prompt , mask );
154+ consoleReader .println ( prompt + " cannot be empty" );
155+ consoleReader .println ();
156+ return promptForNonEmptyText (prompt , consoleReader , mask );
140157 }
141158
142159 /**
143160 * @param prompt
144161 * to display to the user
145162 * @param mask
146163 * single character to display instead of what the user is typing, use null if text is not secret
164+ * @param consoleReader
165+ * the reader
147166 * @return the text which was entered
148167 * @throws Exception
149168 * in case of errors
150169 */
151170 @ Nonnull
152- private String promptForText (@ Nonnull String prompt , @ Nullable Character mask ) throws Exception {
153- String line ;
154- ConsoleReader consoleReader = new ConsoleReader (in , out );
155- // Disable expansion of bangs: !
156- consoleReader .setExpandEvents (false );
157- // Ensure Reader does not handle user input for ctrl+C behaviour
158- consoleReader .setHandleUserInterrupt (false );
159- line = consoleReader .readLine (prompt + ": " , mask );
160- consoleReader .close ();
161-
171+ private String promptForText (@ Nonnull String prompt , @ Nonnull ConsoleReader consoleReader , @ Nullable Character mask ) throws Exception {
172+ String line = consoleReader .readLine (prompt + ": " , mask );
162173 if (line == null ) {
163174 throw new CommandException ("No text could be read, exiting..." );
164175 }
165176
166177 return line ;
167178 }
179+
180+ private static class ThrowawayOutputStream extends OutputStream {
181+ @ Override
182+ public void write ( int b )
183+ {
184+ }
185+ }
168186}
0 commit comments