package org.elixir_lang.jps.builder; import com.intellij.execution.ExecutionException; import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.execution.process.BaseOSProcessHandler; import com.intellij.execution.process.ProcessAdapter; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.text.StringUtil; import org.elixir_lang.jps.mix.JpsMixConfigurationExtension; import org.elixir_lang.jps.model.ElixirCompilerOptions; import org.elixir_lang.jps.model.JpsElixirCompilerOptionsExtension; import org.elixir_lang.jps.model.JpsElixirSdkType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.builders.BuildOutputConsumer; import org.jetbrains.jps.builders.DirtyFilesHolder; import org.jetbrains.jps.incremental.CompileContext; import org.jetbrains.jps.incremental.ProjectBuildException; import org.jetbrains.jps.incremental.TargetBuilder; import org.jetbrains.jps.incremental.messages.BuildMessage; import org.jetbrains.jps.incremental.messages.CompilerMessage; import org.jetbrains.jps.model.JpsDummyElement; import org.jetbrains.jps.model.JpsProject; import org.jetbrains.jps.model.library.sdk.JpsSdk; import org.jetbrains.jps.model.module.JpsModule; import java.io.File; import java.io.IOException; import java.net.URL; import java.nio.charset.Charset; import java.util.Collections; /** * Created by zyuyou on 15/7/12. */ public class MixBuilder extends TargetBuilder<ElixirSourceRootDescriptor, ElixirTarget> { private static final String NAME = "mix"; private static final String MIX_CONFIG_FILE_NAME = "mix.config"; private final static Logger LOG = Logger.getInstance(MixBuilder.class); protected MixBuilder() { super(Collections.singleton(ElixirTargetType.PRODUCTION)); } @Override public void build(@NotNull ElixirTarget target, @NotNull DirtyFilesHolder<ElixirSourceRootDescriptor, ElixirTarget> holder, @NotNull BuildOutputConsumer outputConsumer, @NotNull CompileContext context) throws ProjectBuildException, IOException { if(!holder.hasDirtyFiles() && !holder.hasRemovedFiles()) return; JpsModule module = target.getModule(); JpsProject project = module.getProject(); ElixirCompilerOptions compilerOptions = JpsElixirCompilerOptionsExtension.getOrCreateExtension(project).getOptions(); if(!compilerOptions.myUseMixCompiler) return; String mixPath = getMixExecutablePath(project); if(mixPath == null){ String errorMessage = "Mix path is not set."; context.processMessage(new CompilerMessage(NAME, BuildMessage.Kind.ERROR, errorMessage)); throw new ProjectBuildException(errorMessage); } JpsSdk<JpsDummyElement> sdk = ElixirTargetBuilderUtil.getSdk(context, module); String elixirPath = JpsElixirSdkType.getScriptInterpreterExecutable(sdk.getHomePath()).getAbsolutePath(); for(String contentRootUrl: module.getContentRootsList().getUrls()){ String contentRootPath = new URL(contentRootUrl).getPath(); File contentRootDir = new File(contentRootPath); File mixConfigFile = new File(contentRootDir, MIX_CONFIG_FILE_NAME); if(!mixConfigFile.exists()) continue; runMix(elixirPath, mixPath, contentRootPath, compilerOptions.myAttachDebugInfoEnabled, context); } } @NotNull @Override public String getPresentableName() { return NAME; } private static void runMix(@NotNull String elixirPath, @NotNull String mixPath, @Nullable String contentRootPath, boolean addDebugInfo, @NotNull CompileContext context) throws ProjectBuildException{ GeneralCommandLine commandLine = new GeneralCommandLine(); commandLine.withWorkDirectory(contentRootPath); commandLine.setExePath(elixirPath); commandLine.addParameter(mixPath); commandLine.addParameter("compile"); if(!addDebugInfo){ commandLine.addParameter("--no-debug-info"); } Process process; try{ process = commandLine.createProcess(); } catch (ExecutionException e) { throw new ProjectBuildException("Failed to run mix.", e); } BaseOSProcessHandler handler = new BaseOSProcessHandler(process, commandLine.getCommandLineString(), Charset.defaultCharset()); ProcessAdapter adapter = new ElixirCompilerProcessAdapter(context, NAME, commandLine.getWorkDirectory().getPath()); handler.addProcessListener(adapter); handler.startNotify(); handler.waitFor(); } @Nullable private static String getMixExecutablePath(@Nullable JpsProject project){ JpsMixConfigurationExtension mixConfigurationExtension = JpsMixConfigurationExtension.getExtension(project); String mixPath = mixConfigurationExtension != null ? mixConfigurationExtension.getMixPath() : null; return StringUtil.isEmptyOrSpaces(mixPath) ? null : mixPath; } }