Skip to content
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

SpotlessCache extension for Eclipse formatters #279

Merged
merged 2 commits into from
Aug 29, 2018

Conversation

fvgh
Copy link
Member

@fvgh fvgh commented Aug 8, 2018

Started WTP integration.
Provided proposal for SpotlessCache extension required by some Eclipse Formatters.
The extension shall support the following scenarios:

  1. Eclipse Formatter Step implementation provides multiple formatters which cannot live in the same class loader
  2. Eclipse Formatter only supports static configuration on workspace level

Both scenarios are covered by the new tests. The WTP is basically just an example, but the workspace level configuration and usage of statics is quite common.

The solution itself is just a proposal. Feel free to make changes on this branch.

Provided proposal for SpotlessCache extension required by some Eclipse Formatters.
@fvgh fvgh requested a review from nedtwigg August 8, 2018 19:15
@fvgh
Copy link
Member Author

fvgh commented Aug 8, 2018

@nedtwigg I will continue with the CDT integration on a separate branch. The CDT is quite independent and as mature as JDT. So if you like, we can either merge this branch, or continue the development until the integration of WTP in lib/lib-extra is complete.

@nedtwigg
Copy link
Member

Sorry for slowness, I'll take a look this weekend.

Copy link
Member

@nedtwigg nedtwigg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, very clean. The modification you made to SpotlessCache is well done. I think the modification to EclipseBasedStepBuilder is unnecessary, but maybe I'm missing something? See comments inline.


private enum WTP {
CSS("body {\na: v; b: \nv;\n} \n", "body {\n\ta: v;\n\tb: v;\n}", WtpEclipseFormatterStep::createCssBuilder), HTML("<!DOCTYPE html> <html>\t<head> <meta charset=\"UTF-8\"></head>\n</html> ", "<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"UTF-8\">\n</head>\n</html>\n", WtpEclipseFormatterStep::createHtmlBuilder), JS("function f( ) {\na.b(1,\n2);}", "function f() {\n a.b(1, 2);\n}", WtpEclipseFormatterStep::createJsBuilder), JSON("{\"a\": \"b\", \"c\": { \"d\": \"e\",\"f\": \"g\"}}", "{\n\t\"a\": \"b\",\n\t\"c\": {\n\t\t\"d\": \"e\",\n\t\t\"f\": \"g\"\n\t}\n}", WtpEclipseFormatterStep::createJsonBuilder), XML("<a><b> c</b></a>", "<a>\n\t<b> c</b>\n</a>", WtpEclipseFormatterStep::createXmlBuilder);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be more readable with:

// @formatter:off
private enum WTP {
  CSS("body {\na: v;   b:  ...
  HTML("<!DOCTYPE html> ..
}
// @formatter:on

/** Provides default configuration for CSSformatter */
public static EclipseBasedStepBuilder createCssBuilder(Provisioner provisioner) {
return new EclipseBasedStepBuilder(NAME, " - css", provisioner, state -> apply("EclipseCssFormatterStepImpl", state));
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be missing something, but I think you can avoid adding the formatterStepExt variable to EclipseBasedStepBuilder and EclipseBasedStepBuilder.State if you apply the following change:

- new EclipseBasedStepBuilder(NAME, " - css", ...
+ new EclipseBasedStepBuilder(NAME + " - css", ...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently I use formatterName to lookup the dependencies, which are equal for the different format methods (JSONS, JS, HTML...). So question remains whether I need a different name.
Each format method name per extension must be unique. Actually I should have not made this change, but addressed the question instead, whether we want a distinct FormatterExtension.
For typescript-formatter, there was the decision not to have a separate formatter extension.
But I understood that the typescript-formatter is one formatter for all. This is not the case for WTP. I can use the default WTP file extension settings to pick a formatter method for a file, but that should be configurable... So maybe it is worth to have dedicated FormatterExtension.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently I use formatterName to lookup the dependencies

Aha! That's what I was missing. In that case, this LGTM!

Copy link
Member

@nedtwigg nedtwigg Aug 20, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re: FormatterExtension, you means a typescript {} extension and a javascript {} extension (and css {} and html {})? I lean towards the default FormatterExtension, but I'm okay with having separate extensions instead. Here is my argument:

"Convention-over-configuration" is a great idea, and gradle has strong conventions for all the JVM languages. For the JVM languages we support (java{}, groovy{}, kotlin{}, scala{}), we can slurp the file locations from gradle's project model, and take advantage of that convention. In my gradle web projects, I've found that there aren't strong conventions for the location of web resources. Sometimes they're kinda scattered around in the src/main/resources directory, but other times they're being used for a static site outside of the JVM context, and they're just in the project root. So we're not really able to use the "convention-over-configuration" to simplify setup for web resources.

On the other hand, it probably helps user-discoverability to have dedicated html {}, css {}, etc. blocks... The real proof will be the docs. If it's easier to document html {}, css {} - dedicated formats, then that's what we should do.

We already have a sql{} block that isn't able to use conventions to know where the sql files are...

Copy link
Member Author

@fvgh fvgh Aug 20, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I'll remove the name extension and aim for one FormatExtension per WTP formatter method.

@fvgh
Copy link
Member Author

fvgh commented Aug 20, 2018

Sorry, @nedtwigg, I think I found a mistake in my approach:

The SpotlessCache shall remain according to #284, so that FormatterStep states can be reused for repetitive Spotless task execution. In case there are no configuration changes, the SpotlessExtension.configure is only called once. In case of configuration changes, the 'old' ClassLoader is not removed from the SpotlessCache.cache map, since the key is the serialized EclipseBasedStepBuilder.State, which includes the settingsFiles. So for example my static Eclipse Preferences configured for the previous task execution are not going out of scope. The SpotlessCache is only cleaned when the clean task is run manually.

Is my understanding correct?

If my understanding is correct:
I think there should be a solution, which ensures that there is only one <project/Eclipse-Formatter-Method> combination in the cache. The Eclipse does a lot of static processing (loads internal DTDs for XHTML, ...). It is good to cache these things, but there should be not too much waste of memory if they get obsolete.

@nedtwigg
Copy link
Member

Is my understanding correct?

Yes.

There should be not too much waste of memory if they get obsolete.

Since we are both spotless devs, I think we overestimate how much people change settings. I think 99+% of the calls to spotless tasks do not involve changes to their spotless configuration. Anytime the user does gradlew clean or gradlew --stop, the cache is cleared. So I don't worry about the memory-consumption of the "actively changing configuration use-case". I only care about performance of the "I'm just running tasks" use-case, because it's 99+% of all the runs.

That said, if you see an easy way to make it more resource-efficient, I'm all for it :)

@fvgh
Copy link
Member Author

fvgh commented Aug 20, 2018

I have to call it a day. Got too late... Will have time end of the week to make up my mind.
CDT is also ready, just fine tune the LincenseHeader delimiter. But I am afraid I am quite busy the next few days...

@fvgh
Copy link
Member Author

fvgh commented Aug 29, 2018

@nedtwigg Had a look at the memory development of the gradle daemon when applying Spotless Eclipse Groovy/Java/Cpp to existing Android project. Think you are right, it seems not worth to make the interface more complicated to save about 15-20% memory consumption during build script development.

@nedtwigg
Copy link
Member

Then I think all this needs is to update the changelogs and merge :) Press the merge button whenever you're ready.

@fvgh
Copy link
Member Author

fvgh commented Aug 29, 2018

@nedtwigg See no need for change-log entry, do you? The cache modification is quite low level and the WTP integration has not finished.

@nedtwigg
Copy link
Member

Good call.

@nedtwigg nedtwigg merged commit e3b3d3e into master Aug 29, 2018
@nedtwigg nedtwigg deleted the eclipse_classloader_cache_extension branch August 29, 2018 18:41
@fvgh fvgh mentioned this pull request Nov 4, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants