new Compiler API based compiler (java6 only)

This commit is contained in:
Alexey Kudravtsev
2009-04-08 15:36:56 +04:00
parent a83fe9173f
commit a85a62bb5c
28 changed files with 1183 additions and 593 deletions
+9
View File
@@ -24,6 +24,15 @@
<orderEntry type="module" module-name="j2ee-openapi" />
<orderEntry type="module" module-name="boot" />
<orderEntry type="module" module-name="platform-api" />
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/../lib/dev/compilerapi.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
</component>
<component name="copyright">
<Base>
@@ -10,13 +10,15 @@ package com.intellij.compiler;
import com.intellij.CommonBundle;
import com.intellij.compiler.impl.javaCompiler.BackendCompiler;
import com.intellij.compiler.impl.javaCompiler.api.CompilerAPICompiler;
import com.intellij.compiler.impl.javaCompiler.eclipse.EclipseCompiler;
import com.intellij.compiler.impl.javaCompiler.eclipse.EclipseEmbeddedCompiler;
import com.intellij.compiler.impl.javaCompiler.javac.JavacCompiler;
import com.intellij.compiler.impl.javaCompiler.javac.JavacEmbeddedCompiler;
import com.intellij.compiler.impl.javaCompiler.javac.JavacSettings;
import com.intellij.compiler.impl.javaCompiler.jikes.JikesCompiler;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ApplicationNamesInfo;
import com.intellij.openapi.application.ex.ApplicationManagerEx;
import com.intellij.openapi.compiler.CompilerBundle;
import com.intellij.openapi.compiler.options.ExcludedEntriesConfiguration;
import com.intellij.openapi.components.*;
@@ -65,7 +67,6 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
private final Collection<BackendCompiler> myRegisteredCompilers = new ArrayList<BackendCompiler>();
private BackendCompiler JAVAC_EXTERNAL_BACKEND;
private BackendCompiler JAVAC_EMBEDDED_BACKEND;
private final Perl5Matcher myPatternMatcher = new Perl5Matcher();
{
@@ -178,8 +179,6 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
private void createCompilers() {
JAVAC_EXTERNAL_BACKEND = new JavacCompiler(myProject);
myRegisteredCompilers.add(JAVAC_EXTERNAL_BACKEND);
JAVAC_EMBEDDED_BACKEND = new JavacEmbeddedCompiler(myProject);
//myRegisteredCompilers.add(JAVAC_EMBEDDED_BACKEND);
if (!ApplicationManager.getApplication().isUnitTestMode()) {
final BackendCompiler JIKES_BACKEND = new JikesCompiler(myProject);
@@ -189,13 +188,26 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
final EclipseCompiler eclipse = new EclipseCompiler(myProject);
myRegisteredCompilers.add(eclipse);
}
//try {
// final EclipseEmbeddedCompiler eclipseEmbedded = new EclipseEmbeddedCompiler(myProject);
// myRegisteredCompilers.add(eclipseEmbedded);
//}
//catch (NoClassDefFoundError e) {
// // eclipse jar must be not in the classpath
//}
if (ApplicationManagerEx.getApplicationEx().isInternal()) {
try {
final EclipseEmbeddedCompiler eclipseEmbedded = new EclipseEmbeddedCompiler(myProject);
myRegisteredCompilers.add(eclipseEmbedded);
}
catch (NoClassDefFoundError e) {
// eclipse jar must be not in the classpath
}
}
if (ApplicationManagerEx.getApplicationEx().isInternal()) {
try {
CompilerAPICompiler compiler = new CompilerAPICompiler(myProject);
myRegisteredCompilers.add(compiler);
}
catch (NoClassDefFoundError e) {
// wrong JDK
}
}
}
myDefaultJavaCompiler = JAVAC_EXTERNAL_BACKEND;
@@ -394,11 +406,7 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
if (JAVAC_EXTERNAL_BACKEND == null) {
createCompilers();
}
if (myDefaultJavaCompiler != JAVAC_EXTERNAL_BACKEND) return myDefaultJavaCompiler;
boolean runEmbedded = ApplicationManager.getApplication().isUnitTestMode()
? !JavacSettings.getInstance(myProject).isTestsUseExternalCompiler()
: Boolean.parseBoolean(System.getProperty(PROPERTY_IDEA_USE_EMBEDDED_JAVAC));
return runEmbedded ? JAVAC_EMBEDDED_BACKEND : JAVAC_EXTERNAL_BACKEND;
return myDefaultJavaCompiler;
}
public void setDefaultCompiler(BackendCompiler defaultCompiler) {
@@ -2,6 +2,7 @@ package com.intellij.compiler;
import com.intellij.openapi.compiler.CompilerMessageCategory;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.compiler.impl.javaCompiler.FileObject;
import org.jetbrains.annotations.NonNls;
import java.util.ArrayList;
@@ -15,7 +16,7 @@ public abstract class OutputParser {
@NonNls String getCurrentLine();
void setProgressText(String text);
void fileProcessed(@NonNls String path);
void fileGenerated(@NonNls String path);
void fileGenerated(@NonNls FileObject path);
void message(CompilerMessageCategory category, String message, @NonNls String url, int lineNum, int columnNum);
}
@@ -58,10 +58,7 @@ import com.intellij.psi.PsiCompiledElement;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.util.Chunk;
import com.intellij.util.LocalTimeCounter;
import com.intellij.util.ProfilingUtil;
import com.intellij.util.StringBuilderSpinAllocator;
import com.intellij.util.*;
import com.intellij.util.containers.HashMap;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NonNls;
@@ -85,8 +82,16 @@ public class CompileDriver {
@NonNls private static final boolean GENERATE_CLASSPATH_INDEX = "true".equals(System.getProperty("generate.classpath.index"));
private final FileProcessingCompilerAdapterFactory myProcessingCompilerAdapterFactory;
private final FileProcessingCompilerAdapterFactory myPackagingCompilerAdapterFactory;
private static final FileProcessingCompilerAdapterFactory FILE_PROCESSING_COMPILER_ADAPTER_FACTORY = new FileProcessingCompilerAdapterFactory() {
public FileProcessingCompilerAdapter create(CompileContext context, FileProcessingCompiler compiler) {
return new FileProcessingCompilerAdapter(context, compiler);
}
};
private static final FileProcessingCompilerAdapterFactory FILE_PACKAGING_COMPILER_ADAPTER_FACTORY = new FileProcessingCompilerAdapterFactory() {
public FileProcessingCompilerAdapter create(CompileContext context, FileProcessingCompiler compiler) {
return new PackagingCompilerAdapter(context, (PackagingCompiler)compiler);
}
};
public CompileDriver(Project project) {
myProject = project;
@@ -109,16 +114,6 @@ public class CompileDriver {
}
}
myProcessingCompilerAdapterFactory = new FileProcessingCompilerAdapterFactory() {
public FileProcessingCompilerAdapter create(CompileContext context, FileProcessingCompiler compiler) {
return new FileProcessingCompilerAdapter(context, compiler);
}
};
myPackagingCompilerAdapterFactory = new FileProcessingCompilerAdapterFactory() {
public FileProcessingCompilerAdapter create(CompileContext context, FileProcessingCompiler compiler) {
return new PackagingCompilerAdapter(context, (PackagingCompiler)compiler);
}
};
}
public void rebuild(CompileStatusNotification callback) {
@@ -150,10 +145,11 @@ public class CompileDriver {
return false;
}
for (Pair<IntermediateOutputCompiler, Module> pair : myGenerationCompilerModuleToOutputDirMap.keySet()) {
final Pair<VirtualFile, VirtualFile> outputs = myGenerationCompilerModuleToOutputDirMap.get(pair);
compileContext.assignModule(outputs.getFirst(), pair.getSecond(), false);
compileContext.assignModule(outputs.getSecond(), pair.getSecond(), true);
for (Map.Entry<Pair<IntermediateOutputCompiler, Module>, Pair<VirtualFile, VirtualFile>> entry : myGenerationCompilerModuleToOutputDirMap.entrySet()) {
final Pair<VirtualFile, VirtualFile> outputs = entry.getValue();
Module module = entry.getKey().getSecond();
compileContext.assignModule(outputs.getFirst(), module, false);
compileContext.assignModule(outputs.getSecond(), module, true);
}
final Ref<ExitStatus> status = new Ref<ExitStatus>();
@@ -188,7 +184,7 @@ public class CompileDriver {
final int CACHE_FORMAT_VERSION;
final boolean COMPILATION_IN_PROGRESS;
public CompileStatus(int cacheVersion, boolean isCompilationInProgress) {
private CompileStatus(int cacheVersion, boolean isCompilationInProgress) {
CACHE_FORMAT_VERSION = cacheVersion;
COMPILATION_IN_PROGRESS = isCompilationInProgress;
}
@@ -260,10 +256,11 @@ public class CompileDriver {
private CompileScope addAdditionalRoots(CompileScope originalScope) {
CompileScope scope = originalScope;
final Set<Module> affected = new HashSet<Module>(Arrays.asList(originalScope.getAffectedModules()));
for (final Pair<IntermediateOutputCompiler, Module> pair : myGenerationCompilerModuleToOutputDirMap.keySet()) {
if (affected.contains(pair.getSecond())) {
final Pair<VirtualFile, VirtualFile> outputs = myGenerationCompilerModuleToOutputDirMap.get(pair);
scope = new CompositeScope(scope, new FileSetCompileScope(new VirtualFile[]{outputs.getFirst(), outputs.getSecond()}, new Module[]{pair.getSecond()}));
for (Map.Entry<Pair<IntermediateOutputCompiler, Module>, Pair<VirtualFile, VirtualFile>> entry : myGenerationCompilerModuleToOutputDirMap.entrySet()) {
Module module = entry.getKey().getSecond();
if (affected.contains(module)) {
final Pair<VirtualFile, VirtualFile> outputs = entry.getValue();
scope = new CompositeScope(scope, new FileSetCompileScope(new VirtualFile[]{outputs.getFirst(), outputs.getSecond()}, new Module[]{module}));
}
}
@@ -303,10 +300,11 @@ public class CompileDriver {
final CompileContextImpl compileContext =
new CompileContextImpl(myProject, compileTask, scope, dependencyCache, !isRebuild && !forceCompile, isRebuild);
compileContext.putUserData(COMPILATION_START_TIMESTAMP, LocalTimeCounter.currentTime());
for (Pair<IntermediateOutputCompiler, Module> pair : myGenerationCompilerModuleToOutputDirMap.keySet()) {
final Pair<VirtualFile, VirtualFile> outputs = myGenerationCompilerModuleToOutputDirMap.get(pair);
compileContext.assignModule(outputs.getFirst(), pair.getSecond(), false);
compileContext.assignModule(outputs.getSecond(), pair.getSecond(), true);
for (Map.Entry<Pair<IntermediateOutputCompiler, Module>, Pair<VirtualFile, VirtualFile>> entry : myGenerationCompilerModuleToOutputDirMap.entrySet()) {
final Pair<VirtualFile, VirtualFile> outputs = entry.getValue();
Module module = entry.getKey().getSecond();
compileContext.assignModule(outputs.getFirst(), module, false);
compileContext.assignModule(outputs.getSecond(), module, true);
}
compileTask.start(new Runnable() {
@@ -355,7 +353,6 @@ public class CompileDriver {
ExitStatus status = ExitStatus.ERRORS;
boolean wereExceptions = false;
try {
compileContext.getProgressIndicator().pushState();
if (checkCachesVersion) {
checkCachesVersion(compileContext);
if (compileContext.isRebuildRequested()) {
@@ -379,7 +376,6 @@ public class CompileDriver {
}
finally {
dropDependencyCache(compileContext);
compileContext.getProgressIndicator().popState();
final ExitStatus _status = status;
if (compileContext.isRebuildRequested()) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@@ -464,7 +460,7 @@ public class CompileDriver {
private static class ExitException extends Exception {
private final ExitStatus myStatus;
public ExitException(ExitStatus status) {
private ExitException(ExitStatus status) {
myStatus = status;
}
@@ -473,7 +469,7 @@ public class CompileDriver {
}
}
private ExitStatus doCompile(CompileContextEx context,
private ExitStatus doCompile(final CompileContextEx context,
boolean isRebuild,
final boolean forceCompile,
final boolean trackDependencies,
@@ -491,17 +487,11 @@ public class CompileDriver {
}
if (!onlyCheckStatus) {
try {
context.getProgressIndicator().pushState();
if (!executeCompileTasks(context, true)) {
if (LOG.isDebugEnabled()) {
LOG.debug("Compilation cancelled");
}
return ExitStatus.CANCELLED;
if (!executeCompileTasks(context, true)) {
if (LOG.isDebugEnabled()) {
LOG.debug("Compilation cancelled");
}
}
finally {
context.getProgressIndicator().popState();
return ExitStatus.CANCELLED;
}
}
@@ -512,42 +502,8 @@ public class CompileDriver {
return ExitStatus.ERRORS;
}
// need this to make sure the VFS is built
boolean needRecalcOutputDirs = false;
final List<VirtualFile> outputsToRefresh = new ArrayList<VirtualFile>();
for (VirtualFile output : context.getAllOutputDirectories()) {
if (output.isValid()) {
walkChildren(output, context);
}
else {
needRecalcOutputDirs = true;
final File file = new File(output.getPath());
if (!file.exists()) {
final boolean created = file.mkdirs();
if (!created) {
context.addMessage(CompilerMessageCategory.ERROR, "Failed to create output directory " + file.getPath(), null, 0, 0);
return ExitStatus.ERRORS;
}
}
output = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file);
if (output == null) {
context.addMessage(CompilerMessageCategory.ERROR, "Failed to locate output directory " + file.getPath(), null, 0, 0);
return ExitStatus.ERRORS;
}
}
outputsToRefresh.add(output);
}
for (Pair<IntermediateOutputCompiler, Module> pair : myGenerationCompilerModuleToOutputDirMap.keySet()) {
final Pair<VirtualFile, VirtualFile> generated = myGenerationCompilerModuleToOutputDirMap.get(pair);
walkChildren(generated.getFirst(), context);
outputsToRefresh.add(generated.getFirst());
walkChildren(generated.getSecond(), context);
outputsToRefresh.add(generated.getSecond());
}
RefreshQueue.getInstance().refresh(false, true, null, outputsToRefresh.toArray(new VirtualFile[outputsToRefresh.size()]));
if (needRecalcOutputDirs) {
context.recalculateOutputDirs();
}
final ExitStatus status = refreshFiles(context);
if (status != null) return status;
boolean didSomething = false;
@@ -557,23 +513,24 @@ public class CompileDriver {
didSomething |= generateSources(compilerManager, context, forceCompile, onlyCheckStatus);
didSomething |= invokeFileProcessingCompilers(compilerManager, context, SourceInstrumentingCompiler.class,
myProcessingCompilerAdapterFactory, forceCompile, true, onlyCheckStatus);
FILE_PROCESSING_COMPILER_ADAPTER_FACTORY, forceCompile, true, onlyCheckStatus);
didSomething |= translate(context, compilerManager, forceCompile, isRebuild, trackDependencies, outputDirectories, onlyCheckStatus);
didSomething |= invokeFileProcessingCompilers(compilerManager, context, ClassInstrumentingCompiler.class,
myProcessingCompilerAdapterFactory, isRebuild, false, onlyCheckStatus);
FILE_PROCESSING_COMPILER_ADAPTER_FACTORY, isRebuild, false, onlyCheckStatus);
// explicitly passing forceCompile = false because in scopes that is narrower than ProjectScope it is impossible
// to understand whether the class to be processed is in scope or not. Otherwise compiler may process its items even if
// there were changes in completely independent files.
didSomething |= invokeFileProcessingCompilers(compilerManager, context, ClassPostProcessingCompiler.class,
myProcessingCompilerAdapterFactory, isRebuild, false, onlyCheckStatus);
FILE_PROCESSING_COMPILER_ADAPTER_FACTORY, isRebuild, false, onlyCheckStatus);
didSomething |= invokeFileProcessingCompilers(compilerManager, context, PackagingCompiler.class, myPackagingCompilerAdapterFactory,
didSomething |= invokeFileProcessingCompilers(compilerManager, context, PackagingCompiler.class,
FILE_PACKAGING_COMPILER_ADAPTER_FACTORY,
isRebuild, false, onlyCheckStatus);
didSomething |= invokeFileProcessingCompilers(compilerManager, context, Validator.class, myProcessingCompilerAdapterFactory,
didSomething |= invokeFileProcessingCompilers(compilerManager, context, Validator.class, FILE_PROCESSING_COMPILER_ADAPTER_FACTORY,
forceCompile, true, onlyCheckStatus);
}
catch (ExitException e) {
@@ -590,14 +547,15 @@ public class CompileDriver {
final VirtualFile[] allOutputDirs = context.getAllOutputDirectories();
if (didSomething && GENERATE_CLASSPATH_INDEX) {
context.getProgressIndicator().pushState();
context.getProgressIndicator().setText("Generating classpath index...");
int count = 0;
for (VirtualFile file : allOutputDirs) {
context.getProgressIndicator().setFraction(((double)++count) / allOutputDirs.length);
createClasspathIndex(file);
}
context.getProgressIndicator().popState();
runInContext(context, "Generating classpath index...", new ThrowableRunnable<RuntimeException>(){
public void run() {
int count = 0;
for (VirtualFile file : allOutputDirs) {
context.getProgressIndicator().setFraction((double)++count / allOutputDirs.length);
createClasspathIndex(file);
}
}
});
}
if (!context.getProgressIndicator().isCanceled() && context.getMessageCount(CompilerMessageCategory.ERROR) == 0) {
@@ -610,14 +568,8 @@ public class CompileDriver {
}
if (!onlyCheckStatus) {
try {
context.getProgressIndicator().pushState();
if (!executeCompileTasks(context, false)) {
return ExitStatus.CANCELLED;
}
}
finally {
context.getProgressIndicator().popState();
if (!executeCompileTasks(context, false)) {
return ExitStatus.CANCELLED;
}
}
@@ -637,6 +589,53 @@ public class CompileDriver {
}
}
private ExitStatus refreshFiles(final CompileContextEx context) {
final ExitStatus[] status = {null};
runInContext(context, "Refreshing files...",new ThrowableRunnable<RuntimeException>(){
public void run() {
// need this to make sure the VFS is built
boolean needRecalcOutputDirs = false;
final List<VirtualFile> outputsToRefresh = new ArrayList<VirtualFile>();
for (VirtualFile output : context.getAllOutputDirectories()) {
if (output.isValid()) {
walkChildren(output, context);
}
else {
needRecalcOutputDirs = true;
final File file = new File(output.getPath());
if (!file.exists()) {
final boolean created = file.mkdirs();
if (!created) {
context.addMessage(CompilerMessageCategory.ERROR, "Failed to create output directory " + file.getPath(), null, 0, 0);
status[0] = ExitStatus.ERRORS;
return;
}
}
output = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file);
if (output == null) {
context.addMessage(CompilerMessageCategory.ERROR, "Failed to locate output directory " + file.getPath(), null, 0, 0);
status[0] = ExitStatus.ERRORS;
return;
}
}
outputsToRefresh.add(output);
}
for (Map.Entry<Pair<IntermediateOutputCompiler, Module>, Pair<VirtualFile, VirtualFile>> entry : myGenerationCompilerModuleToOutputDirMap.entrySet()) {
final Pair<VirtualFile, VirtualFile> generated = entry.getValue();
walkChildren(generated.getFirst(), context);
outputsToRefresh.add(generated.getFirst());
walkChildren(generated.getSecond(), context);
outputsToRefresh.add(generated.getSecond());
}
RefreshQueue.getInstance().refresh(false, true, null, outputsToRefresh.toArray(new VirtualFile[outputsToRefresh.size()]));
if (needRecalcOutputDirs) {
context.recalculateOutputDirs();
}
}
});
return status[0];
}
private static void logErrorMessages(final CompileContext context) {
final CompilerMessage[] errors = context.getMessages(CompilerMessageCategory.ERROR);
if (errors.length > 0) {
@@ -700,14 +699,11 @@ public class CompileDriver {
}
private static void dropDependencyCache(final CompileContextEx context) {
context.getProgressIndicator().pushState();
try {
context.getProgressIndicator().setText(CompilerBundle.message("progress.saving.caches"));
context.getDependencyCache().dispose();
}
finally {
context.getProgressIndicator().popState();
}
runInContext(context, CompilerBundle.message("progress.saving.caches"), new ThrowableRunnable<RuntimeException>(){
public void run() {
context.getDependencyCache().dispose();
}
});
}
private boolean generateSources(final CompilerManager compilerManager,
@@ -867,70 +863,78 @@ public class CompileDriver {
return map;
}
private void deleteAll(final CompileContextEx context, Set<File> outputDirectories) {
private static <T extends Throwable> void runInContext(CompileContext context, String title, ThrowableRunnable<T> action) throws T {
context.getProgressIndicator().pushState();
context.getProgressIndicator().setText(title);
try {
final boolean isTestMode = ApplicationManager.getApplication().isUnitTestMode();
final VirtualFile[] allSources = context.getProjectCompileScope().getFiles(null, true);
context.getProgressIndicator().setText(CompilerBundle.message("progress.clearing.output"));
if (myShouldClearOutputDirectory) {
clearOutputDirectories(outputDirectories);
}
else { // refresh is still required
try {
for (final Compiler compiler : CompilerManager.getInstance(myProject).getCompilers(Compiler.class)) {
try {
if (compiler instanceof GeneratingCompiler) {
final StateCache<ValidityState> cache = getGeneratingCompilerCache((GeneratingCompiler)compiler);
final Iterator<String> urlIterator = cache.getUrlsIterator();
while (urlIterator.hasNext()) {
context.getProgressIndicator().checkCanceled();
deleteFile(new File(VirtualFileManager.extractPath(urlIterator.next())));
}
}
else if (compiler instanceof TranslatingCompiler) {
final ArrayList<Trinity<File, String, Boolean>> toDelete = new ArrayList<Trinity<File, String, Boolean>>();
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
TranslatingCompilerFilesMonitor.getInstance().collectFiles(
context,
(TranslatingCompiler)compiler, Arrays.<VirtualFile>asList(allSources).iterator(),
true /*pass true to make sure that every source in scope file is processed*/,
false /*important! should pass false to enable collection of files to delete*/,
new ArrayList<VirtualFile>(),
toDelete
);
}
});
for (Trinity<File, String, Boolean> trinity : toDelete) {
context.getProgressIndicator().checkCanceled();
final File file = trinity.getFirst();
final boolean deleted = deleteFile(file);
if (isTestMode && deleted) {
CompilerManagerImpl.addDeletedPath(FileUtil.toSystemIndependentName(file.getPath()));
}
}
}
}
catch (IOException e) {
LOG.info(e);
}
}
pruneEmptyDirectories(context.getProgressIndicator(), outputDirectories); // to avoid too much files deleted events
}
finally {
CompilerUtil.refreshIODirectories(outputDirectories);
}
}
dropScopesCaches();
clearCompilerSystemDirectory(context);
action.run();
}
finally {
context.getProgressIndicator().popState();
}
}
private void deleteAll(final CompileContextEx context, final Set<File> outputDirectories) {
runInContext(context, CompilerBundle.message("progress.clearing.output"), new ThrowableRunnable<RuntimeException>(){
public void run() {
final boolean isTestMode = ApplicationManager.getApplication().isUnitTestMode();
final VirtualFile[] allSources = context.getProjectCompileScope().getFiles(null, true);
if (myShouldClearOutputDirectory) {
clearOutputDirectories(outputDirectories);
}
else { // refresh is still required
try {
for (final Compiler compiler : CompilerManager.getInstance(myProject).getCompilers(Compiler.class)) {
try {
if (compiler instanceof GeneratingCompiler) {
final StateCache<ValidityState> cache = getGeneratingCompilerCache((GeneratingCompiler)compiler);
final Iterator<String> urlIterator = cache.getUrlsIterator();
while (urlIterator.hasNext()) {
context.getProgressIndicator().checkCanceled();
deleteFile(new File(VirtualFileManager.extractPath(urlIterator.next())));
}
}
else if (compiler instanceof TranslatingCompiler) {
final ArrayList<Trinity<File, String, Boolean>> toDelete = new ArrayList<Trinity<File, String, Boolean>>();
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
TranslatingCompilerFilesMonitor.getInstance().collectFiles(
context,
(TranslatingCompiler)compiler, Arrays.<VirtualFile>asList(allSources).iterator(),
true /*pass true to make sure that every source in scope file is processed*/,
false /*important! should pass false to enable collection of files to delete*/,
new ArrayList<VirtualFile>(),
toDelete
);
}
});
for (Trinity<File, String, Boolean> trinity : toDelete) {
context.getProgressIndicator().checkCanceled();
final File file = trinity.getFirst();
final boolean deleted = deleteFile(file);
if (isTestMode && deleted) {
CompilerManagerImpl.addDeletedPath(FileUtil.toSystemIndependentName(file.getPath()));
}
}
}
}
catch (IOException e) {
LOG.info(e);
}
}
pruneEmptyDirectories(context.getProgressIndicator(), outputDirectories); // to avoid too much files deleted events
}
finally {
CompilerUtil.refreshIODirectories(outputDirectories);
}
}
dropScopesCaches();
clearCompilerSystemDirectory(context);
}
});
}
private void dropScopesCaches() {
// hack to be sure the classpath will include the output directories
ApplicationManager.getApplication().runReadAction(new Runnable() {
@@ -946,23 +950,26 @@ public class CompileDriver {
}
}
private static boolean doPrune(ProgressIndicator progress, final File directory, final Set<File> outPutDirectories) {
private static boolean doPrune(ProgressIndicator progress, final File directory, final Set<File> outputDirectories) {
progress.checkCanceled();
final File[] files = directory.listFiles();
boolean isEmpty = true;
if (files != null) {
if (files == null) {
isEmpty = false;
}
else {
for (File file : files) {
if (file.isDirectory() && !outPutDirectories.contains(file)) {
if (doPrune(progress, file, outPutDirectories)) {
if (outputDirectories.contains(file)) {
isEmpty = false;
}
else {
if (doPrune(progress, file, outputDirectories)) {
deleteFile(file);
}
else {
isEmpty = false;
}
}
else {
isEmpty = false;
}
}
}
@@ -1074,13 +1081,13 @@ public class CompileDriver {
final List<GeneratingCompiler.GenerationItem> toGenerate = new ArrayList<GeneratingCompiler.GenerationItem>();
final List<File> filesToRefresh = new ArrayList<File>();
final List<File> generatedFiles = new ArrayList<File>();
final List<Module> affectedModules = new ArrayList<Module>();
final Set<Module> affectedModules = new THashSet<Module>();
try {
final StateCache<ValidityState> cache = getGeneratingCompilerCache(compiler);
final Set<String> pathsToRemove = new HashSet<String>(cache.getUrls());
final Map<GeneratingCompiler.GenerationItem, String> itemToOutputPathMap = new HashMap<GeneratingCompiler.GenerationItem, String>();
final IOException[] ex = new IOException[] {null};
final IOException[] ex = {null};
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
for (final GeneratingCompiler.GenerationItem item : allItems) {
@@ -1091,7 +1098,7 @@ public class CompileDriver {
try {
final ValidityState savedState = cache.getState(outputPath);
if (forceGenerate || savedState == null || !savedState.equalsTo(item.getValidityState())) {
final String outputPathUrl = VirtualFileManager.constructUrl(LocalFileSystem.PROTOCOL, outputPath);
if (context.getCompileScope().belongs(outputPathUrl)) {
@@ -1131,20 +1138,21 @@ public class CompileDriver {
}
if (!pathsToRemove.isEmpty()) {
context.getProgressIndicator().pushState();
context.getProgressIndicator().setText(CompilerBundle.message("progress.synchronizing.output.directory"));
for (final String path : pathsToRemove) {
final File file = new File(path);
final boolean deleted = deleteFile(file);
if (deleted) {
cache.remove(path);
filesToRefresh.add(file);
runInContext(context, CompilerBundle.message("progress.synchronizing.output.directory"), new ThrowableRunnable<IOException>(){
public void run() throws IOException {
for (final String path : pathsToRemove) {
final File file = new File(path);
final boolean deleted = deleteFile(file);
if (deleted) {
cache.remove(path);
filesToRefresh.add(file);
}
}
}
}
context.getProgressIndicator().popState();
});
}
Map<Module, Set<GeneratingCompiler.GenerationItem>> moduleToItemMap =
final Map<Module, Set<GeneratingCompiler.GenerationItem>> moduleToItemMap =
buildModuleToGenerationItemMap(toGenerate.toArray(new GeneratingCompiler.GenerationItem[toGenerate.size()]));
List<Module> modules = new ArrayList<Module>(moduleToItemMap.size());
for (final Module module : moduleToItemMap.keySet()) {
@@ -1153,38 +1161,36 @@ public class CompileDriver {
ModuleCompilerUtil.sortModules(myProject, modules);
for (final Module module : modules) {
context.getProgressIndicator().pushState();
try {
final Set<GeneratingCompiler.GenerationItem> items = moduleToItemMap.get(module);
if (items != null && !items.isEmpty()) {
final GeneratingCompiler.GenerationItem[][] productionAndTestItems = splitGenerationItems(items);
boolean moduleAffected = false;
for (GeneratingCompiler.GenerationItem[] _items : productionAndTestItems) {
if (_items.length > 0) {
final VirtualFile outputDir = getGenerationOutputDir(compiler, module, _items[0].isTestSource());
final GeneratingCompiler.GenerationItem[] successfullyGenerated = compiler.generate(context, _items, outputDir);
context.getProgressIndicator().setText(CompilerBundle.message("progress.updating.caches"));
if (successfullyGenerated.length > 0) {
moduleAffected = true;
}
for (final GeneratingCompiler.GenerationItem item : successfullyGenerated) {
final String fullOutputPath = itemToOutputPathMap.get(item);
cache.update(fullOutputPath, item.getValidityState());
final File file = new File(fullOutputPath);
filesToRefresh.add(file);
generatedFiles.add(file);
runInContext(context, "Generating output from "+compiler.getDescription(),new ThrowableRunnable<IOException>(){
public void run() throws IOException {
final Set<GeneratingCompiler.GenerationItem> items = moduleToItemMap.get(module);
if (items != null && !items.isEmpty()) {
final GeneratingCompiler.GenerationItem[][] productionAndTestItems = splitGenerationItems(items);
for (GeneratingCompiler.GenerationItem[] _items : productionAndTestItems) {
if (_items.length > 0) {
final VirtualFile outputDir = getGenerationOutputDir(compiler, module, _items[0].isTestSource());
final GeneratingCompiler.GenerationItem[] successfullyGenerated = compiler.generate(context, _items, outputDir);
context.getProgressIndicator().setText(CompilerBundle.message("progress.updating.caches"));
runInContext(context, CompilerBundle.message("progress.updating.caches"), new ThrowableRunnable<IOException>() {
public void run() throws IOException {
if (successfullyGenerated.length > 0) {
affectedModules.add(module);
}
for (final GeneratingCompiler.GenerationItem item : successfullyGenerated) {
final String fullOutputPath = itemToOutputPathMap.get(item);
cache.update(fullOutputPath, item.getValidityState());
final File file = new File(fullOutputPath);
filesToRefresh.add(file);
generatedFiles.add(file);
}
}
});
}
}
}
if (moduleAffected) {
affectedModules.add(module);
}
}
}
finally {
context.getProgressIndicator().popState();
}
});
}
}
catch (IOException e) {
@@ -1193,7 +1199,6 @@ public class CompileDriver {
throw new ExitException(ExitStatus.ERRORS);
}
finally {
context.getProgressIndicator().pushState();
CompilerUtil.refreshIOFiles(filesToRefresh);
if (!generatedFiles.isEmpty()) {
List<VirtualFile> vFiles = ApplicationManager.getApplication().runReadAction(new Computable<List<VirtualFile>>() {
@@ -1244,116 +1249,118 @@ public class CompileDriver {
final boolean trackDependencies,
final Set<File> outputDirectories,
final boolean onlyCheckStatus) throws ExitException {
final Set<VirtualFile> toCompile = new HashSet<VirtualFile>();
final List<Trinity<File, String, Boolean>> toDelete = new ArrayList<Trinity<File, String, Boolean>>();
context.getProgressIndicator().pushState();
final boolean[] wereFilesDeleted = new boolean[]{false};
try {
final TranslatingCompilerFilesMonitor monitor = TranslatingCompilerFilesMonitor.getInstance();
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
TranslatingCompilerFilesMonitor.getInstance().collectFiles(
context, compiler, Arrays.asList(snapshot).iterator(), forceCompile, isRebuild, toCompile, toDelete
);
if (trackDependencies && !toCompile.isEmpty()) { // should add dependent files
final FileTypeManager fileTypeManager = FileTypeManager.getInstance();
final PsiManager psiManager = PsiManager.getInstance(myProject);
final VirtualFile[] filesToCompile = toCompile.toArray(new VirtualFile[toCompile.size()]);
for (final VirtualFile file : filesToCompile) {
if (fileTypeManager.getFileTypeByFile(file) == StdFileTypes.JAVA) {
final PsiFile psiFile = psiManager.findFile(file);
if (psiFile != null) {
addDependentFiles(psiFile, toCompile, compiler, context);
final boolean[] wereFilesDeleted = {false};
runInContext(context, "Compiling using "+compiler.getDescription(), new ThrowableRunnable<ExitException>(){
public void run() throws ExitException {
try {
final TranslatingCompilerFilesMonitor monitor = TranslatingCompilerFilesMonitor.getInstance();
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
TranslatingCompilerFilesMonitor.getInstance().collectFiles(
context, compiler, Arrays.asList(snapshot).iterator(), forceCompile, isRebuild, toCompile, toDelete
);
if (trackDependencies && !toCompile.isEmpty()) { // should add dependent files
final FileTypeManager fileTypeManager = FileTypeManager.getInstance();
final PsiManager psiManager = PsiManager.getInstance(myProject);
final VirtualFile[] filesToCompile = toCompile.toArray(new VirtualFile[toCompile.size()]);
for (final VirtualFile file : filesToCompile) {
if (fileTypeManager.getFileTypeByFile(file) == StdFileTypes.JAVA) {
final PsiFile psiFile = psiManager.findFile(file);
if (psiFile != null) {
addDependentFiles(psiFile, toCompile, compiler, context);
}
}
}
}
}
});
if (onlyCheckStatus) {
if (toDelete.isEmpty() && toCompile.isEmpty()) {
return;
}
if (LOG.isDebugEnabled()) {
if (!toDelete.isEmpty()) {
LOG.debug("Found items to delete, compiler " + compiler.getDescription());
}
if (!toCompile.isEmpty()) {
LOG.debug("Found items to compile, compiler " + compiler.getDescription());
}
}
throw new ExitException(ExitStatus.CANCELLED);
}
}
});
if (onlyCheckStatus) {
if (toDelete.isEmpty() && toCompile.isEmpty()) {
return false;
}
if (LOG.isDebugEnabled()) {
if (!toDelete.isEmpty()) {
LOG.debug("Found items to delete, compiler " + compiler.getDescription());
try {
wereFilesDeleted[0] = syncOutputDir(context, toDelete, outputDirectories);
}
catch (CacheCorruptedException e) {
LOG.info(e);
context.requestRebuildNextTime(e.getMessage());
}
}
if (!toCompile.isEmpty()) {
LOG.debug("Found items to compile, compiler " + compiler.getDescription());
}
}
throw new ExitException(ExitStatus.CANCELLED);
}
if (!toDelete.isEmpty()) {
try {
wereFilesDeleted[0] = syncOutputDir(context, toDelete, outputDirectories);
if ((wereFilesDeleted[0] || !toCompile.isEmpty()) && context.getMessageCount(CompilerMessageCategory.ERROR) == 0) {
final TranslatingCompiler.ExitStatus exitStatus = compiler.compile(context, toCompile.toArray(new VirtualFile[toCompile.size()]));
monitor.update(context, exitStatus.getSuccessfullyCompiled(), exitStatus.getFilesToRecompile());
}
}
catch (CacheCorruptedException e) {
catch (IOException e) {
LOG.info(e);
context.requestRebuildNextTime(e.getMessage());
throw new ExitException(ExitStatus.ERRORS);
}
}
if ((wereFilesDeleted[0] || !toCompile.isEmpty()) && context.getMessageCount(CompilerMessageCategory.ERROR) == 0) {
final TranslatingCompiler.ExitStatus exitStatus = compiler.compile(context, toCompile.toArray(new VirtualFile[toCompile.size()]));
monitor.update(context, exitStatus.getSuccessfullyCompiled(), exitStatus.getFilesToRecompile());
}
}
catch (IOException e) {
LOG.info(e);
context.requestRebuildNextTime(e.getMessage());
throw new ExitException(ExitStatus.ERRORS);
}
finally {
context.getProgressIndicator().popState();
}
});
return !toCompile.isEmpty() || wereFilesDeleted[0];
}
private static boolean syncOutputDir(final CompileContextEx context, final Collection<Trinity<File, String, Boolean>> toDelete, final Set<File> outputDirectories) throws CacheCorruptedException {
int total = toDelete.size();
final int total = toDelete.size();
final DependencyCache dependencyCache = context.getDependencyCache();
final boolean isTestMode = ApplicationManager.getApplication().isUnitTestMode();
context.getProgressIndicator().pushState();
final List<File> filesToRefresh = new ArrayList<File>();
try {
context.getProgressIndicator().setText(CompilerBundle.message("progress.synchronizing.output.directory"));
int current = 0;
boolean wereFilesDeleted = false;
for (final Trinity<File, String, Boolean> trinity : toDelete) {
context.getProgressIndicator().setFraction(((double)(++current)) / total);
context.getProgressIndicator().checkCanceled();
final File outputPath = trinity.getFirst();
filesToRefresh.add(outputPath);
if (deleteFile(outputPath)) {
wereFilesDeleted = true;
final String className = trinity.getSecond();
if (className != null) {
final int id = dependencyCache.getSymbolTable().getId(className);
dependencyCache.addTraverseRoot(id);
final boolean sourcePresent = trinity.getThird().booleanValue();
if (!sourcePresent) {
dependencyCache.markSourceRemoved(id);
final boolean[] wereFilesDeleted = {false};
runInContext(context, CompilerBundle.message("progress.synchronizing.output.directory"), new ThrowableRunnable<CacheCorruptedException>(){
public void run() throws CacheCorruptedException {
int current = 0;
for (final Trinity<File, String, Boolean> trinity : toDelete) {
context.getProgressIndicator().setFraction((double)++current / total);
context.getProgressIndicator().checkCanceled();
final File outputPath = trinity.getFirst();
filesToRefresh.add(outputPath);
if (deleteFile(outputPath)) {
wereFilesDeleted[0] = true;
final String className = trinity.getSecond();
if (className != null) {
final int id = dependencyCache.getSymbolTable().getId(className);
dependencyCache.addTraverseRoot(id);
final boolean sourcePresent = trinity.getThird().booleanValue();
if (!sourcePresent) {
dependencyCache.markSourceRemoved(id);
}
}
if (isTestMode) {
CompilerManagerImpl.addDeletedPath(outputPath.getPath());
}
}
}
if (isTestMode) {
CompilerManagerImpl.addDeletedPath(outputPath.getPath());
}
runInContext(context, "Pruning empty directories...", new ThrowableRunnable<RuntimeException>() {
public void run() throws RuntimeException {
pruneEmptyDirectories(context.getProgressIndicator(), outputDirectories);
}
});
}
}
pruneEmptyDirectories(context.getProgressIndicator(), outputDirectories);
return wereFilesDeleted;
});
return wereFilesDeleted[0];
}
finally {
CompilerUtil.refreshIOFiles(filesToRefresh);
context.getProgressIndicator().popState();
}
}
@@ -1409,14 +1416,14 @@ public class CompileDriver {
final CompileScope scope = context.getCompileScope();
final List<FileProcessingCompiler.ProcessingItem> toProcess = new ArrayList<FileProcessingCompiler.ProcessingItem>();
final Set<String> allUrls = new HashSet<String>();
final IOException[] ex = new IOException[] {null};
final IOException[] ex = {null};
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
try {
for (FileProcessingCompiler.ProcessingItem item : items) {
final VirtualFile file = item.getFile();
if (file == null) {
LOG.assertTrue(false, "FileProcessingCompiler.ProcessingItem.getFile() must not return null: compiler " + adapter.getCompiler().getDescription());
LOG.error("FileProcessingCompiler.ProcessingItem.getFile() must not return null: compiler " + adapter.getCompiler().getDescription());
}
final String url = file.getUrl();
allUrls.add(url);
@@ -1446,26 +1453,27 @@ public class CompileDriver {
final Collection<String> urls = cache.getUrls();
final List<String> urlsToRemove = new ArrayList<String>();
if (!urls.isEmpty()) {
context.getProgressIndicator().pushState();
context.getProgressIndicator().setText(CompilerBundle.message("progress.processing.outdated.files"));
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
for (final String url : urls) {
if (!allUrls.contains(url)) {
if (!checkScope || scope.belongs(url)) {
urlsToRemove.add(url);
runInContext(context, CompilerBundle.message("progress.processing.outdated.files"), new ThrowableRunnable<IOException>(){
public void run() throws IOException {
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
for (final String url : urls) {
if (!allUrls.contains(url)) {
if (!checkScope || scope.belongs(url)) {
urlsToRemove.add(url);
}
}
}
}
});
if (!onlyCheckStatus && !urlsToRemove.isEmpty()) {
for (final String url : urlsToRemove) {
adapter.processOutdatedItem(context, url, cache.getExtState(url));
cache.remove(url);
}
}
}
});
if (!onlyCheckStatus && !urlsToRemove.isEmpty()) {
for (final String url : urlsToRemove) {
adapter.processOutdatedItem(context, url, cache.getExtState(url));
cache.remove(url);
}
}
context.getProgressIndicator().popState();
}
if (onlyCheckStatus) {
@@ -1493,33 +1501,33 @@ public class CompileDriver {
return false;
}
context.getProgressIndicator().pushState();
final FileProcessingCompiler.ProcessingItem[] processed =
adapter.process(toProcess.toArray(new FileProcessingCompiler.ProcessingItem[toProcess.size()]));
context.getProgressIndicator().popState();
if (processed.length > 0) {
context.getProgressIndicator().pushState();
context.getProgressIndicator().setText(CompilerBundle.message("progress.updating.caches"));
List<VirtualFile> vFiles = new ArrayList<VirtualFile>(processed.length);
for (FileProcessingCompiler.ProcessingItem aProcessed : processed) {
final VirtualFile file = aProcessed.getFile();
vFiles.add(file);
if (LOG.isDebugEnabled()) {
LOG.debug("File processed by " + adapter.getCompiler().getDescription());
LOG.debug("\tFile processed " + file.getPresentableUrl() + "; ts=" + file.getTimeStamp());
runInContext(context, CompilerBundle.message("progress.updating.caches"), new ThrowableRunnable<RuntimeException>(){
public void run() {
List<VirtualFile> vFiles = new ArrayList<VirtualFile>(processed.length);
for (FileProcessingCompiler.ProcessingItem aProcessed : processed) {
final VirtualFile file = aProcessed.getFile();
vFiles.add(file);
if (LOG.isDebugEnabled()) {
LOG.debug("File processed by " + adapter.getCompiler().getDescription());
LOG.debug("\tFile processed " + file.getPresentableUrl() + "; ts=" + file.getTimeStamp());
}
}
LocalFileSystem.getInstance().refreshFiles(vFiles);
if (LOG.isDebugEnabled()) {
LOG.debug("Files after VFS refresh:");
for (VirtualFile file : vFiles) {
LOG.debug("\t" + file.getPresentableUrl() + "; ts=" + file.getTimeStamp());
}
}
for (FileProcessingCompiler.ProcessingItem item : processed) {
cacheUpdater.addFileForUpdate(item, cache);
}
}
}
LocalFileSystem.getInstance().refreshFiles(vFiles);
if (LOG.isDebugEnabled()) {
LOG.debug("Files after VFS refresh:");
for (VirtualFile file : vFiles) {
LOG.debug("\t" + file.getPresentableUrl() + "; ts=" + file.getTimeStamp());
}
}
for (FileProcessingCompiler.ProcessingItem item : processed) {
cacheUpdater.addFileForUpdate(item, cache);
}
});
}
return true;
}
@@ -1556,21 +1564,25 @@ public class CompileDriver {
}, null);
}
private boolean executeCompileTasks(CompileContext context, boolean beforeTasks) {
private boolean executeCompileTasks(final CompileContext context, final boolean beforeTasks) {
final CompilerManager manager = CompilerManager.getInstance(myProject);
final ProgressIndicator progressIndicator = context.getProgressIndicator();
try {
CompileTask[] tasks = beforeTasks ? manager.getBeforeTasks() : manager.getAfterTasks();
if (tasks.length > 0) {
progressIndicator.setText(beforeTasks
? CompilerBundle.message("progress.executing.precompile.tasks")
: CompilerBundle.message("progress.executing.postcompile.tasks"));
for (CompileTask task : tasks) {
if (!task.execute(context)) {
return false;
final boolean[] result = {true};
runInContext(context, beforeTasks
? CompilerBundle.message("progress.executing.precompile.tasks")
: CompilerBundle.message("progress.executing.postcompile.tasks"),new ThrowableRunnable<RuntimeException>(){
public void run() {
CompileTask[] tasks = beforeTasks ? manager.getBeforeTasks() : manager.getAfterTasks();
for (CompileTask task : tasks) {
if (!task.execute(context)) {
result[0] = false;
return;
}
}
}
}
});
return result[0];
}
finally {
WindowManager.getInstance().getStatusBar(myProject).setInfo("");
@@ -1582,7 +1594,6 @@ public class CompileDriver {
});
}
}
return true;
}
// todo: add validation for module chunks: all modules that form a chunk must have the same JDK
@@ -1877,7 +1888,7 @@ public class CompileDriver {
}
public void doUpdate() throws IOException{
final IOException[] ex = new IOException[] {null};
final IOException[] ex = {null};
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
try {
@@ -172,7 +172,7 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent {
final Project project = context.getProject();
final int projectId = getProjectId(project);
final LocalFileSystem lfs = LocalFileSystem.getInstance();
final IOException[] _ex = new IOException[] {null};
final IOException[] _ex = {null};
// need read action here to ensure that no modifications were made to VFS while updating file attributes
ApplicationManager.getApplication().runReadAction(new Runnable() {
@@ -1032,7 +1032,7 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent {
private final String mySrcUrl;
private final LocalFileSystem myFileSystem;
public ScheduleOutputsForDeletionProc(final String srcUrl) {
private ScheduleOutputsForDeletionProc(final String srcUrl) {
mySrcUrl = srcUrl;
myFileSystem = LocalFileSystem.getInstance();
}
@@ -16,17 +16,16 @@ public interface BackendCompiler {
@NotNull @NonNls String getId(); // used for externalization
@NotNull String getPresentableName();
@NotNull Configurable createConfigurable();
@NotNull
Set<FileType> getCompilableFileTypes();
@Nullable OutputParser createErrorParser(final String outputDir);
@Nullable OutputParser createOutputParser(final String outputDir);
@NotNull Set<FileType> getCompilableFileTypes();
@Nullable OutputParser createErrorParser(@NotNull String outputDir);
@Nullable OutputParser createOutputParser(@NotNull String outputDir);
boolean checkCompiler(final CompileScope scope);
@NotNull Process launchProcess(
final ModuleChunk chunk,
final String outputDir,
final CompileContext compileContext) throws IOException;
@NotNull ModuleChunk chunk,
@NotNull String outputDir,
@NotNull CompileContext compileContext) throws IOException;
void compileFinished();
@@ -35,17 +35,17 @@ import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Chunk;
import com.intellij.util.StringBuilderSpinAllocator;
import com.intellij.util.cls.ClsFormatException;
import gnu.trove.TIntHashSet;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ArrayBlockingQueue;
@@ -64,35 +64,36 @@ public class BackendCompilerWrapper {
private final List<TranslatingCompiler.OutputItem> myOutputItems;
private final CompileContextEx myCompileContext;
private final VirtualFile[] myFilesToCompile;
private final List<VirtualFile> myFilesToCompile;
private final Project myProject;
private final Set<VirtualFile> myFilesToRecompile;
private final Map<Module, VirtualFile> myModuleToTempDirMap = new HashMap<Module, VirtualFile>();
private final ProjectFileIndex myProjectFileIndex;
@NonNls private static final String PACKAGE_ANNOTATION_FILE_NAME = "package-info.java";
private static final FileObject myStopThreadToken = new FileObject(null,null);
public BackendCompilerWrapper(final Project project,
VirtualFile[] filesToCompile,
CompileContextEx compileContext,
BackendCompiler compiler) {
public BackendCompilerWrapper(@NotNull final Project project,
@NotNull List<VirtualFile> filesToCompile,
@NotNull CompileContextEx compileContext,
@NotNull BackendCompiler compiler) {
myProject = project;
myCompiler = compiler;
myCompileContext = compileContext;
myFilesToCompile = filesToCompile;
myFilesToRecompile = new HashSet<VirtualFile>(Arrays.asList(filesToCompile));
myFilesToRecompile = new HashSet<VirtualFile>(filesToCompile);
myProjectFileIndex = ProjectRootManager.getInstance(myProject).getFileIndex();
mySuccesfullyCompiledJavaFiles = new HashSet<VirtualFile>(filesToCompile.length);
myOutputItems = new ArrayList<TranslatingCompiler.OutputItem>(filesToCompile.length);
myFileNameToSourceMap = new HashMap<String, Set<CompiledClass>>(filesToCompile.length);
myFilesToRefresh = new ArrayList<File>(filesToCompile.length);
mySuccesfullyCompiledJavaFiles = new HashSet<VirtualFile>(filesToCompile.size());
myOutputItems = new ArrayList<TranslatingCompiler.OutputItem>(filesToCompile.size());
myFileNameToSourceMap = new HashMap<String, Set<CompiledClass>>(filesToCompile.size());
myFilesToRefresh = new ArrayList<File>(filesToCompile.size());
}
public TranslatingCompiler.OutputItem[] compile() throws CompilerException, CacheCorruptedException {
public List<TranslatingCompiler.OutputItem> compile() throws CompilerException, CacheCorruptedException {
Application application = ApplicationManager.getApplication();
final Set<VirtualFile> allDependent = new HashSet<VirtualFile>();
COMPILE:
try {
if (myFilesToCompile.length > 0) {
if (!myFilesToCompile.isEmpty()) {
if (application.isUnitTestMode()) {
saveTestData();
}
@@ -101,20 +102,18 @@ public class BackendCompilerWrapper {
compileModules(moduleToFilesMap);
}
VirtualFile[] dependentFiles;
Collection<VirtualFile> dependentFiles;
do {
dependentFiles = findDependentFiles();
if (dependentFiles.length > 0) {
final List<VirtualFile> deps = Arrays.asList(dependentFiles);
myFilesToRecompile.addAll(deps);
allDependent.addAll(deps);
if (!dependentFiles.isEmpty()) {
myFilesToRecompile.addAll(dependentFiles);
allDependent.addAll(dependentFiles);
if (myCompileContext.getProgressIndicator().isCanceled() || myCompileContext.getMessageCount(CompilerMessageCategory.ERROR) > 0) {
break COMPILE;
}
final VirtualFile[] filesInScope = getFilesInScope(dependentFiles);
if (filesInScope.length == 0) {
final List<VirtualFile> filesInScope = getFilesInScope(dependentFiles);
if (filesInScope.isEmpty()) {
break;
}
final Map<Module, Set<VirtualFile>> moduleToFilesMap = buildModuleToFilesMap(myCompileContext, filesInScope);
@@ -122,7 +121,7 @@ public class BackendCompilerWrapper {
compileModules(moduleToFilesMap);
}
}
while (dependentFiles.length > 0 && myCompileContext.getMessageCount(CompilerMessageCategory.ERROR) == 0);
while (!dependentFiles.isEmpty() && myCompileContext.getMessageCount(CompilerMessageCategory.ERROR) == 0);
}
catch (IOException e) {
throw new CompilerException(CompilerBundle.message("error.compiler.process.not.started", e.getMessage()), e);
@@ -151,7 +150,7 @@ public class BackendCompilerWrapper {
if (myCompileContext.getProgressIndicator().isCanceled()) {
myFilesToRecompile.clear();
// when cancelled pretend nothing was compiled and next compile will compile everything from the scratch
return TranslatingCompiler.EMPTY_OUTPUT_ITEM_ARRAY;
return Collections.emptyList();
}
// do not update caches if cancelled because there is a chance that they will be incomplete
@@ -163,7 +162,7 @@ public class BackendCompilerWrapper {
myFilesToRecompile.addAll(allDependent);
}
processPackageInfoFiles();
return myOutputItems.toArray(new TranslatingCompiler.OutputItem[myOutputItems.size()]);
return myOutputItems;
}
// package-info.java hack
@@ -192,8 +191,8 @@ public class BackendCompilerWrapper {
});
}
private VirtualFile[] getFilesInScope(final VirtualFile[] dependentFiles) {
final List<VirtualFile> filesInScope = new ArrayList<VirtualFile>(dependentFiles.length);
private List<VirtualFile> getFilesInScope(final Collection<VirtualFile> dependentFiles) {
final List<VirtualFile> filesInScope = new ArrayList<VirtualFile>(dependentFiles.size());
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
for (VirtualFile dependentFile : dependentFiles) {
@@ -203,7 +202,7 @@ public class BackendCompilerWrapper {
}
}
});
return filesInScope.toArray(new VirtualFile[filesInScope.size()]);
return filesInScope;
}
private void compileModules(final Map<Module, Set<VirtualFile>> moduleToFilesMap) throws IOException {
@@ -328,7 +327,7 @@ public class BackendCompilerWrapper {
private final TIntHashSet myProcessedNames = new TIntHashSet();
private final Set<VirtualFile> myProcessedFiles = new HashSet<VirtualFile>();
private VirtualFile[] findDependentFiles() throws CacheCorruptedException {
private Collection<VirtualFile> findDependentFiles() throws CacheCorruptedException {
myCompileContext.getProgressIndicator().setText(CompilerBundle.message("progress.checking.dependencies"));
final DependencyCache dependencyCache = myCompileContext.getDependencyCache();
@@ -388,7 +387,7 @@ public class BackendCompilerWrapper {
}
myCompileContext.getProgressIndicator().setText(CompilerBundle.message("progress.found.dependent.files", dependentFiles.size()));
return dependentFiles.toArray(new VirtualFile[dependentFiles.size()]);
return dependentFiles;
}
private final Object lock = new Object();
@@ -424,14 +423,14 @@ public class BackendCompilerWrapper {
}
}
protected void processCompiledClass(final String classFileToProcess) throws CacheCorruptedException {
protected void processCompiledClass(final FileObject classFileToProcess) throws CacheCorruptedException {
synchronized (lock) {
myClassParsingThread.addPath(classFileToProcess);
}
}
}
private void doCompile(final ModuleChunk chunk, String outputDir, int sourcesFilter) throws IOException {
private void doCompile(@NotNull final ModuleChunk chunk, @NotNull String outputDir, int sourcesFilter) throws IOException {
myCompileContext.getProgressIndicator().checkCanceled();
chunk.setSourcesFilter(sourcesFilter);
@@ -866,7 +865,7 @@ public class BackendCompilerWrapper {
myCompileContext.getProgressIndicator().setText2(msg);
}
private static Map<Module, Set<VirtualFile>> buildModuleToFilesMap(final CompileContext context, final VirtualFile[] files) {
private static Map<Module, Set<VirtualFile>> buildModuleToFilesMap(final CompileContext context, final List<VirtualFile> files) {
final Map<Module, Set<VirtualFile>> map = new HashMap<Module, Set<VirtualFile>>();
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
@@ -890,9 +889,8 @@ public class BackendCompilerWrapper {
}
private class ClassParsingThread implements Runnable {
private final BlockingQueue<String> myPaths = new ArrayBlockingQueue<String>(50000);
private final BlockingQueue<FileObject> myPaths = new ArrayBlockingQueue<FileObject>(50000);
private CacheCorruptedException myError = null;
private final String myStopThreadToken = new String();
private final boolean myAddNotNullAssertions;
private final boolean myIsJdk16;
@@ -903,10 +901,11 @@ public class BackendCompilerWrapper {
public void run() {
try {
//noinspection StringEquality
String path;
while ((path = getNextPath()) != myStopThreadToken) {
processPath(path.replace('/', File.separatorChar));
while (true) {
FileObject path = myPaths.take();
if (path == myStopThreadToken) break;
processPath(path);
}
}
catch (InterruptedException e) {
@@ -917,30 +916,23 @@ public class BackendCompilerWrapper {
}
}
public void addPath(String path) throws CacheCorruptedException {
public void addPath(FileObject path) throws CacheCorruptedException {
if (myError != null) {
throw myError;
}
myPaths.offer(path);
}
private String getNextPath() throws InterruptedException {
return myPaths.take();
}
public void stopParsing() {
myPaths.offer(myStopThreadToken);
}
private void processPath(final String path) throws CacheCorruptedException {
private void processPath(FileObject fileObject) throws CacheCorruptedException {
File file = fileObject.getFile();
byte[] fileContent = fileObject.getContent();
String path = file.getPath();
try {
final File file = new File(path); // the file is assumed to exist!
byte[] fileContent = ArrayUtil.EMPTY_BYTE_ARRAY;
try{
fileContent = FileUtil.loadFileBytes(file);
}
catch(IOException ignored){
}
// the file is assumed to exist!
final DependencyCache dependencyCache = myCompileContext.getDependencyCache();
final int newClassQName = dependencyCache.reparseClassFile(file, fileContent);
@@ -949,7 +941,8 @@ public class BackendCompilerWrapper {
final String qName = dependencyCache.resolve(newClassQName);
String relativePathToSource = "/" + MakeUtil.createRelativePathToSource(qName, sourceFileName);
putName(sourceFileName, newClassQName, relativePathToSource, path);
boolean fileContentChanged = false;
if (myAddNotNullAssertions && hasNotNullAnnotations(newClassesCache, dependencyCache.getSymbolTable(), newClassQName)) {
try {
ClassReader reader = new ClassReader(fileContent, 0, fileContent.length);
@@ -958,19 +951,18 @@ public class BackendCompilerWrapper {
final NotNullVerifyingInstrumenter instrumenter = new NotNullVerifyingInstrumenter(writer);
reader.accept(instrumenter, 0);
if (instrumenter.isModification()) {
final FileOutputStream output = new FileOutputStream(file);
try {
output.write(writer.toByteArray());
}
finally {
output.close();
}
fileContent = writer.toByteArray();
fileContentChanged = true;
}
}
catch (Exception ignored) {
LOG.info(ignored);
}
}
if (fileContentChanged || !fileObject.isSaved()) {
writeFile(file, fileContent);
}
}
catch (ClsFormatException e) {
String message;
@@ -983,11 +975,24 @@ public class BackendCompilerWrapper {
}
myCompileContext.addMessage(CompilerMessageCategory.ERROR, message, null, -1, -1);
}
catch (IOException e) {
myCompileContext.addMessage(CompilerMessageCategory.ERROR, e.getMessage(), null, -1, -1);
}
finally {
myClassesCount += 1;
updateStatistics();
}
}
private void writeFile(File file, byte[] fileContent) throws IOException {
try {
FileUtil.writeToFile(file, fileContent);
}
catch (FileNotFoundException e) {
FileUtil.createParentDirs(file);
FileUtil.writeToFile(file, fileContent);
}
}
}
private static boolean hasNotNullAnnotations(final Cache cache, final SymbolTable symbolTable, final int className) throws CacheCorruptedException {
@@ -1025,11 +1030,12 @@ public class BackendCompilerWrapper {
private final String myPath;
private final int myKind;
private OutputDir(String path, int kind) {
private OutputDir(@NotNull String path, int kind) {
myPath = path;
myKind = kind;
}
@NotNull
public String getPath() {
return myPath;
}
@@ -24,10 +24,9 @@ public abstract class CompilerParsingThread implements Runnable, OutputParser.Ca
private boolean mySkipLF = false;
private Throwable myError = null;
private final boolean myIsUnitTestMode;
private String myClassFileToProcess = null;
private FileObject myClassFileToProcess = null;
private String myLastReadLine = null;
private boolean myProcessExited = false;
private volatile boolean myProcessExited = false;
public CompilerParsingThread(Process process, OutputParser outputParser, final boolean readErrorStream, boolean trimLines) {
myProcess = process;
@@ -44,7 +43,7 @@ public abstract class CompilerParsingThread implements Runnable, OutputParser.Ca
if (!myIsUnitTestMode && myProcess == null) {
break;
}
if (isCanceled()) {
if (myProcessExited || isCanceled()) {
break;
}
if (!myOutputParser.processMessageLine(this)) {
@@ -57,6 +56,7 @@ public abstract class CompilerParsingThread implements Runnable, OutputParser.Ca
}
}
catch (Throwable e) {
e.printStackTrace();
myError = e;
LOG.info(e);
}
@@ -92,8 +92,8 @@ public abstract class CompilerParsingThread implements Runnable, OutputParser.Ca
return myLastReadLine;
}
public final void fileGenerated(String path) {
String previousPath = myClassFileToProcess;
public final void fileGenerated(FileObject path) {
FileObject previousPath = myClassFileToProcess;
myClassFileToProcess = path;
if (previousPath != null) {
try {
@@ -108,8 +108,7 @@ public abstract class CompilerParsingThread implements Runnable, OutputParser.Ca
protected abstract boolean isCanceled();
protected abstract void processCompiledClass(final String classFileToProcess) throws CacheCorruptedException;
protected abstract void processCompiledClass(final FileObject classFileToProcess) throws CacheCorruptedException;
private String readLine(final Reader reader) {
StringBuilder buffer;
@@ -176,11 +175,11 @@ public abstract class CompilerParsingThread implements Runnable, OutputParser.Ca
}
}
private synchronized boolean isProcessTerminated() {
private boolean isProcessTerminated() {
return myProcessExited;
}
public synchronized void setProcessTerminated(final boolean procesExited) {
public void setProcessTerminated(final boolean procesExited) {
myProcessExited = procesExited;
}
}
@@ -31,7 +31,7 @@ public abstract class ExternalCompiler implements BackendCompiler {
}
@NotNull
public Process launchProcess(final ModuleChunk chunk, final String outputDir, final CompileContext compileContext) throws IOException {
public Process launchProcess(@NotNull final ModuleChunk chunk, @NotNull final String outputDir, @NotNull final CompileContext compileContext) throws IOException {
final String[] commands = createStartupCommand(chunk, compileContext, outputDir);
if (LOG.isDebugEnabled()) {
@@ -0,0 +1,46 @@
package com.intellij.compiler.impl.javaCompiler;
import com.intellij.util.ArrayUtil;
import com.intellij.openapi.util.io.FileUtil;
import java.io.File;
import java.io.IOException;
/**
* @author cdr
*/
public class FileObject {
private final File myFile;
private final byte[] myContent;
private final boolean mySaved;
public FileObject(File file, byte[] content) {
myFile = file;
myContent = content;
mySaved = false;
}
public FileObject(File file) {
myFile = file;
byte[] fileContent = ArrayUtil.EMPTY_BYTE_ARRAY;
try{
fileContent = FileUtil.loadFileBytes(file);
}
catch(IOException ignored){
}
myContent = fileContent;
mySaved = true;
}
public File getFile() {
return myFile;
}
public byte[] getContent() {
return myContent;
}
public boolean isSaved() {
return mySaved;
}
}
@@ -18,6 +18,10 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class JavaCompiler implements TranslatingCompiler {
private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.impl.javaCompiler.JavaCompiler");
private final Project myProject;
@@ -38,19 +42,19 @@ public class JavaCompiler implements TranslatingCompiler {
public ExitStatus compile(CompileContext context, VirtualFile[] files) {
final BackendCompiler backEndCompiler = getBackEndCompiler();
final BackendCompilerWrapper wrapper = new BackendCompilerWrapper(myProject, files, (CompileContextEx)context, backEndCompiler);
OutputItem[] outputItems;
final BackendCompilerWrapper wrapper = new BackendCompilerWrapper(myProject, Arrays.asList(files), (CompileContextEx)context, backEndCompiler);
List<OutputItem> outputItems;
try {
outputItems = wrapper.compile();
}
catch (CompilerException e) {
outputItems = EMPTY_OUTPUT_ITEM_ARRAY;
outputItems = Collections.emptyList();
context.addMessage(CompilerMessageCategory.ERROR, e.getMessage(), null, -1, -1);
}
catch (CacheCorruptedException e) {
LOG.info(e);
context.requestRebuildNextTime(e.getMessage());
outputItems = EMPTY_OUTPUT_ITEM_ARRAY;
outputItems = Collections.emptyList();
}
return new ExitStatusImpl(outputItems, wrapper.getFilesToRecompile());
@@ -66,17 +70,16 @@ public class JavaCompiler implements TranslatingCompiler {
}
private static class ExitStatusImpl implements ExitStatus {
private final OutputItem[] myOuitputItems;
private final List<OutputItem> myOutputItems;
private final VirtualFile[] myMyFilesToRecompile;
public ExitStatusImpl(OutputItem[] ouitputItems, VirtualFile[] myFilesToRecompile) {
myOuitputItems = ouitputItems;
private ExitStatusImpl(List<OutputItem> outputItems, VirtualFile[] myFilesToRecompile) {
myOutputItems = outputItems;
myMyFilesToRecompile = myFilesToRecompile;
}
public OutputItem[] getSuccessfullyCompiled() {
return myOuitputItems;
return myOutputItems.toArray(new OutputItem[myOutputItems.size()]);
}
public VirtualFile[] getFilesToRecompile() {
@@ -0,0 +1,110 @@
package com.intellij.compiler.impl.javaCompiler.api;
import com.intellij.compiler.OutputParser;
import com.sun.source.util.JavacTask;
import com.sun.source.util.TaskEvent;
import com.sun.source.util.TaskListener;
import org.jetbrains.annotations.NotNull;
import javax.tools.*;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.File;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
/**
* @author cdr
*/
@SuppressWarnings({"Since15"})
public class CompAPIDriver {
private final BlockingQueue<CompilationEvent> myCompilationResults = new LinkedBlockingQueue<CompilationEvent>();
private static final CompilationEvent GUARD = new CompilationEvent() {
@Override
protected void process(OutputParser.Callback callback) {
}
};
public void compile(List<String> commandLine, List<File> paths, final String outputDir) {
JavaCompiler compiler = new com.sun.tools.javac.api.JavacTool(); //use current classloader
StandardJavaFileManager manager = new MyFileManager(this, outputDir);
Iterable<? extends JavaFileObject> input = manager.getJavaFileObjectsFromFiles(paths);
DiagnosticListener<JavaFileObject> listener = new DiagnosticListener<JavaFileObject>() {
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
CompilationEvent event = CompilationEvent.diagnostic(diagnostic);
myCompilationResults.offer(event);
}
};
try {
PrintWriter silent = new PrintWriter(new OutputStream(){
public void write(int b) {}
});
JavaCompiler.CompilationTask task = compiler.getTask(silent, manager, listener, commandLine, null, input);
((JavacTask)task).setTaskListener(new TaskListener() {
public void started(TaskEvent taskEvent) {
JavaFileObject sourceFile = taskEvent.getSourceFile();
CompilationEvent event;
switch (taskEvent.getKind()) {
case ANALYZE:
event = CompilationEvent.progress("Analyzing ",sourceFile);
break;
case PARSE:
event = CompilationEvent.progress("Parsing ", sourceFile);
break;
default:
event = null;
}
if (event != null) {
myCompilationResults.offer(event);
}
}
public void finished(TaskEvent taskEvent) {
CompilationEvent event;
switch (taskEvent.getKind()) {
case ENTER:
event = CompilationEvent.fileProcessed();
break;
default:
event = null;
}
if (event != null) {
myCompilationResults.offer(event);
}
}
});
task.call();
}
finally {
myCompilationResults.offer(GUARD);
}
}
public boolean processAll(@NotNull OutputParser.Callback callback) {
try {
while (true) {
CompilationEvent event = myCompilationResults.take();
if (event == GUARD) break;
event.process(callback);
}
}
catch (InterruptedException ignored) {
System.out.println("ignored " + ignored);
}
return false;
}
public void finish() {
myCompilationResults.clear();
}
public void offer(CompilationEvent compilationEvent) {
myCompilationResults.offer(compilationEvent);
}
}
@@ -0,0 +1,70 @@
package com.intellij.compiler.impl.javaCompiler.api;
import com.intellij.compiler.OutputParser;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.compiler.CompilerMessageCategory;
import javax.tools.JavaFileObject;
import javax.tools.Diagnostic;
import java.net.URI;
import java.io.File;
/**
* @author cdr
*/
@SuppressWarnings({"Since15"})
abstract class CompilationEvent {
protected abstract void process(OutputParser.Callback callback);
static CompilationEvent progress(final String title, final JavaFileObject fileObject) {
return new CompilationEvent() {
@Override
protected void process(OutputParser.Callback callback) {
showProgressFor(title, fileObject.toUri(), callback);
}
};
}
private static void showProgressFor(String title, URI uri, OutputParser.Callback callback) {
callback.setProgressText(title + StringUtil.last(uri.toString(), 70, true));
}
static CompilationEvent generateClass(final URI uri, final byte[] bytes) {
return new CompilationEvent() {
@Override
protected void process(OutputParser.Callback callback) {
showProgressFor("Writing ", uri, callback);
File file = new File(uri);
callback.fileGenerated(new com.intellij.compiler.impl.javaCompiler.FileObject(file,bytes));
}
};
}
static CompilationEvent diagnostic(final Diagnostic<? extends JavaFileObject> diagnostic) {
return new CompilationEvent() {
@Override
protected void process(OutputParser.Callback callback) {
JavaFileObject fileObject = diagnostic.getSource();
String message = diagnostic.getMessage(null);
String url = fileObject == null ? null : VfsUtil.pathToUrl(FileUtil.toSystemIndependentName(new File(fileObject.toUri()).getPath()));
CompilerMessageCategory category = diagnostic.getKind() == Diagnostic.Kind.ERROR
? CompilerMessageCategory.ERROR
: diagnostic.getKind() == Diagnostic.Kind.WARNING ||
diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING
? CompilerMessageCategory.WARNING
: CompilerMessageCategory.INFORMATION;
callback.message(category, message, url, (int)diagnostic.getLineNumber(), (int)diagnostic.getColumnNumber());
}
};
}
public static CompilationEvent fileProcessed() {
return new CompilationEvent() {
@Override
protected void process(OutputParser.Callback callback) {
callback.fileProcessed(null);
}
};
}
}
@@ -0,0 +1,182 @@
package com.intellij.compiler.impl.javaCompiler.api;
import com.intellij.compiler.OutputParser;
import com.intellij.compiler.impl.CompilerUtil;
import com.intellij.compiler.impl.javaCompiler.BackendCompiler;
import com.intellij.compiler.impl.javaCompiler.DependencyProcessor;
import com.intellij.compiler.impl.javaCompiler.ModuleChunk;
import com.intellij.compiler.impl.javaCompiler.javac.JavacCompiler;
import com.intellij.compiler.impl.javaCompiler.javac.JavacConfigurable;
import com.intellij.compiler.impl.javaCompiler.javac.JavacSettings;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.compiler.CompileContext;
import com.intellij.openapi.compiler.CompileScope;
import com.intellij.openapi.compiler.CompilerMessageCategory;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;
public class CompilerAPICompiler implements BackendCompiler {
private final Project myProject;
private int myExitCode;
private static final Set<FileType> COMPILABLE_TYPES = Collections.<FileType>singleton(StdFileTypes.JAVA);
private final CompAPIDriver myCompAPIDriver = new CompAPIDriver();
public CompilerAPICompiler(Project project) {
myProject = project;
}
public DependencyProcessor getDependencyProcessor() {
return null;
}
public boolean checkCompiler(final CompileScope scope) {
final Module[] modules = scope.getAffectedModules();
final Set<Sdk> checkedJdks = new HashSet<Sdk>();
for (final Module module : modules) {
final Sdk jdk = ModuleRootManager.getInstance(module).getSdk();
if (jdk == null) {
continue;
}
checkedJdks.add(jdk);
}
Sdk projectJdk = ProjectRootManager.getInstance(myProject).getProjectJdk();
if (projectJdk != null) checkedJdks.add(projectJdk);
for (Sdk sdk : checkedJdks) {
if (!CompilerUtil.isOfVersion(sdk.getVersionString(), "1.6")) {
Messages.showErrorDialog(myProject, "Compiler API supports JDK of version 6 only: "+sdk.getVersionString(), "Incompatible JDK");
return false;
}
}
return true;
}
@NotNull
@NonNls
// used for externalization
public String getId() {
return "compAPI";
}
@NotNull
public String getPresentableName() {
return "Javac in-process (Java6 only)";
}
@NotNull
public Configurable createConfigurable() {
return new JavacConfigurable(JavacSettings.getInstance(myProject));
}
@NotNull
public Set<FileType> getCompilableFileTypes() {
return COMPILABLE_TYPES;
}
@Nullable
public OutputParser createErrorParser(@NotNull final String outputDir) {
return new OutputParser() {
public boolean processMessageLine(Callback callback) {
return myCompAPIDriver.processAll(callback);
}
};
}
@Nullable
public OutputParser createOutputParser(@NotNull final String outputDir) {
return null;
}
public void compileFinished() {
myCompAPIDriver.finish();
}
@NotNull
public Process launchProcess(@NotNull final ModuleChunk chunk, @NotNull final String outputDir, @NotNull final CompileContext compileContext) throws IOException {
final IOException[] ex = {null};
@NonNls final List<String> commandLine = ApplicationManager.getApplication().runReadAction(new Computable<List<String>>() {
public List<String> compute() {
try {
List<String> commandLine = new ArrayList<String>();
JavacSettings javacSettings = JavacSettings.getInstance(myProject);
final List<String> additionalOptions =
JavacCompiler.addAdditionalSettings(commandLine, javacSettings, false, false, false, false, false);
JavacCompiler.addCommandLineOptions(chunk, commandLine, outputDir, chunk.getJdk(), false,false, null, false, false);
commandLine.addAll(additionalOptions);
return commandLine;
}
catch (IOException e) {
ex[0] = e;
}
return null;
}
});
if (ex[0] != null) {
throw ex[0];
}
return new Process() {
public OutputStream getOutputStream() {
throw new UnsupportedOperationException();
}
public InputStream getInputStream() {
return null;
}
public InputStream getErrorStream() {
return null;
}
public void destroy() {
}
public int waitFor() {
try {
//commandLine.remove("-verbose");
compile(commandLine, chunk, outputDir);
myExitCode = 0;
return myExitCode;
}
catch (Exception e) {
compileContext.addMessage(CompilerMessageCategory.ERROR, e.getMessage(), null, -1, -1);
myExitCode = -1;
return -1;
}
}
public int exitValue() {
return myExitCode;
}
};
}
private void compile(List<String> commandLine, ModuleChunk chunk, String outputDir) {
VirtualFile[] filesToCompile = chunk.getFilesToCompile();
List<File> paths = new ArrayList<File>(filesToCompile.length);
for (VirtualFile file : filesToCompile) {
paths.add(new File(file.getPresentableUrl()));
}
myCompAPIDriver.compile(commandLine, paths, outputDir);
}
}
@@ -0,0 +1,126 @@
package com.intellij.compiler.impl.javaCompiler.api;
import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.DefaultFileManager;
import gnu.trove.THashMap;
import javax.tools.FileObject;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* @author cdr
*/
class MyFileManager extends DefaultFileManager {
private final String myOutputDir;
private final CompAPIDriver myCompAPIDriver;
private final Map<URI, JavaFileObject> uri2Output = new THashMap<URI, JavaFileObject>();
private final Map<URI, JavaFileObject> uri2Source = new THashMap<URI, JavaFileObject>();
MyFileManager(CompAPIDriver compAPIDriver, String outputDir) {
super(new Context(), false, null);
myCompAPIDriver = compAPIDriver;
myOutputDir = outputDir;
}
@Override
public Iterable<? extends JavaFileObject> getJavaFileObjectsFromFiles(Iterable<? extends File> files) {
//return super.getJavaFileObjectsFromFiles(files);
int size = ((Collection)files).size();
List<JavaFileObject> result = new ArrayList<JavaFileObject>(size);
for (File file : files) {
result.add(getSource(file));
}
return result;
}
private JavaFileObject getSource(File file) {
URI uri = file.toURI();
JavaFileObject fileObject = uri2Source.get(uri);
if (fileObject == null) {
fileObject = new JavaFile(file);
uri2Source.put(uri, fileObject);
}
return fileObject;
}
private JavaFileObject getOutput(URI uri) {
JavaFileObject fileObject = uri2Output.get(uri);
if (fileObject == null) {
fileObject = new Output(uri) {
protected void offerClassFile(URI uri, byte[] bytes) {
myCompAPIDriver.offer(CompilationEvent.generateClass(uri, bytes));
}
};
uri2Output.put(uri, fileObject);
}
return fileObject;
}
@Override
public JavaFileObject getJavaFileForOutput(Location location, String name, JavaFileObject.Kind kind, FileObject fileObject) {
return getOutput(toURI(myOutputDir,name));
}
private static class JavaFile extends SimpleJavaFileObject {
private final File myFile;
protected JavaFile(File file) {
super(file.toURI(), Kind.SOURCE);
myFile = file;
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByIoFile(myFile);
if (virtualFile == null) return null;
return LoadTextUtil.loadText(virtualFile);
}
@Override
public String toString() {
return toUri().toString();
}
}
private abstract static class Output extends SimpleJavaFileObject {
private Output(URI uri) {
super(uri, Kind.CLASS);
}
@Override
public ByteArrayOutputStream openOutputStream() {
return new ByteArrayOutputStream() {
@Override
public void close() throws IOException {
super.close();
offerClassFile(toUri(), toByteArray());
}
};
}
protected abstract void offerClassFile(URI uri, byte[] bytes);
}
private static URI toURI(String outputDir, String name) {
try {
return new URI("file:///" + outputDir.replace('\\','/') + "/" + name.replace('.', '/') + JavaFileObject.Kind.CLASS.extension);
}
catch (URISyntaxException exception) {
throw new Error(exception);
}
}
}
@@ -19,6 +19,7 @@
package com.intellij.compiler.impl.javaCompiler.eclipse;
import com.intellij.compiler.OutputParser;
import com.intellij.compiler.impl.javaCompiler.FileObject;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.compiler.CompilerBundle;
import com.intellij.openapi.compiler.CompilerMessageCategory;
@@ -55,7 +56,7 @@ import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class EclipseCompilerDriver implements IEclipseCompilerDriver {
public class EclipseCompilerDriver {
private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.impl.javaCompiler.eclipse.EclipseCompilerDriver");
private String[] sourceFilePaths;
@@ -183,17 +184,11 @@ public class EclipseCompilerDriver implements IEclipseCompilerDriver {
String filePath = String.valueOf(classFile.fileName());
String relativePath = FileUtil.toSystemDependentName(filePath + ".class");
String path = FileUtil.toSystemDependentName(outputDir) + File.separatorChar + relativePath;
try {
File out = new File(path);
FileUtil.createParentDirs(out);
FileUtil.writeToFile(out, classFile.getBytes());
}
catch (IOException e) {
LOG.error(e);
}
callback.fileGenerated(path);
byte[] bytes = classFile.getBytes();
File out = new File(path);
callback.fileGenerated(new FileObject(out,bytes));
}
IProblem[] problems = result.getProblems();
if (problems != null) {
@@ -1,11 +1,13 @@
package com.intellij.compiler.impl.javaCompiler.eclipse;
import com.intellij.compiler.OutputParser;
import com.intellij.compiler.impl.javaCompiler.FileObject;
import com.intellij.openapi.compiler.CompilerBundle;
import com.intellij.openapi.compiler.CompilerMessageCategory;
import com.intellij.openapi.util.io.FileUtil;
import org.jetbrains.annotations.NonNls;
import java.io.File;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -61,7 +63,7 @@ public class EclipseCompilerOutputParser extends OutputParser {
String path = matcher.group(1);
String absPath = FileUtil.toSystemDependentName(myOutputDir + '/' + path);
//callback.setProgressText(CompilerBundle.message("eclipse.compiler.writing", absPath));
callback.fileGenerated(absPath);
callback.fileGenerated(new FileObject(new File(absPath)));
return true;
}
if (COMPILED_PATTERN.matcher(line).matches() || GENERATED_PATTERN.matcher(line).matches()) {
@@ -30,13 +30,13 @@ public class EclipseEmbeddedCompiler implements BackendCompiler {
private final Project myProject;
private final EclipseCompiler myEclipseExternalCompiler;
private int myExitCode;
private IEclipseCompilerDriver myEclipseCompilerDriver;
private final EclipseCompilerDriver myEclipseCompilerDriver;
private static final Set<FileType> COMPILABLE_TYPES = Collections.<FileType>singleton(StdFileTypes.JAVA);
public EclipseEmbeddedCompiler(Project project) {
myProject = project;
myEclipseExternalCompiler = new EclipseCompiler(project);
createCompileDriver();
myEclipseCompilerDriver = new EclipseCompilerDriver();
}
public DependencyProcessor getDependencyProcessor() {
@@ -49,8 +49,8 @@ public class EclipseEmbeddedCompiler implements BackendCompiler {
@NotNull
@NonNls
public String getId() // used for externalization
{
public String getId() {
// used for externalization
return "EclipseEmbedded";
}
@@ -70,7 +70,7 @@ public class EclipseEmbeddedCompiler implements BackendCompiler {
}
@Nullable
public OutputParser createErrorParser(final String outputDir) {
public OutputParser createErrorParser(@NotNull final String outputDir) {
return new OutputParser() {
public boolean processMessageLine(Callback callback) {
return myEclipseCompilerDriver.processMessageLine(callback, outputDir, myProject);
@@ -79,7 +79,7 @@ public class EclipseEmbeddedCompiler implements BackendCompiler {
}
@Nullable
public OutputParser createOutputParser(final String outputDir) {
public OutputParser createOutputParser(@NotNull final String outputDir) {
return null;
}
@@ -88,9 +88,9 @@ public class EclipseEmbeddedCompiler implements BackendCompiler {
@NotNull
public Process launchProcess(final ModuleChunk chunk, final String outputDir, final CompileContext compileContext) throws IOException {
public Process launchProcess(@NotNull final ModuleChunk chunk, @NotNull final String outputDir, @NotNull final CompileContext compileContext) throws IOException {
@NonNls final ArrayList<String> commandLine = new ArrayList<String>();
final IOException[] ex = new IOException[]{null};
final IOException[] ex = {null};
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
try {
@@ -141,8 +141,4 @@ public class EclipseEmbeddedCompiler implements BackendCompiler {
}
};
}
private void createCompileDriver() {
myEclipseCompilerDriver = new EclipseCompilerDriver();
}
}
@@ -16,12 +16,14 @@
package com.intellij.compiler.impl.javaCompiler.javac;
import com.intellij.compiler.OutputParser;
import com.intellij.compiler.impl.javaCompiler.FileObject;
import com.intellij.openapi.compiler.CompilerBundle;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.fileTypes.StdFileTypes;
import java.io.File;
import java.util.regex.Matcher;
/**
@@ -48,8 +50,7 @@ public class FilePathActionJavac extends JavacParserAction {
callback.setProgressText(CompilerBundle.message("progress.parsing.file", name));
}
else if (StdFileTypes.CLASS.equals(fileType)) {
callback.fileGenerated(filePath);
callback.fileGenerated(new FileObject(new File(filePath)));
}
}
}
@@ -21,6 +21,7 @@ import com.intellij.openapi.projectRoots.ex.JavaSdkUtil;
import com.intellij.openapi.projectRoots.impl.MockJdkWrapper;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.java.LanguageLevel;
@@ -112,61 +113,54 @@ public class JavacCompiler extends ExternalCompiler {
return new JavacConfigurable(JavacSettings.getInstance(myProject));
}
public OutputParser createErrorParser(final String outputDir) {
public OutputParser createErrorParser(@NotNull final String outputDir) {
return new JavacOutputParser(myProject);
}
public OutputParser createOutputParser(final String outputDir) {
public OutputParser createOutputParser(@NotNull final String outputDir) {
return null;
}
private static class MyException extends RuntimeException {
private MyException(Throwable cause) {
super(cause);
}
}
@NotNull
public String[] createStartupCommand(final ModuleChunk chunk, final CompileContext context, final String outputPath)
throws IOException, IllegalArgumentException {
final ArrayList<String> commandLine = new ArrayList<String>();
final Exception[] ex = new Exception[]{null};
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
try {
createStartupCommand(chunk, commandLine, outputPath);
try {
return ApplicationManager.getApplication().runReadAction(new Computable<String[]>() {
public String[] compute() {
try {
final List<String> commandLine = new ArrayList<String>();
createStartupCommand(chunk, commandLine, outputPath, JavacSettings.getInstance(myProject));
return ArrayUtil.toStringArray(commandLine);
}
catch (IOException e) {
throw new MyException(e);
}
}
catch (IllegalArgumentException e) {
ex[0] = e;
}
catch (IOException e) {
ex[0] = e;
}
}
});
if (ex[0] != null) {
if (ex[0] instanceof IOException) {
throw (IOException)ex[0];
}
else if (ex[0] instanceof IllegalArgumentException) {
throw (IllegalArgumentException)ex[0];
}
else {
LOG.error(ex[0]);
}
});
}
catch (MyException e) {
Throwable cause = e.getCause();
if (cause instanceof IOException) {
throw (IOException)cause;
}
throw e;
}
return ArrayUtil.toStringArray(commandLine);
}
private void createStartupCommand(final ModuleChunk chunk, @NonNls final List<String> commandLine, final String outputPath) throws IOException {
private void createStartupCommand(final ModuleChunk chunk, @NonNls final List<String> commandLine, final String outputPath,
JavacSettings javacSettings) throws IOException {
final Sdk jdk = getJdkForStartupCommand(chunk);
final String versionString = jdk.getVersionString();
if (versionString == null || "".equals(versionString) || !(jdk.getSdkType() instanceof JavaSdkType)) {
throw new IllegalArgumentException(CompilerBundle.message("javac.error.unknown.jdk.version", jdk.getName()));
}
final JavaSdkType sdkType = (JavaSdkType)jdk.getSdkType();
final String toolsJarPath = sdkType.getToolsPath(jdk);
if (toolsJarPath == null) {
throw new IllegalArgumentException(CompilerBundle.message("javac.error.tools.jar.missing", jdk.getName()));
}
final boolean isVersion1_0 = CompilerUtil.isOfVersion(versionString, "1.0");
final boolean isVersion1_1 = CompilerUtil.isOfVersion(versionString, "1.1");
final boolean isVersion1_2 = CompilerUtil.isOfVersion(versionString, "1.2");
@@ -175,11 +169,18 @@ public class JavacCompiler extends ExternalCompiler {
final boolean isVersion1_5 = CompilerUtil.isOfVersion(versionString, "1.5") || CompilerUtil.isOfVersion(versionString, "5.0");
final boolean isVersion1_5_or_higher = isVersion1_5 || !(isVersion1_0 || isVersion1_1 || isVersion1_2 || isVersion1_3 || isVersion1_4);
final JavacSettings javacSettings = JavacSettings.getInstance(myProject);
JavaSdkType sdkType = (JavaSdkType)jdk.getSdkType();
final String toolsJarPath = sdkType.getToolsPath(jdk);
if (toolsJarPath == null) {
throw new IllegalArgumentException(CompilerBundle.message("javac.error.tools.jar.missing", jdk.getName()));
}
final String vmExePath = sdkType.getVMExecutablePath(jdk);
commandLine.add(vmExePath);
if (isVersion1_1 || isVersion1_0) {
commandLine.add("-mx" + javacSettings.MAXIMUM_HEAP_SIZE + "m");
}
@@ -187,27 +188,8 @@ public class JavacCompiler extends ExternalCompiler {
commandLine.add("-Xmx" + javacSettings.MAXIMUM_HEAP_SIZE + "m");
}
final List<String> additionalOptions = new ArrayList<String>();
StringTokenizer tokenizer = new StringTokenizer(javacSettings.getOptionsString(), " ");
while (tokenizer.hasMoreTokens()) {
@NonNls String token = tokenizer.nextToken();
if (isVersion1_0) {
if ("-deprecation".equals(token)) {
continue; // not supported for this version
}
}
if (isVersion1_0 || isVersion1_1 || isVersion1_2 || isVersion1_3 || isVersion1_4) {
if ("-Xlint".equals(token)) {
continue; // not supported in these versions
}
}
if (token.startsWith("-J-")) {
commandLine.add(token.substring("-J".length()));
}
else {
additionalOptions.add(token);
}
}
final List<String> additionalOptions =
addAdditionalSettings(commandLine, javacSettings, isVersion1_0, isVersion1_1, isVersion1_2, isVersion1_3, isVersion1_4);
CompilerUtil.addLocaleOptions(commandLine, false);
@@ -229,40 +211,9 @@ public class JavacCompiler extends ExternalCompiler {
commandLine.add(JAVAC_MAIN_CLASS);
}
LanguageLevel languageLevel = chunk.getLanguageLevel();
CompilerUtil.addSourceCommandLineSwitch(jdk, languageLevel, commandLine);
addCommandLineOptions(chunk, commandLine, outputPath, jdk, isVersion1_0, isVersion1_1, myTempFiles, true, true);
commandLine.add("-verbose");
final String cp = chunk.getCompilationClasspath();
final String bootCp = chunk.getCompilationBootClasspath();
final String classPath;
if (isVersion1_0 || isVersion1_1) {
classPath = bootCp + File.pathSeparator + cp;
}
else {
classPath = cp;
commandLine.add("-bootclasspath");
addClassPathValue(jdk, false, commandLine, bootCp, "javac_bootcp");
}
commandLine.add("-classpath");
addClassPathValue(jdk, isVersion1_0, commandLine, classPath, "javac_cp");
if (!isVersion1_1 && !isVersion1_0) {
commandLine.add("-sourcepath");
// this way we tell the compiler that the sourcepath is "empty". However, javac thinks that sourcepath is 'new File("")'
// this may cause problems if we have java code in IDEA working directory
commandLine.add("\"\"");
}
commandLine.add("-d");
commandLine.add(outputPath.replace('/', File.separatorChar));
for (String option : additionalOptions) {
commandLine.add(option);
}
commandLine.addAll(additionalOptions);
final VirtualFile[] files = chunk.getFilesToCompile();
@@ -298,11 +249,80 @@ public class JavacCompiler extends ExternalCompiler {
}
}
private void addClassPathValue(final Sdk jdk,
final boolean isVersion1_0,
final List<String> commandLine,
final String cpString,
@NonNls final String tempFileName) throws IOException {
public static List<String> addAdditionalSettings(List<String> commandLine, JavacSettings javacSettings,
boolean version1_0,
boolean version1_1,
boolean version1_2,
boolean version1_3,
boolean version1_4) {
final List<String> additionalOptions = new ArrayList<String>();
StringTokenizer tokenizer = new StringTokenizer(javacSettings.getOptionsString(), " ");
while (tokenizer.hasMoreTokens()) {
@NonNls String token = tokenizer.nextToken();
if (version1_0) {
if ("-deprecation".equals(token)) {
continue; // not supported for this version
}
}
if (version1_0 || version1_1 || version1_2 || version1_3 || version1_4) {
if ("-Xlint".equals(token)) {
continue; // not supported in these versions
}
}
if (token.startsWith("-J-")) {
commandLine.add(token.substring("-J".length()));
}
else {
additionalOptions.add(token);
}
}
return additionalOptions;
}
public static void addCommandLineOptions(ModuleChunk chunk, @NonNls List<String> commandLine, String outputPath, Sdk jdk,
boolean version1_0,
boolean version1_1,
List<File> tempFiles, boolean addSourcePath, boolean useTempFile) throws IOException {
LanguageLevel languageLevel = chunk.getLanguageLevel();
CompilerUtil.addSourceCommandLineSwitch(jdk, languageLevel, commandLine);
commandLine.add("-verbose");
final String cp = chunk.getCompilationClasspath();
final String bootCp = chunk.getCompilationBootClasspath();
final String classPath;
if (version1_0 || version1_1) {
classPath = bootCp + File.pathSeparator + cp;
}
else {
classPath = cp;
commandLine.add("-bootclasspath");
addClassPathValue(jdk, false, commandLine, bootCp, "javac_bootcp", tempFiles, useTempFile);
}
commandLine.add("-classpath");
addClassPathValue(jdk, version1_0, commandLine, classPath, "javac_cp", tempFiles, useTempFile);
if (!version1_1 && !version1_0 && addSourcePath) {
commandLine.add("-sourcepath");
// this way we tell the compiler that the sourcepath is "empty". However, javac thinks that sourcepath is 'new File("")'
// this may cause problems if we have java code in IDEA working directory
commandLine.add("\"\"");
}
commandLine.add("-d");
commandLine.add(outputPath.replace('/', File.separatorChar));
}
private static void addClassPathValue(final Sdk jdk, final boolean isVersion1_0, final List<String> commandLine, final String cpString, @NonNls final String tempFileName,
List<File> tempFiles,
boolean useTempFile) throws IOException {
if (!useTempFile) {
commandLine.add(cpString);
return;
}
// must include output path to classpath, otherwise javac will compile all dependent files no matter were they compiled before or not
if (isVersion1_0) {
commandLine.add(((JavaSdkType)jdk.getSdkType()).getToolsPath(jdk) + File.pathSeparator + cpString);
@@ -310,7 +330,7 @@ public class JavacCompiler extends ExternalCompiler {
else {
File cpFile = FileUtil.createTempFile(tempFileName, ".tmp");
cpFile.deleteOnExit();
myTempFiles.add(cpFile);
tempFiles.add(cpFile);
final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(cpFile)));
try {
CompilerIOUtil.writeString(cpString, out);
@@ -337,5 +357,6 @@ public class JavacCompiler extends ExternalCompiler {
public void compileFinished() {
FileUtil.asyncDelete(myTempFiles);
myTempFiles.clear();
}
}
@@ -99,12 +99,12 @@ public class JikesCompiler extends ExternalCompiler {
return new JikesConfigurable(JikesSettings.getInstance(myProject));
}
public OutputParser createErrorParser(final String outputDir) {
public OutputParser createErrorParser(@NotNull final String outputDir) {
return new JikesOutputParser(myProject);
}
@Nullable
public OutputParser createOutputParser(final String outputDir) {
public OutputParser createOutputParser(@NotNull final String outputDir) {
return null;
}
@@ -22,6 +22,7 @@ import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.compiler.ParserAction;
import com.intellij.compiler.OutputParser;
import com.intellij.compiler.impl.javaCompiler.FileObject;
import org.jetbrains.annotations.NonNls;
import java.io.File;
@@ -81,7 +82,7 @@ public class ParserActionJikes extends ParserAction {
callback.setProgressText(CompilerBundle.message("progress.parsing.file", name));
}
else if (StdFileTypes.CLASS.equals(fileType)) {
callback.fileGenerated(filePath);
callback.fileGenerated(new FileObject(new File(filePath)));
}
}
}
@@ -57,7 +57,7 @@ public class ResourceCompiler implements TranslatingCompiler {
return !StdFileTypes.JAVA.equals(FILE_TYPE_MANAGER.getFileTypeByFile(file)) && myConfiguration.isResourceFile(file.getName());
}
public TranslatingCompiler.ExitStatus compile(final CompileContext context, final VirtualFile[] files) {
public ExitStatus compile(final CompileContext context, final VirtualFile[] files) {
context.getProgressIndicator().pushState();
context.getProgressIndicator().setText(CompilerBundle.message("progress.copying.resources"));
@@ -116,6 +116,7 @@ public class ResourceCompiler implements TranslatingCompiler {
break;
}
context.getProgressIndicator().setFraction(i * 1.0 / copyCommands.size());
context.getProgressIndicator().setText2("Copying "+command.getToPath()+"...");
try {
final MyOutputItem outputItem = command.copy(filesToRefresh);
processed.add(outputItem);
@@ -128,7 +129,7 @@ public class ResourceCompiler implements TranslatingCompiler {
);
}
}
if (filesToRefresh.size() > 0) {
if (!filesToRefresh.isEmpty()) {
CompilerUtil.refreshIOFiles(filesToRefresh);
}
@@ -145,7 +146,7 @@ public class ResourceCompiler implements TranslatingCompiler {
private final String myToPath;
private final VirtualFile mySourceFile;
public CopyCommand(String outputPath, String fromPath, String toPath, VirtualFile sourceFile) {
private CopyCommand(String outputPath, String fromPath, String toPath, VirtualFile sourceFile) {
myOutputPath = outputPath;
myFromPath = fromPath;
myToPath = toPath;
@@ -181,7 +182,7 @@ public class ResourceCompiler implements TranslatingCompiler {
private final String myTargetPath;
private final VirtualFile myFile;
public MyOutputItem(String outputPath, String targetPath, VirtualFile file) {
private MyOutputItem(String outputPath, String targetPath, VirtualFile file) {
myOutputPath = outputPath;
myTargetPath = targetPath;
myFile = file;
@@ -202,7 +203,7 @@ public class ResourceCompiler implements TranslatingCompiler {
private static class MyExitStatus implements ExitStatus {
private final OutputItem[] myItemsArray;
public MyExitStatus(OutputItem[] itemsArray) {
private MyExitStatus(OutputItem[] itemsArray) {
myItemsArray = itemsArray;
}
@@ -5,6 +5,7 @@ import com.intellij.compiler.RmicSettings;
import com.intellij.compiler.impl.CompilerUtil;
import com.intellij.compiler.impl.javaCompiler.CompilerParsingThread;
import com.intellij.compiler.impl.javaCompiler.CompilerParsingThreadImpl;
import com.intellij.compiler.impl.javaCompiler.FileObject;
import com.intellij.compiler.make.Cache;
import com.intellij.compiler.make.CacheCorruptedException;
import com.intellij.compiler.make.DependencyCache;
@@ -230,8 +231,9 @@ public class RmicCompiler implements ClassPostProcessingCompiler{
final Process process = Runtime.getRuntime().exec(cmdLine);
final Set<RmicProcessingItem> successfullyCompiledItems = new HashSet<RmicProcessingItem>();
final CompilerParsingThread parsingThread = new CompilerParsingThreadImpl(process, context, outputParser, false, true) {
protected void processCompiledClass(String classFileToProcess) {
final RmicProcessingItem item = pathToItemMap.get(classFileToProcess.replace(File.separatorChar, '/'));
protected void processCompiledClass(FileObject classFileToProcess) {
String key = classFileToProcess.getFile().getPath().replace(File.separatorChar, '/');
final RmicProcessingItem item = pathToItemMap.get(key);
if (item != null) {
successfullyCompiledItems.add(item);
}
@@ -251,9 +253,9 @@ public class RmicCompiler implements ClassPostProcessingCompiler{
try {
parsingThreadFuture.get();
}
catch (InterruptedException e) {
catch (InterruptedException ignored) {
}
catch (ExecutionException e) {
catch (ExecutionException ignored) {
}
return successfullyCompiledItems.toArray(new RmicProcessingItem[successfullyCompiledItems.size()]);
}
@@ -407,7 +409,7 @@ public class RmicCompiler implements ClassPostProcessingCompiler{
private final long mySkelTimestamp;
private final long myTieTimestamp;
public RemoteClassValidityState(long remoteClassTimestamp, long stubTimestamp, long skelTimestamp, long tieTimestamp) {
private RemoteClassValidityState(long remoteClassTimestamp, long stubTimestamp, long skelTimestamp, long tieTimestamp) {
myRemoteClassTimestamp = remoteClassTimestamp;
myStubTimestamp = stubTimestamp;
mySkelTimestamp = skelTimestamp;
@@ -443,7 +445,7 @@ public class RmicCompiler implements ClassPostProcessingCompiler{
private final File myTie;
private boolean myIsRemoteObject = false;
public RmicProcessingItem(Module module, final VirtualFile outputClassFile, File outputDir, String qName) {
private RmicProcessingItem(Module module, final VirtualFile outputClassFile, File outputDir, String qName) {
myModule = module;
myOutputClassFile = outputClassFile;
myOutputDir = outputDir;
Binary file not shown.
@@ -2,6 +2,7 @@ package com.intellij.lang.ant.config.execution;
import com.intellij.compiler.impl.javaCompiler.javac.JavacOutputParser;
import com.intellij.compiler.impl.javaCompiler.jikes.JikesOutputParser;
import com.intellij.compiler.impl.javaCompiler.FileObject;
import com.intellij.execution.process.OSProcessHandler;
import com.intellij.lang.ant.AntBundle;
import com.intellij.openapi.application.ApplicationManager;
@@ -263,7 +264,7 @@ public class OutputParser{
public void fileProcessed(String path) {
}
public void fileGenerated(String path) {
public void fileGenerated(FileObject path) {
}
};
try {
@@ -140,7 +140,7 @@ eclipse.options.group.title=Eclipse Options
eclipse.compiler.parsing=Parsing {0}
eclipse.compiler.reading=Reading classes
eclipse.compiler.analyzing=Analyzing {0}
compiler.eclipse.embedded.name=Eclipse embedded (faster, but requires more/leaks memory)
compiler.eclipse.embedded.name=Eclipse in-process
generate.ant.build.title=Generate Ant Build
generate.ant.build.progress.message=Generating ant build...
@@ -153,7 +153,7 @@ public final class Form2ByteCodeCompiler implements ClassInstrumentingCompiler {
}
});
return items.toArray(new FileProcessingCompiler.ProcessingItem[items.size()]);
return items.toArray(new ProcessingItem[items.size()]);
}
private static boolean belongsToCompileScope(final CompileContext context, final VirtualFile formFile, final String classToBind) {
@@ -184,7 +184,7 @@ public final class Form2ByteCodeCompiler implements ClassInstrumentingCompiler {
return module2formFiles;
}
private HashMap<Module, ArrayList<MyInstrumentationItem>> sortByModules(final FileProcessingCompiler.ProcessingItem[] items) {
private HashMap<Module, ArrayList<MyInstrumentationItem>> sortByModules(final ProcessingItem[] items) {
final HashMap<Module, ArrayList<MyInstrumentationItem>> module2formFiles = new HashMap<Module,ArrayList<MyInstrumentationItem>>();
for (ProcessingItem item1 : items) {
final MyInstrumentationItem item = (MyInstrumentationItem)item1;
@@ -282,7 +282,7 @@ public final class Form2ByteCodeCompiler implements ClassInstrumentingCompiler {
final ArrayList<MyInstrumentationItem> list = module2itemsList.get(module);
for (final MyInstrumentationItem item : list) {
context.getProgressIndicator().setFraction((double)(++formsProcessed) / ((double)items.length));
context.getProgressIndicator().setFraction((double)++formsProcessed / (double)items.length);
final VirtualFile formFile = item.getFormFile();