Provide pty info
- Enhance ShellContext for pty info - Enhance CommandContext to include ShellContext - Fixes #985
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022 the original author or authors.
|
||||
* Copyright 2022-2024 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.
|
||||
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
package org.springframework.shell.boot;
|
||||
|
||||
import org.jline.terminal.Terminal;
|
||||
import org.jline.terminal.spi.TerminalExt;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.shell.context.DefaultShellContext;
|
||||
@@ -24,7 +27,11 @@ import org.springframework.shell.context.ShellContext;
|
||||
public class ShellContextAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public ShellContext shellContext() {
|
||||
return new DefaultShellContext();
|
||||
public ShellContext shellContext(Terminal terminal) {
|
||||
boolean pty = false;
|
||||
if (terminal instanceof TerminalExt ext) {
|
||||
pty = ext.getSystemStream() != null;
|
||||
}
|
||||
return new DefaultShellContext(pty);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022-2023 the original author or authors.
|
||||
* Copyright 2022-2024 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.
|
||||
@@ -36,7 +36,8 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
public class CommandCatalogAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(CommandCatalogAutoConfiguration.class, ShellContextAutoConfiguration.class));
|
||||
.withConfiguration(AutoConfigurations.of(CommandCatalogAutoConfiguration.class,
|
||||
JLineShellAutoConfiguration.class, ShellContextAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void defaultCommandCatalog() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 the original author or authors.
|
||||
* Copyright 2017-2024 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.
|
||||
@@ -238,7 +238,7 @@ public class Shell {
|
||||
|
||||
CommandExecution execution = CommandExecution.of(
|
||||
argumentResolvers != null ? argumentResolvers.getResolvers() : null, validator, terminal,
|
||||
conversionService, commandRegistry);
|
||||
shellContext, conversionService, commandRegistry);
|
||||
|
||||
List<CommandExceptionResolver> commandExceptionResolvers = commandRegistration.get().getExceptionResolvers();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022-2023 the original author or authors.
|
||||
* Copyright 2022-2024 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.
|
||||
@@ -23,6 +23,7 @@ import org.jline.terminal.Terminal;
|
||||
|
||||
import org.springframework.shell.command.CommandParser.CommandParserResult;
|
||||
import org.springframework.shell.command.CommandParser.CommandParserResults;
|
||||
import org.springframework.shell.context.ShellContext;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
@@ -77,6 +78,13 @@ public interface CommandContext {
|
||||
*/
|
||||
Terminal getTerminal();
|
||||
|
||||
/**
|
||||
* Gets a {@link ShellContext} associated with {@link CommandContext}.
|
||||
*
|
||||
* @return a shell context
|
||||
*/
|
||||
ShellContext getShellContext();
|
||||
|
||||
/**
|
||||
* Gets an instance of a default {@link CommandContext}.
|
||||
*
|
||||
@@ -87,8 +95,8 @@ public interface CommandContext {
|
||||
* @return a command context
|
||||
*/
|
||||
static CommandContext of(String[] args, CommandParserResults results, Terminal terminal,
|
||||
CommandRegistration commandRegistration) {
|
||||
return new DefaultCommandContext(args, results, terminal, commandRegistration);
|
||||
CommandRegistration commandRegistration, ShellContext shellContext) {
|
||||
return new DefaultCommandContext(args, results, terminal, commandRegistration, shellContext);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,13 +108,15 @@ public interface CommandContext {
|
||||
private final CommandParserResults results;
|
||||
private final Terminal terminal;
|
||||
private final CommandRegistration commandRegistration;
|
||||
private final ShellContext shellContext;
|
||||
|
||||
DefaultCommandContext(String[] args, CommandParserResults results, Terminal terminal,
|
||||
CommandRegistration commandRegistration) {
|
||||
CommandRegistration commandRegistration, ShellContext shellContext) {
|
||||
this.args = args;
|
||||
this.results = results;
|
||||
this.terminal = terminal;
|
||||
this.commandRegistration = commandRegistration;
|
||||
this.shellContext = shellContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -144,6 +154,11 @@ public interface CommandContext {
|
||||
return terminal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShellContext getShellContext() {
|
||||
return shellContext;
|
||||
}
|
||||
|
||||
private Optional<CommandParserResult> find(String name) {
|
||||
return results.results().stream()
|
||||
.filter(r -> {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022-2023 the original author or authors.
|
||||
* Copyright 2022-2024 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.
|
||||
@@ -41,6 +41,7 @@ import org.springframework.shell.command.CommandRegistration.TargetInfo.TargetTy
|
||||
import org.springframework.shell.command.invocation.InvocableShellMethod;
|
||||
import org.springframework.shell.command.invocation.ShellMethodArgumentResolverComposite;
|
||||
import org.springframework.shell.command.parser.ParserConfig;
|
||||
import org.springframework.shell.context.ShellContext;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
@@ -65,7 +66,7 @@ public interface CommandExecution {
|
||||
* @return default command execution
|
||||
*/
|
||||
public static CommandExecution of(List<? extends HandlerMethodArgumentResolver> resolvers) {
|
||||
return new DefaultCommandExecution(resolvers, null, null, null, null);
|
||||
return new DefaultCommandExecution(resolvers, null, null, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,8 +79,8 @@ public interface CommandExecution {
|
||||
* @return default command execution
|
||||
*/
|
||||
public static CommandExecution of(List<? extends HandlerMethodArgumentResolver> resolvers, Validator validator,
|
||||
Terminal terminal, ConversionService conversionService) {
|
||||
return new DefaultCommandExecution(resolvers, validator, terminal, conversionService, null);
|
||||
Terminal terminal, ShellContext shellContext, ConversionService conversionService) {
|
||||
return new DefaultCommandExecution(resolvers, validator, terminal, shellContext, conversionService, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,8 +93,8 @@ public interface CommandExecution {
|
||||
* @return default command execution
|
||||
*/
|
||||
public static CommandExecution of(List<? extends HandlerMethodArgumentResolver> resolvers, Validator validator,
|
||||
Terminal terminal, ConversionService conversionService, CommandCatalog commandCatalog) {
|
||||
return new DefaultCommandExecution(resolvers, validator, terminal, conversionService, commandCatalog);
|
||||
Terminal terminal, ShellContext shellContext, ConversionService conversionService, CommandCatalog commandCatalog) {
|
||||
return new DefaultCommandExecution(resolvers, validator, terminal, shellContext, conversionService, commandCatalog);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,14 +105,16 @@ public interface CommandExecution {
|
||||
private List<? extends HandlerMethodArgumentResolver> resolvers;
|
||||
private Validator validator;
|
||||
private Terminal terminal;
|
||||
private ShellContext shellContext;
|
||||
private ConversionService conversionService;
|
||||
private CommandCatalog commandCatalog;
|
||||
|
||||
public DefaultCommandExecution(List<? extends HandlerMethodArgumentResolver> resolvers, Validator validator,
|
||||
Terminal terminal, ConversionService conversionService, CommandCatalog commandCatalog) {
|
||||
Terminal terminal, ShellContext shellContext, ConversionService conversionService, CommandCatalog commandCatalog) {
|
||||
this.resolvers = resolvers;
|
||||
this.validator = validator;
|
||||
this.terminal = terminal;
|
||||
this.shellContext = shellContext;
|
||||
this.conversionService = conversionService;
|
||||
this.commandCatalog = commandCatalog;
|
||||
}
|
||||
@@ -175,7 +178,7 @@ public interface CommandExecution {
|
||||
throw new CommandParserExceptionsException("Command parser resulted errors", results.errors());
|
||||
}
|
||||
|
||||
CommandContext ctx = CommandContext.of(args, results, terminal, usedRegistration);
|
||||
CommandContext ctx = CommandContext.of(args, results, terminal, usedRegistration, shellContext);
|
||||
|
||||
Object res = null;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022 the original author or authors.
|
||||
* Copyright 2022-2024 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.
|
||||
@@ -25,6 +25,15 @@ import org.springframework.util.Assert;
|
||||
public class DefaultShellContext implements ShellContext {
|
||||
|
||||
private InteractionMode interactionMode = InteractionMode.ALL;
|
||||
private final boolean pty;
|
||||
|
||||
public DefaultShellContext() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
public DefaultShellContext(boolean pty) {
|
||||
this.pty = pty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionMode getInteractionMode() {
|
||||
@@ -36,4 +45,9 @@ public class DefaultShellContext implements ShellContext {
|
||||
Assert.notNull(interactionMode, "mode cannot be null");
|
||||
this.interactionMode = interactionMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPty() {
|
||||
return this.pty;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022 the original author or authors.
|
||||
* Copyright 2022-2024 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.
|
||||
@@ -36,4 +36,13 @@ public interface ShellContext {
|
||||
* @param interactionMode the interaction mode
|
||||
*/
|
||||
void setInteractionMode(InteractionMode interactionMode);
|
||||
|
||||
/**
|
||||
* Gets if shell has a proper {@code pty} terminal. Terminal don't have
|
||||
* {@code pty} in cases where output is piped into a file or terminal is run in
|
||||
* an ci system where there is no real user interaction.
|
||||
*
|
||||
* @return {@code true} if terminal has pty features
|
||||
*/
|
||||
boolean hasPty();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2023 the original author or authors.
|
||||
* Copyright 2023-2024 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.
|
||||
@@ -43,7 +43,7 @@ public class CommandExecutionCustomConversionTests {
|
||||
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
|
||||
resolvers.add(new ArgumentHeaderMethodArgumentResolver(conversionService, null));
|
||||
resolvers.add(new CommandContextMethodArgumentResolver());
|
||||
execution = CommandExecution.of(resolvers, null, null, conversionService, commandCatalog);
|
||||
execution = CommandExecution.of(resolvers, null, null, null, conversionService, commandCatalog);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -47,7 +47,7 @@ public class CommandExecutionTests extends AbstractCommandTests {
|
||||
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
|
||||
resolvers.add(new ArgumentHeaderMethodArgumentResolver(conversionService, null));
|
||||
resolvers.add(new CommandContextMethodArgumentResolver());
|
||||
execution = CommandExecution.of(resolvers, null, null, conversionService, commandCatalog);
|
||||
execution = CommandExecution.of(resolvers, null, null, null, conversionService, commandCatalog);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
*** xref:appendices/techintro/registration.adoc[]
|
||||
*** xref:appendices/techintro/parser.adoc[]
|
||||
*** xref:appendices/techintro/execution.adoc[]
|
||||
*** xref:appendices/techintro/shellcontext.adoc[]
|
||||
*** xref:appendices/techintro/commandcontext.adoc[]
|
||||
*** xref:appendices/techintro/commandcatalog.adoc[]
|
||||
*** xref:appendices/techintro/theming.adoc[]
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
[[shell-context]]
|
||||
= Shell Context
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
ifndef::snippets[:snippets: ../../../../../src/test/java/org/springframework/shell/docs]
|
||||
|
||||
The `ShellContext` interface gives access to a currently running
|
||||
shell context. You can use it to get access to a generic shell options.
|
||||
|
||||
_InteractionMode_ is telling if shell is running on a _non-interactive_ or
|
||||
_interactive_ mode.
|
||||
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/ShellContextSnippets.java[tag=interactionMode]
|
||||
----
|
||||
|
||||
_Pty_ is telling if current terminal has a pty features which not a case
|
||||
when output is piped into file or if terminal is run in a ci system.
|
||||
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/ShellContextSnippets.java[tag=hasPty]
|
||||
----
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022 the original author or authors.
|
||||
* Copyright 2022-2024 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.
|
||||
@@ -22,7 +22,7 @@ import org.springframework.shell.command.CommandContext;
|
||||
@SuppressWarnings("unused")
|
||||
public class CommandContextSnippets {
|
||||
|
||||
CommandContext ctx = CommandContext.of(null, null, null, null);
|
||||
CommandContext ctx = CommandContext.of(null, null, null, null, null);
|
||||
|
||||
void dump1() {
|
||||
// tag::snippet1[]
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2024 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.docs;
|
||||
|
||||
import org.springframework.shell.context.InteractionMode;
|
||||
import org.springframework.shell.context.ShellContext;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
class ShellContextSnippets {
|
||||
|
||||
ShellContext ctx = new ShellContext() {
|
||||
|
||||
@Override
|
||||
public InteractionMode getInteractionMode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInteractionMode(InteractionMode interactionMode) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void dump1() {
|
||||
// tag::hasPty[]
|
||||
boolean hasPty = ctx.hasPty();
|
||||
// end::hasPty[]
|
||||
}
|
||||
|
||||
void dump2() {
|
||||
// tag::interactionMode[]
|
||||
InteractionMode interactionMode = ctx.getInteractionMode();
|
||||
// end::interactionMode[]
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2024 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.samples.e2e;
|
||||
|
||||
import org.jline.terminal.Terminal;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.shell.command.CommandContext;
|
||||
import org.springframework.shell.command.CommandRegistration;
|
||||
import org.springframework.shell.command.annotation.Command;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
public class StdOutTypeCommands {
|
||||
|
||||
@Command(command = BaseE2ECommands.ANNO, group = BaseE2ECommands.GROUP)
|
||||
public static class Annotation extends BaseE2ECommands {
|
||||
|
||||
@Autowired
|
||||
Terminal terminal;
|
||||
|
||||
@Command(command = "stdout")
|
||||
public String testStdoutAnnotation(
|
||||
CommandContext commandContext
|
||||
) {
|
||||
boolean hasPty = commandContext.getShellContext().hasPty();
|
||||
return String.format("hasPty='%s'", hasPty);
|
||||
}
|
||||
}
|
||||
|
||||
@Component
|
||||
public static class Registration extends BaseE2ECommands {
|
||||
|
||||
@Bean
|
||||
public CommandRegistration testStdoutRegistration() {
|
||||
return getBuilder()
|
||||
.command(REG, "stdout")
|
||||
.group(GROUP)
|
||||
.withTarget()
|
||||
.function(ctx -> {
|
||||
boolean hasPty = ctx.getShellContext().hasPty();
|
||||
return String.format("hasPty='%s'", hasPty);
|
||||
})
|
||||
.and()
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user