/* * Copyright 2000-2009 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.napile.idea.thermit.config.execution; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.napile.idea.thermit.ThermitBundle; import com.intellij.compiler.impl.javaCompiler.FileObject; import com.intellij.compiler.impl.javaCompiler.javac.JavacOutputParser; import com.intellij.execution.process.OSProcessHandler; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.compiler.CompilerMessageCategory; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.rt.ant.execution.IdeaAntLogger2; import com.intellij.util.text.StringTokenizer; public class OutputParser { @NonNls private static final String JAVAC = "javac"; @NonNls private static final String NAPILEC = "napilec"; @NonNls private static final String ECHO = "echo"; private static final Logger LOG = Logger.getInstance(OutputParser.class); private final Project myProject; private final AntBuildMessageView myMessageView; private final WeakReference<ProgressIndicator> myProgress; private final String myBuildName; private final OSProcessHandler myProcessHandler; private boolean isStopped; private List<String> myJavacMessages; private List<String> myNapileMessages; private boolean myFirstLineProcessed; private boolean myStartedSuccessfully; private boolean myIsEcho; public OutputParser(Project project, OSProcessHandler processHandler, AntBuildMessageView errorsView, ProgressIndicator progress, String buildName) { myProject = project; myProcessHandler = processHandler; myMessageView = errorsView; myProgress = new WeakReference<ProgressIndicator>(progress); myBuildName = buildName; myMessageView.setParsingThread(this); } public final void stopProcess() { myProcessHandler.destroyProcess(); } public boolean isTerminateInvoked() { return myProcessHandler.isProcessTerminating(); } protected Project getProject() { return myProject; } protected OSProcessHandler getProcessHandler() { return myProcessHandler; } public final boolean isStopped() { return isStopped; } public final void setStopped(boolean stopped) { isStopped = stopped; } private void setProgressStatistics(String s) { final ProgressIndicator progress = myProgress.get(); if(progress != null) { progress.setText2(s); } } private void setProgressText(String s) { final ProgressIndicator progress = myProgress.get(); if(progress != null) { progress.setText(s); } } private void printRawError(String text) { myMessageView.outputError(text, 0); } public final void readErrorOutput(String text) { if(!myFirstLineProcessed) { myFirstLineProcessed = true; myStartedSuccessfully = false; myMessageView.buildFailed(myBuildName); } if(!myStartedSuccessfully) { printRawError(text); } } protected final void processTag(char tagName, final String tagValue, final int priority) { if(LOG.isDebugEnabled()) { LOG.debug(String.valueOf(tagName) + priority + "=" + tagValue); } if(IdeaAntLogger2.TARGET == tagName) { setProgressStatistics(ThermitBundle.message("target.tag.name.status.text", tagValue)); } else if(IdeaAntLogger2.TASK == tagName) { setProgressText(ThermitBundle.message("executing.task.tag.value.status.text", tagValue)); if(JAVAC.equals(tagValue)) { myJavacMessages = new ArrayList<String>(); } else if(NAPILEC.equals(tagValue)) { myNapileMessages = new ArrayList<String>(); } else if(ECHO.equals(tagValue)) { myIsEcho = true; } } if(myJavacMessages != null && (IdeaAntLogger2.MESSAGE == tagName || IdeaAntLogger2.ERROR == tagName)) { myJavacMessages.add(tagValue); return; } if(myNapileMessages != null && (IdeaAntLogger2.MESSAGE == tagName || IdeaAntLogger2.ERROR == tagName)) { myNapileMessages.add(tagValue); return; } if(IdeaAntLogger2.MESSAGE == tagName) { if(myIsEcho) { myMessageView.outputMessage(tagValue, AntBuildMessageView.PRIORITY_VERBOSE); } else { myMessageView.outputMessage(tagValue, priority); } } else if(IdeaAntLogger2.TARGET == tagName) { myMessageView.startTarget(tagValue); } else if(IdeaAntLogger2.TASK == tagName) { myMessageView.startTask(tagValue); } else if(IdeaAntLogger2.ERROR == tagName) { myMessageView.outputError(tagValue, priority); } else if(IdeaAntLogger2.EXCEPTION == tagName) { String exceptionText = tagValue.replace(IdeaAntLogger2.EXCEPTION_LINE_SEPARATOR, '\n'); myMessageView.outputException(exceptionText); } else if(IdeaAntLogger2.BUILD == tagName) { myMessageView.startBuild(myBuildName); } else if(IdeaAntLogger2.TARGET_END == tagName || IdeaAntLogger2.TASK_END == tagName) { if(myJavacMessages != null) { processJavacMessages(myJavacMessages, myMessageView, myProject); myJavacMessages = null; } if(myNapileMessages != null) { processNapilecMessages(myNapileMessages, myMessageView, myProject); myNapileMessages = null; } myIsEcho = false; if(IdeaAntLogger2.TARGET_END == tagName) { myMessageView.finishTarget(); } else { myMessageView.finishTask(); } } } private static void processNapilecMessages(final List<String> napileMessages, final AntBuildMessageView messageView, Project project) { for(final String str : napileMessages) { try { AntBuildMessageView.MessageType category = AntBuildMessageView.MessageType.MESSAGE; String categoryOfMessage = str.substring(0, str.indexOf(":")); if(categoryOfMessage.equals("ERROR")) category = AntBuildMessageView.MessageType.ERROR; int fileEnd = str.indexOf(".ns: ("); final String url = str.substring(str.indexOf(":") + 2, fileEnd + 3); String ranges = str.substring(fileEnd + 6, str.indexOf(")", fileEnd)); final int line = Integer.parseInt(ranges.substring(0, ranges.indexOf(","))); final int column = Integer.parseInt(ranges.substring(ranges.indexOf(",") + 2, ranges.length())); final String message = str.substring(str.indexOf(")", fileEnd) + 2, str.length()); final AntBuildMessageView.MessageType c = category; ApplicationManager.getApplication().runReadAction(new Runnable() { public void run() { VirtualFile file = VirtualFileManager.getInstance().findFileByUrl("file://" + url); messageView.outputJavacMessage(c, new String[]{message}, file, null, line, column); } }); } catch(Exception e) { messageView.outputMessage(str, AntBuildMessageView.PRIORITY_VERBOSE); //throw new UnsupportedOperationException("Unknown how parse string : " + str, e); } } } private static void processJavacMessages(@NotNull final List<String> javacMessages, final AntBuildMessageView messageView, Project project) { com.intellij.compiler.OutputParser outputParser = new JavacOutputParser(project); com.intellij.compiler.OutputParser.Callback callback = new com.intellij.compiler.OutputParser.Callback() { private int myIndex = -1; @Nullable public String getCurrentLine() { if(myIndex >= javacMessages.size()) { return null; } return javacMessages.get(myIndex); } public String getNextLine() { final int size = javacMessages.size(); final int next = Math.min(myIndex + 1, javacMessages.size()); myIndex = next; if(next >= size) { return null; } return javacMessages.get(next); } @Override public void pushBack(String line) { myIndex--; } public void message(final CompilerMessageCategory category, final String message, final String url, final int lineNum, final int columnNum) { StringTokenizer tokenizer = new StringTokenizer(message, "\n", false); final String[] strings = new String[tokenizer.countTokens()]; //noinspection ForLoopThatDoesntUseLoopVariable for(int idx = 0; tokenizer.hasMoreTokens(); idx++) { strings[idx] = tokenizer.nextToken(); } ApplicationManager.getApplication().runReadAction(new Runnable() { public void run() { VirtualFile file = url == null ? null : VirtualFileManager.getInstance().findFileByUrl(url); messageView.outputJavacMessage(convertCategory(category), strings, file, url, lineNum, columnNum); } }); } public void setProgressText(String text) { } public void fileProcessed(String path) { } public void fileGenerated(FileObject path) { } }; try { while(true) { if(!outputParser.processMessageLine(callback)) { break; } } } catch(Exception e) { //ignore } } private static AntBuildMessageView.MessageType convertCategory(CompilerMessageCategory category) { if(CompilerMessageCategory.ERROR.equals(category)) { return AntBuildMessageView.MessageType.ERROR; } return AntBuildMessageView.MessageType.MESSAGE; } }