com.telenav.cactus.maven.util.CliCommand Maven / Gradle / Ivy
The newest version!
package com.telenav.cactus.maven.util;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.function.Supplier;
/**
* A utility program we need to run, which takes care of the general ugliness of
* java process management, and converting output into a usable object.
*
* @author Tim Boudreau
*/
public abstract class CliCommand implements Supplier
{
protected final String name;
protected final ProcessResultConverter resultCreator;
public CliCommand(String name, ProcessResultConverter resultCreator)
{
this.name = name;
this.resultCreator = resultCreator;
}
public static CliCommand fixed(String command, Path workingDir, String... fixedArgs)
{
return new SimpleCommand(command, workingDir, fixedArgs);
}
static class SimpleCommand extends CliCommand
{
private final Path workingDir;
private final String[] fixedArgs;
public SimpleCommand(String name, Path workingDir, String... fixedArgs)
{
super(name, new StringProcessResultConverterImpl());
this.workingDir = workingDir;
this.fixedArgs = fixedArgs;
}
@Override
protected Optional workingDirectory()
{
return Optional.ofNullable(workingDir);
}
@Override
protected void configureArguments(List list)
{
list.addAll(Arrays.asList(fixedArgs));
}
}
public String get()
{
return toString();
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder(name);
List args = new ArrayList<>();
configureArguments(args);
for (String arg : args)
{
sb.append(' ').append(arg);
}
workingDirectory().ifPresent(dir ->
{
sb.append(" (in ").append(dir).append(')');
});
return sb.toString();
}
protected Optional workingDirectory()
{
return Optional.empty();
}
/**
* Append command-line arguments passed to the found binary to the list.
*
* @param list A list
*/
protected abstract void configureArguments(List list);
/**
* Do any customization of the process builder (env, etc) here.
*
* @param bldr A process builder
*/
protected void configureProcessBulder(ProcessBuilder bldr)
{
// for subclasses
}
/**
* Throw here if the command is misconfigured and cannot be run.
*/
protected void validate()
{
// do nothing
}
private void internalConfigureProcessBuilder(ProcessBuilder bldr)
{
workingDirectory().ifPresent(dir ->
{
bldr.directory(dir.toFile());
});
configureProcessBulder(bldr);
}
public AwaitableCompletionStage run()
{
return AwaitableCompletionStage.from(() ->
{
ThrowingOptional p = launch();
if (!p.isPresent())
{
return CompletableFuture.failedStage(
new IOException("Could not find executable for " + this));
}
return resultCreator.onProcessStarted(this, p.get());
});
}
/**
* Override to log process start or similar.
*
* @param proc A process
*/
protected void onLaunch(Process proc)
{
}
protected ThrowingOptional launch()
{
validate();
return ThrowingOptional.from(PathUtils.findExecutable(name)).map(path ->
{
List commandLine = new ArrayList<>();
commandLine.add(path.toString());
configureArguments(commandLine);
ProcessBuilder pb = new ProcessBuilder(commandLine);
internalConfigureProcessBuilder(pb);
Process proc = pb.start();
onLaunch(proc);
return proc;
});
}
}