groovy-eclipse icon indicating copy to clipboard operation
groovy-eclipse copied to clipboard

Add support for gradle file editing

Open gayanper opened this issue 4 years ago • 14 comments

Today in eclipse buildship team is not providing gradle file editing support pointing this project doesn't support well. I would like to request to have support for gradle file from this project if build ship is not intrested.

From what i understand we need to have a classpath for a give gradle file based on

  1. gradle API
  2. plugin jars in the build script

I think if we can have support to add a custom classpath for a groovy file editor and open it we can achieve some support for gradle file editing.

gayanper avatar Jun 09 '20 19:06 gayanper

The classpath issue is the biggest hurdle. You can get some basic editor support by adding "gradleApi()" in your dependencies block. Here are some issues related to that:

https://github.com/eclipse/buildship/issues/547 https://github.com/gradle/gradle/issues/1003 https://github.com/gradle/gradle/issues/6089

You can add a dsld script to your project like this (the is poc/alpha stuff):

package dsld

def isBuildScript = fileExtension('gradle') & (~fileName('settings.gradle'))

contribute(isBuildScript & isThisType()) {
  delegatesTo 'org.gradle.api.Project'

  method name: 'apply', type: void, params: [block: Closure]
  method name: 'apply', type: void, namedParams: [plugin: String, from: Object, to: Object]
  method name: 'apply', type: void, params: [action: 'org.gradle.api.Action<? super org.gradle.api.plugins.ObjectConfigurationAction>']
}

contribute(isBuildScript & enclosingCallName('configurations') & inClosure() & currentType('org.gradle.api.Project')) {
  setDelegateType('org.gradle.api.artifacts.ConfigurationContainer')
}

contribute(isBuildScript & enclosingCallName('dependencies') & inClosure() & currentType('org.gradle.api.Project')) {
  setDelegateType('org.gradle.api.artifacts.dsl.DependencyHandler')
}

contribute(isBuildScript & enclosingCallName('repositories') & inClosure() & currentType('org.gradle.api.Project')) {
  setDelegateType('org.gradle.api.artifacts.dsl.RepositoryHandler')
}

contribute(fileName('settings.gradle') & isThisType()) {
  setDelegateType('org.gradle.api.initialization.Settings')
}



/* https://github.com/gluck/gradle-scripts/blob/master/GradleDSLD.dsld.custom
artifacts 'org.gradle.api.artifacts.dsl.ArtifactHandler'
install, upload  'org.gradle.api.tasks.Upload'
task 'org.gradle.api.Task'
clean 'org.gradle.api.tasks.Delete'

block('org.gradle.api.tasks.Upload', 'repositories') {
  setDelegateType 'org.gradle.api.artifacts.dsl.RepositoryHandler'
  delegatesTo 'org.gradle.api.plugins.MavenRepositoryHandlerConvention'
  collectOuterScope(scope).each {
    delegatesTo it
  }
}
blockSetDelegateType 'org.gradle.api.plugins.MavenRepositoryHandlerConvention', 'mavenInstaller', 'org.gradle.api.artifacts.maven.MavenResolver'
blockSetDelegateType 'org.gradle.api.plugins.MavenRepositoryHandlerConvention', 'mavenDeployer', 'org.gradle.api.artifacts.maven.GroovyMavenDeployer'

rootBlockSetDelegateType 'eclipse'       , 'org.gradle.plugins.ide.eclipse.model.EclipseModel'
blockSetDelegateType 'org.gradle.plugins.ide.eclipse.model.EclipseModel', 'classpath', 'org.gradle.plugins.ide.eclipse.model.EclipseClasspath'
blockSetDelegateType 'org.gradle.plugins.ide.eclipse.model.EclipseClasspath', 'file', 'org.gradle.plugins.ide.api.XmlFileContentMerger'

rootBlockSetDelegateType 'idea'          , 'org.gradle.plugins.ide.idea.model.IdeaModel'

// requires gradle-plugins-1.2.jar & sources
rootBlockSetDelegateType 'javadoc'       ,'org.gradle.api.tasks.javadoc.Javadoc'
rootBlockSetDelegateType 'groovydoc'     ,'org.gradle.api.tasks.javadoc.Groovydoc'

// requires gradle-scala-1.2.jar & sources
rootBlockSetDelegateType 'scaladoc'       ,'org.gradle.api.tasks.scala.ScalaDoc'

// requires gradle-signing-1.2.jar & sources
rootBlockSetDelegateType 'signing'        ,'org.gradle.plugins.signing.SigningExtension'
*/

eric-milles avatar Jun 09 '20 21:06 eric-milles

I was thinking if we can provide virtual project when opening a gradle file in groovy editor and include this dsl and the gradle api dependencies ? Do you think that's possible ?

gayanper avatar Nov 05 '20 07:11 gayanper

You can try out the DSLD now by adding it to your ~/.groovy/greclipse/global_dsld_support directory and adding gradleApi() to the dependencies block of your gradle script. If the DSLD gets to a sufficient point of capability, then we can explore how to integrate it and bootstrap its dependencies. I may have tried @Grab within a DLSD to add library references; I can't remember the outcome of the experiment.

eric-milles avatar Nov 06 '20 13:11 eric-milles

@eric-milles i tried you suggestion. But it seems like the dsl file isn’t getting loaded. For example blocks like dependencies and properties of dependencies block is not completing. And when i check the dsld settings window I cannot see the global dsld i added either

gayanper avatar Nov 25 '20 11:11 gayanper

it seems like the dsl file isn’t getting loaded

If you add a DSLD to the global folder, you need to restart Eclipse or run Window > Preferences > Groovy > DSLD > Recompile Scripts.

eric-milles avatar Nov 25 '20 15:11 eric-milles

Once a DSLD is accepted, you can look at Console view > New toolbar button > Groovy Event Console to see the compiler's logging. If you add log statements in your DSLD this is where you would see them.

eric-milles avatar Nov 25 '20 16:11 eric-milles

@eric-milles i added the file content at ~/.groovy/greclipse/global_dsld_support/gradle.dsld

But this how the eclipse settings look like Screenshot 2020-11-25 at 20 50 45

And following is my gradle file

/*
 * This file was generated by the Gradle 'init' task.
 *
 * This generated file contains a sample Java Library project to get you started.
 * For more details take a look at the Java Libraries chapter in the Gradle
 * User Manual available at https://docs.gradle.org/6.3/userguide/java_library_plugin.html
 */

plugins {
    // Apply the java-library plugin to add support for Java Library
    id 'java-library'
}

repositories {
    // Use jcenter for resolving dependencies.
    // You can declare any Maven/Ivy/file repository here.
    jcenter()
}

dependencies {
	gradleApi()
    // This dependency is exported to consumers, that is to say found on their compile classpath.
    api 'org.apache.commons:commons-math3:3.6.1'

    // This dependency is used internally, and not exposed to consumers on their own compile classpath.
    implementation 'com.google.guava:guava:28.2-jre'

    // Use JUnit test framework
    testImplementation 'junit:junit:4.12'
}

I still don't get gradle specific completions.

gayanper avatar Nov 25 '20 19:11 gayanper

I even tried converting the project into a groovy project as well. But it didn't work.

gayanper avatar Nov 25 '20 20:11 gayanper

gradleApi() is a pseudo-dependency (or whatever the term is). You still need to put a specifier in front of it. I would probably use implementation gradleApi(). Your project should also have the Groovy DSL Support classpath container. You can open the Groovy Event Console before you try the Recompile Scripts button to see the compiler's progress when it tries to compile them.

eric-milles avatar Nov 26 '20 17:11 eric-milles

For a single project, you can just place the DSLD in a source folder like this: image

Either way, it will show on the DSLD preference panel when it has been accepted.

Note: I don't think it is required to be in the dsld package. That is more of a convention.

eric-milles avatar Nov 26 '20 17:11 eric-milles

Nice it is working now. But seems like the completions inside the dependency and repository like closures are not working. How can we get those to work ? And how can we add this dsld classpath and groovy nature and gradle api into project classpath when opening a gradle file ? I was hoping if we are capable of having a virtual project with this setup to be used underneath when opening a gradle file.

gayanper avatar Nov 26 '20 19:11 gayanper

For now, I'd stick with enhancing the DSLD so that you get the experience you are looking for. If you can't get there, all the bootstrapping is unneeded. Can you show a quick screenshot of what you have and describe what kind of completion proposals you are expecting?

eric-milles avatar Nov 27 '20 15:11 eric-milles

In the below i'm expecting to get completions for api and implementation Screenshot 2020-11-27 at 17 33 12

below i'm expecting for completions of mavenCentral, maven blocks like https://docs.gradle.org/current/userguide/declaring_repositories.html#sec:declaring_multiple_repositories

Screenshot 2020-11-27 at 17 33 48

gayanper avatar Nov 27 '20 16:11 gayanper

For dependencies you can hover over and it should display a type or method. This indicates that the DSLDTypeLookup knowns something about it. In terms of code completion within the block, you need to look at org.gradle.api.artifacts.dsl.DependencyHandler (the delegate type according to the DSLD). What fields and methods does it expose? Those should be available within the block.

If there are items you want for completion beyond what the delegate type offers, then more DSLD script will be required. For example, adding "method name:'jcenter', type:void, parameters:[]" inside the "contribute(isBuildScript & enclosingCallName('dependencies') ..." closure would enable the jcenter method.

The DSLD given in the second comment is a skeleton. There will be much more script required to provide for a typical gradle build script.

eric-milles avatar Dec 01 '20 15:12 eric-milles