/** * 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()); } }