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:
Janne Valkealahti
2022-11-18 07:26:37 +00:00
parent 57fac23bfc
commit 83fb5f71fc
2 changed files with 75 additions and 3 deletions

View File

@@ -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;

View File

@@ -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");
}
}