blob: 669ea1fb12b2b65f75d2b9c229bef40b101337ff [file] [log] [blame]
/*
* Copyright 2000-2012 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 com.intellij.ide.util.projectWizard.importSources.impl;
import com.intellij.icons.AllIcons;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.util.importProject.LibraryDescriptor;
import com.intellij.ide.util.importProject.ModuleDescriptor;
import com.intellij.ide.util.importProject.ModuleInsight;
import com.intellij.ide.util.importProject.ProjectDescriptor;
import com.intellij.ide.util.newProjectWizard.modes.ImportImlMode;
import com.intellij.ide.util.projectWizard.ExistingModuleLoader;
import com.intellij.ide.util.projectWizard.ModuleBuilder;
import com.intellij.ide.util.projectWizard.WizardContext;
import com.intellij.ide.util.projectWizard.importSources.*;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.module.*;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.SdkTypeId;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTable;
import com.intellij.openapi.roots.ui.configuration.DefaultModulesProvider;
import com.intellij.openapi.roots.ui.configuration.ModulesProvider;
import com.intellij.openapi.roots.ui.configuration.projectRoot.LibrariesContainer;
import com.intellij.openapi.roots.ui.configuration.projectRoot.LibrariesContainerFactory;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.packaging.artifacts.ModifiableArtifactModel;
import com.intellij.projectImport.ProjectImportBuilder;
import com.intellij.util.containers.MultiMap;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.util.*;
/**
* @author Eugene Zhuravlev
* Date: Jul 17, 2007
*/
public class ProjectFromSourcesBuilderImpl extends ProjectImportBuilder implements ProjectFromSourcesBuilder {
private static final Logger LOG = Logger.getInstance("#com.intellij.ide.util.projectWizard.importSources.impl.ProjectFromSourcesBuilderImpl");
private static final String NAME = "Existing Sources";
private String myBaseProjectPath;
private final List<ProjectConfigurationUpdater> myUpdaters = new ArrayList<ProjectConfigurationUpdater>();
private final Map<ProjectStructureDetector, ProjectDescriptor> myProjectDescriptors = new LinkedHashMap<ProjectStructureDetector, ProjectDescriptor>();
private MultiMap<ProjectStructureDetector, DetectedProjectRoot> myRoots = MultiMap.emptyInstance();
private final WizardContext myContext;
private final ModulesProvider myModulesProvider;
private Set<String> myModuleNames;
private Set<String> myProjectLibrariesNames;
public ProjectFromSourcesBuilderImpl(WizardContext context, ModulesProvider modulesProvider) {
myContext = context;
myModulesProvider = modulesProvider;
for (ProjectStructureDetector detector : ProjectStructureDetector.EP_NAME.getExtensions()) {
myProjectDescriptors.put(detector, new ProjectDescriptor());
}
}
@NotNull
@Override
public Set<String> getExistingModuleNames() {
if (myModuleNames == null) {
myModuleNames = new HashSet<String>();
for (Module module : myModulesProvider.getModules()) {
myModuleNames.add(module.getName());
}
}
return myModuleNames;
}
@NotNull
@Override
public Set<String> getExistingProjectLibraryNames() {
if (myProjectLibrariesNames == null) {
myProjectLibrariesNames = new HashSet<String>();
final LibrariesContainer container = LibrariesContainerFactory.createContainer(myContext, myModulesProvider);
for (Library library : container.getLibraries(LibrariesContainer.LibraryLevel.PROJECT)) {
myProjectLibrariesNames.add(library.getName());
}
}
return myProjectLibrariesNames;
}
@NotNull
@Override
public WizardContext getContext() {
return myContext;
}
public void setBaseProjectPath(final String contentRootPath) {
myBaseProjectPath = contentRootPath;
}
@Override
public String getBaseProjectPath() {
return myBaseProjectPath;
}
public void setupProjectStructure(MultiMap<ProjectStructureDetector, DetectedProjectRoot> roots) {
myRoots = roots;
for (ProjectStructureDetector detector : roots.keySet()) {
detector.setupProjectStructure(roots.get(detector), getProjectDescriptor(detector), this);
}
}
@NotNull
@Override
public Collection<DetectedProjectRoot> getProjectRoots(@NotNull ProjectStructureDetector detector) {
return myRoots.get(detector);
}
@NotNull
@Override
public String getName() {
return NAME;
}
@Override
public Icon getIcon() {
return AllIcons.Nodes.Folder;
}
@Override
public List getList() {
return null;
}
@Override
public boolean isMarked(Object element) {
return false;
}
@Override
public void setList(List list) throws ConfigurationException {
}
@Override
public void setOpenProjectSettingsAfter(boolean on) {
}
public void setFileToImport(String path) {
setBaseProjectPath(path);
}
public List<Module> commit(final Project project, final ModifiableModuleModel model, final ModulesProvider modulesProvider) {
final boolean fromProjectStructure = model != null;
ModifiableModelsProvider modelsProvider = new IdeaModifiableModelsProvider();
final LibraryTable.ModifiableModel projectLibraryTable = modelsProvider.getLibraryTableModifiableModel(project);
final Map<LibraryDescriptor, Library> projectLibs = new HashMap<LibraryDescriptor, Library>();
final List<Module> result = new ArrayList<Module>();
try {
AccessToken token = WriteAction.start();
try {
// create project-level libraries
for (ProjectDescriptor projectDescriptor : getSelectedDescriptors()) {
for (LibraryDescriptor lib : projectDescriptor.getLibraries()) {
final Collection<File> files = lib.getJars();
final Library projectLib = projectLibraryTable.createLibrary(lib.getName());
final Library.ModifiableModel libraryModel = projectLib.getModifiableModel();
for (File file : files) {
libraryModel.addRoot(VfsUtil.getUrlForLibraryRoot(file), OrderRootType.CLASSES);
}
libraryModel.commit();
projectLibs.put(lib, projectLib);
}
}
if (!fromProjectStructure) {
projectLibraryTable.commit();
}
}
finally {
token.finish();
}
}
catch (Exception e) {
LOG.info(e);
Messages.showErrorDialog(IdeBundle.message("error.adding.module.to.project", e.getMessage()), IdeBundle.message("title.add.module"));
}
final Map<ModuleDescriptor, Module> descriptorToModuleMap = new HashMap<ModuleDescriptor, Module>();
try {
AccessToken token = WriteAction.start();
try {
final ModifiableModuleModel moduleModel = fromProjectStructure ? model : ModuleManager.getInstance(project).getModifiableModel();
for (ProjectDescriptor descriptor : getSelectedDescriptors()) {
for (final ModuleDescriptor moduleDescriptor : descriptor.getModules()) {
final Module module;
if (moduleDescriptor.isReuseExistingElement()) {
final ExistingModuleLoader moduleLoader =
ImportImlMode.setUpLoader(FileUtil.toSystemIndependentName(moduleDescriptor.computeModuleFilePath()));
module = moduleLoader.createModule(moduleModel);
}
else {
module = createModule(descriptor, moduleDescriptor, projectLibs, moduleModel);
}
result.add(module);
descriptorToModuleMap.put(moduleDescriptor, module);
}
}
if (!fromProjectStructure) {
moduleModel.commit();
}
}
finally {
token.finish();
}
}
catch (Exception e) {
LOG.info(e);
Messages.showErrorDialog(IdeBundle.message("error.adding.module.to.project", e.getMessage()), IdeBundle.message("title.add.module"));
}
// setup dependencies between modules
try {
AccessToken token = WriteAction.start();
try {
for (ProjectDescriptor data : getSelectedDescriptors()) {
for (final ModuleDescriptor descriptor : data.getModules()) {
final Module module = descriptorToModuleMap.get(descriptor);
if (module == null) {
continue;
}
final Set<ModuleDescriptor> deps = descriptor.getDependencies();
if (deps.size() == 0) {
continue;
}
final ModifiableRootModel rootModel = ModuleRootManager.getInstance(module).getModifiableModel();
for (ModuleDescriptor dependentDescriptor : deps) {
final Module dependentModule = descriptorToModuleMap.get(dependentDescriptor);
if (dependentModule != null) {
rootModel.addModuleOrderEntry(dependentModule);
}
}
rootModel.commit();
}
}
}
finally {
token.finish();
}
}
catch (Exception e) {
LOG.info(e);
Messages.showErrorDialog(IdeBundle.message("error.adding.module.to.project", e.getMessage()), IdeBundle.message("title.add.module"));
}
AccessToken token = WriteAction.start();
try {
ModulesProvider updatedModulesProvider = fromProjectStructure ? modulesProvider : new DefaultModulesProvider(project);
for (ProjectConfigurationUpdater updater : myUpdaters) {
updater.updateProject(project, modelsProvider, updatedModulesProvider);
}
}
finally {
token.finish();
}
return result;
}
@Nullable
@Override
public List<Module> commit(Project project,
ModifiableModuleModel model,
ModulesProvider modulesProvider,
ModifiableArtifactModel artifactModel) {
return commit(project, model, modulesProvider);
}
public Collection<ProjectDescriptor> getSelectedDescriptors() {
return myProjectDescriptors.values();
}
public void addConfigurationUpdater(ProjectConfigurationUpdater updater) {
myUpdaters.add(updater);
}
public boolean hasRootsFromOtherDetectors(ProjectStructureDetector thisDetector) {
for (ProjectStructureDetector projectStructureDetector : Extensions.getExtensions(ProjectStructureDetector.EP_NAME)) {
if (projectStructureDetector != thisDetector && !getProjectRoots(projectStructureDetector).isEmpty()) {
return true;
}
}
return false;
}
@Override
public void setupModulesByContentRoots(ProjectDescriptor projectDescriptor, Collection<DetectedProjectRoot> roots) {
if (projectDescriptor.getModules().isEmpty()) {
List<ModuleDescriptor> modules = new ArrayList<ModuleDescriptor>();
for (DetectedProjectRoot root : roots) {
if (root instanceof DetectedContentRoot) {
modules.add(new ModuleDescriptor(root.getDirectory(), ((DetectedContentRoot)root).getModuleType(), Collections.<DetectedSourceRoot>emptyList()));
}
}
projectDescriptor.setModules(modules);
}
}
@NotNull
private static Module createModule(ProjectDescriptor projectDescriptor, final ModuleDescriptor descriptor,
final Map<LibraryDescriptor, Library> projectLibs, final ModifiableModuleModel moduleModel)
throws InvalidDataException, IOException, ModuleWithNameAlreadyExists, JDOMException, ConfigurationException {
final String moduleFilePath = descriptor.computeModuleFilePath();
ModuleBuilder.deleteModuleFile(moduleFilePath);
final Module module = moduleModel.newModule(moduleFilePath, descriptor.getModuleType().getId());
final ModifiableRootModel modifiableModel = ModuleRootManager.getInstance(module).getModifiableModel();
setupRootModel(projectDescriptor, descriptor, modifiableModel, projectLibs);
descriptor.updateModuleConfiguration(module, modifiableModel);
modifiableModel.commit();
return module;
}
private static void setupRootModel(ProjectDescriptor projectDescriptor, final ModuleDescriptor descriptor,
final ModifiableRootModel rootModel, final Map<LibraryDescriptor, Library> projectLibs) {
final CompilerModuleExtension compilerModuleExtension = rootModel.getModuleExtension(CompilerModuleExtension.class);
compilerModuleExtension.setExcludeOutput(true);
rootModel.inheritSdk();
final Set<File> contentRoots = descriptor.getContentRoots();
for (File contentRoot : contentRoots) {
final LocalFileSystem lfs = LocalFileSystem.getInstance();
VirtualFile moduleContentRoot = lfs.refreshAndFindFileByPath(FileUtil.toSystemIndependentName(contentRoot.getPath()));
if (moduleContentRoot != null) {
final ContentEntry contentEntry = rootModel.addContentEntry(moduleContentRoot);
final Collection<DetectedSourceRoot> sourceRoots = descriptor.getSourceRoots(contentRoot);
for (DetectedSourceRoot srcRoot : sourceRoots) {
final String srcpath = FileUtil.toSystemIndependentName(srcRoot.getDirectory().getPath());
final VirtualFile sourceRoot = lfs.refreshAndFindFileByPath(srcpath);
if (sourceRoot != null) {
contentEntry.addSourceFolder(sourceRoot, shouldBeTestRoot(srcRoot.getDirectory()), getPackagePrefix(srcRoot));
}
}
}
}
compilerModuleExtension.inheritCompilerOutputPath(true);
final LibraryTable moduleLibraryTable = rootModel.getModuleLibraryTable();
for (LibraryDescriptor libDescriptor : ModuleInsight.getLibraryDependencies(descriptor, projectDescriptor.getLibraries())) {
final Library projectLib = projectLibs.get(libDescriptor);
if (projectLib != null) {
rootModel.addLibraryEntry(projectLib);
}
else {
// add as module library
final Collection<File> jars = libDescriptor.getJars();
for (File file : jars) {
Library library = moduleLibraryTable.createLibrary();
Library.ModifiableModel modifiableModel = library.getModifiableModel();
modifiableModel.addRoot(VfsUtil.getUrlForLibraryRoot(file), OrderRootType.CLASSES);
modifiableModel.commit();
}
}
}
}
public static String getPackagePrefix(final DetectedSourceRoot srcRoot) {
return srcRoot.getPackagePrefix();
}
@NotNull
@Override
public ProjectDescriptor getProjectDescriptor(@NotNull ProjectStructureDetector detector) {
return myProjectDescriptors.get(detector);
}
private static boolean shouldBeTestRoot(final File srcRoot) {
if (isTestRootName(srcRoot.getName())) {
return true;
}
final File parentFile = srcRoot.getParentFile();
return parentFile != null && isTestRootName(parentFile.getName());
}
private static boolean isTestRootName(final String name) {
return "test".equalsIgnoreCase(name) ||
"tests".equalsIgnoreCase(name) ||
"testSource".equalsIgnoreCase(name) ||
"testSources".equalsIgnoreCase(name) ||
"testSrc".equalsIgnoreCase(name);
}
public interface ProjectConfigurationUpdater {
void updateProject(@NotNull Project project, @NotNull ModifiableModelsProvider modelsProvider, @NotNull ModulesProvider modulesProvider);
}
@Override
public boolean isSuitableSdkType(final SdkTypeId sdkTypeId) {
for (ProjectDescriptor projectDescriptor : getSelectedDescriptors()) {
for (ModuleDescriptor moduleDescriptor : projectDescriptor.getModules()) {
try {
final ModuleType moduleType = getModuleType(moduleDescriptor);
if (moduleType != null && !moduleType.createModuleBuilder().isSuitableSdkType(sdkTypeId)) return false;
}
catch (Exception ignore) {
}
}
}
return true;
}
@Nullable
private static ModuleType getModuleType(ModuleDescriptor moduleDescriptor) throws InvalidDataException, JDOMException, IOException {
if (moduleDescriptor.isReuseExistingElement()) {
final File file = new File(moduleDescriptor.computeModuleFilePath());
if (file.exists()) {
final Element rootElement = JDOMUtil.loadDocument(file).getRootElement();
final String type = rootElement.getAttributeValue("type");
if (type != null) {
return ModuleTypeManager.getInstance().findByID(type);
}
}
return null;
}
else {
return moduleDescriptor.getModuleType();
}
}
}