001 /*
002 * Copyright 2010-2013 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.jet.cli.jvm.compiler;
018
019 import com.intellij.codeInsight.ExternalAnnotationsManager;
020 import com.intellij.core.CoreApplicationEnvironment;
021 import com.intellij.core.CoreJavaFileManager;
022 import com.intellij.core.JavaCoreApplicationEnvironment;
023 import com.intellij.core.JavaCoreProjectEnvironment;
024 import com.intellij.lang.java.JavaParserDefinition;
025 import com.intellij.mock.MockApplication;
026 import com.intellij.mock.MockProject;
027 import com.intellij.openapi.Disposable;
028 import com.intellij.openapi.components.ServiceManager;
029 import com.intellij.openapi.extensions.Extensions;
030 import com.intellij.openapi.fileTypes.PlainTextFileType;
031 import com.intellij.openapi.project.Project;
032 import com.intellij.openapi.vfs.VirtualFile;
033 import com.intellij.psi.PsiElementFinder;
034 import com.intellij.psi.PsiFile;
035 import com.intellij.psi.PsiManager;
036 import com.intellij.psi.impl.compiled.ClsCustomNavigationPolicy;
037 import com.intellij.psi.impl.file.impl.JavaFileManager;
038 import org.jetbrains.annotations.NotNull;
039 import org.jetbrains.jet.CompilerModeProvider;
040 import org.jetbrains.jet.OperationModeProvider;
041 import org.jetbrains.jet.asJava.JavaElementFinder;
042 import org.jetbrains.jet.asJava.LightClassGenerationSupport;
043 import org.jetbrains.jet.cli.common.CLIConfigurationKeys;
044 import org.jetbrains.jet.cli.common.messages.CompilerMessageLocation;
045 import org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity;
046 import org.jetbrains.jet.cli.common.messages.MessageCollector;
047 import org.jetbrains.jet.cli.jvm.JVMConfigurationKeys;
048 import org.jetbrains.jet.config.CommonConfigurationKeys;
049 import org.jetbrains.jet.config.CompilerConfiguration;
050 import org.jetbrains.jet.lang.parsing.JetParserDefinition;
051 import org.jetbrains.jet.lang.parsing.JetScriptDefinitionProvider;
052 import org.jetbrains.jet.lang.psi.JetFile;
053 import org.jetbrains.jet.lang.resolve.java.JetFilesProvider;
054 import org.jetbrains.jet.lang.resolve.java.vfilefinder.VirtualFileFinder;
055 import org.jetbrains.jet.plugin.JetFileType;
056 import org.jetbrains.jet.utils.PathUtil;
057
058 import java.io.File;
059 import java.util.ArrayList;
060 import java.util.List;
061
062 import static org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity.ERROR;
063 import static org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity.WARNING;
064
065 public class JetCoreEnvironment {
066
067 private final JavaCoreApplicationEnvironment applicationEnvironment;
068 private final JavaCoreProjectEnvironment projectEnvironment;
069 private final List<JetFile> sourceFiles = new ArrayList<JetFile>();
070 private final ClassPath classPath = new ClassPath();
071
072 private final CoreExternalAnnotationsManager annotationsManager;
073
074 private final CompilerConfiguration configuration;
075
076 public JetCoreEnvironment(Disposable parentDisposable, @NotNull CompilerConfiguration configuration) {
077 this.configuration = configuration.copy();
078 this.configuration.setReadOnly(true);
079
080 this.applicationEnvironment = new JavaCoreApplicationEnvironment(parentDisposable);
081
082 // ability to get text from annotations xml files
083 applicationEnvironment.registerFileType(PlainTextFileType.INSTANCE, "xml");
084
085 applicationEnvironment.registerFileType(JetFileType.INSTANCE, "kt");
086 applicationEnvironment.registerFileType(JetFileType.INSTANCE, "kts");
087 applicationEnvironment.registerFileType(JetFileType.INSTANCE, "ktm");
088 applicationEnvironment.registerFileType(JetFileType.INSTANCE, JetParserDefinition.KTSCRIPT_FILE_SUFFIX); // should be renamed to kts
089 applicationEnvironment.registerFileType(JetFileType.INSTANCE, "jet");
090 applicationEnvironment.registerParserDefinition(new JavaParserDefinition());
091 applicationEnvironment.registerParserDefinition(new JetParserDefinition());
092
093 applicationEnvironment.getApplication().registerService(OperationModeProvider.class, new CompilerModeProvider());
094
095 projectEnvironment = new JavaCoreProjectEnvironment(parentDisposable, applicationEnvironment);
096
097 MockProject project = projectEnvironment.getProject();
098 project.registerService(JetScriptDefinitionProvider.class, new JetScriptDefinitionProvider());
099 project.registerService(JetFilesProvider.class, new CliJetFilesProvider(this));
100 project.registerService(CoreJavaFileManager.class, (CoreJavaFileManager) ServiceManager.getService(project, JavaFileManager.class));
101
102 CliLightClassGenerationSupport cliLightClassGenerationSupport = new CliLightClassGenerationSupport();
103 project.registerService(LightClassGenerationSupport.class, cliLightClassGenerationSupport);
104 project.registerService(CliLightClassGenerationSupport.class, cliLightClassGenerationSupport);
105
106 Extensions.getArea(project)
107 .getExtensionPoint(PsiElementFinder.EP_NAME)
108 .registerExtension(new JavaElementFinder(project, cliLightClassGenerationSupport));
109
110 // This extension point should be registered in JavaCoreApplicationEnvironment
111 CoreApplicationEnvironment.registerExtensionPoint(Extensions.getRootArea(), ClsCustomNavigationPolicy.EP_NAME,
112 ClsCustomNavigationPolicy.class);
113
114 annotationsManager = new CoreExternalAnnotationsManager(project.getComponent(PsiManager.class));
115 project.registerService(ExternalAnnotationsManager.class, annotationsManager);
116
117 for (File path : configuration.getList(JVMConfigurationKeys.CLASSPATH_KEY)) {
118 addToClasspath(path);
119 }
120 for (File path : configuration.getList(JVMConfigurationKeys.ANNOTATIONS_PATH_KEY)) {
121 addExternalAnnotationsRoot(path);
122 }
123 for (String path : configuration.getList(CommonConfigurationKeys.SOURCE_ROOTS_KEY)) {
124 addSources(path);
125 }
126
127 JetScriptDefinitionProvider.getInstance(project).addScriptDefinitions(
128 configuration.getList(CommonConfigurationKeys.SCRIPT_DEFINITIONS_KEY));
129
130 project.registerService(VirtualFileFinder.class, new CliVirtualFileFinder(classPath));
131 }
132
133 public CompilerConfiguration getConfiguration() {
134 return configuration;
135 }
136
137 @NotNull
138 public MockApplication getApplication() {
139 return applicationEnvironment.getApplication();
140 }
141
142 @NotNull
143 public Project getProject() {
144 return projectEnvironment.getProject();
145 }
146
147 private void addExternalAnnotationsRoot(File path) {
148 if (!path.exists()) {
149 report(WARNING, "Annotations path entry points to a non-existent location: " + path);
150 return;
151 }
152 annotationsManager.addExternalAnnotationsRoot(PathUtil.jarFileOrDirectoryToVirtualFile(path));
153 }
154
155 private void addSources(File file) {
156 if (file.isDirectory()) {
157 File[] files = file.listFiles();
158 if (files != null) {
159 for (File child : files) {
160 addSources(child);
161 }
162 }
163 }
164 else {
165 VirtualFile fileByPath = applicationEnvironment.getLocalFileSystem().findFileByPath(file.getAbsolutePath());
166 if (fileByPath != null) {
167 PsiFile psiFile = PsiManager.getInstance(getProject()).findFile(fileByPath);
168 if (psiFile instanceof JetFile) {
169 sourceFiles.add((JetFile) psiFile);
170 }
171 }
172 }
173 }
174
175 private void addSources(String path) {
176 if (path == null) {
177 return;
178 }
179
180 VirtualFile vFile = applicationEnvironment.getLocalFileSystem().findFileByPath(path);
181 if (vFile == null) {
182 report(ERROR, "Source file or directory not found: " + path);
183 return;
184 }
185 if (!vFile.isDirectory() && vFile.getFileType() != JetFileType.INSTANCE) {
186 report(ERROR, "Source entry is not a Kotlin file: " + path);
187 return;
188 }
189
190 addSources(new File(path));
191 }
192
193 private void addToClasspath(File path) {
194 if (path.isFile()) {
195 VirtualFile jarFile = applicationEnvironment.getJarFileSystem().findFileByPath(path + "!/");
196 if (jarFile == null) {
197 report(WARNING, "Classpath entry points to a file that is not a JAR archive: " + path);
198 return;
199 }
200 projectEnvironment.addJarToClassPath(path);
201 classPath.add(jarFile);
202 }
203 else {
204 VirtualFile root = applicationEnvironment.getLocalFileSystem().findFileByPath(path.getAbsolutePath());
205 if (root == null) {
206 report(WARNING, "Classpath entry points to a non-existent location: " + path);
207 return;
208 }
209 projectEnvironment.addSourcesToClasspath(root);
210 classPath.add(root);
211 }
212 }
213
214 public List<JetFile> getSourceFiles() {
215 return sourceFiles;
216 }
217
218 private void report(@NotNull CompilerMessageSeverity severity, @NotNull String message) {
219 MessageCollector messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY);
220 if (messageCollector != null) {
221 messageCollector.report(severity, message, CompilerMessageLocation.NO_LOCATION);
222 }
223 else {
224 throw new CompileEnvironmentException(message);
225 }
226 }
227 }