Custom nature override by buildship 2.0.2

Hey I am using buildship 2.0.2 and we are developing eclipse plugin based buildship and we will add some custom nature to project, but after gradle-refresh the project , our nature is removed and only
org.eclipse.jdt.core.javanature
org.eclipse.buildship.core.gradleprojectnature

left.

So I don’t understand why buildship remove other eclipse nature and just keep the two.

Please help about this. Thanks in advance.

This is not something I’ve tried, but I believe you should specify the nature in an ‘eclipse’ block of your gradle definitions.

The following posts might be of help?

thanks for the reply , now I know the buildship is forcing eclipse project nature same as gradle configuration.
see https://github.com/eclipse/buildship/commit/f515066d0e774e926cd86b022f91e6edbec7a72b
So we are going to find a workaround for custom nature.

Please add your comment to https://github.com/eclipse/buildship/issues/392 if you find this behaviour of Buildship 2.x extremely detrimental (as I do).

thanks for the reminding , we are on the same way… :slight_smile:

@AndyWu2015 if you are building an Eclipse plugin that needs to add natures/builders etc. to Gradle projects, then please take a look at the InvocationCustomizer extension point. This extension point allows you (among other things) to inject an init script into the build (using the --init-script option) which can then change the eclipse model in any way you need.

ok , I will try this way. Thanks for the reminding.

Hi Stefan,
so, is your plan to make all the other Eclipse plugins to provide a Buildship integration package in order to make them live well with Buildship?

Sorry, but I’m still missing the point of this strategy… :pensive:

1 Like

Only if they want to automatically inject some logic into the build and the build otherwise has no knowledge about that plugin. That’s a rather small set of Eclipse plugins. In general there already is a Gradle plugin that provides the right Eclipse config. For instance, the java plugin adds the Java nature and Java builder, the groovy plugin adds the Groovy nature and Groovy builder, the eclipse-wtp plugin configures WTP etc.

There are way more plugins than Java, Groovy and WTP…

What about Spring IDE, JPA Tooling, JRebel, JSDT… and, in general, whatever is related to tooling rather than building?

You can always add those to your eclipse.project {} configuration. You have to check that config in one way or another (if it wasn’t in your build.gradle file, it would have to be in a .project file).

Yes, but the .project file is edited by using the official UI elements and actions, as designed by the respective plugin authors. Manually configuring those plugins in build.gradle, instead, requires me to know for every plugin which natures and builders they require… information that I consider “implementation details”. I’ve never seen Eclipse plugin providers documenting (to the final user at least) how to enable plugins by manually editing the .project file.

In order to do the same in build.gradle (which is equivalent, from this point of view), I substantially have to “reverse engineer” the .project file as changed by the tooling to know what I have to put in the build.gradle file… And I also have to handle plugin upgrades if they desire to change natures and/or builders (replace them, add new ones, etc.), because any automatic upgrade facilities provided by the plugin themselves would be useless if Buildship overrides the whole .project file.

I would like Buildship to ease my life, not to add complexity where it does not exist…

I agree overriding natures/builders for Java, Groovy, WTP, etc. plugins and features (and in general whatever is natively supported by Buildship), but not for everything else!

1 Like

I agree , it is a little enforced to let user config what they don’t need to config.

The main problem (and the reason we did this in the first place) is that there is no good way to determine what is “user-created” and what is just “outdated stuff left over from the last synchronization”. In many cases user-defined things also conflict (e.g. a user-defined source folder preventing us from setting the ones defined in the Gradle build). There’s also the question about ordering, i.e. when the user addes a builder that Gradle doesn’t have in its model, where should it put it? Builder ordering is often important.

We got lots of complaints about Buildship not “properly synchronizing”, i.e. leaving things around that aren’t actually in the Gradle model or ordering things the wrong way. That’s why we decided to go with the current approach. If this is causing a lot of grief for a different group of users, then we need to find a middle ground. So my question would be:

Which configuration elements would you expect Buildship to “leave untouched”? For instance, project natures would be relatively easy, classpath entries would be a much more complex story as they’d often end up conflicting with the build. And if we do leave them untouched, what if a user actually wants to get back into a “pristine” state? I’m very hesitant to add more dials and knobs to the synchronization UI.

I have 2 sugestions…

1st Suggestion

Buildship has 2 modes of synchronization: ‘update’ and ‘full synchronization’.

  • In ‘full synchronization’, buildship does what it currently does, rewriting the entire project config.
  • Every time a synchronization is run, buildship keeps a record (in the project gradle cache?) of what project settings it authored. E.g. a list of natures and builders it added, classpath entries, etc.
  • In ‘update’, you endeavour to change only those settings you changed before. For example, you can change the settings of builders you added, but not add/remove builders if the list of builders has been changed since the last synchronization. You can add natures, and remove those you added before, but don’t touch any you don’t recognize. If the classpath has changed, don’t touch it.
  • If when running update, you detect that the project config is not as you last left it, and you need to change it in a conflicting manner (e.g. classpath changed and you need to change it again, builders added and you also need to add/remove builders), then you inform the user with a dialog, giving them the option to run ‘full synchronization’ instead.

Edit

Actually, I only have 1 suggestion. I’ve realised my second one was silly, and basically reduces to the first.

IMHO the main question is: what is “build” and what is tooling?

For me, classpath/buildpath configuration is about “build”, so it should be fully managed by Buildship, just like it is right now.
Unsupported project natures is most likely to be about “tooling”, so Buildship should merge the natures it needs to properly set up the project build (JDT, Groovy, etc.) with those it does not directly support (like JRebel, JPA Tooling, Spring IDE, and anything else)., which are likely to be about tooling. If they were about building, it’s very reasonable to expect the user to properly handle them through build.gradle (by applying a dedicated Gradle plugin, for instance).

So, your only objection that seems to be a bit problematic to me is about builders, more specifically the ordering of builders. They are about “build”, but many tooling also require one or more builders to work properly, and hence a merge approach is required. Honestly, I don’t know how the standard Eclipse UI actions handle this (I never saw any plugin asking me in which position it should add its own builder when using actions like “Convert to XYZ Project”). If this is an issue, I think Buildship should take the most simple/safe approach when merging (i.e.: place all its managed builders at the top or at the bottom) and then let the user customise this through proper code in eclipse { ... } block. But this should be needed only for very specific use cases, not for the basic and most common ones.

You may also enable this “merge” approach as an “opt-in” feature: i.e., the user decides on import (and then the choice is saved among the projects settings) whether a new Gradle synchronization should override the .project file from scratch or merge it with user-defined natures and builders. Actually, this is much like what Buildship 1.0 did (except that it did it only on project import, if I understand it correctly, while synchronization was always a merge operation) and I feel perfectly comfortable with this. In fact, I’m currently stuck at using Buildship 1.0.21 because of this reason!

I think if we can reduce the scope to “don’t touch unknown natures” and “don’t touch unknown builders, with some sensible ordering”, then this should be fine. I wouldn’t want to go and merge classpaths, but it seems we agree that that should be fully under Buildship’s control.

I updated https://github.com/eclipse/buildship/issues/392 to reflect this discussion.

I totally agree with this plan. Thank you Stefan!