[GRADLE-1692] Tooling API should provide a classpath for build.gradle file Created: 26/Jul/11  Updated: 10/Feb/17  Resolved: 10/Feb/17

Status: Resolved
Project: Gradle
Affects Version/s: 1.0-milestone-3
Fix Version/s: None

Type: Improvement
Reporter: Kris De Volder Assignee: Unassigned
Resolution: Won't Fix Votes: 2


To provide good editor support (code completion, semantic highlighting, navigation hyperlinks...) the IDE needs to know what classpath to use for the build.gradle file.

Generally it won't work well to use the same classpath as the project the build file is in (since this is a classpath for the source code of the project, but not the build file itself).

The Tooling API should therefore provide separate classpath information for the build.gradle file.

Note: Just an FYI. In Eclipse there is generally only one classpath per project, but for STS Gradle support, we are working on some solution inside of Greclipse that will allow a separate classpath to be used for 'scripts' in a project. The build.gradle file will be able to use this mechanism to get its own classpath, seperate from that used for the compiling the project's source folders.

Comment by Szczepan Faber [ 24/Apr/12 ]

Hey Kris,

As a first step in improving the editing support for build.gradle files we want to provide:

  1. the classpath for the given build file. For this one, we plan an API that takes a File on input (which is the build.gradle you need the classpath for) and returns a collection of ExternalDependency objects.
  2. the default imports. We haven't talked about the API for that one but I guess the list of strings will do.

Please let us know if above would work for you!

Comment by Kris De Volder [ 24/Apr/12 ]

That seems like the right information. But...

As I already mentioned, it will be difficult for Eclipse to set a classpath for just one file though. That isn't necessarily something for you to worry about.

But... Does Gradle have a concept of a 'build project'. For example what if my build has a buildSrc folder. I understand that code in there is also available to the build script. Sounds like a source folder in a project to me.

So while I think we can make progress just getting a list of external dependencies for build.gradle, I fear it may back us into a corner where it is hard to back out of w.r.t. to handling stuff like buildSrc correctly.

For a number of reasons, I think the correct way to make info about build.gradle's classpath (both external dependencies and source folders) available, is by conceptually considering build.gradle as being part of some project-like entity that represents the build-level classpath.

So after some thought about this, it would, in my opinion, be best if we start thinking about making the concept of a 'build level project' explicit in the tooling API rather than try to retrofit it later.

This will be harder to do than what you propose though. But I think that's what we would need to do for Greclipse code assist and stuff like that to work well.

To make this easier, we could 'map' this 'build-level project' only partially and add bits of it over time. E.g. for now the build-project might just contain 'build.gradle' and provide a list of external dependencies. Later we could add the concept of source folders and add 'buildSrc' etc.


Comment by Adam Murdoch [ 24/Apr/12 ]


Ignoring for a moment the fact that Eclipse really only has one class path, I think the model would look something like this:

Each Gradle script would have its own class path. In Gradle, each script can declare its own set of class path dependencies, plus it inherits some stuff from the context it runs in. So, the class path for a script is independent of the class path of any other script. My 'build.gradle' may have a dependency on, say, my-custom-plugin 1.6, and import 'gradle/some-script.gradle' that does not.

And this class path is independent of the compile class path for the source of the project. So, in a project that uses Gradle 1.0-rc-1 to build source against Groovy 1.7.6, the class path for build.gradle would include groovy 1.8.6, and the compile class path for the project would include groovy 1.7.6.

A build script's class path would be modelled exactly the same way as the project's class path, so that it is made up of a set of EclipseProjectDependency and ExternalDependency instances.

In Gradle, the buildSrc directory is treated as a separate project, and it can have its own build script, dependencies, and so on. It can even have sub-projects and its own buildSrc directory (not that we think this is a good idea). So, it would make sense to map buildSrc to a separate project. Each build script class path would then include a project dependency entry that points to this project.

To make things even more fun, we're planning on allowing build scripts to declare dependencies on regular projects, so that the output of one project can both be published and used later in the same build.

I can see a few options (some of these you've already suggested):

  • Add a 'build' project-like-thing, whose class path is the union of all the build script class paths, and include buildSrc in this. If any build script declares a dependency on a regular project, then this 'build' project-thing would also depend on that project.
  • As above, but slightly more granular, so that buildSrc is mapped to its own project, and there is a 'build' project-thing per real project.
  • Move the content assistance behind the tooling API, where we can handle any set of class paths we like.
Comment by Kris De Volder [ 24/Apr/12 ]

Thinking of what would work best in Eclipse the first two options seem preferable.

I don't believe in the third option. Though I would wish it so, (so you guys do all the work, and my life is easy , I don't think it will work well.

Eclipse/Greclipse may not be very good in having this annoying 'one classpath' assumption built-in. But it does a pretty good Job at robust parsing and type inference of code that is in a broken state. It does this on the fly with a 'reconcile phase' of hot editor contents. I.e. it does this with code that is not even on disk and that may not even parse because you are in the middle of typing somethin and just entered a '.'

To have this content assist work well (i.e. work most of the time and be fast) this sort of thing is important.

Gradle can't really do this (well I guess it can, anything is possible but we will have to provide some way to tell Gradle about unsaved contents in the editors, and Gradle would need to be able to parse this and tell us about content assist in terms of text postions in these 'hot' editor contents.

In Greclipse most of the machinery to make much of this work is already there. You would be reimplementing it mostly. What I quickly hacked up, for example, can already suggest that "rep" in the toplevel of the build.gradle can be completed to "repositories" and will popup the JavaDoc for the corresponding method in the Gradle API. Also when you then are inside the {} behind the "repositories" keyword it will correctly infer that the type of the 'delegate' in that context is 'RepositoryHandler' and so corresponding code assist suggestions for methods implemented there also get suggested in that particular context but not elsewhere. This requires little work. The key is having a mechanims to attach type info to code/expressions and and having those types on the classpath.

So I would think that the first two options are preferable. But I could imagine we may need to decide what side of the api boundary' the work of defining this mapping would be at. I.e. does the tooling API provide this mapping directly, or does it only provide the information needed for the IDE to define its mapping.

I'm guessing you guys probably understand better what such a mapped project should like (e.g. is 'buildSrc a source folder or a project? I haven't got a clue

Even if you decide that the code assist should all go behind the API.. then we probably will still need classpath information. This is because if you see an expression / method call in the code. You probably want to be able to support navigation operations such as 'go to the declaration of this thing'. And this thing will be something like a type or a method in a type. To be able to find it the IDE would need to have the type on the classpath. To be able to go to its source code, we would need source code attachements for the jars (if the type comes from an external dependency).

Gradle so far is doing pretty well with giving us this type of classpath info for 'project level' stuff.
Now I think we need some way to extend this to the 'build level stuff' as well.

Comment by Kris De Volder [ 27/Apr/12 ]

OK, it was not my intention to block progress on this issue by making demands that are too complex.

I'm still open to discussing further, but in the interest of moving forward it may be better to go with what Szczepan originally proposed. I.e. an API that gives just the classpath for the build.gradle file.

I will probably use this in some way to create a 'virtual project' on the IDE side that contains this build file as linked resource (and maybe some other stuff as well) and attach the classpath to it.


Comment by Benjamin Muschko [ 15/Nov/16 ]

As announced on the Gradle blog we are planning to completely migrate issues from JIRA to GitHub.

We intend to prioritize issues that are actionable and impactful while working more closely with the community. Many of our JIRA issues are inactionable or irrelevant. We would like to request your help to ensure we can appropriately prioritize JIRA issues you’ve contributed to.

Please confirm that you still advocate for your JIRA issue before December 10th, 2016 by:

  • Checking that your issues contain requisite context, impact, behaviors, and examples as described in our published guidelines.
  • Leave a comment on the JIRA issue or open a new GitHub issue confirming that the above is complete.

We look forward to collaborating with you more closely on GitHub. Thank you for your contribution to Gradle!

Comment by Benjamin Muschko [ 10/Feb/17 ]

Thanks again for reporting this issue. We haven't heard back from you after our inquiry from November 15th. We are closing this issue now. Please create an issue on GitHub if you still feel passionate about getting it resolved.

Generated at Wed Jun 30 12:01:56 CDT 2021 using Jira 8.4.2#804003-sha1:d21414fc212e3af190e92c2d2ac41299b89402cf.