2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package org.jetbrains.jps.incremental.groovy;
19 import com.intellij.execution.process.BaseOSProcessHandler;
20 import com.intellij.execution.process.ProcessOutputTypes;
21 import com.intellij.openapi.diagnostic.Logger;
22 import com.intellij.openapi.util.Key;
23 import com.intellij.openapi.util.io.FileUtil;
24 import com.intellij.openapi.util.text.StringUtil;
25 import com.intellij.util.Consumer;
26 import com.intellij.util.containers.ContainerUtil;
27 import org.jetbrains.annotations.Nullable;
28 import org.jetbrains.groovy.compiler.rt.GroovycRunner;
29 import org.jetbrains.jps.incremental.messages.BuildMessage;
30 import org.jetbrains.jps.incremental.messages.CompilerMessage;
36 * @author: Dmitry.Krasilschikov
39 public class GroovycOSProcessHandler extends BaseOSProcessHandler {
40 public static final String GROOVY_COMPILER_IN_OPERATION = "Groovy compiler in operation...";
41 private final List<OutputItem> myCompiledItems = new ArrayList<OutputItem>();
42 private final Set<File> toRecompileFiles = new HashSet<File>();
43 private final List<CompilerMessage> compilerMessages = new ArrayList<CompilerMessage>();
44 private final StringBuffer stdErr = new StringBuffer();
46 private static final Logger LOG = Logger.getInstance("org.jetbrains.jps.incremental.groovy.GroovycOSProcessHandler");
47 private final Consumer<String> myStatusUpdater;
49 private GroovycOSProcessHandler(Process process, Consumer<String> statusUpdater) {
50 super(process, null, null);
51 myStatusUpdater = statusUpdater;
54 public void notifyTextAvailable(final String text, final Key outputType) {
55 super.notifyTextAvailable(text, outputType);
57 if (LOG.isDebugEnabled()) {
58 LOG.debug("Received from groovyc: " + text);
61 if (outputType == ProcessOutputTypes.SYSTEM) {
65 if (outputType == ProcessOutputTypes.STDERR) {
66 stdErr.append(StringUtil.convertLineSeparators(text));
74 private final StringBuffer outputBuffer = new StringBuffer();
76 protected void updateStatus(@Nullable String status) {
77 myStatusUpdater.consume(status == null ? GROOVY_COMPILER_IN_OPERATION : status);
80 private void parseOutput(String text) {
81 final String trimmed = text.trim();
83 if (trimmed.startsWith(GroovycRunner.PRESENTABLE_MESSAGE)) {
84 updateStatus(trimmed.substring(GroovycRunner.PRESENTABLE_MESSAGE.length()));
88 if (GroovycRunner.CLEAR_PRESENTABLE.equals(trimmed)) {
94 if (StringUtil.isNotEmpty(text)) {
95 outputBuffer.append(text);
97 //compiled start marker have to be in the beginning on each string
98 if (outputBuffer.indexOf(GroovycRunner.COMPILED_START) != -1) {
99 if (outputBuffer.indexOf(GroovycRunner.COMPILED_END) == -1) {
103 final String compiled = handleOutputBuffer(GroovycRunner.COMPILED_START, GroovycRunner.COMPILED_END);
104 final List<String> list = StringUtil.split(compiled, GroovycRunner.SEPARATOR);
105 String outputPath = list.get(0);
106 String sourceFile = list.get(1);
108 ContainerUtil.addIfNotNull(getOutputItem(outputPath, sourceFile), myCompiledItems);
111 else if (outputBuffer.indexOf(GroovycRunner.TO_RECOMPILE_START) != -1) {
112 if (outputBuffer.indexOf(GroovycRunner.TO_RECOMPILE_END) != -1) {
113 String url = handleOutputBuffer(GroovycRunner.TO_RECOMPILE_START, GroovycRunner.TO_RECOMPILE_END);
114 toRecompileFiles.add(new File(url));
117 else if (outputBuffer.indexOf(GroovycRunner.MESSAGES_START) != -1) {
118 if (!(outputBuffer.indexOf(GroovycRunner.MESSAGES_END) != -1)) {
122 text = handleOutputBuffer(GroovycRunner.MESSAGES_START, GroovycRunner.MESSAGES_END);
124 List<String> tokens = StringUtil.split(text, GroovycRunner.SEPARATOR);
125 LOG.assertTrue(tokens.size() > 4, "Wrong number of output params");
127 String category = tokens.get(0);
128 String message = tokens.get(1);
129 String url = tokens.get(2);
130 String lineNum = tokens.get(3);
131 String columnNum = tokens.get(4);
137 lineInt = Integer.parseInt(lineNum);
138 columnInt = Integer.parseInt(columnNum);
140 catch (NumberFormatException e) {
146 BuildMessage.Kind kind = category.equals(org.jetbrains.groovy.compiler.rt.CompilerMessage.ERROR)
147 ? BuildMessage.Kind.ERROR
148 : category.equals(org.jetbrains.groovy.compiler.rt.CompilerMessage.WARNING)
149 ? BuildMessage.Kind.WARNING
150 : BuildMessage.Kind.INFO;
152 compilerMessages.add(new CompilerMessage("Groovyc", kind, message, url, -1, -1, -1, lineInt, columnInt));
157 private String handleOutputBuffer(String startMarker, String endMarker) {
158 final int start = outputBuffer.indexOf(startMarker);
159 final int end = outputBuffer.indexOf(endMarker);
161 throw new AssertionError("Malformed Groovyc output: " + outputBuffer.toString());
164 String text = outputBuffer.substring(start + startMarker.length(), end);
166 outputBuffer.delete(start, end + endMarker.length());
172 private static OutputItem getOutputItem(final String outputPath, final String sourceFile) {
173 return new OutputItem(outputPath, sourceFile);
176 public List<OutputItem> getSuccessfullyCompiled() {
177 return myCompiledItems;
180 public Set<File> getToRecompileFiles() {
181 return toRecompileFiles;
184 public List<CompilerMessage> getCompilerMessages() {
185 ArrayList<CompilerMessage> messages = new ArrayList<CompilerMessage>(compilerMessages);
186 final StringBuffer unparsedBuffer = getStdErr();
187 if (unparsedBuffer.length() != 0) {
188 messages.add(new CompilerMessage("Groovyc", BuildMessage.Kind.INFO, unparsedBuffer.toString()));
191 final int exitValue = getProcess().exitValue();
192 if (messages.isEmpty() && exitValue != 0) {
193 messages.add(new CompilerMessage("Groovyc", BuildMessage.Kind.ERROR, "Internal groovyc error: code " + exitValue));
199 public StringBuffer getStdErr() {
203 public static File fillFileWithGroovycParameters(final String outputDir,
204 final Collection<String> changedSources,
206 Map<String, String> class2Src, @Nullable final String encoding, List<String> patchers) throws IOException {
207 File tempFile = FileUtil.createTempFile("ideaGroovyToCompile", ".txt", true);
209 final Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(tempFile)));
211 for (String file : changedSources) {
212 writer.write(GroovycRunner.SRC_FILE + "\n");
217 writer.write("class2src\n");
218 for (Map.Entry<String, String> entry : class2Src.entrySet()) {
219 writer.write(entry.getKey() + "\n");
220 writer.write(entry.getValue() + "\n");
222 writer.write(GroovycRunner.END + "\n");
224 writer.write(GroovycRunner.PATCHERS + "\n");
225 for (String patcher : patchers) {
226 writer.write(patcher + "\n");
228 writer.write(GroovycRunner.END + "\n");
229 if (encoding != null) {
230 writer.write(GroovycRunner.ENCODING + "\n");
231 writer.write(encoding + "\n");
233 writer.write(GroovycRunner.OUTPUTPATH + "\n");
234 writer.write(outputDir);
236 writer.write(GroovycRunner.FINAL_OUTPUTPATH + "\n");
237 writer.write(finalOutput);
246 public static GroovycOSProcessHandler runGroovyc(Process process, Consumer<String> updater) {
247 GroovycOSProcessHandler processHandler = new GroovycOSProcessHandler(process, updater);
249 processHandler.startNotify();
250 processHandler.waitFor();
251 return processHandler;
254 public static class OutputItem {
255 public final String outputPath;
256 public final String sourcePath;
258 public OutputItem(String outputPath, String sourceFileName) {
259 this.outputPath = outputPath;
260 sourcePath = sourceFileName;