| /* |
| * Copyright 2000-2014 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. |
| */ |
| |
| package org.jetbrains.plugins.groovy.griffon; |
| |
| import com.intellij.execution.ExecutionException; |
| import com.intellij.execution.configurations.GeneralCommandLine; |
| import com.intellij.execution.configurations.JavaParameters; |
| import com.intellij.execution.configurations.ParametersList; |
| import com.intellij.lang.properties.IProperty; |
| import com.intellij.lang.properties.psi.PropertiesFile; |
| import com.intellij.openapi.application.AccessToken; |
| import com.intellij.openapi.application.WriteAction; |
| import com.intellij.openapi.module.Module; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.projectRoots.JavaSdkType; |
| import com.intellij.openapi.projectRoots.Sdk; |
| import com.intellij.openapi.roots.ModuleRootManager; |
| import com.intellij.openapi.roots.OrderRootType; |
| import com.intellij.openapi.roots.libraries.Library; |
| import com.intellij.openapi.roots.libraries.LibraryKind; |
| import com.intellij.openapi.util.io.FileUtil; |
| import com.intellij.openapi.util.text.StringUtil; |
| import com.intellij.openapi.vcs.changes.ChangeListManager; |
| import com.intellij.openapi.vcs.changes.IgnoredBeanFactory; |
| import com.intellij.openapi.vfs.VfsUtil; |
| import com.intellij.openapi.vfs.VfsUtilCore; |
| import com.intellij.openapi.vfs.VirtualFile; |
| import com.intellij.psi.PsiFile; |
| import com.intellij.psi.PsiManager; |
| import com.intellij.util.containers.MultiMap; |
| import gnu.trove.TIntArrayList; |
| import icons.JetgroovyIcons; |
| import org.jetbrains.annotations.NonNls; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| import org.jetbrains.jps.model.java.JavaSourceRootType; |
| import org.jetbrains.jps.model.module.JpsModuleSourceRootType; |
| import org.jetbrains.plugins.groovy.GroovyFileType; |
| import org.jetbrains.plugins.groovy.mvc.*; |
| |
| import javax.swing.*; |
| import java.io.File; |
| import java.io.IOException; |
| import java.util.List; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| /** |
| * @author peter |
| */ |
| public class GriffonFramework extends MvcFramework { |
| @NonNls private static final String GRIFFON_COMMON_PLUGINS = "-griffonPlugins"; |
| private static final String GLOBAL_PLUGINS_MODULE_NAME = "GriffonGlobalPlugins"; |
| |
| public static final String GRIFFON_USER_LIBRARY = "Griffon:lib"; |
| |
| private static final Pattern PLUGIN_NAME_JSON_PATTERN = Pattern.compile("\"name\"\\s*:\\s*\"([^\"]+)\""); |
| private static final Pattern PLUGIN_VERSION_JSON_PATTERN = Pattern.compile("\"version\"\\s*:\\s*\"([^\"]+)\""); |
| |
| private GriffonFramework() { |
| } |
| |
| @Override |
| public boolean hasSupport(@NotNull Module module) { |
| return findAppRoot(module) != null && !isAuxModule(module) && getSdkRoot(module) != null; |
| } |
| |
| @Override |
| public String getApplicationDirectoryName() { |
| return "griffon-app"; |
| } |
| |
| @Override |
| public boolean isToReformatOnCreation(VirtualFile file) { |
| return file.getFileType() == GroovyFileType.GROOVY_FILE_TYPE; |
| } |
| |
| @Override |
| public void upgradeFramework(@NotNull Module module) { |
| } |
| |
| @Nullable |
| @Override |
| protected GeneralCommandLine getCreationCommandLine(Module module) { |
| GriffonCreateProjectDialog dialog = new GriffonCreateProjectDialog(module); |
| dialog.show(); |
| if (!dialog.isOK()) { |
| return null; |
| } |
| |
| return createCommandAndShowErrors(null, module, true, dialog.getCommand()); |
| } |
| |
| @Override |
| public boolean updatesWholeProject() { |
| return false; |
| } |
| |
| @Override |
| public void updateProjectStructure(@NotNull final Module module) { |
| if (!MvcModuleStructureUtil.isEnabledStructureUpdate()) return; |
| |
| final VirtualFile root = findAppRoot(module); |
| if (root == null) return; |
| |
| AccessToken token = WriteAction.start(); |
| try { |
| MvcModuleStructureUtil.updateModuleStructure(module, createProjectStructure(module, false), root); |
| |
| if (hasSupport(module)) { |
| MvcModuleStructureUtil.updateAuxiliaryPluginsModuleRoots(module, this); |
| MvcModuleStructureUtil.updateGlobalPluginModule(module.getProject(), this); |
| } |
| } |
| finally { |
| token.finish(); |
| } |
| |
| final Project project = module.getProject(); |
| ChangeListManager.getInstance(project).addFilesToIgnore(IgnoredBeanFactory.ignoreUnderDirectory(getUserHomeGriffon(), project)); |
| } |
| |
| @Override |
| public void ensureRunConfigurationExists(@NotNull Module module) { |
| final VirtualFile root = findAppRoot(module); |
| if (root != null) { |
| ensureRunConfigurationExists(module, GriffonRunConfigurationType.getInstance(), "Griffon:" + root.getName()); |
| } |
| } |
| |
| @Override |
| public String getInstalledPluginNameByPath(Project project, @NotNull VirtualFile pluginPath) { |
| String nameFromPluginXml = super.getInstalledPluginNameByPath(project, pluginPath); |
| if (nameFromPluginXml != null) { |
| return nameFromPluginXml; |
| } |
| |
| VirtualFile pluginJson = pluginPath.findChild("plugin.json"); |
| if (pluginJson != null) { |
| String pluginAndVersion = pluginPath.getName(); // pluginName-version |
| |
| TIntArrayList separatorIndexes = new TIntArrayList(); |
| int start = -1; |
| while (true) { |
| start = pluginAndVersion.indexOf('-', start + 1); |
| if (start == -1) break; |
| separatorIndexes.add(start); |
| } |
| |
| if (separatorIndexes.size() == 1) { |
| return pluginAndVersion.substring(0, separatorIndexes.get(0)); |
| } |
| |
| if (!separatorIndexes.isEmpty()) { |
| String json; |
| try { |
| json = VfsUtil.loadText(pluginJson); |
| } |
| catch (IOException e) { |
| return null; |
| } |
| |
| for (int i = 0; i < separatorIndexes.size(); i++) { |
| int idx = separatorIndexes.get(i); |
| String name = pluginAndVersion.substring(0, idx); |
| String version = pluginAndVersion.substring(idx + 1); |
| |
| if (hasValue(PLUGIN_NAME_JSON_PATTERN, json, name) && hasValue(PLUGIN_VERSION_JSON_PATTERN, json, version)) { |
| return name; |
| } |
| } |
| } |
| } |
| |
| return null; |
| } |
| |
| private static boolean hasValue(Pattern pattern, String text, String value) { |
| Matcher matcher = pattern.matcher(text); |
| while (matcher.find()) { |
| if (matcher.group(1).equals(value)) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| @Override |
| protected boolean isCoreJar(@NotNull VirtualFile localFile) { |
| return GriffonLibraryPresentationProvider.isGriffonCoreJar(localFile); |
| } |
| |
| @Override |
| public VirtualFile getSdkRoot(@Nullable Module module) { |
| VirtualFile coreJar = findCoreJar(module); |
| if (coreJar == null) return null; |
| |
| final VirtualFile parent = coreJar.getParent(); |
| if (parent != null) { |
| return parent.getParent(); |
| } |
| return null; |
| } |
| |
| @Override |
| public String getUserLibraryName() { |
| return GRIFFON_USER_LIBRARY; |
| } |
| |
| @Override |
| public JavaParameters createJavaParameters(@NotNull Module module, boolean forCreation, boolean forTests, |
| boolean classpathFromDependencies, |
| @Nullable String jvmParams, |
| @NotNull MvcCommand command) throws ExecutionException { |
| JavaParameters params = new JavaParameters(); |
| |
| Sdk sdk = ModuleRootManager.getInstance(module).getSdk(); |
| |
| params.setJdk(sdk); |
| final VirtualFile sdkRoot = getSdkRoot(module); |
| if (sdkRoot == null) { |
| return params; |
| } |
| |
| params.addEnv(getSdkHomePropertyName(), FileUtil.toSystemDependentName(sdkRoot.getPath())); |
| |
| final VirtualFile lib = sdkRoot.findChild("lib"); |
| if (lib != null) { |
| for (final VirtualFile child : lib.getChildren()) { |
| final String name = child.getName(); |
| if (name.startsWith("groovy-all-") && name.endsWith(".jar")) { |
| params.getClassPath().add(child); |
| } |
| } |
| } |
| final VirtualFile dist = sdkRoot.findChild("dist"); |
| if (dist != null) { |
| for (final VirtualFile child : dist.getChildren()) { |
| final String name = child.getName(); |
| if (name.endsWith(".jar")) { |
| if (name.startsWith("griffon-cli-") || name.startsWith("griffon-rt-") || name.startsWith("griffon-resources-")) { |
| params.getClassPath().add(child); |
| } |
| } |
| } |
| } |
| |
| |
| ///////////////////////////////////////////////////////////// |
| |
| params.setMainClass("org.codehaus.griffon.cli.support.GriffonStarter"); |
| |
| final VirtualFile rootFile; |
| |
| if (forCreation) { |
| VirtualFile[] roots = ModuleRootManager.getInstance(module).getContentRoots(); |
| if (roots.length != 1) { |
| throw new ExecutionException("Failed to initialize griffon module: module " + module.getName() + " contains more than one root"); |
| } |
| |
| command.getArgs().add(0, roots[0].getName()); |
| |
| rootFile = roots[0].getParent(); |
| } |
| else { |
| rootFile = findAppRoot(module); |
| if (rootFile == null) { |
| throw new ExecutionException("Failed to run griffon command: module " + module.getName() + " is not a Griffon module"); |
| } |
| } |
| |
| String workDir = VfsUtilCore.virtualToIoFile(rootFile).getAbsolutePath(); |
| |
| if (jvmParams != null) { |
| params.getVMParametersList().addParametersString(jvmParams); |
| } |
| |
| if (!params.getVMParametersList().getParametersString().contains(XMX_JVM_PARAMETER)) { |
| params.getVMParametersList().add("-Xmx256M"); |
| } |
| |
| final String griffonHomePath = FileUtil.toSystemDependentName(sdkRoot.getPath()); |
| params.getVMParametersList().add("-Dgriffon.home=" + griffonHomePath); |
| params.getVMParametersList().add("-Dbase.dir=" + workDir); |
| |
| assert sdk != null; |
| params.getVMParametersList().add("-Dtools.jar=" + ((JavaSdkType)sdk.getSdkType()).getToolsPath(sdk)); |
| |
| final String confpath = griffonHomePath + GROOVY_STARTER_CONF; |
| params.getVMParametersList().add("-Dgroovy.starter.conf=" + confpath); |
| |
| params.getVMParametersList().add( |
| "-Dgroovy.sanitized.stacktraces=\"groovy., org.codehaus.groovy., java., javax., sun., gjdk.groovy., gant., org.codehaus.gant.\""); |
| |
| params.getProgramParametersList().add("--main"); |
| params.getProgramParametersList().add("org.codehaus.griffon.cli.GriffonScriptRunner"); |
| params.getProgramParametersList().add("--conf"); |
| params.getProgramParametersList().add(confpath); |
| if (!forCreation && classpathFromDependencies) { |
| final String path = getApplicationClassPath(module).getPathsString(); |
| if (StringUtil.isNotEmpty(path)) { |
| params.getProgramParametersList().add("--classpath"); |
| params.getProgramParametersList().add(path); |
| } |
| } |
| |
| params.setWorkingDirectory(workDir); |
| |
| ParametersList paramList = new ParametersList(); |
| command.addToParametersList(paramList); |
| params.getProgramParametersList().add(paramList.getParametersString()); |
| |
| params.setDefaultCharset(module.getProject()); |
| |
| return params; |
| } |
| |
| @Override |
| public String getFrameworkName() { |
| return "Griffon"; |
| } |
| |
| @Override |
| public Icon getIcon() { |
| return JetgroovyIcons.Griffon.Griffon; |
| } |
| |
| @Override |
| public Icon getToolWindowIcon() { |
| return JetgroovyIcons.Griffon.GriffonToolWindow; |
| } |
| |
| @Override |
| public String getSdkHomePropertyName() { |
| return "GRIFFON_HOME"; |
| } |
| |
| @Override |
| protected String getCommonPluginSuffix() { |
| return GRIFFON_COMMON_PLUGINS; |
| } |
| |
| @Override |
| public String getGlobalPluginsModuleName() { |
| return GLOBAL_PLUGINS_MODULE_NAME; |
| } |
| |
| @Override |
| @Nullable |
| public File getDefaultSdkWorkDir(@NotNull Module module) { |
| final String version = GriffonLibraryPresentationProvider.getGriffonVersion(module); |
| if (version == null) return null; |
| |
| return new File(getUserHomeGriffon(), version); |
| } |
| |
| @Override |
| public boolean isSDKLibrary(Library library) { |
| return GriffonLibraryPresentationProvider.isGriffonSdk(library.getFiles(OrderRootType.CLASSES)); |
| } |
| |
| @Override |
| public MvcProjectStructure createProjectStructure(@NotNull Module module, boolean auxModule) { |
| return new GriffonProjectStructure(module, auxModule); |
| } |
| |
| @Override |
| public LibraryKind getLibraryKind() { |
| return GriffonLibraryPresentationProvider.GRIFFON_KIND; |
| } |
| |
| @Override |
| public String getSomeFrameworkClass() { |
| return "griffon.core.GriffonApplication"; |
| } |
| |
| public static String getUserHomeGriffon() { |
| return MvcPathMacros.getSdkWorkDirParent("griffon"); |
| } |
| |
| public static GriffonFramework getInstance() { |
| return EP_NAME.findExtension(GriffonFramework.class); |
| } |
| |
| public VirtualFile getApplicationPropertiesFile(Module module) { |
| final VirtualFile appRoot = findAppRoot(module); |
| return appRoot != null ? appRoot.findChild("application.properties") : null; |
| } |
| |
| @Override |
| public String getApplicationName(Module module) { |
| final VirtualFile appProperties = getApplicationPropertiesFile(module); |
| if (appProperties != null) { |
| final PsiFile file = PsiManager.getInstance(module.getProject()).findFile(appProperties); |
| if (file instanceof PropertiesFile) { |
| final IProperty property = ((PropertiesFile)file).findPropertyByKey("application.name"); |
| return property != null ? property.getValue() : super.getApplicationName(module); |
| } |
| } |
| return super.getApplicationName(module); |
| } |
| |
| private static class GriffonProjectStructure extends MvcProjectStructure { |
| |
| public static final String[] TEST_DIRS = new String[]{"unit", "integration", "shared"}; |
| public static final String[] SRC_DIR_SUBFOLDER = new String[]{"main", "cli"}; |
| public static final String[] GRIFFON_APP_SOURCE_ROOTS = new String[]{"models", "views", "controllers", "services", "conf", "lifecycle"}; |
| |
| public GriffonProjectStructure(Module module, final boolean auxModule) { |
| super(module, auxModule, getUserHomeGriffon(), GriffonFramework.getInstance().getSdkWorkDir(module)); |
| } |
| |
| @Override |
| @NotNull |
| public String getUserLibraryName() { |
| return GRIFFON_USER_LIBRARY; |
| } |
| |
| @Override |
| public MultiMap<JpsModuleSourceRootType<?>, String> getSourceFolders() { |
| MultiMap<JpsModuleSourceRootType<?>, String> res = new MultiMap<JpsModuleSourceRootType<?>, String>(); |
| |
| for (VirtualFile root : ModuleRootManager.getInstance(myModule).getContentRoots()) { |
| VirtualFile srcDir = root.findChild("src"); |
| if (srcDir != null) { |
| for (String child : SRC_DIR_SUBFOLDER) { |
| if (srcDir.findChild(child) != null) { |
| res.putValue(JavaSourceRootType.SOURCE, "src/" + child); |
| } |
| } |
| } |
| |
| VirtualFile griffonApp = root.findChild("griffon-app"); |
| if (griffonApp != null) { |
| for (String child : GRIFFON_APP_SOURCE_ROOTS) { |
| if (griffonApp.findChild(child) != null) { |
| res.putValue(JavaSourceRootType.SOURCE, "griffon-app/" + child); |
| } |
| } |
| |
| for (VirtualFile child : root.getChildren()) { |
| if (child.getNameWithoutExtension().endsWith("GriffonAddon")) { |
| res.putValue(JavaSourceRootType.SOURCE, ""); |
| break; |
| } |
| } |
| } |
| |
| List<GriffonSourceInspector.GriffonSource> sources = GriffonSourceInspector.processModuleMetadata(myModule); |
| for (GriffonSourceInspector.GriffonSource source : sources) { |
| res.putValue(JavaSourceRootType.SOURCE, source.getPath()); |
| } |
| |
| VirtualFile testDir = root.findChild("test"); |
| if (testDir != null) { |
| for (String child : TEST_DIRS) { |
| if (testDir.findChild(child) != null) { |
| res.putValue(JavaSourceRootType.TEST_SOURCE, "test/" + child); |
| } |
| } |
| } |
| } |
| |
| return res; |
| } |
| |
| @Override |
| public String[] getInvalidSourceFolders() { |
| return new String[]{"src"}; |
| } |
| |
| @Override |
| public String[] getExcludedFolders() { |
| return new String[]{"target/classes", "target/test-classes"}; |
| } |
| } |
| } |