package com.github.alexcojocaru.mojo.elasticsearch.v2.util;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ProcessDestroyer;
import org.apache.commons.exec.environment.EnvironmentUtils;
import org.apache.commons.lang3.SystemUtils;
import org.apache.maven.plugin.logging.Log;
import com.github.alexcojocaru.mojo.elasticsearch.v2.ElasticsearchSetupException;
import com.github.alexcojocaru.mojo.elasticsearch.v2.InstanceConfiguration;
/**
* @author Alex Cojocaru
*/
public class ProcessUtil
{
/**
* Build an OS dependent command line around the given executable name / relative path.
* On Windows, the '/' file path separator in the executable are replaced with '\'.
* @param executable - the executable name or relative path
* @return - the command line tailored to the current OS
*/
public static CommandLine buildCommandLine(String executable)
{
CommandLine cmd;
if (SystemUtils.IS_OS_WINDOWS)
{
String windowsExecutable = executable.replace('/', '\\');
cmd = new CommandLine("cmd")
.addArgument("/c")
.addArgument(windowsExecutable);
}
else
{
cmd = new CommandLine(executable);
}
return cmd;
}
/**
* Run the given command as a process within the supplied instance config context
* and wait until it finalizes. An ElasticsearchSetupException is thrown if the exit code
* is not 0.
* @param config - the instance config
* @param command - the command to execute
*/
public static void executeScript(InstanceConfiguration config, CommandLine command)
{
executeScript(config, command, null, null);
}
/**
* Run the given command as a process within the supplied instance config context
* and wait until it finalizes. An ElasticsearchSetupException is thrown if the exit code
* is not 0.
* @param config - the instance config
* @param command - the command to execute
* @param environment - a map of environment variables; can be null
* @param processDestroyer - a destroyer handler for the spawned process; can be null
*/
public static void executeScript(InstanceConfiguration config, CommandLine command,
Map<String, String> environment, ProcessDestroyer processDestroyer)
{
Log log = config.getClusterConfiguration().getLog();
int instanceId = config.getId();
File baseDir = new File(config.getBaseDir());
Map<String, String> completeEnvironment = createEnvironment(environment);
DefaultExecutor executor = new DefaultExecutor();
executor.setWorkingDirectory(baseDir);
executor.setProcessDestroyer(processDestroyer); // allows null
try
{
log.debug(String.format("Using environment: %s", completeEnvironment));
log.info(String.format(
"Elasticsearch[%d]: Executing command '%s' in directory '%s'",
instanceId,
command.toString(),
baseDir));
int exitCode = executor.execute(command, completeEnvironment);
if (exitCode != 0)
{
throw new ElasticsearchSetupException(String.format(
"Elasticsearch [%d]: Command '%s' in directory '%s' finished with exit code %d; see above for details",
instanceId, command, baseDir, exitCode));
}
log.info(String.format(
"Elasticsearch[%d]: The process finished with exit code %d",
instanceId,
exitCode));
}
catch (IOException e)
{
throw new ElasticsearchSetupException(
String.format(
"Elasticsearch [%d]: Cannot execute command '%s' in directory '%s'",
instanceId, command, baseDir),
e);
}
}
/**
* Create an environment by merging the current environment and the supplied one.
* If the supplied environment is null, null is returned.
* @param environment
* @return an execution environment
*/
private static Map<String, String> createEnvironment(Map<String, String> environment)
{
Map<String, String> result = null;
if (environment != null)
{
try
{
result = EnvironmentUtils.getProcEnvironment();
}
catch (IOException ex)
{
throw new ElasticsearchSetupException(
"Cannot get the current process environment", ex);
}
result.putAll(environment);
}
return result;
}
}