/* * Copyright 2013 original Randori IntelliJ Plugin authors. * * 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. */ package randori.plugin.compiler; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; 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.roots.libraries.LibraryUtil; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.io.FileUtilRt; import com.intellij.openapi.vfs.VirtualFile; import org.apache.flex.compiler.internal.workspaces.Workspace; import org.jetbrains.annotations.NotNull; import randori.compiler.bundle.BundleConfiguration; import randori.compiler.bundle.IBundleConfiguration; import randori.compiler.bundle.IBundleConfigurationEntry; import randori.compiler.clients.CompilerArguments; import randori.compiler.internal.projects.RandoriProject; import randori.compiler.plugin.IPreProcessPlugin; import randori.plugin.components.DummyPreProcessPlugin; import randori.plugin.components.RandoriApplicationComponent; import randori.plugin.components.RandoriModuleComponent; import randori.plugin.components.RandoriProjectComponent; import randori.plugin.configuration.RandoriCompilerModel; import randori.plugin.configuration.RandoriModuleModel; import randori.plugin.library.RandoriLibraryType; import randori.plugin.roots.RandoriSdkType; import randori.plugin.service.ProblemsService; import randori.plugin.ui.ProblemsToolWindowFactory; import randori.plugin.util.NotificationUtils; import randori.plugin.util.ProjectUtils; import java.io.File; import java.util.List; /** * @author Frédéric THOMAS Date: 13/04/13 Time: 13:27 */ public class RandoriCompilerSession { private static RandoriProject lastCompiler; private final Project project; private final Workspace workspace; private Module module; private List<VirtualFile> modifiedFiles; private final RandoriCompilerModel projectModel; private RandoriModuleModel moduleModel; private RandoriProject compiler; private String rblOutputPath; private List<Module> usedModules; private boolean isRebuild; private boolean isMake; private boolean isModuleRoot; public static void parseAll(@NotNull Project project) { if (ProjectUtils.isSDKInstalled(project) && ProjectUtils.hasRandoriModuleType(project)) { Module[] sortedModules = ModuleManager.getInstance(project).getSortedModules(); RandoriCompilerSession compilerSession = null; for (Module module : sortedModules) { if (compilerSession == null) compilerSession = new RandoriCompilerSession(project); if (!compilerSession.parse(module)) { ApplicationManager.getApplication().invokeLater( new ProblemBuildRunnable(project, lastCompiler, false)); return; } } ApplicationManager.getApplication().invokeLater(new ProblemBuildRunnable(project, lastCompiler, false)); } } public static RandoriProject getLastCompiler() { return lastCompiler; } public RandoriCompilerSession(@NotNull Project project) { this.project = project; projectModel = RandoriCompilerModel.getInstance(project).getState(); workspace = new Workspace(); } //-------------------------------------------------------------------------- public Workspace getWorkspace() { return workspace; } //-------------------------------------------------------------------------- boolean parse(@NotNull Module module) { return build(module, false, false); } boolean make(@NotNull Module module) { isMake = true; return build(module, true, false); } public boolean build(@NotNull Module module) { isRebuild = true; return build(module, true, true); } private boolean build(Module module, boolean doBuild, boolean doExport) { boolean success = true; isModuleRoot = ProjectUtils.isModuleRoot(project, module); prepareCompilation(module); if (isModuleRoot || isMake || (isRebuild && moduleModel.isGenerateRbl())) { CompilerArguments arguments = new CompilerArguments(); configureDependencies(arguments); final IBundleConfiguration configuration; clearProblems(); if (compiler instanceof RandoriProjectCompiler) compiler.configure(arguments.toArguments()); else if (compiler instanceof RandoriBundleCompiler) { configuration = createConfiguration(arguments); ((RandoriBundleCompiler) compiler).configure(configuration); } // Checked twice because the compiler.compile return true even if it throws errors success = compiler.compile(doBuild, doExport) && !lastCompiler.getProblemQuery().hasErrors(); if (success && doExport) { RandoriSdkType.copySdkLibraries(project); } } return success; } void prepareCompilation(Module module) { this.module = module; //workspace = new Workspace(); lastCompiler = compiler = isModuleRoot ? new RandoriProjectCompiler(workspace) : new RandoriBundleCompiler( workspace); compiler.getPluginFactory().registerPlugin(IPreProcessPlugin.class, DummyPreProcessPlugin.class); final RandoriProjectComponent projectComponent = project.getComponent(RandoriProjectComponent.class); final RandoriModuleComponent moduleComponent = module.getComponent(RandoriModuleComponent.class); if (moduleComponent != null) { modifiedFiles = projectComponent.getModifiedFiles(); moduleModel = moduleComponent.getState(); usedModules = moduleComponent.getDependencies(); String librariesOutputPath = FileUtil.toSystemDependentName(project.getBasePath() + File.separator + projectModel.getLibraryPath()); String libraryOutputPath = librariesOutputPath + File.separator + module.getName(); rblOutputPath = libraryOutputPath + File.separator + module.getName() + RandoriLibraryType.LIBRARY_DOT_EXTENSION; } } //-------------------------------------------------------------------------- private void configureDependencies(CompilerArguments arguments) { arguments.clear(); configure(projectModel, moduleModel, arguments); Sdk projectSdk = ProjectRootManager.getInstance(project).getProjectSdk(); if (projectSdk != null) { arguments.setSDKPath(projectSdk.getHomePath()); if (usedModules != null) for (Module moduleLib : usedModules) { for (String modulePath : ProjectUtils.getAllModuleSourcePaths(moduleLib)) { arguments.addSourcepath(modulePath); } } for (VirtualFile sourceRoot : ModuleRootManager.getInstance(module).getSourceRoots()) { arguments.addSourcepath(sourceRoot.getPath()); } if (!isRebuild && modifiedFiles != null) { for (VirtualFile virtualFile : modifiedFiles) { arguments.addIncludedSources(virtualFile.getPath()); } } Module[] modules = isModuleRoot ? ModuleManager.getInstance(project).getModules() : new Module[] { module }; final VirtualFile[] libraryRoots = LibraryUtil.getLibraryRoots(modules, false, false); for (VirtualFile library : libraryRoots) { final String libraryPath = library.getPath(); if (FileUtilRt.getExtension(libraryPath).equals( RandoriApplicationComponent.RBL_FILE_TYPE.getDefaultExtension())) { arguments.addBundlePath(libraryPath); } else arguments.addLibraryPath(libraryPath); } } } private void configure(RandoriCompilerModel projectModel, RandoriModuleModel moduleModel, CompilerArguments arguments) { arguments.setAppName(project.getName()); arguments.setJsBasePath(projectModel.getBasePath()); arguments.setJsLibraryPath(projectModel.getLibraryPath()); arguments.setJsOutputAsFiles(moduleModel.isExportAsFile()); if (compiler instanceof RandoriProjectCompiler) { arguments.setOutput(project.getBasePath()); } else if (compiler instanceof RandoriBundleCompiler) { arguments.setOutput(rblOutputPath); } } private IBundleConfiguration createConfiguration(CompilerArguments arguments) { BundleConfiguration configuration = new BundleConfiguration(module.getName(), arguments.getOutput()); for (String libraryPath : arguments.getLibraries()) { configuration.addLibraryPath(libraryPath); } for (String bundlePath : arguments.getBundles()) { configuration.addBundlePath(bundlePath); } IBundleConfigurationEntry entry = configuration.addEntry(module.getName()); for (String sourcePath : arguments.getSources()) { entry.addSourcePath(sourcePath); } for (String sourceIncludedPath : arguments.getIncludes()) { entry.addIncludeSources(sourceIncludedPath); } configuration.setSDKPath(arguments.getSDKPath()); return configuration; } void clearProblems() { ApplicationManager.getApplication().invokeLater(new ProblemClearRunnable()); } @SuppressWarnings("unused") private String toErrorCode(int code) { switch (code) { case 1: return "Unknown"; case 2: return "Compiler problems"; case 3: return "Compiler Exceptions"; case 4: return "Configuration Problems"; } return "Unknown error code"; } private class ProblemClearRunnable implements Runnable { @Override public void run() { ProblemsService service = ProblemsService.getInstance(project); service.clearProblems(); } } public static class ProblemBuildRunnable implements Runnable { private final Project project; private final RandoriProject compiler; private final boolean isBuild; ProblemBuildRunnable(Project project, RandoriProject compiler, boolean isBuild) { this.project = project; this.compiler = compiler; this.isBuild = isBuild; } @Override public void run() { ProblemsService service = ProblemsService.getInstance(project); service.addAll(compiler.getProblemQuery().getProblems()); if (service.hasErrors()) { NotificationUtils.sendRandoriError("Error", "Error(s) in project, Check the <a href='" + ProblemsToolWindowFactory.WINDOW_ID + "'>" + ProblemsToolWindowFactory.WINDOW_ID + "</a> for more information", project); } else { final String successBuildMessage; if (isBuild) successBuildMessage = "Successfully compiled and built project"; else successBuildMessage = "Successfully parsed project"; NotificationUtils.sendRandoriInformation("Success", successBuildMessage, project); } } } }