package rod; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.Executors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import rx.Observable; import rx.observables.StringObservable; import rx.subjects.PublishSubject; public abstract class TerminalCommand implements Action { private static final Logger logger = LoggerFactory.getLogger(TerminalCommand.class); private static final String SUDO_COMMAND = "sudo"; private final String command; private final List<String> commandArguments; private final boolean sudo; private final Runtime runtime; private final PublishSubject<String> output = PublishSubject.create(); protected TerminalCommand(final Builder<?> builder) { command = builder.command; commandArguments = builder.commandArguments; sudo = builder.sudo; runtime = builder.runtime; } @Override public void execute() { Executors.newSingleThreadExecutor().execute(this::runFunction); } public Observable<String> getOutput() { return output.asObservable(); } private void runFunction() { try { final String[] command = buildCommand(); logger.debug("Executing command: {}", print(command)); final Process process = runtime.exec(command); final InputStreamReader processOutputReader = new InputStreamReader(process.getInputStream()); StringObservable.from(processOutputReader) .flatMap(s -> Observable.from(s.split("\n"))) .subscribe(output); } catch (final IOException e) { logger.error("Failed to run command " + this.getClass().getName(), e); } } private static String print(final String[] command) { final StringBuilder sb = new StringBuilder(); for (final String c : command) { sb.append(c).append(" "); } sb.deleteCharAt(sb.length() - 1); return sb.toString(); } private String[] buildCommand() { final ArrayList<String> commandBuilder = new ArrayList<>(commandArguments.size() + 1); if (sudo) { commandBuilder.add(SUDO_COMMAND); } commandBuilder.add(command); commandBuilder.addAll(commandArguments); return commandBuilder.toArray(new String[commandBuilder.size()]); } @SuppressWarnings({ "unchecked" }) public static class Builder<T extends Builder<?>> { private String command; private final List<String> commandArguments = new ArrayList<>(); private boolean sudo = false; private Runtime runtime; public T command(final String command) { this.command = command; return (T) this; } public T withArgument(final String argument) { commandArguments.add(argument); return (T) this; } public T withArguments(final String... arguments) { commandArguments.addAll(Arrays.asList(arguments)); return (T) this; } public T sudo(final boolean sudo) { this.sudo = sudo; return (T) this; } public T runtime(final Runtime runtime) { this.runtime = runtime; return (T) this; } } }