/* * Copyright (C) 2015 RoboVM AB * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/gpl-2.0.html>. */ package org.robovm.idea.builder; import java.io.File; import java.io.FileWriter; import java.io.FilenameFilter; import java.io.IOException; import java.nio.charset.StandardCharsets; import com.intellij.openapi.module.*; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.maven.project.MavenProjectsManager; import org.jetbrains.plugins.gradle.service.project.wizard.GradleProjectImportBuilder; import org.jetbrains.plugins.gradle.service.project.wizard.GradleProjectImportProvider; import org.jetbrains.plugins.gradle.settings.DistributionType; import org.robovm.compiler.Version; import org.robovm.idea.RoboVmPlugin; import org.robovm.idea.sdk.RoboVmSdkType; import org.robovm.templater.Templater; import com.intellij.ide.actions.ImportModuleAction; import com.intellij.ide.util.newProjectWizard.AddModuleWizard; 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.application.ApplicationManager; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys; import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.DumbAwareRunnable; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.JavaSdk; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.roots.*; import com.intellij.openapi.roots.ui.configuration.ModulesProvider; import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.java.LanguageLevel; import com.intellij.projectImport.ProjectImportProvider; /** * Creates all the files for a new project/module using the templater. See * https://android.googlesource.com/platform/tools/adt/idea/+/ * 7ac63164a27e301d45d8640852a0bdaa6eabbad0/android/src/org/jetbrains/android/ * newProject/AndroidModuleBuilder.java */ public class RoboVmModuleBuilder extends JavaModuleBuilder { public static final String ROBOVM_VERSION_PLACEHOLDER = "__robovmVersion__"; public static final String PACKAGE_NAME_PLACEHOLDER = "__packageName__"; public static final String APP_NAME_PLACEHOLDER = "__appName__"; protected String templateName; protected String packageName; protected String mainClassName; protected String appName; protected String appId; protected String robovmDir; protected BuildSystem buildSystem; public RoboVmModuleBuilder(String templateName) { this.templateName = templateName; this.robovmDir = ""; } public RoboVmModuleBuilder(String templateName, String robovmDir) { this.templateName = templateName; this.robovmDir = robovmDir; } @Nullable @Override public String getBuilderId() { return this.getClass().getName() + templateName; } @Override public ModuleType getModuleType() { return StdModuleTypes.JAVA; } @Override public ModuleWizardStep[] createWizardSteps(WizardContext wizardContext, ModulesProvider modulesProvider) { RoboVmModuleWizardStep wizardStep = new RoboVmModuleWizardStep(this, wizardContext, modulesProvider); if (!robovmDir.isEmpty()) { wizardStep.disableBuildSystem(); buildSystem = BuildSystem.Gradle; } if (!robovmDir.isEmpty() && !RoboVmPlugin.isAndroidSdkSetup()) { RoboVmAndroidModuleWizardStep androidStep = new RoboVmAndroidModuleWizardStep(this, wizardContext, modulesProvider); return new ModuleWizardStep[] { androidStep, wizardStep }; } else { return new ModuleWizardStep[] { wizardStep }; } } @Override public void setupRootModel(final ModifiableRootModel modifiableRootModel) throws ConfigurationException { // set the Java SDK myJdk = RoboVmPlugin.getSdk(); if (myJdk == null || !robovmDir.isEmpty()) { myJdk = RoboVmSdkType.findBestJdk(); } // set a project jdk if none is set ProjectRootManager manager = ProjectRootManager.getInstance(modifiableRootModel.getProject()); if (manager.getProjectSdk() == null) { manager.setProjectSdk(RoboVmSdkType.findBestJdk()); } if (buildSystem != BuildSystem.None) { // apply the template final Project project = modifiableRootModel.getProject(); StartupManager.getInstance(project).runWhenProjectIsInitialized(new DumbAwareRunnable() { public void run() { DumbService.getInstance(project).smartInvokeLater(new Runnable() { public void run() { ApplicationManager.getApplication().runWriteAction(new Runnable() { public void run() { RoboVmModuleBuilder.this.applyTemplate(project); } }); } }); } }); // apply the build system StartupManager.getInstance(project).registerPostStartupActivity(new DumbAwareRunnable() { public void run() { DumbService.getInstance(project).smartInvokeLater(new Runnable() { public void run() { RoboVmModuleBuilder.this.applyBuildSystem(project); } }); } }); } else { Sdk jdk = RoboVmSdkType.findBestJdk(); LanguageLevel langLevel = ((JavaSdk) jdk.getSdkType()).getVersion(jdk).getMaxLanguageLevel(); modifiableRootModel.getModuleExtension(LanguageLevelModuleExtension.class).setLanguageLevel(langLevel); super.setupRootModel(modifiableRootModel); final VirtualFile contentRoot = LocalFileSystem.getInstance() .findFileByIoFile(new File(modifiableRootModel.getProject().getBasePath())); applyTemplate(modifiableRootModel.getProject()); contentRoot.refresh(false, true); for (ContentEntry entry : modifiableRootModel.getContentEntries()) { for (SourceFolder srcFolder : entry.getSourceFolders()) { entry.removeSourceFolder(srcFolder); } if (robovmDir.isEmpty()) { entry.addSourceFolder(contentRoot.findFileByRelativePath("/src/main/java"), false); } new File(entry.getFile().getCanonicalPath()).delete(); } } } private void applyTemplate(Project project) { // extract the template files and setup the source folders Templater templater = new Templater(templateName); templater.appId(appId); templater.appName(appName); templater.executable(appName); templater.mainClass(packageName + "." + mainClassName); templater.packageName(packageName); templater.androidSdkVersion(RoboVmPlugin.getBestAndroidSdkVersion()); templater.androidBuildToolsVersion(RoboVmPlugin.getBestAndroidBuildToolsVersion()); templater.buildProject(new File(project.getBasePath())); try { // set up robovm version in robovm module build.gradle if (buildSystem == BuildSystem.Gradle) { final File buildFile = new File(project.getBasePath() + "/" + robovmDir + "/build.gradle"); if (buildFile.exists()) { String template = FileUtils.readFileToString(buildFile, StandardCharsets.UTF_8); template = template.replaceAll(ROBOVM_VERSION_PLACEHOLDER, Version.getVersion()); FileUtils.write(buildFile, template); } else { String template = IOUtils.toString(RoboVmModuleBuilder.class.getResource("/template_build.gradle"), "UTF-8"); template = template.replaceAll(ROBOVM_VERSION_PLACEHOLDER, Version.getVersion()); FileUtils.write(buildFile, template); } // write android sdk location to local.properties if (!robovmDir.isEmpty()) { final File localProps = new File(project.getBasePath() + "/local.properties"); try (FileWriter writer = new FileWriter(localProps)) { writer.write("sdk.dir=" + RoboVmPlugin.getBestAndroidSdkDir().getAbsolutePath().replace('\\', '/')); } } } else if (buildSystem == BuildSystem.Maven) { String template = IOUtils.toString(RoboVmModuleBuilder.class.getResource("/pom.xml"), "UTF-8"); template = template.replaceAll(ROBOVM_VERSION_PLACEHOLDER, Version.getVersion()); template = template.replaceAll(PACKAGE_NAME_PLACEHOLDER, packageName); template = template.replaceAll(APP_NAME_PLACEHOLDER, mainClassName); File buildFile = new File(project.getBasePath() + "/pom.xml"); FileUtils.write(buildFile, template); } } catch (IOException e) { RoboVmPlugin.logError(project, "Couldn't create build system file %s", new File(project.getBasePath() + "/" + robovmDir + "/build.gradle").getAbsolutePath()); } RoboVmPlugin.logInfo(project, "Project created in %s", project.getBasePath()); } private void applyBuildSystem(final Project project) { if (buildSystem == BuildSystem.Gradle) { File baseDir = VfsUtilCore.virtualToIoFile(project.getBaseDir()); File[] files = baseDir.listFiles(new FilenameFilter() { public boolean accept(File dir, String name) { return FileUtil.namesEqual("build.gradle", name); } }); if (files != null && files.length != 0) { project.putUserData(ExternalSystemDataKeys.NEWLY_CREATED_PROJECT, Boolean.TRUE); ProjectDataManager projectDataManager = (ProjectDataManager) ServiceManager .getService(ProjectDataManager.class); GradleProjectImportBuilder gradleProjectImportBuilder = new GradleProjectImportBuilder( projectDataManager); gradleProjectImportBuilder.getControl(project).getProjectSettings() .setDistributionType(DistributionType.WRAPPED); GradleProjectImportProvider gradleProjectImportProvider = new GradleProjectImportProvider( gradleProjectImportBuilder); AddModuleWizard wizard = new AddModuleWizard((Project) null, files[0].getPath(), new ProjectImportProvider[] { gradleProjectImportProvider }); if (wizard.getStepCount() <= 0 || wizard.showAndGet()) { ImportModuleAction.createFromWizard(project, wizard); ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { ModifiableModuleModel modifiableModel = ModuleManager.getInstance(project).getModifiableModel(); for (Module module : modifiableModel.getModules()) { try { LanguageLevelModuleExtensionImpl langModel = (LanguageLevelModuleExtensionImpl) LanguageLevelModuleExtensionImpl.getInstance(module).getModifiableModel(true); langModel.setLanguageLevel(LanguageLevel.JDK_1_8); langModel.commit(); } catch(Throwable t) { // could be a non-Java project t.printStackTrace(); } } modifiableModel.commit(); } }); } } } else { FileDocumentManager.getInstance().saveAllDocuments(); MavenProjectsManager.getInstance(project).forceUpdateAllProjectsOrFindAllAvailablePomFiles(); } } public void setApplicationId(String applicationId) { this.appId = applicationId; } public void setApplicationName(String applicationName) { this.appName = applicationName; } public void setPackageName(String packageName) { this.packageName = packageName; } public void setMainClassName(String mainClassName) { this.mainClassName = mainClassName; } public void setBuildSystem(BuildSystem buildSystem) { this.buildSystem = buildSystem; } public static enum BuildSystem { Gradle, Maven, None } }