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