-
Notifications
You must be signed in to change notification settings - Fork 408
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make it possible to report folder changes to jdt.ls (not only file ch… #755
Conversation
6daf588
to
5ccfb9d
Compare
@vrubezhny Could you, please, add some unit tests? |
@snjeza Please don't push the PR until I update it and provide a test for it. |
…anges) Related Issue: eclipse-che/che#10115 Signed-off-by: Victor Rubezhny <[email protected]>
5ccfb9d
to
de9b178
Compare
@snjeza I've pushed the fixed code with junit test added (see
|
test this please |
@@ -601,10 +603,36 @@ private static boolean isJavaIdentifierOrPeriod(char ch) { | |||
return Character.isJavaIdentifierPart(ch) || ch == '.'; | |||
} | |||
|
|||
public static boolean isFolder(String uriString) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return findFolder(uriString).exists();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
findFolder(uriString)
always return a new IResource object of type IContainer (it just creates it) even if uriString
represents a real file (not a folder) as well as not existing file/folder (exactly as well as findFile(ueiString)
returns IFile even if uriString
represents a real folder). So, return findFolder(uriString).exists()
will save us from not existing folder, but still return true in case of synched files - which is wrong. Also it will return false in case of not-synched, but existing folders - which is also wrong.
My goal is to report to jdt.ls on every new just created folder (or a package) in order to make it go through ProjectsManager.fileChanged(String, CHANGE_TYPE)
until it refreshes the specified IResource: https://github.com/eclipse/eclipse.jdt.ls/blob/master/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/ProjectsManager.java#L275 (in case the resource is folder) which is impossible (or involves some other problems/errors) with current realization.
If I do not report folder changes (create/delete/update) to jdt.ls and as such those folders stay not-synchronized (they exist in file system, but not in workspace) then such folders/packages cannot be used as a destination target package of copy/move operations (they just stay invisible for the workspace).
I know that I do an extra refresh of resource in isFolder()
, but otherwise I don't know a 100%-clear way to detect if a specified uri represents a folder or a file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
findFolder(uriString) always return a new IResource object of type IContainer (it just creates it)
findFolder(uriString) doesn't create it.
I know that I do an extra refresh of resource in isFolder(), but otherwise I don't know a 100%-clear way to detect if a specified uri represents a folder or a file.
resource.getType() == IResource.FOLDER && resource.exists()
You can try the following test:
@Test
public void testIsFolder() throws Exception {
IProject project = WorkspaceHelper.getProject(ProjectsManager.DEFAULT_PROJECT_NAME);
IFolder org = project.getFolder("/src/org");
org.delete(true, null);
org.create(true, true, null);
IFolder iFolder = project.getFolder("/src/org/eclipse");
IResource resource = iFolder;
assertFalse(resource.getType() == IResource.FOLDER && resource.exists());
iFolder.create(true, false, null);
assertTrue(resource.getType() == IResource.FOLDER && resource.exists());
URI uriFolder = iFolder.getLocationURI();
IFile iFile = project.getFile("/src/org/eclipse/Test.java");
iFile.create(new ByteArrayInputStream("".getBytes()), true, null);
project.refreshLocal(IResource.DEPTH_INFINITE, null);
assertTrue(iFile.exists());
URI uriFile = iFile.getLocationURI();
assertTrue(JDTUtils.isFolder(uriFolder.toString()));
assertFalse(JDTUtils.isFolder(uriFile.toString()));
assertNotNull(JDTUtils.findFile(uriFile.toString()));
assertNotNull(JDTUtils.findFolder(uriFolder.toString()));
org.delete(true, null);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
findFolder(uriString) always return a new IResource object of type IContainer (it just creates it)
findFolder(uriString) doesn't create it.
JDTUtils.findFolder(...)
creates a new resource of type IContainer as well as JDTUtils.findFile(...)
creates a new resource object of type IFile, independently of real resource type represented by the given URI (either it points to a file or a folder), because the execution of both methods goes through org.eclipse.core.internal.resources.Workspace.newResource(IPath, int)
where new resource object of specified type is created for the given path.
In your test case you're using 'IFile.create(..)and
project.refreshLocal(DEPTH_INFINITE)- the methods which create a file in workspace or even refresh the workspace project file structure. This make all the file system resources to became "visible" for workspace and synchronized before they are tested with
isFolder(),
findFile()and
findFolder()`.
In my case, the folders to be reported are not synchronized with workspace - I do actually reporting their paths to jdt.ls in order to synch them in workspace (from outside of jdt.ls).
And I don't actually care where exactly refresh()
is called - in ProjectManager.fileChanged()
or a bit earlier in JDTUtils.isFolder()
method - both places suite my needs.
I'll look at your test more deeply later - maybe I'm missing something...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
org.eclipse.core.internal.resources.Workspace.newResource(IPath, int) where new resource object of specified type is created for the given path.
See javadoc for org.eclipse.core.resources.IContainer.getFile(IPath) and org.eclipse.core.internal.resources.Container.getFile(IPath)
@Test
public void testFindFileFindFolder() throws Exception {
IProject project = WorkspaceHelper.getProject(ProjectsManager.DEFAULT_PROJECT_NAME);
IFolder org = project.getFolder("/src/org");
org.delete(true, null);
org.create(true, true, null);
IFolder iFolder = project.getFolder("/src/org/eclipse");
URI uriFolder = iFolder.getLocationURI();
IFile file = JDTUtils.findFile(uriFolder.toString());
assertFalse(file.exists());
IContainer folder = JDTUtils.findFolder(uriFolder.toString());
assertFalse(folder.exists());
project.refreshLocal(IResource.DEPTH_INFINITE, null); // it doesn't help
assertFalse(file.exists());
assertFalse(folder.exists());
iFolder.create(true, false, null); // create the folder
assertTrue(folder.exists());
assertTrue(folder.getType() == IResource.FOLDER && folder.exists());
assertFalse(file.getType() == IResource.FOLDER && file.exists());
assertTrue(file.getType() == IResource.FILE);
assertFalse(file.getType() == IResource.FILE && file.exists());
org.delete(true, null);
}
And I don't actually care where exactly refresh()is called - in ProjectManager.fileChanged() or a bit earlier in JDTUtils.isFolder() method - both places suite my needs.
You are right. refresh() should be called in isFolder().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two more notes:
- Your test case doesn't follow my case workflow: I cannot change workspace resources (by calling methods like
IFolder.create()
,IFile.create()
,IFolder.delete()
and so on). Not acceptable for us. - It looks like my testcase still has a problem as it relies on folders that were created by some other test case. It's a bug that I must fix.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@snjeza I have fixed my testcase. In short the workflow is the following:
- [from outside of jdt.ls] some folders (packages) are created by using java.io-API
- [inside jdt.ls] URI of a changed folder is provided to jdt.ls, jdt.ls is to react by refreshing the folder in its workspace (by using org.eclipse.core.resources-API) in
ProjectManager.fileChanged()
method (here's the work ofisFolder()
,findFolder() and
findFile()` methods is being tested)
if (!parent.isSynchronized(DEPTH_ONE)) { | ||
parent.refreshLocal(DEPTH_ONE, null); | ||
} | ||
for (IResource member : parent.members()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return parent.findMember(name) instanceof IFolder;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agreed. that's a way better. fixed
@gorkem @fbricon @vrubezhny We probable need to use After/Before instead of AfterClass/BeforeClass |
…t only file changes) Signed-off-by: Victor Rubezhny <[email protected]>
@snjeza If you do so, |
…anges)
Related Issue: eclipse-che/che#10115
Signed-off-by: Victor Rubezhny [email protected]