/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* created at Jan 3, 2002
* @author Jeka
*/
package com.intellij.compiler.impl;
import com.intellij.CommonBundle;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.compiler.CompileContext;
import com.intellij.openapi.compiler.CompilerBundle;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.RefreshQueue;
import com.intellij.util.ThrowableRunnable;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
import consulo.roots.ContentFolderScopes;
import java.io.File;
import java.io.FileFilter;
import java.util.*;
public class CompilerUtil {
private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.impl.CompilerUtil");
public static String quotePath(String path) {
if(path != null && path.indexOf(' ') != -1) {
path = path.replaceAll("\\\\", "\\\\\\\\");
path = '"' + path + '"';
}
return path;
}
public static void collectFiles(Collection<File> container, File rootDir, FileFilter fileFilter) {
final File[] files = rootDir.listFiles(fileFilter);
if (files == null) {
return;
}
for (File file : files) {
if (file.isDirectory()) {
collectFiles(container, file, fileFilter);
}
else {
container.add(file);
}
}
}
public static Map<Module, List<VirtualFile>> buildModuleToFilesMap(CompileContext context, VirtualFile[] files) {
return buildModuleToFilesMap(context, Arrays.asList(files));
}
public static Map<Module, List<VirtualFile>> buildModuleToFilesMap(final CompileContext context, final List<VirtualFile> files) {
//assertion: all files are different
final Map<Module, List<VirtualFile>> map = new THashMap<Module, List<VirtualFile>>();
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
for (VirtualFile file : files) {
final Module module = context.getModuleByFile(file);
if (module == null) {
continue; // looks like file invalidated
}
List<VirtualFile> moduleFiles = map.get(module);
if (moduleFiles == null) {
moduleFiles = new ArrayList<VirtualFile>();
map.put(module, moduleFiles);
}
moduleFiles.add(file);
}
}
});
return map;
}
/**
* must not be called inside ReadAction
* @param files
*/
public static void refreshIOFiles(@NotNull final Collection<File> files) {
if (!files.isEmpty()) {
LocalFileSystem.getInstance().refreshIoFiles(files);
}
}
public static void refreshIODirectories(@NotNull final Collection<File> files) {
final LocalFileSystem lfs = LocalFileSystem.getInstance();
final List<VirtualFile> filesToRefresh = new ArrayList<VirtualFile>();
for (File file : files) {
final VirtualFile virtualFile = lfs.refreshAndFindFileByIoFile(file);
if (virtualFile != null) {
filesToRefresh.add(virtualFile);
}
}
if (!filesToRefresh.isEmpty()) {
RefreshQueue.getInstance().refresh(false, true, null, filesToRefresh);
}
}
public static void refreshIOFile(final File file) {
final VirtualFile vFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file);
if (vFile != null) {
vFile.refresh(false, false);
}
}
public static void addLocaleOptions(final List<String> commandLine, final boolean launcherUsed) {
// need to specify default encoding so that javac outputs messages in 'correct' language
//noinspection HardCodedStringLiteral
commandLine.add((launcherUsed? "-J" : "") + "-D" + CharsetToolkit.FILE_ENCODING_PROPERTY + "=" + CharsetToolkit.getDefaultSystemCharset().name());
// javac's VM should use the same default locale that IDEA uses in order for javac to print messages in 'correct' language
//noinspection HardCodedStringLiteral
final String lang = System.getProperty("user.language");
if (lang != null) {
//noinspection HardCodedStringLiteral
commandLine.add((launcherUsed? "-J" : "") + "-Duser.language=" + lang);
}
//noinspection HardCodedStringLiteral
final String country = System.getProperty("user.country");
if (country != null) {
//noinspection HardCodedStringLiteral
commandLine.add((launcherUsed? "-J" : "") + "-Duser.country=" + country);
}
//noinspection HardCodedStringLiteral
final String region = System.getProperty("user.region");
if (region != null) {
//noinspection HardCodedStringLiteral
commandLine.add((launcherUsed? "-J" : "") + "-Duser.region=" + region);
}
}
public static boolean isOfVersion(String versionString, String checkedVersion) {
return versionString.contains(checkedVersion);
}
public static <T extends Throwable> void runInContext(CompileContext context, String title, ThrowableRunnable<T> action) throws T {
if (title != null) {
context.getProgressIndicator().pushState();
context.getProgressIndicator().setText(title);
}
try {
action.run();
}
finally {
if (title != null) {
context.getProgressIndicator().popState();
}
}
}
public static void logDuration(final String activityName, long duration) {
LOG.info(activityName + " took " + duration + " ms: " + duration /60000 + " min " +(duration %60000)/1000 + "sec");
}
public static void clearOutputDirectories(final Collection<File> outputDirectories) {
final long start = System.currentTimeMillis();
// do not delete directories themselves, or we'll get rootsChanged() otherwise
final Collection<File> filesToDelete = new ArrayList<File>(outputDirectories.size() * 2);
for (File outputDirectory : outputDirectories) {
File[] files = outputDirectory.listFiles();
if (files != null) {
ContainerUtil.addAll(filesToDelete, files);
}
}
if (filesToDelete.size() > 0) {
FileUtil.asyncDelete(filesToDelete);
// ensure output directories exist
for (final File file : outputDirectories) {
file.mkdirs();
}
final long clearStop = System.currentTimeMillis();
refreshIODirectories(outputDirectories);
final long refreshStop = System.currentTimeMillis();
logDuration("Clearing output dirs", clearStop - start);
logDuration("Refreshing output directories", refreshStop - clearStop);
}
}
public static void computeIntersectingPaths(final Project project,
final Collection<VirtualFile> outputPaths,
final Collection<VirtualFile> result) {
for (Module module : ModuleManager.getInstance(project).getModules()) {
final ModuleRootManager rootManager = ModuleRootManager.getInstance(module);
final VirtualFile[] sourceRoots = rootManager.getContentFolderFiles(ContentFolderScopes.productionAndTest());
for (final VirtualFile outputPath : outputPaths) {
for (VirtualFile sourceRoot : sourceRoots) {
if (VfsUtilCore.isAncestor(outputPath, sourceRoot, true) || VfsUtilCore.isAncestor(sourceRoot, outputPath, false)) {
result.add(outputPath);
}
}
}
}
}
public static boolean askUserToContinueWithNoClearing(Project project, Collection<VirtualFile> affectedOutputPaths) {
final StringBuilder paths = new StringBuilder();
for (final VirtualFile affectedOutputPath : affectedOutputPaths) {
if (paths.length() > 0) {
paths.append(",\n");
}
paths.append(affectedOutputPath.getPath().replace('/', File.separatorChar));
}
final int answer = Messages.showOkCancelDialog(project,
CompilerBundle.message("warning.sources.under.output.paths", paths.toString()),
CommonBundle.getErrorTitle(), Messages.getWarningIcon());
if (answer == Messages.OK) { // ok
return true;
}
else {
return false;
}
}
}