Re-quote whitespace
- NonInteractiveShellRunner has a trouble where incoming argument loses info about "quoted" string which is handled by OS terminal. - Add re-quoting in presense of a whitespace so that jline parser can detect it correctly. - Fixes #567
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.shell.jline;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
@@ -33,6 +34,7 @@ import org.springframework.shell.ShellRunner;
|
||||
import org.springframework.shell.Utils;
|
||||
import org.springframework.shell.context.InteractionMode;
|
||||
import org.springframework.shell.context.ShellContext;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* A {@link ShellRunner} that executes commands without entering interactive shell mode.
|
||||
@@ -58,9 +60,32 @@ public class NonInteractiveShellRunner implements ShellRunner {
|
||||
|
||||
private Parser lineParser;
|
||||
|
||||
private Function<ApplicationArguments, List<String>> commandsFromInputArgs = args -> args
|
||||
.getSourceArgs().length == 0 ? Collections.emptyList()
|
||||
: Collections.singletonList(String.join(" ", args.getSourceArgs()));
|
||||
private static final String SINGLE_QUOTE = "\'";
|
||||
private static final String DOUBLE_QUOTE = "\"";
|
||||
|
||||
private Function<ApplicationArguments, List<String>> commandsFromInputArgs = args -> {
|
||||
if (args.getSourceArgs().length == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// re-quote if needed having whitespace
|
||||
String raw = Arrays.stream(args.getSourceArgs())
|
||||
.map(a -> {
|
||||
if (!isQuoted(a) && StringUtils.containsWhitespace(a)) {
|
||||
return "\"" + a + "\"";
|
||||
}
|
||||
return a;
|
||||
})
|
||||
.collect(Collectors.joining(" "));
|
||||
return Collections.singletonList(raw);
|
||||
};
|
||||
|
||||
private static boolean isQuoted(String str) {
|
||||
if (str == null) {
|
||||
return false;
|
||||
}
|
||||
return str.startsWith(SINGLE_QUOTE) && str.endsWith(SINGLE_QUOTE)
|
||||
|| str.startsWith(DOUBLE_QUOTE) && str.endsWith(DOUBLE_QUOTE);
|
||||
}
|
||||
|
||||
public NonInteractiveShellRunner(Shell shell, ShellContext shellContext) {
|
||||
this.shell = shell;
|
||||
|
||||
@@ -16,13 +16,27 @@
|
||||
package org.springframework.shell.jline;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.Spy;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import org.springframework.boot.DefaultApplicationArguments;
|
||||
import org.springframework.shell.InputProvider;
|
||||
import org.springframework.shell.Shell;
|
||||
import org.springframework.shell.context.DefaultShellContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class NonInteractiveShellRunnerTests {
|
||||
|
||||
@Spy
|
||||
@InjectMocks
|
||||
private Shell shell;
|
||||
|
||||
@Test
|
||||
public void testEmptyArgsDontRun() {
|
||||
NonInteractiveShellRunner runner = new NonInteractiveShellRunner(null, null);
|
||||
@@ -36,4 +50,37 @@ public class NonInteractiveShellRunnerTests {
|
||||
DefaultApplicationArguments args = new DefaultApplicationArguments("hi");
|
||||
assertThat(runner.canRun(args)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldQuoteWithWhitespace() throws Exception {
|
||||
NonInteractiveShellRunner runner = new NonInteractiveShellRunner(shell, new DefaultShellContext());
|
||||
DefaultApplicationArguments args = new DefaultApplicationArguments("foo bar");
|
||||
ArgumentCaptor<InputProvider> valueCapture = ArgumentCaptor.forClass(InputProvider.class);
|
||||
Mockito.doNothing().when(shell).run(valueCapture.capture());
|
||||
runner.run(args);
|
||||
InputProvider value = valueCapture.getValue();
|
||||
assertThat(value.readInput().rawText()).isEqualTo("\"foo bar\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotQuoteIfQuoted() throws Exception {
|
||||
NonInteractiveShellRunner runner = new NonInteractiveShellRunner(shell, new DefaultShellContext());
|
||||
DefaultApplicationArguments args = new DefaultApplicationArguments("'foo bar'");
|
||||
ArgumentCaptor<InputProvider> valueCapture = ArgumentCaptor.forClass(InputProvider.class);
|
||||
Mockito.doNothing().when(shell).run(valueCapture.capture());
|
||||
runner.run(args);
|
||||
InputProvider value = valueCapture.getValue();
|
||||
assertThat(value.readInput().rawText()).isEqualTo("'foo bar'");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotQuoteWithoutWhitespace() throws Exception {
|
||||
NonInteractiveShellRunner runner = new NonInteractiveShellRunner(shell, new DefaultShellContext());
|
||||
DefaultApplicationArguments args = new DefaultApplicationArguments("foobar");
|
||||
ArgumentCaptor<InputProvider> valueCapture = ArgumentCaptor.forClass(InputProvider.class);
|
||||
Mockito.doNothing().when(shell).run(valueCapture.capture());
|
||||
runner.run(args);
|
||||
InputProvider value = valueCapture.getValue();
|
||||
assertThat(value.readInput().rawText()).isEqualTo("foobar");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user