[Pydev-cvs] org.python.pydev/src/org/python/pydev/plugin/nature PythonNatureStore.java, 1.20, 1.21
Brought to you by:
fabioz
From: Fabio Z. <fa...@us...> - 2008-07-31 01:47:28
|
Update of /cvsroot/pydev/org.python.pydev/src/org/python/pydev/plugin/nature In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31519/src/org/python/pydev/plugin/nature Modified Files: PythonNatureStore.java PythonPathNature.java PythonNature.java Log Message: <li>Fixed NPE when creating editor with no interpreter configured</li> <li>Hyperlink works in the same way that F3 (saves file before search)</li> <li>Fixed problem while navigating pydev package explorer ( https://sourceforge.net/tracker/index.php?func=detail&aid=2008015&group_id=85796&atid=577329 )</li> <li>Applied patch that fixes race condition in PythonNature (thanks to Radim Kubacki)</li> <li><strong>Eclipse 3.4</strong>: Move / rename working</li> Index: PythonNature.java =================================================================== RCS file: /cvsroot/pydev/org.python.pydev/src/org/python/pydev/plugin/nature/PythonNature.java,v retrieving revision 1.66 retrieving revision 1.67 diff -C2 -d -r1.66 -r1.67 *** PythonNature.java 28 Feb 2008 01:44:48 -0000 1.66 --- PythonNature.java 31 Jul 2008 01:47:36 -0000 1.67 *************** *** 11,15 **** --- 11,17 ---- import java.util.ArrayList; import java.util.Arrays; + import java.util.HashMap; import java.util.List; + import java.util.Map; import org.eclipse.core.resources.ICommand; *************** *** 62,76 **** */ protected class RebuildPythonNatureModules extends Job { ! private String paths; ! ! private String defaultSelectedInterpreter; ! ! private PythonNature nature; ! protected RebuildPythonNatureModules(String name, String paths, String defaultSelectedInterpreter, PythonNature nature) { ! super(name); ! this.paths = paths; ! this.defaultSelectedInterpreter = defaultSelectedInterpreter; ! this.nature = nature; } --- 64,77 ---- */ protected class RebuildPythonNatureModules extends Job { ! private String submittedPaths; ! private String submittedInterpreter; ! protected RebuildPythonNatureModules() { ! super("Python Nature: rebuilding modules"); ! } ! ! public synchronized void setParams(String paths, String defaultSelectedInterpreter) { ! submittedPaths = paths; ! submittedInterpreter = defaultSelectedInterpreter; } *************** *** 78,81 **** --- 79,88 ---- protected IStatus run(IProgressMonitor monitorArg) { + String paths, defaultSelectedInterpreter; + synchronized (this) { + paths = submittedPaths; + defaultSelectedInterpreter = submittedInterpreter; + } + try { JobProgressComunicator jobProgressComunicator = new JobProgressComunicator(monitorArg, "Rebuilding modules", IProgressMonitor.UNKNOWN, this); *************** *** 87,91 **** synchronized(tempAstManager){ astManager = tempAstManager; ! tempAstManager.setProject(getProject(), false); //it is a new manager, so, remove all deltas //begins task automatically --- 94,98 ---- synchronized(tempAstManager){ astManager = tempAstManager; ! tempAstManager.setProject(getProject(), PythonNature.this, false); //it is a new manager, so, remove all deltas //begins task automatically *************** *** 96,100 **** for (IInterpreterObserver observer : participants) { try { ! observer.notifyProjectPythonpathRestored(nature, jobProgressComunicator, defaultSelectedInterpreter); } catch (Exception e) { //let's keep it safe --- 103,107 ---- for (IInterpreterObserver observer : participants) { try { ! observer.notifyProjectPythonpathRestored(PythonNature.this, jobProgressComunicator, defaultSelectedInterpreter); } catch (Exception e) { //let's keep it safe *************** *** 108,118 **** initializationFinished = true; ! PythonNatureListenersManager.notifyPythonPathRebuilt(project, nature.pythonPathNature.getCompleteProjectPythonPath(null)); //default //end task jobProgressComunicator.done(); }catch (Exception e) { Log.log(e); - } finally { - rebuildJob = null; } return Status.OK_STATUS; --- 115,123 ---- initializationFinished = true; ! PythonNatureListenersManager.notifyPythonPathRebuilt(project, PythonNature.this.pythonPathNature.getCompleteProjectPythonPath(null)); //default //end task jobProgressComunicator.done(); }catch (Exception e) { Log.log(e); } return Status.OK_STATUS; *************** *** 200,203 **** --- 205,210 ---- return project; } + + private static Map<IProject, Job> jobs = new HashMap<IProject, Job>(); /** *************** *** 206,213 **** * @see org.eclipse.core.resources.IProjectNature#setProject(org.eclipse.core.resources.IProject) */ ! public void setProject(IProject project) { ! this.getStore().setProject(project); ! this.pythonPathNature.setProject(project); ! this.project = project; } --- 213,252 ---- * @see org.eclipse.core.resources.IProjectNature#setProject(org.eclipse.core.resources.IProject) */ ! public void setProject(final IProject project) { ! getStore().setProject(project); ! this.project = project; ! this.pythonPathNature.setProject(project, this); ! ! if(project != null && !initializationStarted && !initializationFinished){ ! synchronized (jobs) { ! Job job = jobs.get(project); ! if(job != null){ ! job.cancel(); ! } ! job = new Job("PyDev: Restoring projects python nature") { ! ! protected IStatus run(IProgressMonitor monitor) { ! try { ! if(monitor.isCanceled()){ ! return Status.OK_STATUS; ! } ! init(null, null, monitor); ! synchronized (jobs) { ! if(jobs.get(project) == this){ ! jobs.remove(project); ! } ! } ! } catch (Throwable t) { ! PydevPlugin.log(t); ! } ! return Status.OK_STATUS; ! } ! ! }; ! jobs.put(project, job); ! job.schedule(250L); //wait to see if we've more than 1 request. ! } ! } ! } *************** *** 248,252 **** try { //we have to remove the project from the pythonpath nature too... ! nature.pythonPathNature.setProject(null); } catch (Exception e) { PydevPlugin.log(e); --- 287,291 ---- try { //we have to remove the project from the pythonpath nature too... ! nature.pythonPathNature.setProject(null, null); } catch (Exception e) { PydevPlugin.log(e); *************** *** 319,323 **** } ! IProjectNature n = project.getNature(PYTHON_NATURE_ID); if (n instanceof PythonNature) { PythonNature nature = (PythonNature) n; --- 358,362 ---- } ! IProjectNature n = getPythonNature(project); if (n instanceof PythonNature) { PythonNature nature = (PythonNature) n; *************** *** 353,424 **** @SuppressWarnings("unchecked") private void init(String version, String projectPythonpath, IProgressMonitor monitor) { ! synchronized (this) { ! if(version != null || projectPythonpath != null){ ! this.getStore().startInit(); ! try { ! if(projectPythonpath != null){ ! this.getPythonPathNature().setProjectSourcePath(projectPythonpath); ! } ! if(version != null){ ! this.setVersion(version); ! } ! } catch (CoreException e) { ! PydevPlugin.log(e); ! }finally{ ! this.getStore().endInit(); ! } ! }else{ ! //Change: 1.3.10: it could be reloaded more than once... (when it shouldn't) ! if(astManager != null){ ! return; //already initialized... ! } ! } ! ! final PythonNature nature = this; ! if (initializationStarted == false) { ! initializationStarted = true; ! ! //Change: 1.3.10: no longer in a Job... should already be called in a job if that's needed. ! ! try { ! astManager = (ICodeCompletionASTManager) ASTManager.loadFromFile(getAstOutputFile()); ! if (astManager != null) { ! synchronized (astManager) { ! astManager.setProject(getProject(), true); // this is the project related to it, restore the deltas (we may have some crash) ! ! //just a little validation so that we restore the needed info if we did not get the modules ! if (astManager.getModulesManager().getOnlyDirectModules().length < 5) { ! astManager = null; ! } ! ! if (astManager != null) { ! List<IInterpreterObserver> participants = ExtensionHelper.getParticipants(ExtensionHelper.PYDEV_INTERPRETER_OBSERVER); ! for (IInterpreterObserver observer : participants) { ! try { ! observer.notifyNatureRecreated(nature, monitor); ! } catch (Exception e) { ! //let's not fail because of other plugins ! PydevPlugin.log(e); ! } ! } ! } ! } ! } ! } catch (Exception e) { ! PydevPlugin.log(e); ! astManager = null; } ! ! //errors can happen when restoring it ! if(astManager == null){ ! try { ! rebuildPath(null, monitor); ! } catch (Exception e) { ! PydevPlugin.log(e); ! } ! } ! initializationFinished = true; } } } --- 392,461 ---- @SuppressWarnings("unchecked") private void init(String version, String projectPythonpath, IProgressMonitor monitor) { ! if(version != null || projectPythonpath != null){ ! this.getStore().startInit(); ! try { ! if(projectPythonpath != null){ ! this.getPythonPathNature().setProjectSourcePath(projectPythonpath); } ! if(version != null){ ! this.setVersion(version); ! } ! } catch (CoreException e) { ! PydevPlugin.log(e); ! }finally{ ! this.getStore().endInit(); ! } ! }else{ ! //Change: 1.3.10: it could be reloaded more than once... (when it shouldn't) ! if(astManager != null){ ! return; //already initialized... ! } ! } ! ! if(initializationStarted || monitor.isCanceled()){ ! return; ! } ! ! initializationStarted = true; ! //Change: 1.3.10: no longer in a Job... should already be called in a job if that's needed. ! ! try { ! astManager = (ICodeCompletionASTManager) ASTManager.loadFromFile(getAstOutputFile()); ! if (astManager != null) { ! synchronized (astManager) { ! astManager.setProject(getProject(), this, true); // this is the project related to it, restore the deltas (we may have some crash) ! ! //just a little validation so that we restore the needed info if we did not get the modules ! if (astManager.getModulesManager().getOnlyDirectModules().length < 5) { ! astManager = null; ! } ! ! if (astManager != null) { ! List<IInterpreterObserver> participants = ExtensionHelper.getParticipants(ExtensionHelper.PYDEV_INTERPRETER_OBSERVER); ! for (IInterpreterObserver observer : participants) { ! try { ! observer.notifyNatureRecreated(this, monitor); ! } catch (Exception e) { ! //let's not fail because of other plugins ! PydevPlugin.log(e); ! } ! } ! } ! } ! } ! } catch (Exception e) { ! PydevPlugin.log(e); ! astManager = null; ! } ! ! //errors can happen when restoring it ! if(astManager == null){ ! try { ! rebuildPath(null, monitor); ! } catch (Exception e) { ! PydevPlugin.log(e); } } + initializationFinished = true; } *************** *** 470,474 **** ! private volatile Job rebuildJob; /** --- 507,511 ---- ! private RebuildPythonNatureModules rebuildJob = new RebuildPythonNatureModules(); /** *************** *** 476,486 **** */ private synchronized void rebuildPath(final String defaultSelectedInterpreter, final String paths) { ! if(rebuildJob != null){ ! return;//already in rebuild ! } ! final PythonNature nature = this; ! rebuildJob = new RebuildPythonNatureModules("Python Nature: rebuilding modules", paths, defaultSelectedInterpreter, nature); ! rebuildJob.schedule(); } /** --- 513,521 ---- */ private synchronized void rebuildPath(final String defaultSelectedInterpreter, final String paths) { ! rebuildJob.cancel(); ! rebuildJob.setParams(paths, defaultSelectedInterpreter); ! rebuildJob.schedule(20L); } + /** *************** *** 545,550 **** } return getPythonNature(resource.getProject()); - } /** * @param project the project we want to know about (if it is null, null is returned) --- 580,586 ---- } return getPythonNature(resource.getProject()); } + + /** * @param project the project we want to know about (if it is null, null is returned) Index: PythonPathNature.java =================================================================== RCS file: /cvsroot/pydev/org.python.pydev/src/org/python/pydev/plugin/nature/PythonPathNature.java,v retrieving revision 1.29 retrieving revision 1.30 diff -C2 -d -r1.29 -r1.30 *** PythonPathNature.java 15 Jun 2008 17:39:16 -0000 1.29 --- PythonPathNature.java 31 Jul 2008 01:47:36 -0000 1.30 *************** *** 20,29 **** --- 20,32 ---- import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; + import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.QualifiedName; import org.python.pydev.core.ExtensionHelper; import org.python.pydev.core.IModulesManager; + import org.python.pydev.core.IPythonNature; import org.python.pydev.core.IPythonPathNature; import org.python.pydev.core.REF; + import org.python.pydev.core.log.Log; import org.python.pydev.core.structure.FastStringBuffer; import org.python.pydev.plugin.PydevPlugin; *************** *** 36,39 **** --- 39,43 ---- private IProject project; + private PythonNature nature; *************** *** 60,65 **** ! public void setProject(IProject project){ this.project = project; if(project == null){ this.projectSourcePathSet = null;//empty --- 64,70 ---- ! public void setProject(IProject project, IPythonNature nature){ this.project = project; + this.nature = (PythonNature) nature; if(project == null){ this.projectSourcePathSet = null;//empty *************** *** 86,91 **** return null; } - PythonNature nature = PythonNature.getPythonNature(project); - if(nature == null) { return null; --- 91,94 ---- *************** *** 123,126 **** --- 126,137 ---- if(strings[i].trim().length()>0){ IPath p = new Path(strings[i]); + + if(ResourcesPlugin.getPlugin() == null){ + //in tests + buf.append(strings[i]); + buf.append("|"); + continue; + } + IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); *************** *** 149,155 **** }else{ ! //not in workspace?... maybe it was removed, so, do nothing, but let the user know about it ! PydevPlugin.log("Unable to find the path "+strings[i]+" in the project were it's \n" + ! "added as a source folder for pydev (project: "+project.getName()+") member:"+r); } } --- 160,175 ---- }else{ ! if(root.isSynchronized(IResource.DEPTH_INFINITE)){ ! //if it's synchronized, it really doesn't exist (let's warn about it) ! //not in workspace?... maybe it was removed, so, do nothing, but let the user know about it ! Log.log(IStatus.WARNING, "Unable to find the path "+strings[i]+" in the project were it's \n" + ! "added as a source folder for pydev (project: "+project.getName()+") member:"+r, null); ! } ! ! IPath rootLocation = root.getRawLocation(); ! //still, let's add it there (this'll be cached for later use) ! buf.append(REF.getFileAbsolutePath(rootLocation.append(strings[i].trim()).toFile())); ! buf.append("|"); ! } } *************** *** 192,196 **** synchronized(project){ projectSourcePathSet = null; - PythonNature nature = PythonNature.getPythonNature(project); nature.getStore().setPathProperty(PythonPathNature.getProjectSourcePathQualifiedName(), newSourcePath); } --- 212,215 ---- *************** *** 199,203 **** public void setProjectExternalSourcePath(String newExternalSourcePath) throws CoreException { synchronized(project){ - PythonNature nature = PythonNature.getPythonNature(project); nature.getStore().setPathProperty(PythonPathNature.getProjectExternalSourcePathQualifiedName(), newExternalSourcePath); } --- 218,221 ---- *************** *** 227,231 **** synchronized(project){ boolean restore = false; - PythonNature nature = PythonNature.getPythonNature(project); String projectSourcePath = nature.getStore().getPathProperty(PythonPathNature.getProjectSourcePathQualifiedName()); if(projectSourcePath == null){ --- 245,248 ---- *************** *** 244,248 **** } IPath projectPath = project.getFullPath(); ! if(!projectPath.isPrefixOf(p)){ p = p.removeFirstSegments(1); p = projectPath.append(p); --- 261,265 ---- } IPath projectPath = project.getFullPath(); ! if(projectPath != null && !projectPath.isPrefixOf(p)){ p = p.removeFirstSegments(1); p = projectPath.append(p); *************** *** 275,279 **** synchronized(project){ //no need to validate because those are always 'file-system' related - PythonNature nature = PythonNature.getPythonNature(project); String extPath = nature.getStore().getPathProperty(PythonPathNature.getProjectExternalSourcePathQualifiedName()); if(extPath == null){ --- 292,295 ---- Index: PythonNatureStore.java =================================================================== RCS file: /cvsroot/pydev/org.python.pydev/src/org/python/pydev/plugin/nature/PythonNatureStore.java,v retrieving revision 1.20 retrieving revision 1.21 diff -C2 -d -r1.20 -r1.21 *** PythonNatureStore.java 19 Jul 2008 20:18:14 -0000 1.20 --- PythonNatureStore.java 31 Jul 2008 01:47:36 -0000 1.21 *************** *** 9,16 **** import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; - import java.util.Collections; - import java.util.LinkedList; import java.util.List; --- 9,15 ---- import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; + import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; *************** *** 26,30 **** import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; - import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.IResourceChangeListener; --- 25,28 ---- *************** *** 33,42 **** import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; ! import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; - import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.QualifiedName; import org.eclipse.core.runtime.Status; ! import org.eclipse.core.runtime.jobs.Job; import org.python.pydev.core.docutils.StringUtils; import org.python.pydev.core.structure.FastStringBuffer; --- 31,39 ---- import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; ! import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.QualifiedName; import org.eclipse.core.runtime.Status; ! import org.python.pydev.core.REF; import org.python.pydev.core.docutils.StringUtils; import org.python.pydev.core.structure.FastStringBuffer; *************** *** 60,96 **** class PythonNatureStore implements IResourceChangeListener, IPythonNatureStore { - /** - * This is the class that does the store job. - * - * @author Fabio - */ - private final class PythonNatureStoreJob extends Job { - - private PythonNatureStoreJob(String name) { - super(name); - } - @Override - protected IStatus run(IProgressMonitor monitor) { - synchronized(saveLock){ - ByteArrayInputStream is = (ByteArrayInputStream)pydevprojectStreams.remove(0); // remove() when it becomes queue - try{ - onIgnoreRefresh++; - if (!xmlFile.exists()) { - xmlFile.create(is, true, monitor); - } else { - xmlFile.setContents(is, true, false, monitor); - } - modStamp = xmlFile.getModificationStamp(); - xmlFile.refreshLocal(IResource.DEPTH_ZERO, monitor); - }catch(Exception e){ - PydevPlugin.log(e); - }finally{ - onIgnoreRefresh--; - } - } - return Status.OK_STATUS; - } - } private final static String STORE_FILE_NAME = ".pydevproject"; --- 57,61 ---- *************** *** 108,128 **** private volatile IProject project = null; - private volatile IFile xmlFile = null; - - private volatile long modStamp = IFile.NULL_STAMP; - - private volatile int onIgnoreRefresh = 0; - - private final Object saveLock = new Object(); - - // use Queue and ConcurrentLinkedQueue with 1.5 - private final List<ByteArrayInputStream> pydevprojectStreams = - Collections.synchronizedList(new LinkedList<ByteArrayInputStream>()); - /** ! * 0 means we're not in a store job */ ! private volatile int onStoreJob = 0; /** * Whether the file has already been loaded --- 73,84 ---- private volatile IProject project = null; /** ! * We have an IFile, but the access is mostly through the actual File (because we don't want to deal with any refresh ! * from eclipse and its caching mechanism) */ ! private volatile IFile xmlFile = null; + private volatile String lastLoadedContents = null; + /** * Whether the file has already been loaded *************** *** 136,139 **** --- 92,96 ---- private static final boolean TRACE_PYTHON_NATURE_STORE = false; + private StringBuffer indent = new StringBuffer(); *************** *** 200,208 **** */ private synchronized void checkLoad(String function) { ! traceFunc("checkLoad"); ! if(!loaded){ ! PydevPlugin.log(new RuntimeException(StringUtils.format("%s still not loaded and '%s' already called.", xmlFile, function))); ! } ! traceFunc("END checkLoad"); } --- 157,163 ---- */ private synchronized void checkLoad(String function) { ! if(!loaded){ ! PydevPlugin.log(new RuntimeException(StringUtils.format("%s still not loaded and '%s' already called.", xmlFile, function))); ! } } *************** *** 214,222 **** return ""; } ! traceFunc("getPathProperty - ", key); ! checkLoad("getPathProperty"); ! String ret = getPathStringFromArray(getPathPropertyFromXml(key)); ! traceFunc("END getPathProperty - ", ret); ! return ret; } --- 169,176 ---- return ""; } ! checkLoad("getPathProperty"); ! String ret = getPathStringFromArray(getPathPropertyFromXml(key)); ! traceFunc("END getPathProperty - ", key, ret); ! return ret; } *************** *** 225,232 **** */ public synchronized void setPathProperty(QualifiedName key, String value) throws CoreException { ! traceFunc("setPathProperty"); ! checkLoad("setPathProperty"); ! setPathPropertyToXml(key, getArrayFromPathString(value), true); ! traceFunc("END setPathProperty"); } --- 179,184 ---- */ public synchronized void setPathProperty(QualifiedName key, String value) throws CoreException { ! checkLoad("setPathProperty"); ! setPathPropertyToXml(key, getArrayFromPathString(value), true); } *************** *** 240,298 **** private synchronized boolean loadFromFile() throws CoreException { if(this.project == null){ ! return false; //deconfigured... } traceFunc("loadFromFile"); ! boolean ret; ! try { ! DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); ! try{ ! onIgnoreRefresh++; ! xmlFile.refreshLocal(IResource.DEPTH_ZERO, null); ! }finally{ ! onIgnoreRefresh--; ! } ! if (!xmlFile.exists()) { ! if (document != null) { ! // Someone removed the project descriptor, store it from the memory model ! doStore(); ! ret = true; ! } else { ! // The document never existed ! document = parser.newDocument(); ! ProcessingInstruction version = document.createProcessingInstruction("eclipse-pydev", "version=\"1.0\""); //$NON-NLS-1$ //$NON-NLS-2$ ! document.appendChild(version); ! Element configRootElement = document.createElement(PYDEV_PROJECT_DESCRIPTION); ! document.appendChild(configRootElement); ! ! migrateProperty(PythonNature.getPythonProjectVersionQualifiedName()); ! migratePath(PythonPathNature.getProjectSourcePathQualifiedName()); ! migratePath(PythonPathNature.getProjectExternalSourcePathQualifiedName()); ! doStore(); ! ret = true; ! } } else { ! try{ ! onIgnoreRefresh++; ! xmlFile.refreshLocal(0, new NullProgressMonitor()); ! }catch(Exception e){ ! PydevPlugin.log(e); ! }finally{ ! onIgnoreRefresh--; ! } ! document = parser.parse(xmlFile.getContents()); ! modStamp = xmlFile.getModificationStamp(); ! ret = true; } ! } catch (Exception e) { ! e.printStackTrace(); ! IStatus status = new Status(IStatus.ERROR, "PythonNatureStore", -1, e.toString(), e); ! throw new CoreException(status); } ! traceFunc("END loadFromFile"); ! return ret; } private synchronized void migrateProperty(QualifiedName key) throws CoreException { traceFunc("migrateProperty"); --- 192,254 ---- private synchronized boolean loadFromFile() throws CoreException { if(this.project == null){ ! return false; //not configured... } traceFunc("loadFromFile"); ! ! try { ! DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); ! ! File file = getRawXmlFileLocation(); ! ! if (file == null || !file.exists()) { ! if (document != null) { ! // Someone removed the project descriptor, store it from the memory model ! doStore(); ! return true; } else { ! // The document never existed (create the default) ! document = parser.newDocument(); ! ProcessingInstruction version = document.createProcessingInstruction("eclipse-pydev", "version=\"1.0\""); //$NON-NLS-1$ //$NON-NLS-2$ ! document.appendChild(version); ! Element configRootElement = document.createElement(PYDEV_PROJECT_DESCRIPTION); ! document.appendChild(configRootElement); ! ! migrateProperty(PythonNature.getPythonProjectVersionQualifiedName()); ! migratePath(PythonPathNature.getProjectSourcePathQualifiedName()); ! migratePath(PythonPathNature.getProjectExternalSourcePathQualifiedName()); ! doStore(); ! return true; } ! } else { ! String fileContents = REF.getFileContents(file); ! if(lastLoadedContents != null && fileContents.equals(lastLoadedContents)){ ! return false; ! } ! lastLoadedContents = fileContents; ! document = parser.parse(new ByteArrayInputStream(fileContents.getBytes())); ! return true; } ! } catch (Exception e) { ! PydevPlugin.log("Error loading contents from .pydevproject", e); ! } ! traceFunc("END loadFromFile"); ! return false; } + + /** + * @return the actual file from the IFile we have + */ + private File getRawXmlFileLocation() { + IPath rawLocation = xmlFile.getRawLocation(); + File file = null; + if(rawLocation != null){ + file = rawLocation.toFile(); + } + return file; + } + private synchronized void migrateProperty(QualifiedName key) throws CoreException { traceFunc("migrateProperty"); *************** *** 310,321 **** private synchronized void migratePath(QualifiedName key) throws CoreException { traceFunc("migratePath"); ! // Try to migrate from persistent property ! String[] propertyVal = getArrayFromPathString(project.getPersistentProperty(key)); ! if (propertyVal != null) { ! // set in the xml ! setPathPropertyToXml(key, propertyVal, false); ! // and remove from the project ! project.setPersistentProperty(key, (String) null); ! } traceFunc("END migratePath"); } --- 266,277 ---- private synchronized void migratePath(QualifiedName key) throws CoreException { traceFunc("migratePath"); ! // Try to migrate from persistent property ! String[] propertyVal = getArrayFromPathString(project.getPersistentProperty(key)); ! if (propertyVal != null) { ! // set in the xml ! setPathPropertyToXml(key, propertyVal, false); ! // and remove from the project ! project.setPersistentProperty(key, (String) null); ! } traceFunc("END migratePath"); } *************** *** 329,345 **** private synchronized Node getRootNodeInXml() { traceFunc("getRootNodeInXml"); ! Assert.isNotNull(document); ! NodeList nodeList = document.getElementsByTagName(PYDEV_PROJECT_DESCRIPTION); ! Node ret = null; ! if (nodeList != null && nodeList.getLength() > 0) { ! ret = nodeList.item(0); ! } ! ! traceFunc("END getRootNodeInXml -- ", ret); ! if(ret != null){ ! return ret; ! } ! throw new RuntimeException(StringUtils.format("Error. Unable to get the %s tag by its name. Project: %s", PYDEV_PROJECT_DESCRIPTION, project)); } /** --- 285,301 ---- private synchronized Node getRootNodeInXml() { traceFunc("getRootNodeInXml"); ! Assert.isNotNull(document); ! NodeList nodeList = document.getElementsByTagName(PYDEV_PROJECT_DESCRIPTION); ! Node ret = null; ! if (nodeList != null && nodeList.getLength() > 0) { ! ret = nodeList.item(0); ! } ! ! traceFunc("END getRootNodeInXml -- ", ret); ! if(ret != null){ ! return ret; } + throw new RuntimeException(StringUtils.format("Error. Unable to get the %s tag by its name. Project: %s", PYDEV_PROJECT_DESCRIPTION, project)); + } /** *************** *** 351,359 **** private synchronized String getKeyString(QualifiedName key) { traceFunc("getKeyString"); ! String keyString = key.getQualifier() != null ? key.getQualifier() : ""; ! String ret = keyString + "." + key.getLocalName(); ! traceFunc("END getKeyString"); ! return ret; ! } /** --- 307,315 ---- private synchronized String getKeyString(QualifiedName key) { traceFunc("getKeyString"); ! String keyString = key.getQualifier() != null ? key.getQualifier() : ""; ! String ret = keyString + "." + key.getLocalName(); ! traceFunc("END getKeyString"); ! return ret; ! } /** *************** *** 367,391 **** private synchronized Node findPropertyNodeInXml(String type, QualifiedName key) { traceFunc("findPropertyNodeInXml"); ! Node root = getRootNodeInXml(); ! NodeList childNodes = root.getChildNodes(); ! if (childNodes != null && childNodes.getLength() > 0) { ! String keyString = getKeyString(key); ! for (int i = 0; i < childNodes.getLength(); i++) { ! Node child = childNodes.item(i); ! if (child.getNodeName().equals(type)) { ! NamedNodeMap attrs = child.getAttributes(); ! if (attrs != null && attrs.getLength() > 0) { ! String name = attrs.getNamedItem(PYDEV_NATURE_PROPERTY_NAME).getNodeValue(); ! if (name != null && name.equals(keyString)) { ! traceFunc("END findPropertyNodeInXml - ", child); ! return child; ! } } } } } - traceFunc("END findPropertyNodeInXml (null)"); - return null; } /** --- 323,347 ---- private synchronized Node findPropertyNodeInXml(String type, QualifiedName key) { traceFunc("findPropertyNodeInXml"); ! Node root = getRootNodeInXml(); ! NodeList childNodes = root.getChildNodes(); ! if (childNodes != null && childNodes.getLength() > 0) { ! String keyString = getKeyString(key); ! for (int i = 0; i < childNodes.getLength(); i++) { ! Node child = childNodes.item(i); ! if (child.getNodeName().equals(type)) { ! NamedNodeMap attrs = child.getAttributes(); ! if (attrs != null && attrs.getLength() > 0) { ! String name = attrs.getNamedItem(PYDEV_NATURE_PROPERTY_NAME).getNodeValue(); ! if (name != null && name.equals(keyString)) { ! traceFunc("END findPropertyNodeInXml - ", child); ! return child; } } } } } + traceFunc("END findPropertyNodeInXml (null)"); + return null; + } /** *************** *** 398,417 **** private String[] getChildValuesWithType(Node node, String type) { traceFunc("getChildValuesWithType"); ! NodeList childNodes = node.getChildNodes(); ! if (childNodes != null && childNodes.getLength() > 0) { ! List<String> result = new ArrayList<String>(); ! for (int i = 0; i < childNodes.getLength(); i++) { ! Node child = childNodes.item(i); ! if (child.getNodeName().equals(type)) { ! result.add(getTextContent(child)); ! } } - String[] retval = new String[result.size()]; - traceFunc("END getChildValuesWithType"); - return result.toArray(retval); } ! traceFunc("END getChildValuesWithType (null)"); ! return null; } /** --- 354,373 ---- private String[] getChildValuesWithType(Node node, String type) { traceFunc("getChildValuesWithType"); ! NodeList childNodes = node.getChildNodes(); ! if (childNodes != null && childNodes.getLength() > 0) { ! List<String> result = new ArrayList<String>(); ! for (int i = 0; i < childNodes.getLength(); i++) { ! Node child = childNodes.item(i); ! if (child.getNodeName().equals(type)) { ! result.add(getTextContent(child)); } } ! String[] retval = new String[result.size()]; ! traceFunc("END getChildValuesWithType"); ! return result.toArray(retval); } + traceFunc("END getChildValuesWithType (null)"); + return null; + } /** *************** *** 424,435 **** private void addChildValuesWithType(Node node, String type, String[] values) { traceFunc("addChildValuesWithType"); ! assert (node != null); ! assert (values != null); ! assert (type != null); ! for (int i = 0; i < values.length; i++) { ! Node child = document.createElement(type); ! setTextContent(values[i], child); ! node.appendChild(child); ! } traceFunc("END addChildValuesWithType"); } --- 380,391 ---- private void addChildValuesWithType(Node node, String type, String[] values) { traceFunc("addChildValuesWithType"); ! assert (node != null); ! assert (values != null); ! assert (type != null); ! for (int i = 0; i < values.length; i++) { ! Node child = document.createElement(type); ! setTextContent(values[i], child); ! node.appendChild(child); ! } traceFunc("END addChildValuesWithType"); } *************** *** 443,459 **** private String getPathStringFromArray(String[] pathArray) { traceFunc("getPathStringFromArray"); ! if (pathArray != null) { ! FastStringBuffer s = new FastStringBuffer(); ! for (int i = 0; i < pathArray.length; i++) { ! if (i > 0) { ! s.append('|'); ! } ! s.append(pathArray[i]); } ! traceFunc("END getPathStringFromArray"); ! return s.toString(); } ! traceFunc("END getPathStringFromArray (null)"); ! return null; } --- 399,415 ---- private String getPathStringFromArray(String[] pathArray) { traceFunc("getPathStringFromArray"); ! if (pathArray != null) { ! FastStringBuffer s = new FastStringBuffer(); ! for (int i = 0; i < pathArray.length; i++) { ! if (i > 0) { ! s.append('|'); } ! s.append(pathArray[i]); } ! traceFunc("END getPathStringFromArray"); ! return s.toString(); ! } ! traceFunc("END getPathStringFromArray (null)"); ! return null; } *************** *** 523,527 **** setTextContent(value, child); } - doStore(); } else if (value != null) { // The property is not in the file and we need to set it --- 479,482 ---- *************** *** 533,541 **** getRootNodeInXml().appendChild(property); ! if (store) { ! doStore(); ! } } } catch (Exception e) { traceFunc("END setPropertyToXml (EXCEPTION)"); --- 488,499 ---- getRootNodeInXml().appendChild(property); ! }else{ ! store = false; } + if (store) { + doStore(); + } + } catch (Exception e) { traceFunc("END setPropertyToXml (EXCEPTION)"); *************** *** 553,565 **** private void setTextContent(String textContent, Node self) throws DOMException { traceFunc("setTextContent"); ! // get rid of any existing children ! Node child; ! while ((child = self.getFirstChild()) != null) { ! self.removeChild(child); ! } ! // create a Text node to hold the given content ! if (textContent != null && textContent.length() != 0) { ! self.appendChild(document.createTextNode(textContent)); ! } traceFunc("END setTextContent"); } --- 511,523 ---- private void setTextContent(String textContent, Node self) throws DOMException { traceFunc("setTextContent"); ! // get rid of any existing children ! Node child; ! while ((child = self.getFirstChild()) != null) { ! self.removeChild(child); ! } ! // create a Text node to hold the given content ! if (textContent != null && textContent.length() != 0) { ! self.appendChild(document.createTextNode(textContent)); ! } traceFunc("END setTextContent"); } *************** *** 568,593 **** private String getTextContent(Node self) throws DOMException { traceFunc("getTextContent"); ! FastStringBuffer fBufferStr = new FastStringBuffer(); ! Node child = self.getFirstChild(); ! if (child != null) { ! Node next = child.getNextSibling(); ! if (next == null) { ! if(hasTextContent(child)){ ! String nodeValue = child.getNodeValue(); ! if(nodeValue != null){ ! traceFunc("END getTextContent - ", nodeValue); ! return nodeValue; ! } } - traceFunc("END getTextContent - EMPTY"); - return ""; } ! fBufferStr.clear(); ! getTextContent(fBufferStr, self); ! traceFunc("END getTextContent - ", fBufferStr); ! return fBufferStr.toString(); } ! traceFunc("END getTextContent - EMPTY"); ! return ""; } --- 526,551 ---- private String getTextContent(Node self) throws DOMException { traceFunc("getTextContent"); ! FastStringBuffer fBufferStr = new FastStringBuffer(); ! Node child = self.getFirstChild(); ! if (child != null) { ! Node next = child.getNextSibling(); ! if (next == null) { ! if(hasTextContent(child)){ ! String nodeValue = child.getNodeValue(); ! if(nodeValue != null){ ! traceFunc("END getTextContent - ", nodeValue); ! return nodeValue; } } ! traceFunc("END getTextContent - EMPTY"); ! return ""; } ! fBufferStr.clear(); ! getTextContent(fBufferStr, self); ! traceFunc("END getTextContent - ", fBufferStr); ! return fBufferStr.toString(); ! } ! traceFunc("END getTextContent - EMPTY"); ! return ""; } *************** *** 611,618 **** private boolean hasTextContent(Node child) { traceFunc("hasTextContent"); ! boolean ret = child.getNodeType() != Node.COMMENT_NODE && ! child.getNodeType() != Node.PROCESSING_INSTRUCTION_NODE; ! traceFunc("END hasTextContent ", ret); ! return ret; } --- 569,578 ---- private boolean hasTextContent(Node child) { traceFunc("hasTextContent"); ! ! boolean ret = child.getNodeType() != Node.COMMENT_NODE && ! child.getNodeType() != Node.PROCESSING_INSTRUCTION_NODE; ! ! traceFunc("END hasTextContent ", ret); ! return ret; } *************** *** 661,665 **** if (oldChild != null && paths == null) { getRootNodeInXml().removeChild(oldChild); - doStore(); } else if (paths != null) { // The property is not in the file and we need to set it --- 621,624 ---- *************** *** 674,680 **** getRootNodeInXml().replaceChild(property, oldChild); } ! if (store) { ! doStore(); ! } } --- 633,642 ---- getRootNodeInXml().replaceChild(property, oldChild); } ! }else{ ! store = false; ! } ! ! if (store) { ! doStore(); } *************** *** 716,735 **** } ! /** ! * Stores the internal Xml representation as a project resource. ! * ! */ ! private synchronized void doStore() { ! traceFunc("doStore"); ! synchronized (this) { ! try { ! doStore(new NullProgressMonitor()); ! } catch (Exception e) { ! throw new RuntimeException("Error storing pydev project descriptor:"+project, e); ! } ! } ! traceFunc("END doStore"); ! } ! public void resourceChanged(IResourceChangeEvent event) { if(project == null){ --- 678,682 ---- } ! public void resourceChanged(IResourceChangeEvent event) { if(project == null){ *************** *** 744,759 **** //not synched -- called when a file is changed boolean doRebuild = false; - if (onIgnoreRefresh != 0) { - traceFunc("END resourceChanged (on ignore refresh)"); - return; - } - - if (onStoreJob != 0) { - traceFunc("END resourceChanged (on store)"); - return; // we're on a store job from the store itself, this means that we must - // call the rebuildPath programatically (and that the resource change - // is actually already reflected in our document and file) - } - if(!project.isOpen()){ traceFunc("END resourceChanged (!open)"); --- 691,694 ---- *************** *** 769,781 **** IResourceDelta delta = eventDelta.findMember(xmlFile.getFullPath()); if (delta != null) { ! if (xmlFile.getModificationStamp() != modStamp) { ! try { ! if (loadFromFile()) { ! doRebuild = true; ! } ! } catch (CoreException e) { ! traceFunc("END resourceChanged (EXCEPTION)"); ! throw new RuntimeException(e); } } } --- 704,714 ---- IResourceDelta delta = eventDelta.findMember(xmlFile.getFullPath()); if (delta != null) { ! try { ! if (loadFromFile()) { //it'll only return true if the contents really changed. ! doRebuild = true; } + } catch (CoreException e) { + traceFunc("END resourceChanged (EXCEPTION)"); + throw new RuntimeException(e); } } *************** *** 792,796 **** * This is the function that actually stores the contents of the xml into the file with the configurations. */ ! private synchronized IStatus doStore(IProgressMonitor monitor) throws IOException, TransformerException, CoreException { if(this.project == null){ return Status.OK_STATUS; --- 725,729 ---- * This is the function that actually stores the contents of the xml into the file with the configurations. */ ! private synchronized IStatus doStore() { if(this.project == null){ return Status.OK_STATUS; *************** *** 803,834 **** } synchronized (this) { ! try { ! // that's because while we're in a store job, we don't want to listen to resource changes (we just ! // want resource changes from the user). ! if (onStoreJob != 0) { ! traceFunc("END doStore (already in store)"); ! return Status.OK_STATUS; ! } ! ! onStoreJob++; ! if (document == null) { ! traceFunc("END doStore (document == null)"); ! return new Status(Status.ERROR, "PythonNatureStore.doStore", -2, "document == null", new RuntimeException("document == null")); ! } ! ! pydevprojectStreams.add(new ByteArrayInputStream(serializeDocument(document))); ! ! PythonNatureStoreJob job = new PythonNatureStoreJob("Save .pydevproject"); ! ! if (ProjectModulesManager.IN_TESTS){ ! job.run(new NullProgressMonitor()); ! }else{ ! job.schedule(); ! } ! traceFunc("END doStore"); ! return Status.OK_STATUS; ! } finally { ! onStoreJob--; } } } --- 736,766 ---- } synchronized (this) { ! if (document == null) { ! traceFunc("END doStore (document == null)"); ! return new Status(Status.ERROR, "PythonNatureStore.doStore", -2, "document == null", new RuntimeException("document == null")); } + + File file = getRawXmlFileLocation(); + if(file == null){ + //that's ok... in tests + return Status.OK_STATUS; + } + try { + //Ok, we may receive multiple requests at once (e.g.: when updating the version and the pythonpath together), but + //as the file is pretty small, there should be no problems in writing it directly (if that proves a problem later on, we + //could have a *very* simple mechanism for saving it after some millis) + + String str = new String(serializeDocument(document)); + lastLoadedContents = str; + if(TRACE_PYTHON_NATURE_STORE){ + System.out.println("Writing to file: "+file+" "+str); + } + REF.writeStrToFile(str, file); + } catch (Exception e) { + PydevPlugin.log("Unable to write contents of file: "+file, e); + } + + traceFunc("END doStore"); + return Status.OK_STATUS; } } |