/* * Copyright 2000-2013 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.gradle.service.project.wizard; import com.intellij.ide.fileTemplates.FileTemplate; import com.intellij.ide.fileTemplates.FileTemplateManager; import com.intellij.ide.util.projectWizard.JavaModuleBuilder; import com.intellij.ide.util.projectWizard.ModuleWizardStep; import com.intellij.ide.util.projectWizard.WizardContext; import com.intellij.openapi.Disposable; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys; import com.intellij.openapi.externalSystem.service.project.wizard.AbstractExternalModuleBuilder; import com.intellij.openapi.externalSystem.service.project.wizard.ExternalModuleSettingsStep; import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; import com.intellij.openapi.externalSystem.util.ExternalSystemConstants; import com.intellij.openapi.externalSystem.util.ExternalSystemUtil; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.module.*; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.JavaSdkType; import com.intellij.openapi.projectRoots.SdkTypeId; import com.intellij.openapi.roots.ContentEntry; import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.openapi.roots.ui.configuration.ModulesProvider; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.io.FileUtilRt; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.service.settings.GradleProjectSettingsControl; import org.jetbrains.plugins.gradle.settings.DistributionType; import org.jetbrains.plugins.gradle.settings.GradleProjectSettings; import org.jetbrains.plugins.gradle.util.GradleConstants; import javax.swing.*; import java.io.File; import java.io.IOException; import java.util.Map; /** * @author Denis Zhdanov * @since 6/26/13 11:10 AM */ public class GradleModuleBuilder extends AbstractExternalModuleBuilder { private static final Logger LOG = Logger.getInstance(GradleModuleBuilder.class); private static final String TEMPLATE_GRADLE_SETTINGS = "Gradle Settings.gradle"; private static final String TEMPLATE_GRADLE_SETTINGS_MERGE = "Gradle Settings merge.gradle"; private static final String TEMPLATE_GRADLE_BUILD_WITH_WRAPPER = "Gradle Build Script with wrapper.gradle"; private static final String DEFAULT_TEMPLATE_GRADLE_BUILD = "Gradle Build Script.gradle"; private static final String TEMPLATE_ATTRIBUTE_PROJECT_NAME = "PROJECT_NAME"; private static final String TEMPLATE_ATTRIBUTE_MODULE_DIR_NAME = "MODULE_DIR_NAME"; private static final String TEMPLATE_ATTRIBUTE_MODULE_NAME = "MODULE_NAME"; private @NotNull WizardContext myWizardContext; public GradleModuleBuilder() { super(GradleConstants.SYSTEM_ID, new GradleProjectSettings()); } @Override public void setupRootModel(final ModifiableRootModel modifiableRootModel) throws ConfigurationException { String contentEntryPath = getContentEntryPath(); if (StringUtil.isEmpty(contentEntryPath)) { return; } File contentRootDir = new File(contentEntryPath); FileUtilRt.createDirectory(contentRootDir); LocalFileSystem fileSystem = LocalFileSystem.getInstance(); VirtualFile modelContentRootDir = fileSystem.refreshAndFindFileByIoFile(contentRootDir); if (modelContentRootDir == null) { return; } modifiableRootModel.addContentEntry(modelContentRootDir); // todo this should be moved to generic ModuleBuilder if (myJdk != null){ modifiableRootModel.setSdk(myJdk); } else { modifiableRootModel.inheritSdk(); } final Project project = modifiableRootModel.getProject(); setupGradleBuildFile(modelContentRootDir); setupGradleSettingsFile(modelContentRootDir, modifiableRootModel); if (myWizardContext.isCreatingNewProject()) { String externalProjectPath = FileUtil.toCanonicalPath(project.getBasePath()); getExternalProjectSettings().setExternalProjectPath(externalProjectPath); AbstractExternalSystemSettings settings = ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID); project.putUserData(ExternalSystemDataKeys.NEWLY_CREATED_PROJECT, Boolean.TRUE); //noinspection unchecked settings.linkProject(getExternalProjectSettings()); } else { FileDocumentManager.getInstance().saveAllDocuments(); ExternalSystemUtil.refreshProjects(project, GradleConstants.SYSTEM_ID, false); } } @Override public ModuleWizardStep[] createWizardSteps(@NotNull WizardContext wizardContext, @NotNull ModulesProvider modulesProvider) { myWizardContext = wizardContext; return super.createWizardSteps(wizardContext, modulesProvider); } @Nullable @Override public ModuleWizardStep getCustomOptionsStep(WizardContext context, Disposable parentDisposable) { if (!myWizardContext.isCreatingNewProject()) return new ModuleWizardStep() { @Override public JComponent getComponent() { return new JPanel(); } @Override public void updateDataModel() { } }; final GradleProjectSettingsControl settingsControl = new GradleProjectSettingsControl(getExternalProjectSettings(), myWizardContext.getProject()); return new ExternalModuleSettingsStep(this, settingsControl); } @Override public boolean isSuitableSdkType(SdkTypeId sdk) { return sdk instanceof JavaSdkType; } @Override public String getParentGroup() { return JavaModuleType.BUILD_TOOLS_GROUP; } @Override public int getWeight() { return JavaModuleBuilder.BUILD_SYSTEM_WEIGHT; } @Override public ModuleType getModuleType() { return StdModuleTypes.JAVA; } @Nullable private VirtualFile setupGradleBuildFile(@NotNull VirtualFile modelContentRootDir) throws ConfigurationException { final VirtualFile file = getExternalProjectConfigFile(modelContentRootDir.getPath(), GradleConstants.DEFAULT_SCRIPT_NAME); final String templateName = getExternalProjectSettings().getDistributionType() == DistributionType.WRAPPED ? TEMPLATE_GRADLE_BUILD_WITH_WRAPPER : DEFAULT_TEMPLATE_GRADLE_BUILD; Map attributes = ContainerUtil.newHashMap(); if (file != null) { saveFile(file, templateName, attributes); } return file; } @Nullable private VirtualFile setupGradleSettingsFile(@NotNull VirtualFile modelContentRootDir, @NotNull ModifiableRootModel model) throws ConfigurationException { VirtualFile file = null; if (myWizardContext.isCreatingNewProject()) { final String moduleDirName = VfsUtilCore.getRelativePath(modelContentRootDir, model.getProject().getBaseDir(), '/'); file = getExternalProjectConfigFile(model.getProject().getBasePath(), GradleConstants.SETTINGS_FILE_NAME); if (file == null) return null; Map attributes = ContainerUtil.newHashMap(); final String projectName = model.getProject().getName(); attributes.put(TEMPLATE_ATTRIBUTE_PROJECT_NAME, projectName); attributes.put(TEMPLATE_ATTRIBUTE_MODULE_DIR_NAME, moduleDirName); attributes.put(TEMPLATE_ATTRIBUTE_MODULE_NAME, model.getModule().getName()); saveFile(file, TEMPLATE_GRADLE_SETTINGS, attributes); } else { Map moduleMap = ContainerUtil.newHashMap(); for (Module module : ModuleManager.getInstance(model.getProject()).getModules()) { for (ContentEntry contentEntry : model.getContentEntries()) { if (contentEntry.getFile() != null) { moduleMap.put(contentEntry.getFile().getPath(), module); } } } VirtualFile virtualFile = modelContentRootDir; Module module = null; while (virtualFile != null && module == null) { module = moduleMap.get(virtualFile.getPath()); virtualFile = virtualFile.getParent(); } if (module != null) { String rootProjectPath = module.getOptionValue(ExternalSystemConstants.ROOT_PROJECT_PATH_KEY); if (!StringUtil.isEmpty(rootProjectPath)) { VirtualFile rootProjectFile = VfsUtil.findFileByIoFile(new File(rootProjectPath), true); if (rootProjectFile == null) return null; final String moduleDirName = VfsUtilCore.getRelativePath(modelContentRootDir, rootProjectFile, '/'); file = getExternalProjectConfigFile(rootProjectPath, GradleConstants.SETTINGS_FILE_NAME); if (file == null) return null; Map attributes = ContainerUtil.newHashMap(); attributes.put(TEMPLATE_ATTRIBUTE_MODULE_DIR_NAME, moduleDirName); attributes.put(TEMPLATE_ATTRIBUTE_MODULE_NAME, model.getModule().getName()); appendToFile(file, TEMPLATE_GRADLE_SETTINGS_MERGE, attributes); } } } return file; } private static void saveFile(@NotNull VirtualFile file, @NotNull String templateName, @Nullable Map templateAttributes) throws ConfigurationException { FileTemplateManager manager = FileTemplateManager.getDefaultInstance(); FileTemplate template = manager.getInternalTemplate(templateName); try { VfsUtil.saveText(file, templateAttributes != null ? template.getText(templateAttributes) : template.getText()); } catch (IOException e) { LOG.warn(String.format("Unexpected exception on applying template %s config", GradleConstants.SYSTEM_ID.getReadableName()), e); throw new ConfigurationException( e.getMessage(), String.format("Can't apply %s template config text", GradleConstants.SYSTEM_ID.getReadableName()) ); } } private static void appendToFile(@NotNull VirtualFile file, @NotNull String templateName, @Nullable Map templateAttributes) throws ConfigurationException { FileTemplateManager manager = FileTemplateManager.getDefaultInstance(); FileTemplate template = manager.getInternalTemplate(templateName); try { VfsUtil.saveText(file, VfsUtilCore.loadText(file) + (templateAttributes != null ? template.getText(templateAttributes) : template.getText())); } catch (IOException e) { LOG.warn(String.format("Unexpected exception on appending template %s config", GradleConstants.SYSTEM_ID.getReadableName()), e); throw new ConfigurationException( e.getMessage(), String.format("Can't append %s template config text", GradleConstants.SYSTEM_ID.getReadableName()) ); } } @Nullable private static VirtualFile getExternalProjectConfigFile(@NotNull String parent, @NotNull String fileName) { File file = new File(parent, fileName); FileUtilRt.createIfNotExists(file); return LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file); } }