/**
* Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Eclipse Public License (EPL).
* Please see the license.txt included with this distribution for details.
* Any modifications to this file must keep this entire header intact.
*/
/*
* Created on Sep 13, 2005
*
* @author Fabio Zadrozny
*/
package com.python.pydev.analysis.additionalinfo;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.python.pydev.core.FileUtilsFileBuffer;
import org.python.pydev.core.IModulesManager;
import org.python.pydev.core.IPythonNature;
import org.python.pydev.core.MisconfigurationException;
import org.python.pydev.core.PythonNatureWithoutProjectException;
import org.python.pydev.core.log.Log;
import org.python.pydev.editor.codecompletion.revisited.ProjectModulesManager;
import org.python.pydev.plugin.PydevPlugin;
import org.python.pydev.plugin.nature.PythonNature;
import org.python.pydev.plugin.nature.SystemPythonNature;
import com.aptana.shared_core.structure.Tuple;
import com.python.pydev.analysis.AnalysisPlugin;
public class AdditionalProjectInterpreterInfo extends AbstractAdditionalInfoWithBuild {
/**
* This is the project that contains this info
*/
private final IProject project;
private final File persistingFolder;
private final File persistingLocation;
/**
* holds nature info (project name points to info)
*/
private final static Map<String, AbstractAdditionalDependencyInfo> additionalNatureInfo = new HashMap<String, AbstractAdditionalDependencyInfo>();
private final static Object additionalNatureInfoLock = new Object();
public IProject getProject() {
return project;
}
/**
* @return the path to the folder we want to keep things on
*/
@Override
protected File getPersistingFolder() {
return persistingFolder;
}
@Override
protected File getPersistingLocation() {
return persistingLocation;
}
public AdditionalProjectInterpreterInfo(IProject project) throws MisconfigurationException {
super(false);
Assert.isNotNull(project);
this.project = project;
File f;
try {
f = AnalysisPlugin.getStorageDirForProject(project);
} catch (NullPointerException e) {
//it may fail in tests... (save it in default folder in this cases)
Log.logInfo("Error getting persisting folder", e);
f = new File(".");
}
persistingFolder = f;
persistingLocation = new File(persistingFolder, "AdditionalProjectInterpreterInfo.pydevinfo");
init();
}
public static List<AbstractAdditionalTokensInfo> getAdditionalInfo(IPythonNature nature)
throws MisconfigurationException {
return getAdditionalInfo(nature, true, false);
}
/**
* @param nature the nature we want to get info on
* @return all the additional info that is bounded with some nature (including related projects)
* @throws MisconfigurationException
*/
public static List<AbstractAdditionalTokensInfo> getAdditionalInfo(IPythonNature nature, boolean addSystemInfo,
boolean addReferencingProjects) throws MisconfigurationException {
List<Tuple<AbstractAdditionalTokensInfo, IPythonNature>> infoAndNature = getAdditionalInfoAndNature(nature,
addSystemInfo, addReferencingProjects);
ArrayList<AbstractAdditionalTokensInfo> ret = new ArrayList<AbstractAdditionalTokensInfo>();
for (Tuple<AbstractAdditionalTokensInfo, IPythonNature> tuple : infoAndNature) {
ret.add(tuple.o1);
}
return ret;
}
public static List<Tuple<AbstractAdditionalTokensInfo, IPythonNature>> getAdditionalInfoAndNature(
IPythonNature nature, boolean addSystemInfo, boolean addReferencingProjects)
throws MisconfigurationException {
return getAdditionalInfoAndNature(nature, addSystemInfo, addReferencingProjects, true);
}
public static List<Tuple<AbstractAdditionalTokensInfo, IPythonNature>> getAdditionalInfoAndNature(
IPythonNature nature, boolean addSystemInfo, boolean addReferencingProjects, boolean addReferencedProjects)
throws MisconfigurationException {
List<Tuple<AbstractAdditionalTokensInfo, IPythonNature>> ret = new ArrayList<Tuple<AbstractAdditionalTokensInfo, IPythonNature>>();
IProject project = nature.getProject();
//get for the system info
if (addSystemInfo) {
AbstractAdditionalTokensInfo systemInfo;
try {
systemInfo = AdditionalSystemInterpreterInfo.getAdditionalSystemInfo(
PydevPlugin.getInterpreterManager(nature), nature.getProjectInterpreter().getExecutableOrJar());
} catch (MisconfigurationException e) {
throw e;
} catch (PythonNatureWithoutProjectException e) {
throw new RuntimeException(e);
}
ret.add(new Tuple<AbstractAdditionalTokensInfo, IPythonNature>(systemInfo, new SystemPythonNature(nature
.getRelatedInterpreterManager())));
}
//get for the current project
if (project != null) {
AbstractAdditionalTokensInfo additionalInfoForProject = getAdditionalInfoForProject(nature);
if (additionalInfoForProject != null) {
ret.add(new Tuple<AbstractAdditionalTokensInfo, IPythonNature>(additionalInfoForProject, nature));
}
try {
if (addReferencedProjects) {
//get for the referenced projects
Set<IProject> referencedProjects = ProjectModulesManager.getReferencedProjects(project);
for (IProject refProject : referencedProjects) {
additionalInfoForProject = getAdditionalInfoForProject(PythonNature.getPythonNature(refProject));
if (additionalInfoForProject != null) {
ret.add(new Tuple<AbstractAdditionalTokensInfo, IPythonNature>(additionalInfoForProject,
PythonNature.getPythonNature(refProject)));
}
}
}
if (addReferencingProjects) {
Set<IProject> referencingProjects = ProjectModulesManager.getReferencingProjects(project);
for (IProject refProject : referencingProjects) {
additionalInfoForProject = getAdditionalInfoForProject(PythonNature.getPythonNature(refProject));
if (additionalInfoForProject != null) {
ret.add(new Tuple<AbstractAdditionalTokensInfo, IPythonNature>(additionalInfoForProject,
PythonNature.getPythonNature(refProject)));
}
}
}
} catch (Exception e) {
Log.log(e);
}
}
return ret;
}
/**
* @param project the project we want to get info on
* @return the additional info for a given project (gotten from the cache with its name)
* @throws MisconfigurationException
*/
public static AbstractAdditionalDependencyInfo getAdditionalInfoForProject(IPythonNature nature)
throws MisconfigurationException {
if (nature == null) {
return null;
}
IProject project = nature.getProject();
if (project == null) {
return null;
}
String name = FileUtilsFileBuffer.getValidProjectName(project);
synchronized (additionalNatureInfoLock) {
AbstractAdditionalDependencyInfo info = additionalNatureInfo.get(name);
if (info == null) {
info = new AdditionalProjectInterpreterInfo(project);
additionalNatureInfo.put(name, info);
if (!info.load()) {
recreateAllInfo(nature, new NullProgressMonitor());
}
}
return info;
}
}
//interfaces that iterate through all of them
public static List<IInfo> getTokensEqualTo(String qualifier, IPythonNature nature, int getWhat)
throws MisconfigurationException {
ArrayList<IInfo> ret = new ArrayList<IInfo>(50);
List<AbstractAdditionalTokensInfo> additionalInfo = getAdditionalInfo(nature);
for (AbstractAdditionalTokensInfo info : additionalInfo) {
info.getTokensEqualTo(qualifier, getWhat, ret);
}
return ret;
}
public static List<IInfo> getTokensStartingWith(String qualifier, IPythonNature nature, int getWhat)
throws MisconfigurationException {
ArrayList<IInfo> ret = new ArrayList<IInfo>();
List<AbstractAdditionalTokensInfo> additionalInfo = getAdditionalInfo(nature);
for (AbstractAdditionalTokensInfo info : additionalInfo) {
info.getTokensStartingWith(qualifier, getWhat, ret);
}
return ret;
}
/**
* @param project the project we want to get info on
* @return a list of the additional info for the project + referencing projects
* @throws MisconfigurationException
*/
public static List<AbstractAdditionalDependencyInfo> getAdditionalInfoForProjectAndReferencing(IPythonNature nature)
throws MisconfigurationException {
List<AbstractAdditionalDependencyInfo> ret = new ArrayList<AbstractAdditionalDependencyInfo>();
IProject project = nature.getProject();
if (project == null) {
return ret;
}
ret.add(getAdditionalInfoForProject(nature));
Set<IProject> referencingProjects = ProjectModulesManager.getReferencingProjects(project);
for (IProject p : referencingProjects) {
AbstractAdditionalDependencyInfo info2 = getAdditionalInfoForProject(PythonNature.getPythonNature(p));
if (info2 != null) {
ret.add(info2);
}
}
return ret;
}
public static void recreateAllInfo(IPythonNature nature, IProgressMonitor monitor) {
try {
synchronized (additionalNatureInfoLock) {
//Note: at this point we're 100% certain that the ast manager is there.
IModulesManager m = nature.getAstManager().getModulesManager();
IProject project = nature.getProject();
AbstractAdditionalDependencyInfo currInfo = AdditionalProjectInterpreterInfo
.getAdditionalInfoForProject(nature);
if (currInfo != null) {
currInfo.clearAllInfo();
}
String feedback = "(project:" + project.getName() + ")";
synchronized (m) {
AbstractAdditionalDependencyInfo info = (AbstractAdditionalDependencyInfo) restoreInfoForModuleManager(
monitor, m, feedback, new AdditionalProjectInterpreterInfo(project), nature,
nature.getGrammarVersion());
if (info != null) {
//ok, set it and save it
additionalNatureInfo.put(FileUtilsFileBuffer.getValidProjectName(project), info);
info.save();
}
}
}
} catch (Exception e) {
Log.log(e);
throw new RuntimeException(e);
}
}
//Make it available for being in a HashSet.
@Override
public int hashCode() {
return getProject().hashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof AdditionalProjectInterpreterInfo)) {
return false;
}
AdditionalProjectInterpreterInfo additionalProjectInterpreterInfo = (AdditionalProjectInterpreterInfo) obj;
return this.getProject().equals(additionalProjectInterpreterInfo.getProject());
}
}