All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sshtools.commands.CliCommand Maven / Gradle / Ivy

The newest version!
package com.sshtools.commands;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

import com.sshtools.common.util.Utils;
import com.sshtools.jaul.Phase;
import com.sshtools.sequins.Prompter.PromptContextBuilder;

import picocli.CommandLine;

public abstract class CliCommand extends SshCommand {

	
	protected CliCommand(Optional defaultPhase) {
		super(defaultPhase);
	}

	@Override
	protected int runCommand() {

		try {
			
			int exitCode = 0;
			
			if(startCLI()) {
				do {
					try {
						var cmd = getTerminal().prompt(PromptContextBuilder.builder().withUse(getUsername()).build(), "{0} ", getPrompt());
						if(cmd == null) {
							getTerminal().getWriter().println();
							break;
						}
						else if (cmd.length() > 0) {
							exitCode = executeCommand(cmd);
						}
	
					} catch(Exception e) {
						if(!isQuiet())
							error("Operation failed.", e);
						System.err.println(String.format("%s", e.getMessage()));
					} 
				} while (!canExit());
			}
			
			return exitCode;
		} catch (Exception e1) {
			if(!isQuiet())
				error("Failed.", e1);
			return 1;
		} 

	}
	
	protected boolean startCLI() throws IOException, InterruptedException {
		return true;
	}

	private int executeCommand(String cmd) throws IOException, InterruptedException {
		
		var newargs = parseQuotedString(cmd);
		newargs.removeIf(item -> item == null || "".equals(item));
		var args = newargs.toArray(new String[0]);
		if (args.length > 0) {
			return spawn(args);
		}
		return 0;
	}

	protected int source(InputStream in) throws IOException, InterruptedException {
		
		int exitCode = 0;
		try(BufferedReader r = new BufferedReader(new InputStreamReader(in))) {
			String line = null;
			while ((line = r.readLine()) != null) {
				if(line.startsWith("#") || Utils.isBlank(line)) {
					continue;
				}
				exitCode = executeCommand(line);
			}
		} finally {
			in.close();
		}
		
		return exitCode;
	}
	
	protected int spawn(String[] args) throws IOException, InterruptedException {
		
		if(args[0].startsWith("!")) {
			args[0] = args[0].substring(1);
			var pb = new ProcessBuilder(Arrays.asList(args));
			pb.directory(getLcwd());
			pb.redirectErrorStream(true);
			var p = pb.start();
			try {
				var thread = new Thread(() -> {
					byte[] b = new byte[256];
					var in = System.in;
					var out = p.getOutputStream();
					int r;
					try {
						while( ( r = in.read(b)) != -1) {
							out.write(b, 0, r);
							out.flush();
						}
					}
					catch(Exception ioe) {
					}
				});
				thread.start();
				try {
					p.getInputStream().transferTo(System.out);
				}
				finally {
					thread.interrupt();
				}
			}
			finally {
				if(p.waitFor() != 0) {
					System.err.println(String.format("%s exited with error code %d.", args[0], p.exitValue()));
				}
			}
			
			return p.exitValue();
		}
		else { 
			var cl = new CommandLine(createInteractiveCommand());
			cl.setTrimQuotes(true);
			cl.setExecutionExceptionHandler(new ExceptionHandler(this));
			cl.setUnmatchedArgumentsAllowed(true);
			cl.setUnmatchedOptionsAllowedAsOptionParameters(true);
			cl.setUnmatchedOptionsArePositionalParams(true);
			return cl.execute(args);
		}
		
	}

	protected abstract boolean canExit();

	protected abstract void error(String string, Exception e);

	protected abstract boolean isQuiet();

	protected abstract Object createInteractiveCommand();

	protected File getLcwd() {
		try {
			return new File(".").getCanonicalFile();
		} catch (IOException e) {
			return new File(System.getProperty("user.dir"));
		}
	}

	/**
	 * Parse a space separated string into a list, treating portions quotes with
	 * single quotes as a single element. Single quotes themselves and spaces can be
	 * escaped with a backslash.
	 * 
	 * @param command command to parse
	 * @return parsed command
	 */
	public static List parseQuotedString(String command) {
		var args = new ArrayList();
		var escaped = false;
		var quoted = false;
		var word = new StringBuilder();
		for (int i = 0; i < command.length(); i++) {
			char c = command.charAt(i);
			if (c == '"' && !escaped) {
				if (quoted) {
					quoted = false;
				} else {
					quoted = true;
				}
			} else if (c == '\\' && !escaped) {
				escaped = true;
			} else if (c == ' ' && !escaped && !quoted) {
				if (word.length() > 0) {
					args.add(word.toString());
					word.setLength(0);
					;
				}
			} else {
				word.append(c);
			}
		}
		if (word.length() > 0)
			args.add(word.toString());
		return args;
	}


	protected String getPrompt() {
		return String.format("%s>", getCommandName());
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy