Gradle + Eclipse: How to not export JARs that are dependencies of a dependency?

In my ‘build.gradle’ file I have the following:

...
dependencies {
  ...
  testCompile (group: 'org.uncommons', name: 'reportng', version: '1.1.2') { exclude group: 'org.testng', module: 'testng' }
  ...
}
...

reportng needs ‘velocity-1.4.jar’ and ‘velocity-dep-1.4.jar’, and actually the above testCompile dependency causes these 2 JARs to be fetched and to be placed into the Eclipse’s .classpath file, as “exported” (that is, their checkbox is checked).

The fact that these 2 JARs get set as exported is a problem. I need them to still be fetched but not to be exported.

From the Gradle doc I understand that this is done by using ‘noExportConfigurations’ as per the example:

apply plugin: 'java'
apply plugin: 'eclipse'
  configurations {
  provided
  someBoringConfig
}
  eclipse {
    classpath {
      //if you don't want some classpath entries 'exported' in Eclipse
    noExportConfigurations += configurations.provided
  }
}

My problem is that I don’t have a ‘configurations {}’ section, and while I can certainly add one, I don’t know what to put in it in order to exclude from export not the whole reportng but just two of the JARs that come with it.

You’ll probably want something like:

configurations {
    noExport
}
  dependencies {
    // replace with correct values
    noExport "foo:velocity:1.4"
     noExport "foo:velocity-dep:1.4"
}
  eclipse {
    classpath {
        noExportConfigurations += configurations.noExport
    }
}

Thanks. I didn’t manage to make it work yet but now I have some clues about where my problem lies, although I don’t know the cause - and I should have mentioned in my first post that I use Gradle 1.6 (in Eclipse Kepler SR1 on Windows 8.1, with JRE 1.7.0_51-b13).

Please see the 3 points under ‘classpath’ in the following code I tested:

configurations {
    noExport
}
dependencies {
    noExport "velocity:velocity:1.4"
     noExport "velocity:velocity-dep:1.4"
}
eclipse {
    classpath {
          // 1) This does nothing and causes no errors when I uncomment it:
        // noExportConfigurations += configurations.noExport
          // 2) As expected, this excludes the two Velocity 1.4 JARs from the classpath when I uncomment it:
        // minusConfigurations += configurations.noExport
          // 3) As expected, this errors with
        //
 "Could not find property 'showmesomeerrConfigurations'
        //
 on org.gradle.plugins.ide.eclipse.model.EclipseClasspath_Decorated@60ea2e4d."
        // when I uncomment it:
        // showmesomeerrConfigurations += configurations.noExport
    }
}

Point 1 is my problem: I don’t know why ‘noExportConfigurations’ has no effect for me, nor does it cause any error.

I thought I made some mistake in defining my ‘noExport’ configuration, but point 2 clearly disproves this.

Then I thought perhaps ‘noExportConfigurations’ was introduced in a later Gradle version, so it’s not recognized by my Gradle 1.6 and I see no errors because maybe Gradle simply ignores properties which it does not recognize, but point 3 seems to disprove this.

I couldn’t find any doc about ‘noExportConfigurations’ property that might explain what I’m doing wrong. I did research this problem as much as I could but my only hypothesis so far is that I might have hit this , and in the post linked from there I could not extract any possible workaround (plus I’m not 100% sure it’s the same issue), so I’m at a loss.

How are you integrating with Eclipse? It’s possible that ‘noExportConfigurations’ only has an effect when generating Eclipse files with ‘gradle eclipse’, but not when using the STS plugin.

When I say that noExportConfiguration “does nothing” I mean that when I run the script the 2 Velocity JARs still get set as exported in the classpath, even if I manually set them as not exported before running the script.

The ‘.classpath’ file generated via ‘gradle eclipse’?

Yes but generated via ‘gradlew.bat eclipse’

I actually don’t use the STS plugin, I created and run an “External Tool Configuration” in Eclipse where I have Main / Location set to ‘${workspace_loc:/MyJavaProject/gradlew.bat}’, Working Directory set to ‘${workspace_loc:/MyJavaProject}’, Arguments set to ‘${string_prompt}’ and when I run this and the prompt appears I enter ‘eclipse’ into it.

I just verified that if I run the script not from Eclipse as described above but with ‘gradlew.bat eclipse’ from command prompt it makes no difference.

Would you be able to provide a small self-contained sample build script that allows to reproduce the problem?

I will try to do so. In the meantime thanks a lot for the assistance :slight_smile:

The following ‘build.gradle’ demonstrates the problem - at least on my machine:

// Project settings
project.ext {
   distPath = "$buildDir/dist"
}
  apply plugin: 'java'
apply plugin:'application'
apply plugin: 'eclipse'
  mainClassName = 'main.Main'
  task wrapper(type: Wrapper) {
      gradleVersion = '1.6'
}
  tasks.withType(Compile) {
   options.encoding = 'UTF-8'
}
  repositories {
   mavenCentral()
    maven
  {
  url 'https://nexus.codehaus.org/content/groups/snapshots-group/'
 }
 maven
  {
  url 'http://nexus.devlab722.net/nexus/content/repositories/releases/'
 }
 maven
  {
  url 'http://repo.gradle.org/gradle/plugins-snapshots/'
 }
 maven
  {
  url 'https://repository.apache.org/content/groups/staging/'
 }
 maven
 {
  url 'http://savant.inversoft.org/'
 }
}
  configurations {
      noExport
}
  dependencies {
   testCompile (group: 'org.uncommons', name: 'reportng', version: '1.1.2')
   noExport "velocity:velocity:1.4"
}
  eclipse {
      classpath {
          // This does nothing and causes no errors when I uncomment it:
        noExportConfigurations += configurations.noExport
          // As expected, this excludes the two Velocity 1.4 JARs from the classpath when I uncomment it:
        // minusConfigurations += configurations.noExport
          // As expected, this errors with
        //
 "Could not find property 'showmesomeerrConfigurations'
        //
 on org.gradle.plugins.ide.eclipse.model.EclipseClasspath_Decorated@60ea2e4d."
        // when I uncomment it:
        // showmesomeerrConfigurations += configurations.noExport
    }
}
  // Build deployment dir from all dependencies and compiled jars
task libs(mustRunAfter: 'build', type: Sync) {
    from jar.archivePath
 from jar.destinationDir
 from configurations.runtime
 from jar.destinationDir
 from project.configurations.runtime.allArtifacts*.file
 into distPath
}
  //We make the distribution available after the build
jar.doLast() {
   println ':libs TestGradleNoExport'
 tasks.libs.execute()
}

In case it matters, this is my ‘/TestGradleNoExport/gradle/wrapper/gradle-wrapper.properties’:

#Tue May 28 15:33:56 CEST 2013
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=http\://services.gradle.org/distributions/gradle-1.6-bin.zip

I tested this by creating a minimal Eclipse project which I’ll be glad to zip and send or attach somewhere if the above doesn’t show the problem on other machines.

I run this ‘build.gradle’ in the exact ways mentioned in the previous posts; when I do, the two Velocity 1.4 JARs always become exported, even if I set them as non-exported before running this.

I double-checked that if I use ‘minusConfigurations’ instead of ‘noExportConfigurations’, with no other changes whatsoever, it does have the effect that the 2 Velocity JARs do not appear at all in the classpath.

Below is the console output I get when I run this script with args ‘eclipse --info’:

Starting Build
Settings evaluated using empty settings script.
Projects loaded. Root project using build file 'D:\TestGradleNoExport\build.gradle'.
Included projects: [root project 'TestGradleNoExport']
Evaluating root project 'TestGradleNoExport' using build file 'D:\TestGradleNoExport\build.gradle'.
All projects evaluated.
Selected primary task 'eclipse'
Tasks to be executed: [task ':eclipseClasspath', task ':eclipseJdt', task ':eclipseProject', task ':eclipse']
:eclipseClasspath
Executing task ':eclipseClasspath' due to:
  Task.upToDateWhen is false.
:eclipseJdt
Executing task ':eclipseJdt' due to:
  Task.upToDateWhen is false.
:eclipseProject
Executing task ':eclipseProject' due to:
  Task.upToDateWhen is false.
:eclipse
Skipping task ':eclipse' as it has no actions.
  BUILD SUCCESSFUL
  Total time: 3.803 secs

It smells more and more like that GRADLE-2114, although I cannot back this with any hard fact.

It’s not GRADLE-2114. I just realized that the docs say that ‘noExportConfigurations’ is expected to be a subset of ‘plusConfigurations’. Given that, I’m not sure how it could be leveraged to solve your problem. One alternative is to use one of the provided hooks to alter the ‘.classpath’ file more directly.

PS: ‘mustRunAfter’ was only introduced in a Gradle version later than 1.6, and it needs to go into the body of the task declaration. Also, ‘mustRunAfter build’ is probably not what you really want/need.

Whoops. Thanks for the several pointers. I wonder why that ‘mustRunAfter’ never causes errors here. I’m quite sure we are using Gradle 1.6 but I will see if it’s possible to make Gradle print the version when it runs. I will see if I can still use ‘noExportConfigurations’ as a subset of ‘plusConfigurations’ to achieve my goal otherwise I will use your suggested alternative.

Run ‘gradle -v’. In earlier Gradle versions, Gradle didn’t complain about unknown arguments in a task’s “header”.

When I run the above sample script with args ‘eclipse --version’ it shows 1.6, so I guess that using ‘mustRunAfter’ like that is not supposed to generate errors even though was introduced in a later version than 1.6.

Got it. ‘gradle -v’ :

------------------------------------------------------------
Gradle 1.6
------------------------------------------------------------
  Gradle build time: Tuesday, May 7, 2013 9:12:14 AM UTC
Groovy: 1.8.6
Ant: Apache Ant(TM) version 1.8.4 compiled on May 22 2012
Ivy: 2.2.0
JVM: 1.7.0_21 (Oracle Corporation 23.21-b01)

JFI, this works for me:

eclipse {
    classpath {
        file {
            whenMerged { classpath ->
                classpath.entries.findAll { entry -> entry.path ==~ /.*\/velocity-1\.4\.jar$/ || entry.path ==~ /.*\/velocity-dep-1\.4\.jar$/ }*.exported = false
            }
        }
    }
}