2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package org.jetbrains.plugins.groovy.compiler.generator;
19 import com.intellij.compiler.impl.CompilerUtil;
20 import com.intellij.compiler.impl.FileSetCompileScope;
21 import com.intellij.compiler.impl.TranslatingCompilerFilesMonitor;
22 import com.intellij.openapi.application.AccessToken;
23 import com.intellij.openapi.application.ApplicationManager;
24 import com.intellij.openapi.application.ModalityState;
25 import com.intellij.openapi.application.WriteAction;
26 import com.intellij.openapi.compiler.CompileContext;
27 import com.intellij.openapi.compiler.CompileScope;
28 import com.intellij.openapi.compiler.CompilerPaths;
29 import com.intellij.openapi.compiler.ex.CompileContextEx;
30 import com.intellij.openapi.compiler.options.ExcludedEntriesConfiguration;
31 import com.intellij.openapi.diagnostic.Logger;
32 import com.intellij.openapi.fileTypes.FileType;
33 import com.intellij.openapi.fileTypes.StdFileTypes;
34 import com.intellij.openapi.module.Module;
35 import com.intellij.openapi.module.ModuleManager;
36 import com.intellij.openapi.progress.ProgressIndicator;
37 import com.intellij.openapi.project.Project;
38 import com.intellij.openapi.util.io.FileUtil;
39 import com.intellij.openapi.util.text.StringUtil;
40 import com.intellij.openapi.vfs.LocalFileSystem;
41 import com.intellij.openapi.vfs.VfsUtil;
42 import com.intellij.openapi.vfs.VirtualFile;
43 import com.intellij.psi.JavaPsiFacade;
44 import com.intellij.psi.PsiClass;
45 import com.intellij.psi.PsiManager;
46 import com.intellij.psi.search.GlobalSearchScope;
47 import com.intellij.util.Chunk;
48 import com.intellij.util.Processor;
49 import com.intellij.util.containers.CollectionFactory;
50 import com.intellij.util.containers.ContainerUtil;
51 import org.jetbrains.annotations.NotNull;
52 import org.jetbrains.annotations.Nullable;
53 import org.jetbrains.plugins.groovy.GroovyFileType;
54 import org.jetbrains.plugins.groovy.compiler.GroovyCompilerBase;
55 import org.jetbrains.plugins.groovy.compiler.GroovyCompilerConfiguration;
56 import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
57 import org.jetbrains.plugins.groovy.refactoring.GroovyNamesUtil;
58 import org.jetbrains.plugins.groovy.refactoring.convertToJava.GroovyToJavaGenerator;
61 import java.io.IOException;
67 public class GroovycStubGenerator extends GroovyCompilerBase {
68 private static Logger LOG = Logger.getInstance("#org.jetbrains.plugins.groovy.compiler.generator.GroovycStubGenerator");
70 public static final String GROOVY_STUBS = "groovyStubs";
72 public GroovycStubGenerator(Project project) {
77 public void compile(CompileContext compileContext, Chunk<Module> moduleChunk, VirtualFile[] virtualFiles, OutputSink sink) {
78 boolean hasJava = false;
80 final ExcludedEntriesConfiguration excluded = GroovyCompilerConfiguration.getExcludeConfiguration(myProject);
82 List<VirtualFile> total = new ArrayList<VirtualFile>();
83 for (final VirtualFile virtualFile : virtualFiles) {
84 final FileType fileType = virtualFile.getFileType();
85 if (fileType == StdFileTypes.JAVA) {
89 if (!excluded.isExcluded(virtualFile)) {
90 if (fileType == GroovyFileType.GROOVY_FILE_TYPE && GroovyNamesUtil.isIdentifier(virtualFile.getNameWithoutExtension())) {
91 total.add(virtualFile);
100 if (total.isEmpty()) {
104 //long l = System.currentTimeMillis();
105 super.compile(compileContext, moduleChunk, VfsUtil.toVirtualFileArray(total), sink);
106 //System.out.println("Stub generation took " + (System.currentTimeMillis() - l));
110 public boolean isCompilableFile(VirtualFile file, CompileContext context) {
111 return super.isCompilableFile(file, context) || StdFileTypes.JAVA.equals(file.getFileType());
115 protected void compileFiles(CompileContext compileContext,
117 final List<VirtualFile> toCompile,
120 final File outDir = getStubOutput(module, tests);
123 final VirtualFile tempOutput = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(outDir);
124 assert tempOutput != null;
125 cleanDirectory(tempOutput);
127 ((CompileContextEx)compileContext).assignModule(tempOutput, module, tests, this);
129 ProgressIndicator indicator = compileContext.getProgressIndicator();
130 indicator.pushState();
133 final GroovyToJavaGenerator generator = new GroovyToJavaGenerator(myProject, new HashSet<VirtualFile>(toCompile));
134 for (int i = 0; i < toCompile.size(); i++) {
135 indicator.setFraction((double)i / toCompile.size());
137 final Collection<VirtualFile> stubFiles = generateItems(generator, toCompile.get(i), tempOutput, compileContext, myProject);
138 ((CompileContextEx)compileContext).addScope(new FileSetCompileScope(stubFiles, new Module[]{module}));
142 indicator.popState();
146 private static File getStubOutput(Module module, boolean tests) {
147 final Project project = module.getProject();
148 final String rootPath = CompilerPaths.getGeneratedDataDirectory(project).getPath() + "/" + GROOVY_STUBS + "/";
149 return new File(rootPath + project.getLocationHash() + "/" + module.getName() + "/" + (tests ? "tests" : "production") + "/");
153 public static PsiClass findClassByStub(Project project, VirtualFile stubFile) {
154 final String[] components = StringUtil.trimEnd(stubFile.getPath(), ".java").split("[\\\\/]");
155 final int stubs = Arrays.asList(components).indexOf(GROOVY_STUBS);
156 if (stubs < 0 || stubs >= components.length - 4) return null;
158 final String moduleName = components[stubs + 2];
159 final Module module = ModuleManager.getInstance(project).findModuleByName(moduleName);
160 if (module == null) return null;
162 final String fqn = StringUtil.join(Arrays.asList(components).subList(stubs + 4, components.length), ".");
163 return JavaPsiFacade.getInstance(project).findClass(fqn, GlobalSearchScope.moduleScope(module));
166 private void cleanDirectory(final VirtualFile dir) {
167 Runnable runnable = new Runnable() {
170 AccessToken token = WriteAction.start();
172 VfsUtil.processFilesRecursively(dir, new Processor<VirtualFile>() {
174 public boolean process(VirtualFile virtualFile) {
175 if (!virtualFile.isDirectory()) {
176 TranslatingCompilerFilesMonitor.removeSourceInfo(virtualFile);
178 virtualFile.delete(this);
180 catch (IOException e) {
193 if (ApplicationManager.getApplication().isDispatchThread()) {
194 assert ApplicationManager.getApplication().isUnitTestMode();
197 ApplicationManager.getApplication().invokeAndWait(runnable, ModalityState.NON_MODAL);
202 public String getDescription() {
203 return "Groovy to java source code generator";
206 public boolean validateConfiguration(CompileScope scope) {
210 public static Collection<VirtualFile> generateItems(final GroovyToJavaGenerator generator,
211 final VirtualFile item,
212 final VirtualFile outputRootDirectory,
213 CompileContext context,
214 final Project project) {
215 ProgressIndicator indicator = context.getProgressIndicator();
216 indicator.setText("Generating stubs for " + item.getName() + "...");
218 if (LOG.isDebugEnabled()) {
219 LOG.debug("Generating stubs for " + item.getName() + "...");
222 final Map<String, CharSequence> output;
224 AccessToken accessToken = ApplicationManager.getApplication().acquireReadActionLock();
227 output = generator.generateStubs((GroovyFile)PsiManager.getInstance(project).findFile(item));
230 accessToken.finish();
233 return writeStubs(outputRootDirectory, output, item);
236 private static List<VirtualFile> writeStubs(VirtualFile outputRootDirectory, Map<String, CharSequence> output, VirtualFile src) {
237 final ArrayList<VirtualFile> stubs = CollectionFactory.arrayList();
238 for (String relativePath : output.keySet()) {
239 final File stubFile = new File(outputRootDirectory.getPath(), relativePath);
240 FileUtil.createIfDoesntExist(stubFile);
242 FileUtil.writeToFile(stubFile, output.get(relativePath).toString().getBytes(src.getCharset()));
244 catch (IOException e) {
247 CompilerUtil.refreshIOFile(stubFile);
248 ContainerUtil.addIfNotNull(LocalFileSystem.getInstance().refreshAndFindFileByIoFile(stubFile), stubs);