spring-projects / spring-shell

Spring based shell
http://projects.spring.io/spring-shell/
Apache License 2.0
734 stars 396 forks source link

Add the possibility to start the interactive mode after the end of the non-interactive mode #546

Open Xinerfapre opened 2 years ago

Xinerfapre commented 2 years ago

Is it possible to add the possibility to start the interactive mode after the end of the non-interactive mode?

jvalkeal commented 2 years ago

Currently no, what would be a use case for this?

Xinerfapre commented 2 years ago

If possible, I would like to start my application with non-interactive commands, for example to configure with input data the thread that will be started and then use interactive commands to interact with the thread.

jvalkeal commented 2 years ago

It may be difficult to implement but I see how this could by useful. Traditionally these types of "preparations" are done withing interactive session with additional commands, like "connect/disconnect to env/server" and then commands can dynamically come and go.

Going first via non-interactive would remove one step user needs to do.

Xinerfapre commented 1 year ago

Can't something like this in the run method of the DefaultShellApplicationRunner class do the job?

@Override
public void run(ApplicationArguments args) throws Exception {
    log.debug("Checking shell runners {}", shellRunners);
    // Optional<ShellRunner> optional = shellRunners.stream().filter(sh ->
    // sh.canRun(args)).findFirst();
    // ShellRunner shellRunner = optional.orElse(null);
    shellRunners.stream().filter(sh -> sh.canRun(args)).forEachOrdered(shellRunner -> {
        logger.debug("Using shell runner {}", shellRunner);
        if (shellRunner != null) {
            try {
                shellRunner.run(args);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

Or something like this for the exception.

@Override
public void run(ApplicationArguments args) throws Exception {
    log.debug("Checking shell runners {}", shellRunners);
    //Optional<ShellRunner> optional = shellRunners.stream()
    //      .filter(sh -> sh.canRun(args))
    //      .findFirst();
    //ShellRunner shellRunner = optional.orElse(null);
    for (ShellRunner shellRunner : shellRunners.stream().filter(sh -> sh.canRun(args)).toArray(ShellRunner[]::new)) {
        log.debug("Using shell runner {}", shellRunner);
        if (shellRunner != null) {
            shellRunner.run(args);
        }
    }
}
Xinerfapre commented 1 year ago

If anyone wants :

package myproject.myshell;

import java.util.Collections;
import java.util.List;
import java.util.Optional;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.annotation.Order;
import org.springframework.shell.ShellApplicationRunner;
import org.springframework.shell.ShellRunner;
import org.springframework.stereotype.Component;

@Component
@Order(MyShellApplicationRunner.PRECEDENCE)
public class MyShellApplicationRunner implements ShellApplicationRunner {
    @Value("${myshell.interactive-after-noninteractive:false}")
    boolean interAfterNInter;
    /**
     * The precedence at which this runner is executed with respect to other
     * ApplicationRunner beans
     */
    public static final int PRECEDENCE = 0;
    private static final Logger logger = LoggerFactory
            .getLogger(MyShellApplicationRunner.class);
    private final List<ShellRunner> shellRunners;

    public MyShellApplicationRunner(List<ShellRunner> shellRunners) {
        Collections.sort(shellRunners, new AnnotationAwareOrderComparator());
        this.shellRunners = shellRunners;
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        logger.debug("Checking shell runners {}", shellRunners);
        if (interAfterNInter)
            for (ShellRunner shellRunner : shellRunners.stream()
                    .filter(sh -> sh.canRun(args))
                    .toArray(ShellRunner[]::new)) {
                runShellRunner(shellRunner, args);
            }
        else {
            Optional<ShellRunner> optional = shellRunners.stream()
                    .filter(sh -> sh.canRun(args))
                    .findFirst();
            ShellRunner shellRunner = optional.orElse(null);
            runShellRunner(shellRunner, args);
        }
    }

    private void runShellRunner(ShellRunner shellRunner,
            ApplicationArguments args) throws Exception {
        logger.debug("Using shell runner {}", shellRunner);
        if (shellRunner != null) {
            shellRunner.run(args);
        }
    }
}

And you can enable or disable it in your configuration file (".properties", ".yml") with :

myshell.interactive-after-noninteractive = true # Default value is false
myshell:
    interactive-after-noninteractive: true # Default value is false