blob: f78347298ce858291aa14ff7be3395103f391c6d [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.conversion.impl;
import com.intellij.application.options.PathMacrosImpl;
import com.intellij.application.options.ReplacePathToMacroMap;
import com.intellij.conversion.*;
import com.intellij.ide.highlighter.ProjectFileType;
import com.intellij.ide.highlighter.WorkspaceFileType;
import com.intellij.ide.impl.convert.JDomConvertingUtil;
import com.intellij.ide.impl.convert.ProjectFileVersionImpl;
import com.intellij.ide.impl.convert.ProjectFileVersionState;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.components.ExpandMacroToPathMap;
import com.intellij.openapi.components.StorageScheme;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.impl.ModuleManagerImpl;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.impl.libraries.LibraryImpl;
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.util.ArrayUtil;
import com.intellij.util.PathUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.xmlb.XmlSerializer;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.model.serialization.JDomSerializationUtil;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.*;
/**
* @author nik
*/
public class ConversionContextImpl implements ConversionContext {
private static final Logger LOG = Logger.getInstance("#com.intellij.conversion.impl.ConversionContextImpl");
private final Map<File, SettingsXmlFile> mySettingsFiles = new HashMap<File, SettingsXmlFile>();
private final StorageScheme myStorageScheme;
private final File myProjectBaseDir;
private final File myProjectFile;
private final File myWorkspaceFile;
private final File[] myModuleFiles;
private ProjectSettingsImpl myProjectSettings;
private WorkspaceSettingsImpl myWorkspaceSettings;
private final List<File> myNonExistingModuleFiles = new ArrayList<File>();
private final Map<File, ModuleSettingsImpl> myFile2ModuleSettings = new HashMap<File, ModuleSettingsImpl>();
private final Map<String, ModuleSettingsImpl> myName2ModuleSettings = new HashMap<String, ModuleSettingsImpl>();
private RunManagerSettingsImpl myRunManagerSettings;
private File mySettingsBaseDir;
private ComponentManagerSettings myCompilerManagerSettings;
private ComponentManagerSettings myProjectRootManagerSettings;
private ComponentManagerSettingsImpl myModulesSettings;
private ProjectLibrariesSettingsImpl myProjectLibrariesSettings;
private ArtifactsSettingsImpl myArtifactsSettings;
private ComponentManagerSettings myProjectFileVersionSettings;
private final Set<String> myPerformedConversionIds;
public ConversionContextImpl(String projectPath) throws CannotConvertException {
myProjectFile = new File(projectPath);
File modulesFile;
if (myProjectFile.isDirectory()) {
myStorageScheme = StorageScheme.DIRECTORY_BASED;
myProjectBaseDir = myProjectFile;
mySettingsBaseDir = new File(myProjectBaseDir.getAbsolutePath(), Project.DIRECTORY_STORE_FOLDER);
modulesFile = new File(mySettingsBaseDir, "modules.xml");
myWorkspaceFile = new File(mySettingsBaseDir, "workspace.xml");
}
else {
myStorageScheme = StorageScheme.DEFAULT;
myProjectBaseDir = myProjectFile.getParentFile();
modulesFile = myProjectFile;
myWorkspaceFile = new File(StringUtil.trimEnd(projectPath, ProjectFileType.DOT_DEFAULT_EXTENSION) + WorkspaceFileType.DOT_DEFAULT_EXTENSION);
}
myModuleFiles = modulesFile.exists() ? findModuleFiles(JDomConvertingUtil.loadDocument(modulesFile).getRootElement()) : new File[0];
myPerformedConversionIds = loadPerformedConversionIds();
}
public Set<File> getAllProjectFiles() {
final HashSet<File> files = new HashSet<File>(Arrays.asList(myModuleFiles));
if (myStorageScheme == StorageScheme.DEFAULT) {
files.add(myProjectFile);
files.add(myWorkspaceFile);
}
else {
addFilesRecursively(mySettingsBaseDir, files);
}
return files;
}
private static void addFilesRecursively(File file, Set<File> files) {
if (file.isDirectory()) {
final File[] children = file.listFiles();
if (children != null) {
for (File child : children) {
addFilesRecursively(child, files);
}
}
}
else if (StringUtil.endsWithIgnoreCase(file.getName(), ".xml") && !file.getName().startsWith(".")) {
files.add(file);
}
}
public boolean isConversionAlreadyPerformed(ConverterProvider provider) {
return myPerformedConversionIds.contains(provider.getId());
}
@Override
@NotNull
public File getProjectBaseDir() {
return myProjectBaseDir;
}
@Override
public File[] getModuleFiles() {
return myModuleFiles;
}
private File[] findModuleFiles(final Element root) {
final Element modulesManager = JDomSerializationUtil.findComponent(root, ModuleManagerImpl.COMPONENT_NAME);
if (modulesManager == null) return new File[0];
final Element modules = modulesManager.getChild(ModuleManagerImpl.ELEMENT_MODULES);
if (modules == null) return new File[0];
final ExpandMacroToPathMap macros = createExpandMacroMap();
List<File> files = new ArrayList<File>();
for (Element module : JDOMUtil.getChildren(modules, ModuleManagerImpl.ELEMENT_MODULE)) {
String filePath = module.getAttributeValue(ModuleManagerImpl.ATTRIBUTE_FILEPATH);
filePath = macros.substitute(filePath, true);
files.add(new File(FileUtil.toSystemDependentName(filePath)));
}
return files.toArray(new File[files.size()]);
}
@NotNull
public String expandPath(@NotNull String path, @NotNull ModuleSettingsImpl moduleSettings) {
return createExpandMacroMap(moduleSettings).substitute(path, true);
}
private ExpandMacroToPathMap createExpandMacroMap(@Nullable ModuleSettingsImpl moduleSettings) {
final ExpandMacroToPathMap map = createExpandMacroMap();
if (moduleSettings != null) {
final String modulePath = FileUtil.toSystemIndependentName(moduleSettings.getModuleFile().getParentFile().getAbsolutePath());
map.addMacroExpand(PathMacrosImpl.MODULE_DIR_MACRO_NAME, modulePath);
}
return map;
}
@Override
@NotNull
public String expandPath(@NotNull String path) {
ExpandMacroToPathMap map = createExpandMacroMap(null);
return map.substitute(path, SystemInfo.isFileSystemCaseSensitive);
}
@Override
@NotNull
public String collapsePath(@NotNull String path) {
ReplacePathToMacroMap map = createCollapseMacroMap(PathMacrosImpl.PROJECT_DIR_MACRO_NAME, myProjectBaseDir);
return map.substitute(path, SystemInfo.isFileSystemCaseSensitive);
}
public static String collapsePath(@NotNull String path, @NotNull ModuleSettingsImpl moduleSettings) {
final ReplacePathToMacroMap map = createCollapseMacroMap(PathMacrosImpl.MODULE_DIR_MACRO_NAME, moduleSettings.getModuleFile().getParentFile());
return map.substitute(path, SystemInfo.isFileSystemCaseSensitive);
}
private static ReplacePathToMacroMap createCollapseMacroMap(final String macroName, final File dir) {
ReplacePathToMacroMap map = new ReplacePathToMacroMap();
map.addMacroReplacement(FileUtil.toSystemIndependentName(dir.getAbsolutePath()), macroName);
PathMacrosImpl.getInstanceEx().addMacroReplacements(map);
return map;
}
@Override
public Collection<File> getLibraryClassRoots(@NotNull String name, @NotNull String level) {
try {
Element libraryElement = null;
if (LibraryTablesRegistrar.PROJECT_LEVEL.equals(level)) {
libraryElement = findProjectLibraryElement(name);
}
else if (LibraryTablesRegistrar.APPLICATION_LEVEL.equals(level)) {
libraryElement = findGlobalLibraryElement(name);
}
if (libraryElement != null) {
return getClassRoots(libraryElement, null);
}
return Collections.emptyList();
}
catch (CannotConvertException e) {
return Collections.emptyList();
}
}
@NotNull
public List<File> getClassRoots(Element libraryElement, @Nullable ModuleSettingsImpl moduleSettings) {
List<File> files = new ArrayList<File>();
//todo[nik] support jar directories
final Element classesChild = libraryElement.getChild("CLASSES");
if (classesChild != null) {
final List<Element> roots = JDOMUtil.getChildren(classesChild, "root");
final ExpandMacroToPathMap pathMap = createExpandMacroMap(moduleSettings);
for (Element root : roots) {
final String url = root.getAttributeValue("url");
final String path = VfsUtilCore.urlToPath(url);
files.add(new File(PathUtil.getLocalPath(pathMap.substitute(path, true))));
}
}
return files;
}
@Override
public ComponentManagerSettings getCompilerSettings() {
if (myCompilerManagerSettings == null) {
myCompilerManagerSettings = createProjectSettings("compiler.xml");
}
return myCompilerManagerSettings;
}
@Override
public ComponentManagerSettings getProjectRootManagerSettings() {
if (myProjectRootManagerSettings == null) {
myProjectRootManagerSettings = createProjectSettings("misc.xml");
}
return myProjectRootManagerSettings;
}
@Override
public ComponentManagerSettings getModulesSettings() {
if (myModulesSettings == null) {
myModulesSettings = createProjectSettings("modules.xml");
}
return myModulesSettings;
}
@Nullable
public ComponentManagerSettings getProjectFileVersionSettings() {
if (myProjectFileVersionSettings == null) {
myProjectFileVersionSettings = createProjectSettings("misc.xml");
}
return myProjectFileVersionSettings;
}
@Override
@Nullable
public ComponentManagerSettingsImpl createProjectSettings(@NotNull final String fileName) {
try {
File file;
if (myStorageScheme == StorageScheme.DEFAULT) {
file = myProjectFile;
}
else {
file = new File(mySettingsBaseDir, fileName);
}
return new ComponentManagerSettingsImpl(file, this);
}
catch (CannotConvertException e) {
LOG.info(e);
return null;
}
}
@Nullable
private static Element findGlobalLibraryElement(String name) throws CannotConvertException {
final File file = PathManager.getOptionsFile("applicationLibraries");
if (file.exists()) {
final Element root = JDomConvertingUtil.loadDocument(file).getRootElement();
final Element libraryTable = JDomSerializationUtil.findComponent(root, "libraryTable");
if (libraryTable != null) {
return findLibraryInTable(libraryTable, name);
}
}
return null;
}
@Nullable
private Element findProjectLibraryElement(String name) throws CannotConvertException {
final Collection<? extends Element> libraries = getProjectLibrariesSettings().getProjectLibraries();
final Condition<Element> filter = JDomConvertingUtil.createElementWithAttributeFilter(LibraryImpl.ELEMENT,
LibraryImpl.LIBRARY_NAME_ATTR, name);
return ContainerUtil.find(libraries, filter);
}
@Nullable
private static Element findLibraryInTable(Element tableElement, String name) {
final Condition<Element> filter = JDomConvertingUtil.createElementWithAttributeFilter(LibraryImpl.ELEMENT,
LibraryImpl.LIBRARY_NAME_ATTR, name);
return JDomConvertingUtil.findChild(tableElement, filter);
}
private ExpandMacroToPathMap createExpandMacroMap() {
final ExpandMacroToPathMap macros = new ExpandMacroToPathMap();
final String projectDir = FileUtil.toSystemIndependentName(myProjectBaseDir.getAbsolutePath());
macros.addMacroExpand(PathMacrosImpl.PROJECT_DIR_MACRO_NAME, projectDir);
PathMacrosImpl.getInstanceEx().addMacroExpands(macros);
return macros;
}
@Override
public File getSettingsBaseDir() {
return mySettingsBaseDir;
}
@NotNull
@Override
public File getProjectFile() {
return myProjectFile;
}
@Override
public ProjectSettings getProjectSettings() throws CannotConvertException {
if (myProjectSettings == null) {
myProjectSettings = new ProjectSettingsImpl(myProjectFile, this);
}
return myProjectSettings;
}
@Override
public RunManagerSettingsImpl getRunManagerSettings() throws CannotConvertException {
if (myRunManagerSettings == null) {
if (myStorageScheme == StorageScheme.DEFAULT) {
myRunManagerSettings = new RunManagerSettingsImpl(myWorkspaceFile, myProjectFile, null, this);
}
else {
final File[] files = new File(mySettingsBaseDir, "runConfigurations").listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
return !file.isDirectory() && file.getName().endsWith(".xml");
}
});
myRunManagerSettings = new RunManagerSettingsImpl(myWorkspaceFile, null, files, this);
}
}
return myRunManagerSettings;
}
@Override
public WorkspaceSettings getWorkspaceSettings() throws CannotConvertException {
if (myWorkspaceSettings == null) {
myWorkspaceSettings = new WorkspaceSettingsImpl(myWorkspaceFile, this);
}
return myWorkspaceSettings;
}
@Override
public ModuleSettings getModuleSettings(File moduleFile) throws CannotConvertException {
ModuleSettingsImpl settings = myFile2ModuleSettings.get(moduleFile);
if (settings == null) {
settings = new ModuleSettingsImpl(moduleFile, this);
myFile2ModuleSettings.put(moduleFile, settings);
myName2ModuleSettings.put(settings.getModuleName(), settings);
}
return settings;
}
@Override
public ModuleSettings getModuleSettings(@NotNull String moduleName) {
if (!myName2ModuleSettings.containsKey(moduleName)) {
for (File moduleFile : myModuleFiles) {
try {
getModuleSettings(moduleFile);
}
catch (CannotConvertException ignored) {
}
}
}
return myName2ModuleSettings.get(moduleName);
}
public List<File> getNonExistingModuleFiles() {
return myNonExistingModuleFiles;
}
@NotNull
@Override
public StorageScheme getStorageScheme() {
return myStorageScheme;
}
public File getWorkspaceFile() {
return myWorkspaceFile;
}
public void saveFiles(Collection<File> files, List<ConversionRunner> usedRunners) throws IOException {
Set<String> performedConversions = new HashSet<String>();
for (ConversionRunner runner : usedRunners) {
final ConverterProvider provider = runner.getProvider();
if (!provider.canDetermineIfConversionAlreadyPerformedByProjectFiles()) {
performedConversions.add(provider.getId());
}
}
if (!performedConversions.isEmpty()) {
performedConversions.addAll(myPerformedConversionIds);
final ProjectFileVersionState state = new ProjectFileVersionState();
final List<String> performedConversionsList = new ArrayList<String>(performedConversions);
Collections.sort(performedConversionsList, String.CASE_INSENSITIVE_ORDER);
state.setPerformedConversionIds(performedConversionsList);
final ComponentManagerSettings settings = getProjectFileVersionSettings();
if (settings != null) {
final Element element =
JDomSerializationUtil.findOrCreateComponentElement(settings.getRootElement(), ProjectFileVersionImpl.COMPONENT_NAME);
XmlSerializer.serializeInto(state, element);
}
}
for (File file : files) {
final SettingsXmlFile xmlFile = mySettingsFiles.get(file);
if (xmlFile != null) {
xmlFile.save();
}
}
}
private Set<String> loadPerformedConversionIds() {
final ComponentManagerSettings component = getProjectFileVersionSettings();
if (component != null) {
final Element componentElement = component.getComponentElement(ProjectFileVersionImpl.COMPONENT_NAME);
if (componentElement != null) {
Set<String> performedConversionIds = new HashSet<String>();
final ProjectFileVersionState state = XmlSerializer.deserialize(componentElement, ProjectFileVersionState.class);
if (state != null) {
performedConversionIds.addAll(state.getPerformedConversionIds());
}
return performedConversionIds;
}
}
return Collections.emptySet();
}
public SettingsXmlFile getOrCreateFile(File file) throws CannotConvertException {
SettingsXmlFile settingsFile = mySettingsFiles.get(file);
if (settingsFile == null) {
settingsFile = new SettingsXmlFile(file);
mySettingsFiles.put(file, settingsFile);
}
return settingsFile;
}
@Override
public ProjectLibrariesSettingsImpl getProjectLibrariesSettings() throws CannotConvertException {
if (myProjectLibrariesSettings == null) {
myProjectLibrariesSettings = myStorageScheme == StorageScheme.DEFAULT
? new ProjectLibrariesSettingsImpl(myProjectFile, null, this)
: new ProjectLibrariesSettingsImpl(null, getSettingsXmlFiles("libraries"), this);
}
return myProjectLibrariesSettings;
}
@Override
public ArtifactsSettingsImpl getArtifactsSettings() throws CannotConvertException {
if (myArtifactsSettings == null) {
myArtifactsSettings = myStorageScheme == StorageScheme.DEFAULT
? new ArtifactsSettingsImpl(myProjectFile, null, this)
: new ArtifactsSettingsImpl(null, getSettingsXmlFiles("artifacts"), this);
}
return myArtifactsSettings;
}
@NotNull
private File[] getSettingsXmlFiles(@NotNull String dirName) {
final File librariesDir = new File(mySettingsBaseDir, dirName);
return librariesDir.exists() ? librariesDir.listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
return !file.isDirectory() && file.getName().endsWith(".xml");
}
}) : ArrayUtil.EMPTY_FILE_ARRAY;
}
}