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" ;
@@ -73,7 +74,7 @@ void startShell(@Nonnull CliArgs cliArgs) {
7374 try {
7475 CypherShell shell = new CypherShell (logger , prettyConfig , ShellRunner .shouldBeInteractive ( cliArgs ));
7576 // Can only prompt for password if input has not been redirected
76- connectMaybeInteractively (shell , connectionConfig , isInputInteractive ());
77+ connectMaybeInteractively (shell , connectionConfig , isInputInteractive (), isOutputInteractive () );
7778
7879 // Construct shellrunner after connecting, due to interrupt handling
7980 ShellRunner shellRunner = ShellRunner .getShellRunner (cliArgs , shell , logger , connectionConfig );
@@ -93,9 +94,20 @@ void startShell(@Nonnull CliArgs cliArgs) {
9394 /**
9495 * Connect the shell to the server, and try to handle missing passwords and such
9596 */
96- void connectMaybeInteractively (@ Nonnull CypherShell shell , @ Nonnull ConnectionConfig connectionConfig ,
97- boolean interactively )
97+ void connectMaybeInteractively (@ Nonnull CypherShell shell ,
98+ @ Nonnull ConnectionConfig connectionConfig ,
99+ boolean inputInteractive ,
100+ boolean outputInteractive )
98101 throws Exception {
102+
103+ OutputStream outputStream = outputInteractive ? out : new ThrowawayOutputStream ();
104+
105+ ConsoleReader consoleReader = new ConsoleReader (in , outputStream );
106+ // Disable expansion of bangs: !
107+ consoleReader .setExpandEvents (false );
108+ // Ensure Reader does not handle user input for ctrl+C behaviour
109+ consoleReader .setHandleUserInterrupt (false );
110+
99111 try {
100112 shell .connect (connectionConfig );
101113 } catch (AuthenticationException e ) {
@@ -104,19 +116,24 @@ void connectMaybeInteractively(@Nonnull CypherShell shell, @Nonnull ConnectionCo
104116 throw e ;
105117 }
106118 // else need to prompt for username and password
107- if (interactively ) {
119+ if (inputInteractive ) {
108120 if (connectionConfig .username ().isEmpty ()) {
109- connectionConfig .setUsername (promptForNonEmptyText ("username" , null ));
121+ String username = outputInteractive ?
122+ promptForNonEmptyText ("username" , consoleReader , null ) :
123+ promptForText ("username" , consoleReader , null );
124+ connectionConfig .setUsername (username );
110125 }
111126 if (connectionConfig .password ().isEmpty ()) {
112- connectionConfig .setPassword (promptForText ("password" , '*' ));
127+ connectionConfig .setPassword (promptForText ("password" , consoleReader , '*' ));
113128 }
114129 // try again
115130 shell .connect (connectionConfig );
116131 } else {
117132 // Can't prompt because input has been redirected
118133 throw e ;
119134 }
135+ } finally {
136+ consoleReader .close ();
120137 }
121138 }
122139
@@ -130,40 +147,41 @@ void connectMaybeInteractively(@Nonnull CypherShell shell, @Nonnull ConnectionCo
130147 * in case of errors
131148 */
132149 @ Nonnull
133- private String promptForNonEmptyText (@ Nonnull String prompt , @ Nullable Character mask ) throws Exception {
134- String text = promptForText (prompt , mask );
150+ private String promptForNonEmptyText (@ Nonnull String prompt , @ Nonnull ConsoleReader consoleReader , @ Nullable Character mask ) throws Exception {
151+ String text = promptForText (prompt , consoleReader , mask );
135152 if (!text .isEmpty ()) {
136153 return text ;
137154 }
138- out .println (prompt + " cannot be empty" );
139- out .println ();
140- return promptForNonEmptyText (prompt , mask );
155+ consoleReader .println ( prompt + " cannot be empty" );
156+ consoleReader .println ();
157+ return promptForNonEmptyText (prompt , consoleReader , mask );
141158 }
142159
143160 /**
144161 * @param prompt
145162 * to display to the user
146163 * @param mask
147164 * single character to display instead of what the user is typing, use null if text is not secret
165+ * @param consoleReader
166+ * the reader
148167 * @return the text which was entered
149168 * @throws Exception
150169 * in case of errors
151170 */
152171 @ Nonnull
153- private String promptForText (@ Nonnull String prompt , @ Nullable Character mask ) throws Exception {
154- String line ;
155- ConsoleReader consoleReader = new ConsoleReader (in , out );
156- // Disable expansion of bangs: !
157- consoleReader .setExpandEvents (false );
158- // Ensure Reader does not handle user input for ctrl+C behaviour
159- consoleReader .setHandleUserInterrupt (false );
160- line = consoleReader .readLine (prompt + ": " , mask );
161- consoleReader .close ();
162-
172+ private String promptForText (@ Nonnull String prompt , @ Nonnull ConsoleReader consoleReader , @ Nullable Character mask ) throws Exception {
173+ String line = consoleReader .readLine (prompt + ": " , mask );
163174 if (line == null ) {
164175 throw new CommandException ("No text could be read, exiting..." );
165176 }
166177
167178 return line ;
168179 }
180+
181+ private static class ThrowawayOutputStream extends OutputStream {
182+ @ Override
183+ public void write ( int b )
184+ {
185+ }
186+ }
169187}
0 commit comments