From ef403cc91a2a505ff045d201ebe816455e1ff3ae Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Mon, 12 Nov 2012 16:49:47 +0400 Subject: [PATCH] Alternative methods for progress reporting --- .../jet/codegen/ClassFileFactory.java | 20 +++- .../jetbrains/jet/codegen/state/Progress.java | 18 ++++ .../messages/CompilerMessageSeverity.java | 3 +- .../common/messages/OutputMessageUtil.java | 79 ++++++++++++++ .../messages/PrintingMessageCollector.java | 6 +- .../compiler/KotlinToJVMBytecodeCompiler.java | 15 ++- .../messages/OutputMessageUtilTest.java | 100 ++++++++++++++++++ .../runner/AbstractOutputItemCollector.java | 4 + .../compiler/runner/CompilerRunnerUtil.java | 17 +-- .../compiler/runner/OutputItemsCollector.java | 5 + .../jet/plugin/compiler/CompilerUtils.java | 10 ++ 11 files changed, 263 insertions(+), 14 deletions(-) create mode 100644 compiler/cli/cli-common/src/org/jetbrains/jet/cli/common/messages/OutputMessageUtil.java create mode 100644 compiler/tests/org/jetbrains/jet/cli/common/messages/OutputMessageUtilTest.java diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClassFileFactory.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClassFileFactory.java index f01f58bb838..b1959c93389 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClassFileFactory.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClassFileFactory.java @@ -16,6 +16,8 @@ package org.jetbrains.jet.codegen; +import com.google.common.collect.Lists; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.asm4.Type; @@ -27,6 +29,7 @@ import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.resolve.name.FqName; import javax.inject.Inject; +import java.io.File; import java.util.*; import static org.jetbrains.jet.codegen.AsmUtil.isPrimitive; @@ -56,7 +59,8 @@ public final class ClassFileFactory extends GenerationStateAware { return newVisitor(outputFilePath, Collections.singletonList(sourceFile)); } - ClassBuilder newVisitor(String outputFilePath, Collection sourceFiles) { + private ClassBuilder newVisitor(String outputFilePath, Collection sourceFiles) { + state.getProgress().reportOutput(toIoFilesIgnoringNonPhysical(sourceFiles), new File(outputFilePath)); state.getProgress().log("Emitting: " + outputFilePath); final ClassBuilder answer = builderFactory.newClassBuilder(); generators.put(outputFilePath, answer); @@ -139,4 +143,18 @@ public final class ClassFileFactory extends GenerationStateAware { state.getTypeMapper().mapType(aClass.getDefaultType(), JetTypeMapperMode.TRAIT_IMPL).getInternalName() + ".class", sourceFile); } + + private static Collection toIoFilesIgnoringNonPhysical(Collection psiFiles) { + List result = Lists.newArrayList(); + for (PsiFile psiFile : psiFiles) { + VirtualFile virtualFile = psiFile.getVirtualFile(); + // We ignore non-physical files here, because this code is needed to tell the make what inputs affect which outputs + // a non-physical file cannot be processed by make + if (virtualFile != null) { + result.add(new File(virtualFile.getPath())); + } + } + return result; + } + } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/state/Progress.java b/compiler/backend/src/org/jetbrains/jet/codegen/state/Progress.java index b4e310651c2..c8ac84b1d50 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/state/Progress.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/state/Progress.java @@ -19,11 +19,29 @@ */ package org.jetbrains.jet.codegen.state; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.util.Collection; + public interface Progress { Progress DEAF = new Progress() { @Override public void log(String message) { } + + @Override + public void reportOutput(@NotNull Collection sourceFiles, @Nullable File outputFile) { + } }; + + @Deprecated void log(String message); + + /** + * @param sourceFiles a (possibly empty) collection of source files {@code outputFile} was generated from + * @param outputFile an output file + */ + void reportOutput(@NotNull Collection sourceFiles, @Nullable File outputFile); } diff --git a/compiler/cli/cli-common/src/org/jetbrains/jet/cli/common/messages/CompilerMessageSeverity.java b/compiler/cli/cli-common/src/org/jetbrains/jet/cli/common/messages/CompilerMessageSeverity.java index 2608639a9f6..095886e40c1 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/jet/cli/common/messages/CompilerMessageSeverity.java +++ b/compiler/cli/cli-common/src/org/jetbrains/jet/cli/common/messages/CompilerMessageSeverity.java @@ -26,7 +26,8 @@ public enum CompilerMessageSeverity { ERROR, WARNING, EXCEPTION, - LOGGING; + LOGGING, + OUTPUT; public static final EnumSet ERRORS = EnumSet.of(ERROR, EXCEPTION); } diff --git a/compiler/cli/cli-common/src/org/jetbrains/jet/cli/common/messages/OutputMessageUtil.java b/compiler/cli/cli-common/src/org/jetbrains/jet/cli/common/messages/OutputMessageUtil.java new file mode 100644 index 00000000000..7aa974728c4 --- /dev/null +++ b/compiler/cli/cli-common/src/org/jetbrains/jet/cli/common/messages/OutputMessageUtil.java @@ -0,0 +1,79 @@ +/* + * Copyright 2010-2012 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.jetbrains.jet.cli.common.messages; + +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.util.Collection; + +public class OutputMessageUtil { + private static final String SOURCE_FILES_PREFIX = "Sources:"; + private static final String OUTPUT_FILES_PREFIX = "Output:"; + + public static String formatOutputMessage(Collection sourceFiles, File outputFile) { + return OUTPUT_FILES_PREFIX + "\n" + outputFile.getPath() + "\n" + + SOURCE_FILES_PREFIX + "\n" + StringUtil.join(sourceFiles, "\n"); + } + + @Nullable + public static Output parseOutputMessage(@NotNull String message) { + String[] strings = message.split("\n"); + + // Must have at least one line per prefix + if (strings.length <= 2) return null; + + if (!OUTPUT_FILES_PREFIX.equals(strings[0])) return null; + + if (SOURCE_FILES_PREFIX.equals(strings[1])) { + // Output: + // Sources: + // ... + return new Output(parseSourceFiles(strings, 2), null); + } + else { + File outputFile = new File(strings[1]); + + if (!SOURCE_FILES_PREFIX.equals(strings[2])) return null; + + return new Output(parseSourceFiles(strings, 3), outputFile); + } + } + + private static Collection parseSourceFiles(String[] strings, int start) { + Collection sourceFiles = ContainerUtil.newArrayList(); + for (int i = start; i < strings.length; i++) { + sourceFiles.add(new File(strings[i])); + } + return sourceFiles; + } + + public static class Output { + @NotNull + public final Collection sourceFiles; + @Nullable + public final File outputFile; + + public Output(@NotNull Collection sourceFiles, @Nullable File outputFile) { + this.sourceFiles = sourceFiles; + this.outputFile = outputFile; + } + } +} diff --git a/compiler/cli/cli-common/src/org/jetbrains/jet/cli/common/messages/PrintingMessageCollector.java b/compiler/cli/cli-common/src/org/jetbrains/jet/cli/common/messages/PrintingMessageCollector.java index a5dbe3644c7..3e20629a770 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/jet/cli/common/messages/PrintingMessageCollector.java +++ b/compiler/cli/cli-common/src/org/jetbrains/jet/cli/common/messages/PrintingMessageCollector.java @@ -19,10 +19,6 @@ package org.jetbrains.jet.cli.common.messages; import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.Multimap; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.cli.common.messages.CompilerMessageLocation; -import org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity; -import org.jetbrains.jet.cli.common.messages.MessageCollector; -import org.jetbrains.jet.cli.common.messages.MessageRenderer; import java.io.PrintStream; import java.util.Collection; @@ -52,7 +48,7 @@ public class PrintingMessageCollector implements MessageCollector { @NotNull String message, @NotNull CompilerMessageLocation location) { String text = messageRenderer.render(severity, message, location); - if (severity == CompilerMessageSeverity.LOGGING) { + if (severity == CompilerMessageSeverity.LOGGING || severity == CompilerMessageSeverity.OUTPUT) { if (!verbose) { return; } diff --git a/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java b/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java index 6b66259d8f2..72486928577 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java @@ -36,6 +36,7 @@ import org.jetbrains.jet.cli.jvm.JVMConfigurationKeys; import org.jetbrains.jet.codegen.*; import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.GenerationStrategy; +import org.jetbrains.jet.codegen.state.Progress; import org.jetbrains.jet.config.CommonConfigurationKeys; import org.jetbrains.jet.config.CompilerConfiguration; import org.jetbrains.jet.lang.parsing.JetScriptDefinition; @@ -51,7 +52,6 @@ import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.plugin.JetMainDetector; import org.jetbrains.jet.utils.ExceptionUtils; import org.jetbrains.jet.utils.PathUtil; -import org.jetbrains.jet.codegen.state.Progress; import java.io.File; import java.io.FileNotFoundException; @@ -339,6 +339,19 @@ public class KotlinToJVMBytecodeCompiler { public void log(String message) { configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report(CompilerMessageSeverity.LOGGING, message, CompilerMessageLocation.NO_LOCATION); } + + @Override + public void reportOutput(@NotNull Collection sourceFiles, @Nullable File outputFile) { + if (outputFile == null) return; + + MessageCollector messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY); + if (messageCollector == null) return; + + messageCollector.report( + CompilerMessageSeverity.OUTPUT, + OutputMessageUtil.formatOutputMessage(sourceFiles, outputFile), + CompilerMessageLocation.NO_LOCATION); + } }; GenerationState generationState = new GenerationState( project, ClassBuilderFactories.binaries(stubs), backendProgress, exhaust, environment.getSourceFiles(), diff --git a/compiler/tests/org/jetbrains/jet/cli/common/messages/OutputMessageUtilTest.java b/compiler/tests/org/jetbrains/jet/cli/common/messages/OutputMessageUtilTest.java new file mode 100644 index 00000000000..acb5887c38c --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/cli/common/messages/OutputMessageUtilTest.java @@ -0,0 +1,100 @@ +/* + * Copyright 2010-2012 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.jetbrains.jet.cli.common.messages; + +import junit.framework.TestCase; + +import java.io.File; +import java.util.Arrays; +import java.util.List; + +public class OutputMessageUtilTest extends TestCase { + enum TargetOS { + UNIX { + @Override + public String convert(String path) { + return path.replace('\\', '/'); + } + }, + WINDOWS { + @Override + public String convert(String path) { + // convert absolute paths to declare their disk as C: + if (path.startsWith("/")) { + path = "C:" + path; + } + return path.replace('/', '\\'); + } + }; + + public abstract String convert(String path); + } + + private void doTest(String outputPath, String... sourcePathArray) { + doTest(TargetOS.UNIX, outputPath, sourcePathArray); + doTest(TargetOS.WINDOWS, outputPath, sourcePathArray); + } + + private void doTest(TargetOS os, String outputPath, String... sourcePathArray) { + File[] sourceFileArray = new File[sourcePathArray.length]; + for (int i = 0; i < sourcePathArray.length; i++) { + String path = sourcePathArray[i]; + sourceFileArray[i] = new File(os.convert(path)); + } + doTest(new File(os.convert(outputPath)), sourceFileArray); + } + + private void doTest(File outputFile, File... sourceFileArray) { + List sourceFiles = Arrays.asList(sourceFileArray); + String message = OutputMessageUtil.formatOutputMessage(sourceFiles, outputFile); + OutputMessageUtil.Output output = OutputMessageUtil.parseOutputMessage(message); + assertNotNull("Output is null", output); + assertEquals(sourceFiles, output.sourceFiles); + assertEquals(outputFile, output.outputFile); + } + + public void testOneInOneOut() throws Exception { + doTest("foo/bar.class", "foo/bar.kt"); + doTest("/foo/bar.class", "/foo/bar.kt"); + doTest("/foo/bar.class", "foo/bar.kt"); + doTest("foo/bar.class", "/foo/bar.kt"); + } + + public void testTwoInOneOut() throws Exception { + doTest("foo/bar.class", "foo/bar.kt", "foo/buzz.kt"); + doTest("/foo/bar.class", "/foo/bar.kt", "/foo/buzz.kt"); + doTest("foo/bar.class", "/foo/bar.kt", "foo/buzz.kt"); + doTest("foo/bar.class", "foo/bar.kt", "/foo/buzz.kt"); + } + + public void testOneInNoneOut() throws Exception { + doTest("foo/bar.class"); + doTest("/foo/bar.class"); + } + + public void testWrongStart() throws Exception { + assertNull(OutputMessageUtil.parseOutputMessage("foo\nOutput:\nfoo")); + } + + public void testTwoOuts() throws Exception { + assertNull(OutputMessageUtil.parseOutputMessage("Output:\nfoo\nbar\nInputs:\n")); + } + + public void testTooFewStrings() throws Exception { + assertNull(OutputMessageUtil.parseOutputMessage("Output:\nInputs:")); + } +} diff --git a/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/AbstractOutputItemCollector.java b/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/AbstractOutputItemCollector.java index a1a0b675f5b..eb9112329f1 100644 --- a/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/AbstractOutputItemCollector.java +++ b/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/AbstractOutputItemCollector.java @@ -34,6 +34,10 @@ public abstract class AbstractOutputItemCollector implements OutputItemsCo this.outputPath = outputPath; } + protected void addItem(R item) { + answer.add(item); + } + @Override public final void learn(String message) { message = message.trim(); diff --git a/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/CompilerRunnerUtil.java b/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/CompilerRunnerUtil.java index 655805ca236..7ab53d833a8 100644 --- a/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/CompilerRunnerUtil.java +++ b/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/CompilerRunnerUtil.java @@ -21,10 +21,7 @@ import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.cli.common.messages.CompilerMessageLocation; -import org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity; -import org.jetbrains.jet.cli.common.messages.MessageCollector; -import org.jetbrains.jet.cli.common.messages.MessageRenderer; +import org.jetbrains.jet.cli.common.messages.*; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; @@ -45,6 +42,7 @@ import static org.jetbrains.jet.cli.common.messages.CompilerMessageLocation.NO_L import static org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity.*; public class CompilerRunnerUtil { + private static SoftReference ourClassLoaderRef = new SoftReference(null); public static List kompilerClasspath(File kotlinHome, MessageCollector messageCollector) { @@ -241,8 +239,8 @@ public class CompilerRunnerUtil { } String text = message.toString(); - if (category == LOGGING) { - collector.learn(text); + if (category == OUTPUT) { + reportToCollector(text); } else { messageCollector.report(category, text, CompilerMessageLocation.create(path, line, column)); @@ -250,6 +248,13 @@ public class CompilerRunnerUtil { tags.pop(); } + private void reportToCollector(String text) { + OutputMessageUtil.Output output = OutputMessageUtil.parseOutputMessage(text); + if (output != null) { + collector.add(output.sourceFiles, output.outputFile); + } + } + private static int safeParseInt(@Nullable String value, int defaultValue) { if (value == null) { return defaultValue; diff --git a/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/OutputItemsCollector.java b/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/OutputItemsCollector.java index 1212759691d..325e1fb3dc9 100644 --- a/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/OutputItemsCollector.java +++ b/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/OutputItemsCollector.java @@ -16,9 +16,14 @@ package org.jetbrains.jet.compiler.runner; +import java.io.File; +import java.util.Collection; + /** * @author abreslav */ public interface OutputItemsCollector { + @Deprecated void learn(String message); + void add(Collection sourceFiles, File outputFile); } diff --git a/idea/src/org/jetbrains/jet/plugin/compiler/CompilerUtils.java b/idea/src/org/jetbrains/jet/plugin/compiler/CompilerUtils.java index bb93dc1a123..1bc24ee7731 100644 --- a/idea/src/org/jetbrains/jet/plugin/compiler/CompilerUtils.java +++ b/idea/src/org/jetbrains/jet/plugin/compiler/CompilerUtils.java @@ -28,6 +28,7 @@ import org.jetbrains.jet.compiler.runner.AbstractOutputItemCollector; import org.jetbrains.jet.compiler.runner.CompilerEnvironment; import java.io.File; +import java.util.Collection; /** * @author Pavel Talanov @@ -65,6 +66,15 @@ public final class CompilerUtils { protected VirtualFile convertSource(String sourcePath) { return LocalFileSystem.getInstance().findFileByPath(sourcePath); } + + @Override + public void add(Collection sourceFiles, File outputFile) { + LocalFileSystem.getInstance().refreshAndFindFileByIoFile(outputFile); + for (File sourceFile : sourceFiles) { + VirtualFile virtualFileForSourceFile = LocalFileSystem.getInstance().findFileByIoFile(sourceFile); + addItem(new OutputItemImpl(outputFile.getPath(), virtualFileForSourceFile)); + } + } } }