/****************************************************************************** * Copyright (C) 2011-2013 Fabio Zadrozny and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Fabio Zadrozny <fabiofz@gmail.com> - initial API and implementation * Andrew Ferrazzutti <aferrazz@redhat.com> - ongoing maintenance ******************************************************************************/ package com.python.pydev.analysis.system_info_builder; import java.util.List; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.python.pydev.core.IInterpreterManager; import org.python.pydev.core.IModulesManager; import org.python.pydev.core.IPythonNature; import org.python.pydev.core.ISystemModulesManager; import org.python.pydev.core.MisconfigurationException; import org.python.pydev.core.ModulesKey; import org.python.pydev.core.log.Log; import org.python.pydev.editor.codecompletion.revisited.ModulesFoundStructure; import org.python.pydev.editor.codecompletion.revisited.ModulesManager; import org.python.pydev.editor.codecompletion.revisited.PyPublicTreeMap; import org.python.pydev.editor.codecompletion.revisited.PythonPathHelper; import org.python.pydev.editor.codecompletion.revisited.SystemModulesManager; import org.python.pydev.logging.DebugSettings; import org.python.pydev.shared_core.string.StringUtils; import org.python.pydev.shared_core.structure.Tuple; import org.python.pydev.ui.pythonpathconf.IInterpreterInfoBuilder; import org.python.pydev.ui.pythonpathconf.InterpreterInfo; import com.python.pydev.analysis.additionalinfo.AbstractAdditionalDependencyInfo; import com.python.pydev.analysis.additionalinfo.AdditionalProjectInterpreterInfo; import com.python.pydev.analysis.additionalinfo.AdditionalSystemInterpreterInfo; /** * @author fabioz */ public class InterpreterInfoBuilder implements IInterpreterInfoBuilder { public BuilderResult syncInfoToPythonPath(IProgressMonitor monitor, IPythonNature nature) { PythonPathHelper pythonPathHelper = (PythonPathHelper) nature.getAstManager().getModulesManager() .getPythonPathHelper(); if (pythonPathHelper == null) { return BuilderResult.OK; } AbstractAdditionalDependencyInfo additionalInfo; try { additionalInfo = AdditionalProjectInterpreterInfo.getAdditionalInfoForProject(nature); IModulesManager modulesManager = nature.getAstManager().getModulesManager(); return this.syncInfoToPythonPath(monitor, pythonPathHelper, additionalInfo, modulesManager, null); } catch (MisconfigurationException e) { Log.log(e); return BuilderResult.OK; } } @Override public BuilderResult syncInfoToPythonPath(IProgressMonitor monitor, InterpreterInfo info) { PythonPathHelper pythonPathHelper = new PythonPathHelper(); pythonPathHelper.setPythonPath(info.libs); ISystemModulesManager modulesManager = info.getModulesManager(); IInterpreterManager manager = modulesManager.getInterpreterManager(); AbstractAdditionalDependencyInfo additionalInfo; try { additionalInfo = AdditionalSystemInterpreterInfo.getAdditionalSystemInfo( manager, info.getExecutableOrJar()); } catch (MisconfigurationException e) { Log.log(e); return BuilderResult.OK; } return this.syncInfoToPythonPath(monitor, pythonPathHelper, additionalInfo, modulesManager, info); } public BuilderResult syncInfoToPythonPath(IProgressMonitor monitor, PythonPathHelper pythonPathHelper, AbstractAdditionalDependencyInfo additionalInfo, IModulesManager modulesManager, InterpreterInfo info) { if (monitor == null) { monitor = new NullProgressMonitor(); } if (DebugSettings.DEBUG_INTERPRETER_AUTO_UPDATE) { Log.toLogFile(this, "--- Start run"); } BuilderResult ret = checkEarlyReturn(monitor, info); if (ret != BuilderResult.OK) { return ret; } ModulesFoundStructure modulesFound = pythonPathHelper.getModulesFoundStructure(null, monitor); ret = checkEarlyReturn(monitor, info); if (ret != BuilderResult.OK) { return ret; } PyPublicTreeMap<ModulesKey, ModulesKey> keysFound = ModulesManager.buildKeysFromModulesFound(monitor, modulesFound); if (DebugSettings.DEBUG_INTERPRETER_AUTO_UPDATE) { Log.toLogFile( this, StringUtils.format("Found: %s modules", keysFound.size())); } ret = checkEarlyReturn(monitor, info); if (ret != BuilderResult.OK) { return ret; } try { if (info != null) { String[] builtins = info.getBuiltins(); //Note: consider builtins at this point: we do this only at this point and not in the regular process //(which would be the dialog where the interpreter is configured) because this can be a slow process //as we have to get the completions for all builtin modules from the shell. if (builtins != null) { for (int i = 0; i < builtins.length; i++) { String name = builtins[i]; final ModulesKey k = new ModulesKey(name, null); //Note that it'll override source modules! keysFound.put(k, k); } } } synchronized (additionalInfo.updateKeysLock) { // Use a lock (if we have more than one builder updating we could get into a racing condition here). // Important: do the diff only after the builtins are added (otherwise the modules manager may become wrong)! Tuple<List<ModulesKey>, List<ModulesKey>> diffModules = modulesManager.diffModules(keysFound); if (diffModules.o1.size() > 0 || diffModules.o2.size() > 0) { if (DebugSettings.DEBUG_INTERPRETER_AUTO_UPDATE) { Log.toLogFile(this, StringUtils.format( "Diff modules. Added: %s Removed: %s", diffModules.o1, diffModules.o2)); } //Update the modules manager itself (just pass all the keys as that should be fast) if (modulesManager instanceof SystemModulesManager) { ((SystemModulesManager) modulesManager).updateKeysAndSave(keysFound); } else { for (ModulesKey newEntry : diffModules.o1) { modulesManager.addModule(newEntry); } modulesManager.removeModules(diffModules.o2); } } additionalInfo.updateKeysIfNeededAndSave(keysFound, info, monitor); } } catch (Exception e) { Log.log(e); } if (DebugSettings.DEBUG_INTERPRETER_AUTO_UPDATE) { Log.toLogFile(this, "--- End Run"); } return BuilderResult.OK; } private BuilderResult checkEarlyReturn(IProgressMonitor monitor, InterpreterInfo info) { if (monitor.isCanceled()) { if (DebugSettings.DEBUG_INTERPRETER_AUTO_UPDATE) { Log.toLogFile(this, "Cancelled"); } return BuilderResult.ABORTED; } if (info != null && !info.getLoadFinished()) { if (DebugSettings.DEBUG_INTERPRETER_AUTO_UPDATE) { Log.toLogFile(this, "Load not finished (rescheduling)"); } Log.log("The interpreter sync was cancelled (scheduling for checking the integrity later on again).\n" + "To prevent any scheduling (at the cost of possible index corruptions),\n" + "uncheck the setting at Preferences > PyDev > Interpreters."); return BuilderResult.MUST_SYNCH_LATER; } return BuilderResult.OK; } }