1 package org.jetbrains.jps.server;
3 import com.intellij.openapi.diagnostic.Logger;
4 import com.intellij.openapi.util.io.FileUtil;
5 import com.intellij.openapi.util.text.StringUtil;
6 import org.codehaus.groovy.runtime.MethodClosure;
7 import org.jetbrains.annotations.Nullable;
8 import org.jetbrains.jps.Library;
9 import org.jetbrains.jps.Module;
10 import org.jetbrains.jps.Project;
11 import org.jetbrains.jps.Sdk;
12 import org.jetbrains.jps.api.BuildType;
13 import org.jetbrains.jps.api.CanceledStatus;
14 import org.jetbrains.jps.api.GlobalLibrary;
15 import org.jetbrains.jps.api.SdkLibrary;
16 import org.jetbrains.jps.idea.IdeaProjectLoader;
17 import org.jetbrains.jps.incremental.*;
18 import org.jetbrains.jps.incremental.messages.BuildMessage;
19 import org.jetbrains.jps.incremental.messages.CompilerMessage;
20 import org.jetbrains.jps.incremental.storage.BuildDataManager;
21 import org.jetbrains.jps.incremental.storage.ProjectTimestamps;
22 import org.jetbrains.jps.incremental.storage.TimestampStorage;
25 import java.lang.reflect.Method;
29 * @author Eugene Zhuravlev
31 * @noinspection UnusedDeclaration
34 private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.server.ServerState");
35 public static final String IDEA_PROJECT_DIRNAME = ".idea";
37 private final Map<String, ProjectDescriptor> myProjects = new HashMap<String, ProjectDescriptor>();
39 private final Object myConfigurationLock = new Object();
40 private final Map<String, String> myPathVariables = new HashMap<String, String>();
41 private final List<GlobalLibrary> myGlobalLibraries = new ArrayList<GlobalLibrary>();
42 private volatile String myGlobalEncoding = null;
43 private volatile boolean myKeepTempCachesInMemory = false;
45 public void setGlobals(List<GlobalLibrary> libs, Map<String, String> pathVars, String globalEncoding) {
46 synchronized (myConfigurationLock) {
48 myGlobalLibraries.addAll(libs);
49 myPathVariables.putAll(pathVars);
50 myGlobalEncoding = StringUtil.isEmpty(globalEncoding)? null : globalEncoding;
54 public final void clearCahedState() {
55 synchronized (myConfigurationLock) {
56 for (Map.Entry<String, ProjectDescriptor> entry : myProjects.entrySet()) {
57 final String projectPath = entry.getKey();
58 final ProjectDescriptor descriptor = entry.getValue();
61 myProjects.clear(); // projects should be reloaded against the latest data
62 myGlobalLibraries.clear();
63 myPathVariables.clear();
67 public boolean isKeepTempCachesInMemory() {
68 return myKeepTempCachesInMemory;
71 public void setKeepTempCachesInMemory(boolean keepTempCachesInMemory) {
72 myKeepTempCachesInMemory = keepTempCachesInMemory;
75 public void notifyFileChanged(ProjectDescriptor pd, File file) {
77 final RootDescriptor rd = pd.rootsIndex.getModuleAndRoot(file);
79 pd.fsState.markDirty(file, rd, pd.timestamps.getStorage());
87 public void notifyFileDeleted(final ProjectDescriptor pd, File file) {
89 final RootDescriptor moduleAndRoot = pd.rootsIndex.getModuleAndRoot(file);
90 if (moduleAndRoot != null) {
91 pd.fsState.registerDeleted(moduleAndRoot.module, file, moduleAndRoot.isTestRoot, pd.timestamps.getStorage());
100 public ProjectDescriptor getProjectDescriptor(String projectPath) {
101 final ProjectDescriptor pd;
102 synchronized (myConfigurationLock) {
103 pd = myProjects.get(projectPath);
105 pd.incUsageCounter();
111 public void clearProjectCache(Collection<String> projectPaths) {
112 synchronized (myConfigurationLock) {
113 for (String projectPath : projectPaths) {
114 final ProjectDescriptor descriptor = myProjects.remove(projectPath);
115 if (descriptor != null) {
116 descriptor.release();
122 public void startBuild(String projectPath, BuildType buildType, Set<String> modules, Collection<String> paths, final MessageHandler msgHandler, CanceledStatus cs) throws Throwable{
124 final String projectName = getProjectName(projectPath);
126 ProjectDescriptor pd;
127 synchronized (myConfigurationLock) {
128 pd = myProjects.get(projectPath);
130 final Project project = loadProject(projectPath);
131 final FSState fsState = new FSState(false);
132 ProjectTimestamps timestamps = null;
133 BuildDataManager dataManager = null;
135 timestamps = new ProjectTimestamps(projectName);
136 dataManager = new BuildDataManager(projectName, myKeepTempCachesInMemory);
138 catch (Exception e) {
140 e.printStackTrace(System.err);
141 if (timestamps != null) {
144 if (dataManager != null) {
147 buildType = BuildType.PROJECT_REBUILD; // force project rebuild
148 FileUtil.delete(Paths.getDataStorageRoot(projectName));
149 timestamps = new ProjectTimestamps(projectName);
150 dataManager = new BuildDataManager(projectName, myKeepTempCachesInMemory);
151 // second attempt succeded
152 msgHandler.processMessage(new CompilerMessage("compile-server", BuildMessage.Kind.INFO, "Project rebuild forced: " + e.getMessage()));
155 pd = new ProjectDescriptor(projectName, project, fsState, timestamps, dataManager);
156 myProjects.put(projectPath, pd);
158 pd.incUsageCounter();
161 final Project project = pd.project;
164 final CompileScope compileScope = createCompilationScope(buildType, pd, modules, paths);
165 final IncProjectBuilder builder = new IncProjectBuilder(pd, BuilderRegistry.getInstance(), cs);
166 if (msgHandler != null) {
167 builder.addMessageHandler(msgHandler);
170 case PROJECT_REBUILD:
171 builder.build(compileScope, false, true);
174 case FORCED_COMPILATION:
175 builder.build(compileScope, false, false);
179 builder.build(compileScope, true, false);
184 // new ProjectBuilder(new GantBinding(), project).clean();
190 clearZipIndexCache();
194 private static CompileScope createCompilationScope(BuildType buildType, ProjectDescriptor pd, Set<String> modules, Collection<String> paths) throws Exception {
195 final CompileScope compileScope;
196 if (buildType == BuildType.PROJECT_REBUILD || (modules.isEmpty() && paths.isEmpty())) {
197 compileScope = new AllProjectScope(pd.project, buildType != BuildType.MAKE);
200 final Set<Module> forcedModules;
201 if (!modules.isEmpty()) {
202 forcedModules = new HashSet<Module>();
203 for (Module m : pd.project.getModules().values()) {
204 if (modules.contains(m.getName())){
205 forcedModules.add(m);
210 forcedModules = Collections.emptySet();
213 final TimestampStorage tsStorage = pd.timestamps.getStorage();
215 final Map<Module, Set<File>> filesToCompile;
216 if (!paths.isEmpty()) {
217 filesToCompile = new HashMap<Module, Set<File>>();
218 for (String path : paths) {
219 final File file = new File(path);
220 final RootDescriptor rd = pd.rootsIndex.getModuleAndRoot(file);
222 Set<File> files = filesToCompile.get(rd.module);
224 files = new HashSet<File>();
225 filesToCompile.put(rd.module, files);
228 if (buildType == BuildType.FORCED_COMPILATION) {
229 pd.fsState.markDirty(file, rd, tsStorage);
235 filesToCompile = Collections.emptyMap();
238 if (filesToCompile.isEmpty()) {
239 compileScope = new ModulesScope(pd.project, forcedModules, buildType != BuildType.MAKE);
242 compileScope = new ModulesAndFilesScope(pd.project, forcedModules, filesToCompile, buildType != BuildType.MAKE);
249 private static boolean ourCleanupFailed = false;
251 private static void clearZipIndexCache() {
252 if (!ourCleanupFailed) {
254 final Class<?> indexClass = Class.forName("com.sun.tools.javac.zip.ZipFileIndex");
255 final Method clearMethod = indexClass.getMethod("clearCache");
256 clearMethod.invoke(null);
258 catch (Throwable ex) {
259 ourCleanupFailed = true;
265 private static String getProjectName(String projectPath) {
266 final File path = new File(projectPath);
267 final String name = path.getName().toLowerCase(Locale.US);
268 if (!isDirectoryBased(path) && name.endsWith(".ipr")) {
269 return name.substring(0, name.length() - ".ipr".length());
274 private Project loadProject(String projectPath) {
275 final Project project = new Project();
276 // setup JDKs and global libraries
277 final MethodClosure fakeClosure = new MethodClosure(new Object(), "hashCode");
278 for (GlobalLibrary library : myGlobalLibraries) {
279 if (library instanceof SdkLibrary) {
280 final SdkLibrary sdk = (SdkLibrary)library;
281 final Sdk jdk = project.createSdk("JavaSDK", sdk.getName(), sdk.getHomePath(), null);
282 jdk.setClasspath(sdk.getPaths());
285 final Library lib = project.createGlobalLibrary(library.getName(), fakeClosure);
286 lib.setClasspath(library.getPaths());
290 final File projectFile = new File(projectPath);
292 //String root = dirBased ? projectPath : projectFile.getParent();
294 final String loadPath = isDirectoryBased(projectFile) ? new File(projectFile, IDEA_PROJECT_DIRNAME).getPath() : projectPath;
295 IdeaProjectLoader.loadFromPath(project, loadPath, myPathVariables, getStartupScript());
296 final String globalEncoding = myGlobalEncoding;
297 if (globalEncoding != null && project.getProjectCharset() == null) {
298 project.setProjectCharset(globalEncoding);
303 private static boolean isDirectoryBased(File projectFile) {
304 return !(projectFile.isFile() && projectFile.getName().endsWith(".ipr"));
307 private String getStartupScript() {
308 //return "import org.jetbrains.jps.*\n";
312 private static class InstanceHolder {
313 static final ServerState ourInstance = new ServerState();
316 public static ServerState getInstance() {
317 return InstanceHolder.ourInstance;