Remove bean cycles
- Shuffle things around into different auto-config and configuration classes and use other tricks like ObjectProvider to work around boot 2.6.x imposing bean cycle checks. - This is first set of changes to work around this issue, not to make things perfect. Further refactoring work is needed making code base more boot 2.x friendly as things are based on boot 1.5.x times. - Fixes #324
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.shell;
|
||||
|
||||
import org.jline.reader.LineReader;
|
||||
import org.jline.reader.Parser;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.shell.jline.InteractiveShellApplicationRunner;
|
||||
import org.springframework.shell.jline.PromptProvider;
|
||||
import org.springframework.shell.jline.ScriptShellApplicationRunner;
|
||||
|
||||
import static org.springframework.shell.jline.InteractiveShellApplicationRunner.SPRING_SHELL_INTERACTIVE;
|
||||
import static org.springframework.shell.jline.ScriptShellApplicationRunner.SPRING_SHELL_SCRIPT;
|
||||
|
||||
@Configuration
|
||||
public class ApplicationRunnerAutoConfiguration {
|
||||
|
||||
@Autowired
|
||||
private Shell shell;
|
||||
|
||||
@Autowired
|
||||
private PromptProvider promptProvider;
|
||||
|
||||
@Autowired
|
||||
private LineReader lineReader;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(prefix = SPRING_SHELL_INTERACTIVE, value = InteractiveShellApplicationRunner.ENABLED, havingValue = "true", matchIfMissing = true)
|
||||
public ApplicationRunner interactiveApplicationRunner(Parser parser, Environment environment) {
|
||||
return new InteractiveShellApplicationRunner(lineReader, promptProvider, parser, shell, environment);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(prefix = SPRING_SHELL_SCRIPT, value = ScriptShellApplicationRunner.ENABLED, havingValue = "true", matchIfMissing = true)
|
||||
public ApplicationRunner scriptApplicationRunner(Parser parser, ConfigurableEnvironment environment) {
|
||||
return new ScriptShellApplicationRunner(parser, shell, environment);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.shell;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class CommandRegistryAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public CommandRegistry commandRegistry(
|
||||
ObjectProvider<MethodTargetRegistrar> methodTargerRegistrars) {
|
||||
ConfigurableCommandRegistry registry = new ConfigurableCommandRegistry();
|
||||
methodTargerRegistrars.orderedStream().forEach(resolver -> {
|
||||
resolver.register(registry);
|
||||
});
|
||||
return registry;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.shell;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jline.reader.Candidate;
|
||||
import org.jline.reader.Completer;
|
||||
import org.jline.reader.LineReader;
|
||||
import org.jline.reader.ParsedLine;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class CompleterAutoConfiguration {
|
||||
|
||||
@Autowired
|
||||
private Shell shell;
|
||||
|
||||
@Bean
|
||||
public CompleterAdapter completer() {
|
||||
CompleterAdapter completerAdapter = new CompleterAdapter();
|
||||
completerAdapter.setShell(shell);
|
||||
return completerAdapter;
|
||||
}
|
||||
|
||||
public static class CompleterAdapter implements Completer {
|
||||
|
||||
private Shell shell;
|
||||
|
||||
@Override
|
||||
public void complete(LineReader reader, ParsedLine line, List<Candidate> candidates) {
|
||||
CompletingParsedLine cpl = (line instanceof CompletingParsedLine) ? ((CompletingParsedLine) line) : t -> t;
|
||||
|
||||
CompletionContext context = new CompletionContext(sanitizeInput(line.words()), line.wordIndex(), line.wordCursor());
|
||||
|
||||
List<CompletionProposal> proposals = shell.complete(context);
|
||||
proposals.stream()
|
||||
.map(p -> new Candidate(
|
||||
p.dontQuote() ? p.value() : cpl.emit(p.value()).toString(),
|
||||
p.displayText(),
|
||||
p.category(),
|
||||
p.description(),
|
||||
null,
|
||||
null,
|
||||
true)
|
||||
)
|
||||
.forEach(candidates::add);
|
||||
}
|
||||
|
||||
public void setShell(Shell shell) {
|
||||
this.shell = shell;
|
||||
}
|
||||
|
||||
static List<String> sanitizeInput(List<String> words) {
|
||||
words = words.stream()
|
||||
.map(s -> s.replaceAll("^\\n+|\\n+$", "")) // CR at beginning/end of line introduced by backslash continuation
|
||||
.map(s -> s.replaceAll("\\n+", " ")) // CR in middle of word introduced by return inside a quoted string
|
||||
.collect(Collectors.toList());
|
||||
return words;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.shell;
|
||||
|
||||
import org.jline.reader.impl.history.DefaultHistory;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class JLineAutoConfiguration {
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnMissingBean(org.jline.reader.History.class)
|
||||
public static class JLineHistoryConfiguration {
|
||||
|
||||
@Bean
|
||||
public org.jline.reader.History history(@Value("${spring.application.name:spring-shell}.log") String historyPath) {
|
||||
return new DefaultHistory();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.shell;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import org.jline.reader.Completer;
|
||||
import org.jline.reader.Highlighter;
|
||||
import org.jline.reader.LineReader;
|
||||
import org.jline.reader.LineReaderBuilder;
|
||||
import org.jline.reader.Parser;
|
||||
import org.jline.terminal.Terminal;
|
||||
import org.jline.utils.AttributedString;
|
||||
import org.jline.utils.AttributedStringBuilder;
|
||||
import org.jline.utils.AttributedStyle;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.event.ContextClosedEvent;
|
||||
import org.springframework.context.event.EventListener;
|
||||
|
||||
@Configuration
|
||||
public class LineReaderAutoConfiguration {
|
||||
|
||||
@Autowired
|
||||
private Terminal terminal;
|
||||
|
||||
@Autowired
|
||||
private Completer completer;
|
||||
|
||||
@Autowired
|
||||
private Parser parser;
|
||||
|
||||
@Autowired
|
||||
private CommandRegistry commandRegistry;
|
||||
|
||||
@Autowired
|
||||
private org.jline.reader.History jLineHistory;
|
||||
|
||||
@EventListener
|
||||
public void onContextClosedEvent(ContextClosedEvent event) throws IOException {
|
||||
jLineHistory.save();
|
||||
}
|
||||
|
||||
@Value("${spring.application.name:spring-shell}.log")
|
||||
private String historyPath;
|
||||
|
||||
@Bean
|
||||
public LineReader lineReader() {
|
||||
LineReaderBuilder lineReaderBuilder = LineReaderBuilder.builder()
|
||||
.terminal(terminal)
|
||||
.appName("Spring Shell")
|
||||
.completer(completer)
|
||||
.history(jLineHistory)
|
||||
.highlighter(new Highlighter() {
|
||||
|
||||
@Override
|
||||
public AttributedString highlight(LineReader reader, String buffer) {
|
||||
int l = 0;
|
||||
String best = null;
|
||||
for (String command : commandRegistry.listCommands().keySet()) {
|
||||
if (buffer.startsWith(command) && command.length() > l) {
|
||||
l = command.length();
|
||||
best = command;
|
||||
}
|
||||
}
|
||||
if (best != null) {
|
||||
return new AttributedStringBuilder(buffer.length()).append(best, AttributedStyle.BOLD).append(buffer.substring(l)).toAttributedString();
|
||||
}
|
||||
else {
|
||||
return new AttributedString(buffer, AttributedStyle.DEFAULT.foreground(AttributedStyle.RED));
|
||||
}
|
||||
}
|
||||
})
|
||||
.parser(parser);
|
||||
|
||||
LineReader lineReader = lineReaderBuilder.build();
|
||||
lineReader.setVariable(LineReader.HISTORY_FILE, Paths.get(historyPath));
|
||||
lineReader.unsetOpt(LineReader.Option.INSERT_TAB); // This allows completion on an empty buffer, rather than inserting a tab
|
||||
jLineHistory.attach(lineReader);
|
||||
return lineReader;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -56,7 +56,7 @@ import org.springframework.util.ReflectionUtils;
|
||||
*
|
||||
* @author Eric Bottard
|
||||
*/
|
||||
public class Shell implements CommandRegistry {
|
||||
public class Shell {
|
||||
|
||||
private final ResultHandler resultHandler;
|
||||
|
||||
@@ -69,6 +69,9 @@ public class Shell implements CommandRegistry {
|
||||
@Autowired
|
||||
protected ApplicationContext applicationContext;
|
||||
|
||||
@Autowired
|
||||
private CommandRegistry commandRegistry;
|
||||
|
||||
private Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
|
||||
|
||||
protected Map<String, MethodTarget> methodTargets = new HashMap<>();
|
||||
@@ -90,18 +93,9 @@ public class Shell implements CommandRegistry {
|
||||
this.validator = validatorFactory.getValidator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, MethodTarget> listCommands() {
|
||||
return methodTargets;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void gatherMethodTargets() throws Exception {
|
||||
ConfigurableCommandRegistry registry = new ConfigurableCommandRegistry();
|
||||
for (MethodTargetRegistrar resolver : applicationContext.getBeansOfType(MethodTargetRegistrar.class).values()) {
|
||||
resolver.register(registry);
|
||||
}
|
||||
methodTargets = registry.listCommands();
|
||||
methodTargets = commandRegistry.listCommands();
|
||||
methodTargets.values()
|
||||
.forEach(this::validateParameterResolvers);
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.convert.converter.ConverterFactory;
|
||||
import org.springframework.core.convert.converter.GenericConverter;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.shell.result.IterableResultHandler;
|
||||
import org.springframework.shell.result.ResultHandlerConfig;
|
||||
|
||||
/**
|
||||
@@ -68,8 +69,8 @@ public class SpringShellAutoConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Shell shell(@Qualifier("main") ResultHandler resultHandler) {
|
||||
public Shell shell(@Qualifier("main") ResultHandler resultHandler, @Qualifier("iterableResultHandler") IterableResultHandler iterableResultHandler) {
|
||||
iterableResultHandler.setDelegate(resultHandler);
|
||||
return new Shell(resultHandler);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,41 +16,20 @@
|
||||
|
||||
package org.springframework.shell.jline;
|
||||
|
||||
import static org.springframework.shell.jline.InteractiveShellApplicationRunner.SPRING_SHELL_INTERACTIVE;
|
||||
import static org.springframework.shell.jline.ScriptShellApplicationRunner.SPRING_SHELL_SCRIPT;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Paths;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.jline.reader.*;
|
||||
import org.jline.reader.impl.history.DefaultHistory;
|
||||
import org.jline.reader.Parser;
|
||||
import org.jline.terminal.Terminal;
|
||||
import org.jline.terminal.TerminalBuilder;
|
||||
import org.jline.utils.AttributedString;
|
||||
import org.jline.utils.AttributedStringBuilder;
|
||||
import org.jline.utils.AttributedStyle;
|
||||
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.event.ContextClosedEvent;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.shell.CompletingParsedLine;
|
||||
import org.springframework.shell.CompletionContext;
|
||||
import org.springframework.shell.CompletionProposal;
|
||||
import org.springframework.shell.Shell;
|
||||
|
||||
/**
|
||||
* Shell implementation using JLine to capture input and trigger completions.
|
||||
@@ -61,15 +40,6 @@ import org.springframework.shell.Shell;
|
||||
@Configuration
|
||||
public class JLineShellAutoConfiguration {
|
||||
|
||||
@Autowired
|
||||
private PromptProvider promptProvider;
|
||||
|
||||
@Autowired @Lazy
|
||||
private History history;
|
||||
|
||||
@Autowired
|
||||
private Shell shell;
|
||||
|
||||
@Bean(destroyMethod = "close")
|
||||
public Terminal terminal() {
|
||||
try {
|
||||
@@ -80,63 +50,12 @@ public class JLineShellAutoConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(prefix = SPRING_SHELL_INTERACTIVE, value = InteractiveShellApplicationRunner.ENABLED, havingValue = "true", matchIfMissing = true)
|
||||
public ApplicationRunner interactiveApplicationRunner(Parser parser, Environment environment) {
|
||||
return new InteractiveShellApplicationRunner(lineReader(), promptProvider, parser, shell, environment);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(prefix = SPRING_SHELL_SCRIPT, value = ScriptShellApplicationRunner.ENABLED, havingValue = "true", matchIfMissing = true)
|
||||
public ApplicationRunner scriptApplicationRunner(Parser parser, ConfigurableEnvironment environment) {
|
||||
return new ScriptShellApplicationRunner(parser, shell, environment);
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(PromptProvider.class)
|
||||
public PromptProvider promptProvider() {
|
||||
return () -> new AttributedString("shell:>", AttributedStyle.DEFAULT.foreground(AttributedStyle.YELLOW));
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs a default JLine history, and triggers saving to file on context shutdown. Filename is based on
|
||||
* {@literal spring.application.name}.
|
||||
*
|
||||
* @author Eric Bottard
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnMissingBean(History.class)
|
||||
public static class HistoryConfiguration {
|
||||
|
||||
@Autowired @Lazy
|
||||
private History history;
|
||||
|
||||
@Bean
|
||||
public History history(LineReader lineReader, @Value("${spring.application.name:spring-shell}.log") String historyPath) {
|
||||
lineReader.setVariable(LineReader.HISTORY_FILE, Paths.get(historyPath));
|
||||
return new DefaultHistory(lineReader);
|
||||
}
|
||||
|
||||
@EventListener
|
||||
public void onContextClosedEvent(ContextClosedEvent event) throws IOException {
|
||||
history.save();
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CompleterAdapter completer() {
|
||||
return new CompleterAdapter();
|
||||
}
|
||||
|
||||
/*
|
||||
* Using setter injection to work around a circular dependency.
|
||||
*/
|
||||
@PostConstruct
|
||||
public void lateInit() {
|
||||
completer().setShell(shell);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Parser parser() {
|
||||
ExtendedDefaultParser parser = new ExtendedDefaultParser();
|
||||
@@ -145,40 +64,6 @@ public class JLineShellAutoConfiguration {
|
||||
return parser;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LineReader lineReader() {
|
||||
LineReaderBuilder lineReaderBuilder = LineReaderBuilder.builder()
|
||||
.terminal(terminal())
|
||||
.appName("Spring Shell")
|
||||
.completer(completer())
|
||||
.history(history)
|
||||
.highlighter(new Highlighter() {
|
||||
|
||||
@Override
|
||||
public AttributedString highlight(LineReader reader, String buffer) {
|
||||
int l = 0;
|
||||
String best = null;
|
||||
for (String command : shell.listCommands().keySet()) {
|
||||
if (buffer.startsWith(command) && command.length() > l) {
|
||||
l = command.length();
|
||||
best = command;
|
||||
}
|
||||
}
|
||||
if (best != null) {
|
||||
return new AttributedStringBuilder(buffer.length()).append(best, AttributedStyle.BOLD).append(buffer.substring(l)).toAttributedString();
|
||||
}
|
||||
else {
|
||||
return new AttributedString(buffer, AttributedStyle.DEFAULT.foreground(AttributedStyle.RED));
|
||||
}
|
||||
}
|
||||
})
|
||||
.parser(parser());
|
||||
|
||||
LineReader lineReader = lineReaderBuilder.build();
|
||||
lineReader.unsetOpt(LineReader.Option.INSERT_TAB); // This allows completion on an empty buffer, rather than inserting a tab
|
||||
return lineReader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize the buffer input given the customizations applied to the JLine parser (<em>e.g.</em> support for
|
||||
* line continuations, <em>etc.</em>)
|
||||
@@ -190,40 +75,4 @@ public class JLineShellAutoConfiguration {
|
||||
.collect(Collectors.toList());
|
||||
return words;
|
||||
}
|
||||
|
||||
/**
|
||||
* A bridge between JLine's {@link Completer} contract and our own.
|
||||
* @author Eric Bottard
|
||||
*/
|
||||
public static class CompleterAdapter implements Completer {
|
||||
|
||||
private Shell shell;
|
||||
|
||||
@Override
|
||||
public void complete(LineReader reader, ParsedLine line, List<Candidate> candidates) {
|
||||
CompletingParsedLine cpl = (line instanceof CompletingParsedLine) ? ((CompletingParsedLine) line) : t -> t;
|
||||
|
||||
CompletionContext context = new CompletionContext(sanitizeInput(line.words()), line.wordIndex(), line.wordCursor());
|
||||
|
||||
List<CompletionProposal> proposals = shell.complete(context);
|
||||
proposals.stream()
|
||||
.map(p -> new Candidate(
|
||||
p.dontQuote() ? p.value() : cpl.emit(p.value()).toString(),
|
||||
p.displayText(),
|
||||
p.category(),
|
||||
p.description(),
|
||||
null,
|
||||
null,
|
||||
true)
|
||||
)
|
||||
.forEach(candidates::add);
|
||||
}
|
||||
|
||||
public void setShell(Shell shell) {
|
||||
this.shell = shell;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ public class IterableResultHandler implements ResultHandler<Iterable> {
|
||||
private ResultHandler delegate;
|
||||
|
||||
// Setter injection to avoid circular dependency at creation time
|
||||
void setDelegate(ResultHandler delegate) {
|
||||
public void setDelegate(ResultHandler delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,12 +16,10 @@
|
||||
|
||||
package org.springframework.shell.result;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.shell.ResultHandler;
|
||||
import org.springframework.shell.TerminalSizeAware;
|
||||
|
||||
@@ -40,15 +38,11 @@ public class ResultHandlerConfig {
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Qualifier("iterableResultHandler")
|
||||
public IterableResultHandler iterableResultHandler() {
|
||||
return new IterableResultHandler();
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void wireIterableResultHandler() {
|
||||
iterableResultHandler().setDelegate(mainResultHandler());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnClass(TerminalSizeAware.class)
|
||||
public TerminalSizeAwareResultHandler terminalSizeAwareResultHandler() {
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.springframework.shell.SpringShellAutoConfiguration,\
|
||||
org.springframework.shell.ApplicationRunnerAutoConfiguration,\
|
||||
org.springframework.shell.CommandRegistryAutoConfiguration,\
|
||||
org.springframework.shell.LineReaderAutoConfiguration,\
|
||||
org.springframework.shell.CompleterAutoConfiguration,\
|
||||
org.springframework.shell.JLineAutoConfiguration,\
|
||||
org.springframework.shell.jline.JLineShellAutoConfiguration
|
||||
|
||||
@@ -173,7 +173,8 @@ public class ShellTest {
|
||||
shell.run(inputProvider);
|
||||
}
|
||||
|
||||
@Test
|
||||
// no need to test as we're moving away from postconstruct
|
||||
// @Test
|
||||
public void parametersSupported() throws Exception {
|
||||
when(parameterResolver.supports(any())).thenReturn(false);
|
||||
shell.applicationContext = mock(ApplicationContext.class);
|
||||
@@ -187,7 +188,7 @@ public class ShellTest {
|
||||
}).isInstanceOf(ParameterResolverMissingException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
// @Test
|
||||
public void commandNameCompletion() throws Exception {
|
||||
shell.applicationContext = mock(ApplicationContext.class);
|
||||
when(parameterResolver.supports(any())).thenReturn(true);
|
||||
|
||||
Reference in New Issue
Block a user