Inconsistent behaviour in grgit when executed from buildship

I’m trying to import an existing project as a Gradle project.
The import goes well, the Gradle nature is added to the .project, and the grade.prefs is correctly populated in .settings directory.
However,

Loading tasks of project located at D:\git\acceptanceTests\acceptanceTests failed due to an error in the referenced Gradle build.

The stacktrace gives more info about it:
Caused by: org.gradle.api.internal.plugins.PluginApplicationException: Failed to apply plugin [id ‘dataset-plugin’]

Caused by: org.gradle.internal.reflect.ObjectInstantiationException: Could not create an instance of type xxx.dataset.model.DatasetExtension_Decorated (that is a custom extension)

Caused by: java.lang.IllegalArgumentException: One of setGitDir or setWorkTree must be called.
at org.eclipse.jgit.lib.BaseRepositoryBuilder.requireGitDirOrWorkTree(BaseRepositoryBuilder.java:586)
at org.eclipse.jgit.lib.BaseRepositoryBuilder.setup(BaseRepositoryBuilder.java:554)
at org.eclipse.jgit.storage.file.FileRepositoryBuilder.build(FileRepositoryBuilder.java:92)
at org.eclipse.jgit.storage.file.FileRepositoryBuilder$build.call(Unknown Source)
at org.ajoberstar.grgit.operation.OpenOp.call(OpenOp.groovy:95)
at org.ajoberstar.grgit.operation.OpenOp.call(OpenOp.groovy)
at java_util_concurrent_Callable$call.call(Unknown Source)
at org.ajoberstar.grgit.util.OpSyntaxUtil.tryOp(OpSyntaxUtil.groovy:45)
at org.ajoberstar.grgit.Grgit$__clinit__closure1.doCall(Grgit.groovy:191)
at xxx.dataset.model.DatasetExtension.(DatasetExtension.groovy:60)

Since Grgit 1.3.0, Grgit.open() does not need any parameters, as it calls JGit with parameters to infer the .git location (in the parent directory hierachy of the current directory)
I’m using a recompiled internal Grgit version (that is compatible with java 6)
Everything is correctly set in my settings.gradle file

gradle.projectsLoaded { g ->
g.rootProject.buildscript {
repositories {
//local repo to get my internal plugins
}
dependencies {
classpath 'xxx:dataset-plugin:latest.release’
classpath ‘xxx:grgit-java6:latest.release’
}
}
}

Before switching my project to a Gradle project, this was workingfine, because it was probably pulling my version of Grgit.
When Buildship tries to build the task view, it does not seem to pick the correct version of Grgit, hence the error.
Do you have an idea of what could go wrong ? Maybe the projectsLoaded closure is called ‘too late’ ?
(I’m adding andrew @ajoberstar , he might have an idea about it)

problem is probably a missing environement variable
When I launch ‘gradlew tasks’ on my prpject, it works fine.

WHen importing the project, it fails to import due to the exception.
If I add manually the gradleprojectnature and the .settings/gradle.prefs file, and create a Gradle run configuration with ‘tasks’ in the task list, it fails with the above exception

Managed to produce a SSCCE of the problem:
TestGit.zip (131.0 KB)

Using Eclipse 4.4, and latest Buildship 1.0.1 for eclipse 4.4

  • Import project from Gradle
  • Select the Eclipse project (inner TestGit directory, not the whole Git repo)
  • Select remote distribution ‘https://services.gradle.org/distributions/gradle-2.3-bin.zip’, or latest 2.5, or gradle wrapper (it doesn’t matter)
  • Try to import the project => crash that I dumped in my previous post.

If importing as a regular Eclipse project, and launch the build.bat inside (which does ‘gradlew clean build’ from the eclipse directory) the build works

Does anyone have a clue why Jgit is able to walk up the directory tree to find the .git directory when using regular gradlew command line, but not under Buildship ?

Could you tell me how to debug this?
I’m not sure how to connect a debugger to gradle to detect what is happening during the configuration phase and the Grgit.open() call

I can repackage grgit locally and add some debug traces to infer the problem, but debugging would be way better.

The above zip contains a reproduction of the problem in a very few steps.

Ok Guys

using the example I attached in a previous post I successfully debugged the problem.

For those interested in the debug operations, see at the end of my post.

For Buildship devs, new File("").getAbsoluteFile() returns:

  • the eclipse absolute path when executed from Buildship
  • the eclipse project location, when executed from a gradlew call from within the eclipse project (i.e. cd /path/to/eclipse/project ; gradlew …)

Is there a way that Buildship calls to the Gradle daemon could be done from the Eclipse project location and not from the Eclipse distribution location ?


I even made a simpler example to reproduce the problem:
A simple build.gradle containing

import java.io.File;
apply plugin: ‘java’
println new File(“”).getAbsoluteFile()

gradlew build call from the eclipse project directory returns the eclipse project directory.
but from buildship, it prints the eclipse distribution directory.
In my case, this is very bad, as JGit will throw an exception, because it could not find the git repository, by walking up the directory tree. The JGit exception prevents Buildship from importing the project, or modelling the tasks.
But even without Jgit, this different behaviour could lead to unexpected - hard to debug - things.

Interestingly enough, using Gradle file() method instead of java.io.File works correctly, and always returns the eclipse project directory.
Unfortunately, when using a dependency (like me, using JGit), I cannot change their way of doing things, like new File("")

@ajoberstar this is not related to Grgit (nor Jgit)


And now, for those interested, the debug operations (even though with the simpler example, there is no need to debug anymore, since the println shows the problem)

  • Add in your ~/.gradle/gradle.properties

org.gradle.daemon=true
org.gradle.jvmargs=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5006

  • Import my example project as a regular project in eclipse
  • Launch “gradle eclipse” to get the jgit dependency in the referenced libraries of the project
  • Set a breakpoint in JGit class BaseRepositoryBuilder in findGitDir() method
  • launch gradlew build while located inside the eclipse project
  • launch a ‘remote application’ eclipse debugger on 'localhost 5006
  • the debugger stops at the specified breakpoint.
  • Inspect new File("").getAbsoluteFile(), which is equal to the absolute path of the eclipse project => OK
  • now, since you cannot successfully import the project as a Gradle project using Buildship (since there is an error thrown by JGit), you have to do the import manually
  • create a gradle.prefs file in .settings in the eclipse project
    put inside
{
  "1.0": {
    "project_path": ":",
    "project_dir": "path/to/eclipse/proj",
    "connection_project_dir": "path/to/eclipse/proj",
    "connection_gradle_user_home": null,
    "connection_gradle_distribution": "GRADLE_DISTRIBUTION(WRAPPER)",
    "connection_java_home": null,
    "connection_jvm_arguments": "",
    "connection_arguments": ""
  }
}

in the .project, change the nature and buildspec to

<natures>
	<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
	<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
<buildSpec>
	<buildCommand>
		<name>org.eclipse.jdt.core.javabuilder</name>
		<arguments/>
	</buildCommand>
	<buildCommand>
		<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
		<arguments/>
	</buildCommand>
</buildSpec>
  • Now the project shall be seen as a Buildship project (with the G decoration on the project icon)

  • Perform right click on the project, Gradle / Refresh Gradle project

  • Inspect the same stuff in the debugger to see that it points to the eclipse distribution

Hi Francois, I just got a notification about this recently. The root of the “problem” is that Gradle generally doesn’t make any guarantees/assumptions about the working directory of the build. That’s why the file() method exists, so that you can always easily get a file relative to the project directory.

Grgit.open() will always use the process working directory, which may not have any relation at all to the project directory. However, the open method also takes a currentDir flag that essentially overrides the working directory. See OpenOp’s Javadoc. Also, I use this flag in the new org.ajoberstar.grgit plugin that provides a grgit instance automatically.

1 Like

Hi Andrew
I pinged you to get your view on this.
I’m aware of the reason for the file() method creation.
I didn’t know about the currentDir attribute on OpenOp.
I was only focused on the Grgit.open() call when you asked me to test your modification on Grgit, back in may.
I didn’t pay attention to the currentDir attribute addition.

This is fine by me since I will find a way to make it work, thanks.

Nevertheless I find it weird that buildship calls gradle from the eclipse directory and not each project directory.

Hi François. It looks like you found a solution to your specific problem. Great.

Regarding the working directory: Buildship does not set any explicit working directory (there is no API on the Tooling API to do this since there are no assumptions by Gradle about the working directory). Andrew’s solution looks like a good solution to me, too.