Find the build dir for a given Eclipse IProject

Hi,

I want to ignore the Gradle build dir from some expensive resource processing in Eclipse. Therefore I need to find the build dir for a given IProject. This code will be run with a high frequency.

I tried several things and wonder if there is a solution that works in Buildship 2.x and 3.x. So far I did only find a way to achieve this either in 2.x or in 3.x but no reflection-free code did work for both versions.

  1. With 3.x I can use GradleCore.getWorkspace and friends to figure the build dir. At a first glance the implementation appears to be reasonably simple, but I’m a little concerned about the runtime cost. As far as I saw it does not use any caching, e.g. it does not use o.e.b.c.internal.preferences.PersistentModel.getBuildDir()

     Optional<GradleBuild> gradleBuild = GradleCore.getWorkspace().getBuild(iProject);
     if (gradleBuild.isPresent()) {
     	GradleProject gradleProject = gradleBuild.get().withConnection(connection->connection.getModel(GradleProject.class), new NullProgressMonitor());
     	File buildDirectory = gradleProject.getBuildDirectory();
     	..
     }
    
  2. Thinking this through, I came across the ProjectConfigurator extension point. Maybe this is the right thing to do to the caching of the build dir per project. Unfortunately it is only available in 3.x and not in 2.x. Also I assume that my code will now do something that is already available internally, e.g. via the persistent model.

     IProject project = context.getProject();
     Optional<GradleBuild> gradleBuild = GradleCore.getWorkspace().getBuild(project);
     if (gradleBuild.isPresent()) {
     	try {
     		GradleProject gradleProject = gradleBuild.get().withConnection(
     				connection -> connection.getModel(GradleProject.class), new NullProgressMonitor());
     		File buildDirectory = gradleProject.getBuildDirectory();
     		File projectDirectory = gradleProject.getProjectDirectory();
     		IPath relativePath = Path.fromOSString(projectDirectory.toPath().relativize(buildDirectory.toPath()).toString());
     		IFolder buildDirAsFolder = project.getFolder(relativePath);
     		buildDirs.add(buildDirAsFolder);
     		buildDirsPerProject.put(project, buildDirAsFolder);
     	} catch (Exception e) {
     		e.printStackTrace();
     	}
     }
    
  3. The internal API of the persistent model was extremely straight forward but well … internal

     PersistentModel gradleModel = CorePlugin.modelPersistence().loadModel(folder.getProject());
     if (gradleModel.isPresent()) {
     		IPath buildDir = gradleModel.getBuildDir();
     		..
     }
    

With 2.x I’d have to do something else I suppose.

Long story short: What would be the recommend way to do this for 3.x and is there a solution that works for both major versions of Buildship?

Best
Sebastian

Hi! First of all, why do you need to support Buildship 2.x versions? Do you need to support really old Gradle versions? Would it be possible to move those projects to newer Gradle versions (there are so many improvements in recent releases!).

Your findings are correct.

GradleCore.getWorkspace would be an expensive operation and not designed for your use-case.

The PersistentModel is internal but provides easy access to the build directory. You could use it for Buildship 2.x because we won’t do any releases for that major version.

You could use interface for Buildship 3.x as we won’t change it anytime soon. Still, we reserve the right to do it, so it’s not a guarantee. It might be better to use projectConfigurator extension point. If you reuse the init() method from BaseConfigurator then you will get the EclipseProject model from the cache, making the configurator execution cheaper.

Alternatively, you can combine the two solutions together and read the persistent model in a project configurator and exclude the build dir there. This way your custom code would be executed as part of the synchronization without dealing with loading the tasks. But again, it requires access to an internal API.

In any case, you’ll need two implementation, one for Buildship 2.x and one for 3.x. Unless you use reflection to load/read the PersistentModel depending on the current version (in Buildship 3.0 we moved it to a different package).

Thank you for the detailled answer. We’ll revisit the usecase for 2.x and can thereby hopefully avoid reflection.

Best
Sebastian