Programmatically list open projects in an eclipse workspace from outside of eclipse
Asked Answered
A

2

10

I want to write a Gradle plugin which can inspect an eclipse workspace directory and iterate over the open projects within the workspace and determine the location of each.

Something like

Workspace workspace = EclipseUtils.parseWorkspace("c:/myEclipseWorkspace");
Collection<Project> projects = workspace.getProjects();
for (Project project : projects) {
   System.out.println(String.format("name=%s, location=%s, open=%s",
      project.getName(), project.getLocation(), project.isOpen()));
}

I've looked at my workspace and can see some .location files under c:\myEclipseWorkspace\.metadata\.plugins\org.eclipse.core.resources\.projects\

But these files are a custom binary format enter image description here

Is there an eclipse API that I can invoke to parse these? Or some other solution to iterate the open projects in a workspace.

Please note that I want to do this externally to eclipse and NOT within an eclipse plugin.

Antitoxin answered 20/11, 2015 at 10:4 Comment(0)
S
5

Reading the Private Description to Obtain Location

Since you are writing in Java, then reuse the Eclipse code from your external location.

i.e. Pull out some of the key code from org.eclipse.core.resources.ResourcesPlugin. Start with the impl of org.eclipse.core.resources.ResourcesPlugin.getWorkspace() and then work your way to org.eclipse.core.resources.IWorkspaceRoot.getProjects()

The above code reads the project description here: org.eclipse.core.internal.resources.LocalMetaArea.readPrivateDescription(IProject, ProjectDescription) and that is called from org.eclipse.core.internal.localstore.FileSystemResourceManager.read(IProject, boolean) which has some logic about default locations.

This is the joy of EPL, as long as your new program/feature is EPL you can reuse Eclipse's core code to do new and wonderful things.

Reading Workspace State to Obtain Open/Close State

When reading workspace state, you are moving into the ElementTree data structures. Reading this without using the ElementTree classes is probably unrealistic. Using the ElementTree classes without full OSGi is probably unrealistic. I provide the following notes to help you on your way.

Working backwards:

  • ICoreConstants.M_OPEN is the flag value indicating project is open or closed (set for open, clear for closed)
  • M_OPEN is tested when Project.isOpen() is called
  • The flags at runtime are in ResourceInfo.flags
  • The flags are loaded by ResourceInfo.readFrom() called from SaveManager.readElement()
  • The DataInput input passed to readElement is from the Element Tree stored in the workspace meta directory in .metadata/.plugins/org.eclipse.core.resources/.root/<id>.tree. The specific version (id) of the file to use is recorded in the safe table .metadata/.plugins/org.eclipse.core.resources/.safetable/org.eclipse.core.resources
  • The safe table is part of the SaveManager's internal state stored in a MasterTable
Surely answered 20/11, 2015 at 10:24 Comment(4)
PS. I look forward to seeing what you come up with (and am very intrigued by your direction)Surely
Thanks for the info. Since you're intrigued, here is the end goalAntitoxin
This is proving very difficult to isolate the code responsible for parsing the .location file. Any more pointers would be much appreciated. This would be soooooo much simpler if they were xml / jsonAntitoxin
Added some more pointers. Most stuff in Eclipse is xml (sometimes xml serialized into other xml files). Of course most of this code started before json was coined! I don't know why this particular bit of code is not xml.Surely
A
1

I've managed to parse the file using this as a reference

    protected Location parseLocation(File locationFile) throws IOException {
        String name = locationFile.getParentFile().getName();
        DataInputStream in = new DataInputStream(new FileInputStream(locationFile));
        try {
            in.skip(ILocalStoreConstants.BEGIN_CHUNK.length);
            String path = in.readUTF();
            int numRefs = in.readInt();
            String[] refNames = new String[numRefs];
            for (int i = 0; i < numRefs; ++ i) {
                refNames[i] = in.readUTF();
            }
            in.skipBytes(ILocalStoreConstants.END_CHUNK.length);
            return new Location(name, path, refNames);
        } finally {
            in.close();
        }
    }

Unfortunately this doesn't seem to be able to detect if a project is closed or not. Any pointers on getting the closed flag would be much appreciated

Antitoxin answered 20/11, 2015 at 16:26 Comment(4)
I'm going to have to leave you there. You have figured out loads already, and I don't "just know" this stuff. As for the closed or not, sounds like a new question would be a good idea, maybe more people will see it again?Surely
The project info like that is generally stored under in the workspace .metadata directory, see https://mcmap.net/q/261126/-where-are-projects-stored-in-eclipse . It's binary data, though so it's not clear where the open/closed state is stored within there (or even if it is). For that level of detail you might have to ask on the Eclipse forums or dive into the Eclipse resources code.Fotina
I have noticed (with Eclipse Oxygen) that a project is closed if and only if the corresponding project folder (inside .projects) contains a file called 1.tree.Carpus
Thanks @lodovik, I guess I could take a copy of the .metadata directory before/after closing a project and do a diff of the two. These 1.tree files should show up as well as anything elseAntitoxin

© 2022 - 2024 — McMap. All rights reserved.