package com.intellij.lang.javascript.flex.flashbuilder; import com.intellij.ide.highlighter.ModuleFileType; import com.intellij.ide.util.projectWizard.ModuleBuilder; import com.intellij.lang.javascript.flex.FlexBundle; import com.intellij.lang.javascript.flex.FlexModuleType; import com.intellij.lang.javascript.flex.projectStructure.FlexBuildConfigurationsExtension; import com.intellij.lang.javascript.flex.projectStructure.model.impl.FlexProjectConfigurationEditor; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.ModifiableModuleModel; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.roots.impl.ModifiableModelCommitter; import com.intellij.openapi.roots.ui.configuration.ModulesProvider; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.packaging.artifacts.ModifiableArtifactModel; import com.intellij.projectImport.ProjectImportBuilder; import com.intellij.util.PathUtil; import com.intellij.util.io.ZipUtil; import gnu.trove.THashMap; import gnu.trove.THashSet; import icons.FlexIcons; import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.util.*; public class FlashBuilderImporter extends ProjectImportBuilder<String> { public static final String DOT_PROJECT = ".project"; public static final String DOT_FXP = ".fxp"; public static final String DOT_FXPL = ".fxpl"; public static final String DOT_ZIP = ".zip"; public static final String DOT_ACTION_SCRIPT_PROPERTIES = ".actionScriptProperties"; public static final String DOT_FXP_PROPERTIES = ".fxpProperties"; public static final String DOT_FLEX_PROPERTIES = ".flexProperties"; public static final String DOT_FLEX_LIB_PROPERTIES = ".flexLibProperties"; private Parameters myParameters; public static class Parameters { private String myInitiallySelectedPath = ""; private List<String> myFlashBuilderProjectFilePaths = Collections.emptyList(); private String myExtractPath = ""; private boolean myExtractToSubfolder = false; private boolean myOpenProjectSettingsAfter = false; } public Parameters getParameters() { if (myParameters == null) { myParameters = new Parameters(); } return myParameters; } public void cleanup() { super.cleanup(); myParameters = null; } @NotNull public String getName() { return FlexBundle.message("flash.builder"); } public Icon getIcon() { return FlexIcons.Flex.Flash_builder; } public boolean isMarked(final String element) { return true; } public boolean isOpenProjectSettingsAfter() { return getParameters().myOpenProjectSettingsAfter; } public void setOpenProjectSettingsAfter(boolean openProjectSettingsAfter) { getParameters().myOpenProjectSettingsAfter = openProjectSettingsAfter; } public boolean isExtractToSubfolder() { return getParameters().myExtractToSubfolder; } public void setExtractToSubfolder(final boolean extractToSubfolder) { getParameters().myExtractToSubfolder = extractToSubfolder; } public String getExtractPath() { return getParameters().myExtractPath; } public void setExtractPath(final String extractPath) { getParameters().myExtractPath = extractPath; } public List<String> getList() { return getParameters().myFlashBuilderProjectFilePaths; } public void setList(final List<String> flashBuilderProjectFiles) /*throws ConfigurationException*/ { getParameters().myFlashBuilderProjectFilePaths = flashBuilderProjectFiles; } void setInitiallySelectedPath(final String dirPath) { getParameters().myInitiallySelectedPath = dirPath; } String getInitiallySelectedPath() { return getParameters().myInitiallySelectedPath; } public String getSuggestedProjectName() { final String path = getInitiallySelectedPath(); final VirtualFile file = path.isEmpty() ? null : LocalFileSystem.getInstance().findFileByPath(path); if (file == null) { return PathUtil.getFileName(path); } if (file.isDirectory()) { final VirtualFile dotProjectFile = file.findChild(DOT_PROJECT); if (dotProjectFile != null && FlashBuilderProjectFinder.isFlashBuilderProject(dotProjectFile)) { return FlashBuilderProjectLoadUtil.readProjectName(dotProjectFile.getPath()); } } else if (FlashBuilderProjectFinder.hasArchiveExtension(path)) { return file.getNameWithoutExtension(); } if (DOT_PROJECT.equalsIgnoreCase(file.getName())) { return FlashBuilderProjectLoadUtil.readProjectName(file.getPath()); } return PathUtil.getFileName(path); } public List<Module> commit(final Project project, final ModifiableModuleModel model, final ModulesProvider modulesProvider, final ModifiableArtifactModel artifactModel) { //FlexModuleBuilder.setupResourceFilePatterns(project); final boolean needToCommit = model == null; final ModifiableModuleModel moduleModel = model != null ? model : ModuleManager.getInstance(project).getModifiableModel(); final List<String> paths = getList(); final boolean isArchive = paths.size() == 1 && FlashBuilderProjectFinder.hasArchiveExtension(paths.get(0)); final List<String> dotProjectPaths = getDotProjectPaths(project); final List<FlashBuilderProject> flashBuilderProjects = FlashBuilderProjectLoadUtil.loadProjects(dotProjectPaths, isArchive); final Map<FlashBuilderProject, ModifiableRootModel> flashBuilderProjectToModifiableModelMap = new THashMap<>(); final Map<Module, ModifiableRootModel> moduleToModifiableModelMap = new THashMap<>(); final Set<String> moduleNames = new THashSet<>(flashBuilderProjects.size()); final FlexProjectConfigurationEditor currentFlexEditor = FlexBuildConfigurationsExtension.getInstance().getConfigurator().getConfigEditor(); assert needToCommit == (currentFlexEditor == null); for (FlashBuilderProject flashBuilderProject : flashBuilderProjects) { final String moduleName = makeUnique(flashBuilderProject.getName(), moduleNames); moduleNames.add(moduleName); final String moduleFilePath = flashBuilderProject.getProjectRootPath() + "/" + moduleName + ModuleFileType.DOT_DEFAULT_EXTENSION; if (LocalFileSystem.getInstance().findFileByPath(moduleFilePath) != null) { ApplicationManager.getApplication().runWriteAction(() -> ModuleBuilder.deleteModuleFile(moduleFilePath)); } final Module module = moduleModel.newModule(moduleFilePath, FlexModuleType.getInstance().getId()); final ModifiableRootModel rootModel = currentFlexEditor != null ? currentFlexEditor.getModifiableRootModel(module) : ModuleRootManager.getInstance(module).getModifiableModel(); flashBuilderProjectToModifiableModelMap.put(flashBuilderProject, rootModel); moduleToModifiableModelMap.put(module, rootModel); } final FlexProjectConfigurationEditor flexConfigEditor = currentFlexEditor != null ? currentFlexEditor : FlexProjectConfigurationEditor .createEditor(project, moduleToModifiableModelMap, null, null); final FlashBuilderSdkFinder sdkFinder = new FlashBuilderSdkFinder(project, getParameters().myInitiallySelectedPath, flashBuilderProjects); final FlashBuilderModuleImporter flashBuilderModuleImporter = new FlashBuilderModuleImporter(project, flexConfigEditor, flashBuilderProjects, sdkFinder); for (final FlashBuilderProject flashBuilderProject : flashBuilderProjects) { flashBuilderModuleImporter.setupModule(flashBuilderProjectToModifiableModelMap.get(flashBuilderProject), flashBuilderProject); } if (needToCommit) { try { flexConfigEditor.commit(); } catch (ConfigurationException e) { Logger.getInstance(FlashBuilderImporter.class).error(e); } ApplicationManager.getApplication().runWriteAction(() -> { ModifiableModelCommitter.multiCommit(moduleToModifiableModelMap.values(), moduleModel); }); } return new ArrayList<>(moduleToModifiableModelMap.keySet()); } private List<String> getDotProjectPaths(final Project project) { final boolean creatingNewProject = !isUpdate(); final List<String> paths = getList(); if (paths.size() == 1 && FlashBuilderProjectFinder.hasArchiveExtension(paths.get(0))) { final List<String> dotProjectFiles = new ArrayList<>(); final boolean multipleProjects = FlashBuilderProjectFinder.isMultiProjectArchive(paths.get(0)); final String basePath = creatingNewProject ? project.getBaseDir().getPath() : getExtractPath(); assert basePath != null; final String extractDir = multipleProjects || isExtractToSubfolder() ? basePath + "/" + FileUtil.getNameWithoutExtension(PathUtil.getFileName(paths.get(0))) : basePath; try { final File outputDir = new File(extractDir); ZipUtil.extract(new File(paths.get(0)), outputDir, null); dotProjectFiles.add(extractDir + "/" + DOT_PROJECT); extractNestedFxpAndAppendProjects(outputDir, dotProjectFiles); ApplicationManager.getApplication().runWriteAction(() -> { for (String dotProjectFile : dotProjectFiles) { final VirtualFile file = LocalFileSystem.getInstance().refreshAndFindFileByPath(PathUtil.getParentPath(dotProjectFile)); if (file != null) { file.refresh(false, true); } } }); } catch (IOException e) { Messages.showErrorDialog(project, FlexBundle.message("failed.to.extract.project", e.getMessage()), FlexBundle.message("open.project.0", PathUtil.getFileName(paths.get(0)))); return Collections.emptyList(); } return dotProjectFiles; } return paths; } private static void extractNestedFxpAndAppendProjects(final File dir, final List<String> dotProjectFiles) throws IOException { final FilenameFilter filter = (dir1, name) -> { final String lowercased = name.toLowerCase(); return lowercased.endsWith(DOT_FXP) || lowercased.endsWith(DOT_FXPL); }; for (File file : dir.listFiles(filter)) { final File extractDir = new File(file.getParentFile().getParentFile(), FileUtil.getNameWithoutExtension(file.getName())); ZipUtil.extract(file, extractDir, null); dotProjectFiles.add(extractDir + "/" + DOT_PROJECT); extractNestedFxpAndAppendProjects(extractDir, dotProjectFiles); } } private static String makeUnique(final String name, final Set<String> moduleNames) { String uniqueName = name; int i = 1; while (moduleNames.contains(uniqueName)) { uniqueName = name + '(' + i++ + ')'; } return uniqueName; } }