package com.jaumard.sails.utils;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.process.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.containers.ContainerUtil;
import org.apache.commons.codec.Charsets;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* Created by jaumard on 04/04/2015.
*/
public class SailsJSCommandLine
{
private static final Logger LOGGER = Logger.getInstance(SailsJSCommandLine.class);
public static final String GENERATE_API = "api";
public static final String GENERATE_MODEL = "model";
public static final String GENERATE_CONTROLLER = "controller";
public static final String GENERATE_ADAPTER = "adapter";
public static final String NPM = "npm";
public static final String PLATFORM_SAILS = "sails";
public static final String PLATFORM_TREELINE = "treeline";
@Nullable
private final String myWorkDir;
@NotNull
private final String myPath;
@Nullable
private String version;
private boolean myIsCorrect = true;
private Map<String, String> myEnv = ContainerUtil.newHashMap();
public SailsJSCommandLine(@NotNull String path, @Nullable String dir)
{
myWorkDir = dir;
myPath = path;
try
{
version = getInnerVersion(myPath, "--version").replace("\"", "").trim();
}
catch (Exception e)
{
version = null;
LOGGER.debug(e.getMessage(), e);
myIsCorrect = false;
}
}
public boolean isCorrectExecutable()
{
return myIsCorrect;
}
public String version()
{
return version;
}
public void createNewProject(String name) throws Exception
{
executeVoidCommand(myPath, "new", name);
}
public void generateNew(String what, String name, String[] extras) throws Exception
{
if (extras == null)
{
extras = new String[]{};
}
String[] command = new String[4 + extras.length];
command[0] = myPath;
command[1] = "generate";
command[2] = what;
command[3] = name;
System.arraycopy(extras, 0, command, 4, extras.length);
executeVoidCommand(command);
}
/**
* @param path is path a sails executable
* @return true - sails / false - not sails / null - cannot detect
*/
@Nullable
public static Boolean isSailsJSExecutableByPath(@Nullable String path)
{
if (StringUtil.isEmpty(path))
{
return false;
}
File file = new File(path);
if (!file.exists())
{
return false;
}
if (file.getName().contains(PLATFORM_TREELINE))
{
return false;
}
if (file.getName().contains(PLATFORM_SAILS))
{
return true;
}
return null;
}
private void executeVoidCommand(final String... command)
{
try
{
ProcessOutput output = executeAndGetOut(command);
if (output.getExitCode() > 0)
{
throw new RuntimeException("Command error: " + output.getStderr());
}
}
catch (Exception e)
{
LOGGER.debug(e.getMessage(), e);
throw new RuntimeException("Select correct executable path", e);
}
}
private String getInnerVersion(String... command)
{
try
{
final ProcessOutput output = executeAndGetOut(command);
String stderr = output.getStderr();
if (output.getExitCode() > 0)
{
throw new RuntimeException("Command error: " + stderr);
}
String stdout = output.getStdout();
if (StringUtil.isEmpty(stdout) && !StringUtil.isEmpty(stderr))
{
return stderr;
}
return stdout;
}
catch (Exception e)
{
throw new RuntimeException(e.getMessage(), e);
}
}
private String executeAndReturnResult(String[] command)
{
try
{
final ProcessOutput output = executeAndGetOut(command);
if (output.getExitCode() > 0)
{
throw new RuntimeException("Command error: " + output.getStderr());
}
return output.getStdout();
}
catch (Exception e)
{
throw new RuntimeException(e.getMessage(), e);
}
}
private ProcessOutput executeAndGetOut(String[] command) throws ExecutionException
{
final GeneralCommandLine commandLine = new GeneralCommandLine(command);
commandLine.withWorkDirectory(myWorkDir);
commandLine.setPassParentEnvironment(true);
commandLine.withEnvironment(myEnv);
Process process = commandLine.createProcess();
OSProcessHandler processHandler = new ColoredProcessHandler(process, commandLine.getCommandLineString(), Charsets.UTF_8);
final ProcessOutput output = new ProcessOutput();
processHandler.addProcessListener(new ProcessAdapter()
{
@Override
public void onTextAvailable(ProcessEvent event, Key outputType)
{
if (outputType == ProcessOutputTypes.STDERR)
{
output.appendStderr(event.getText());
}
else if (outputType != ProcessOutputTypes.SYSTEM)
{
output.appendStdout(event.getText());
}
}
});
processHandler.startNotify();
if (processHandler.waitFor(TimeUnit.SECONDS.toMillis(120)))
{
output.setExitCode(process.exitValue());
}
else
{
processHandler.destroyProcess();
output.setTimeout();
}
return output;
}
public void npmInstall()
{
executeVoidCommand(myPath, "install");
}
}