Native/jna dir creation does not honor {-g, --gradle-user-home} command line option

I want complete control over where the files that gradle creates are going to go. Specifically, I do not want anything to end up in ~/.gradle

To test this, I have created my own ~/.gradle dir, but made it read only:

dr-xr-xr-x
  2 rich engr
     4096 2013-11-14 15:42 .gradle/

As expected, if I try to invoke gradle with minimal options, it fails:

$ gradle-1.9-rc-3/bin/gradle -version
  FAILURE: Build failed with an exception.
  * What went wrong:
Could not create JNA native library '/ext/home2/rich/.gradle/native/jna/linux-amd64/libjnidispatch.so'.
  * Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
rich@rich2 [16:25:06 Thu Nov 14] ~/bugs/br-170

This is effectively doing the same thing, but using the lower level java invocation rather than the gradle front-end script to give me more control in later examples:

$ java -Dorg.gradle.appname=gradle -classpath gradle-1.9-rc-3/lib/gradle-launcher-1.9-rc-3.jar org.gradle.launcher.GradleMain -version
  FAILURE: Build failed with an exception.
  * What went wrong:
Could not create JNA native library '/ext/home2/rich/.gradle/native/jna/linux-amd64/libjnidispatch.so'.
  * Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
rich@rich2 [16:26:04 Thu Nov 14] ~/bugs/br-170

The problem is that if I run it with the -g option, pointing to a dir where I do have access:

$ ls -l /var/tmp | grep br-170
drwxr-xr-x
3 rich engr
     4096 2013-11-14 16:20 br-170
rich@rich2 [16:26:44 Thu Nov 14] ~/bugs/br-170

I get the same failure. Here, I’m showing it with a full stacktrace, which I have left out of the other examples for brevity:

$ java -Dorg.gradle.appname=gradle -classpath gradle-1.9-rc-3/lib/gradle-launcher-1.9-rc-3.jar org.gradle.launcher.GradleMain -g /var/tmp/br-170 --stacktrace -version
  FAILURE: Build failed with an exception.
  * What went wrong:
Could not create JNA native library '/ext/home2/rich/.gradle/native/jna/linux-amd64/libjnidispatch.so'.
  * Try:
Run with --info or --debug option to get more log output.
  * Exception is:
org.gradle.internal.nativeplatform.NativeIntegrationException: Could not create JNA native library '/ext/home2/rich/.gradle/native/jna/linux-amd64/libjnidispatch.so'.
 at org.gradle.internal.nativeplatform.jna.JnaBootPathConfigurer.configure(JnaBootPathConfigurer.java:61)
 at org.gradle.internal.nativeplatform.services.NativeServices.initialize(NativeServices.java:65)
 at org.gradle.logging.internal.ConsoleConfigureAction.execute(ConsoleConfigureAction.java:30)
 at org.gradle.logging.internal.ConsoleConfigureAction.execute(ConsoleConfigureAction.java:27)
 at org.gradle.logging.internal.OutputEventRenderer.attachConsole(OutputEventRenderer.java:68)
 at org.gradle.logging.internal.DefaultLoggingManager.attachConsole(DefaultLoggingManager.java:146)
 at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:168)
 at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:139)
 at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:33)
 at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:22)
 at org.gradle.launcher.Main.doAction(Main.java:46)
 at org.gradle.launcher.bootstrap.EntryPoint.run(EntryPoint.java:45)
 at org.gradle.launcher.Main.main(Main.java:37)
 at org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBootstrap.java:50)
 at org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.java:32)
 at org.gradle.launcher.GradleMain.main(GradleMain.java:23)
Caused by: java.io.FileNotFoundException: /ext/home2/rich/.gradle/native/jna/linux-amd64/libjnidispatch.so (No such file or directory)
 at org.gradle.internal.nativeplatform.jna.JnaBootPathConfigurer.configure(JnaBootPathConfigurer.java:51)
 ... 15 more
  rich@rich2 [16:29:17 Thu Nov 14] ~/bugs/br-170

Using the alternate version of the option (–gradle-user-home) makes no difference:

$ java -Dorg.gradle.appname=gradle -classpath gradle-1.9-rc-3/lib/gradle-launcher-1.9-rc-3.jar org.gradle.launcher.GradleMain --gradle-user-home /var/tmp/br-170 -version
  FAILURE: Build failed with an exception.
  * What went wrong:
Could not create JNA native library '/ext/home2/rich/.gradle/native/jna/linux-amd64/libjnidispatch.so'.
  * Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
rich@rich2 [16:29:48 Thu Nov 14] ~/bugs/br-170

However, I can get it to work by passing this either as a java system property (gradle.user.home):

$ java -Dgradle.user.home=/var/tmp/br-170 -Dorg.gradle.appname=gradle -classpath gradle-1.9-rc-3/lib/gradle-launcher-1.9-rc-3.jar org.gradle.launcher.GradleMain -version
  ------------------------------------------------------------
Gradle 1.9-rc-3
------------------------------------------------------------
  Build time:
 2013-11-07 12:26:42 UTC
Build number: none
Revision:
   7970ec3503b4f5767ee1c1c69f8b4186c4763e3d
  Groovy:
     1.8.6
Ant:
        Apache Ant(TM) version 1.9.2 compiled on July 8 2013
Ivy:
        2.2.0
JVM:
        1.6.0_45 (Sun Microsystems Inc. 20.45-b01)
OS:
         Linux 2.6.32-26-server amd64
  rich@rich2 [16:30:33 Thu Nov 14] ~/bugs/br-170

or as an environment variable (GRADLE_USER_HOME):

$ GRADLE_USER_HOME=/var/tmp/br-170 java -Dorg.gradle.appname=gradle -classpath gradle-1.9-rc-3/lib/gradle-launcher-1.9-rc-3.jar org.gradle.launcher.GradleMain -version
  ------------------------------------------------------------
Gradle 1.9-rc-3
------------------------------------------------------------
  Build time:
 2013-11-07 12:26:42 UTC
Build number: none
Revision:
   7970ec3503b4f5767ee1c1c69f8b4186c4763e3d
  Groovy:
     1.8.6
Ant:
        Apache Ant(TM) version 1.9.2 compiled on July 8 2013
Ivy:
        2.2.0
JVM:
        1.6.0_45 (Sun Microsystems Inc. 20.45-b01)
OS:
         Linux 2.6.32-26-server amd64
  rich@rich2 [16:31:28 Thu Nov 14] ~/bugs/br-170

org.gradle.internal.nativeplatform.jna.JnaBootPathConfigurer.configure(File storageDir) uses as a basis for this the value that is passed to it.

This in turn comes from the value passed to org.gradle.internal.nativeplatform.services.NativeServices.initialize(File userHomeDir)

And that value is set by org.gradle.logging.internal.ConsoleConfigureAction.execute(), which calls org.gradle.StartParameter.getGradleUserHomeDir()

That is just returning the member gradleUserHomeDir, which is set in the StartParameter constructor by org.gradle.initialization.BuildLayoutParameters.getGradleUserHomeDir()

And that is just returning the member gradleUserHomeDir, which is set in by the BuildLayoutParameters constructor. So the problematic code might be in the constructor in src/core/org/gradle/initialization/BuildLayoutParameters.java

Here are the complete contents of the constructor:

public BuildLayoutParameters() {
        String gradleUserHome = System.getProperty(StartParameter.GRADLE_USER_HOME_PROPERTY_KEY);
        if (gradleUserHome == null) {
            gradleUserHome = System.getenv("GRADLE_USER_HOME");
            if (gradleUserHome == null) {
                gradleUserHome = StartParameter.DEFAULT_GRADLE_USER_HOME.getAbsolutePath();
            }
        }
        gradleUserHomeDir = canonicalise(new File(gradleUserHome));
    }

You can see that we first consider the system property (and StartParameter.GRADLE_USER_HOME_PROPERTY_KEY is set to “gradle.user.home”); and if that is not set, we next consider the environment variable “GRADLE_USER_HOME”, and if that is not set, then we resort to StartParameter.DEFAULT_GRADLE_USER_HOME, which is set to ~/.gradle. Nowhere do we consider the command line flags.

Or maybe that’s fine, because if I look in org.gradle.wrapper.GradleWrapperMain, it does seem to have a method to parse this option:

private static File gradleUserHome(ParsedCommandLine options) {
        if (options.hasOption(GRADLE_USER_HOME_OPTION)) {
            return new File(options.option(GRADLE_USER_HOME_OPTION).getValue());
        }
        String gradleUserHome;
        if ((gradleUserHome = System.getProperty(GRADLE_USER_HOME_PROPERTY_KEY)) != null) {
            return new File(gradleUserHome);
        }
        if ((gradleUserHome = System.getenv(GRADLE_USER_HOME_ENV_KEY)) != null) {
            return new File(gradleUserHome);
        }
        return new File(DEFAULT_GRADLE_USER_HOME);
    }

and (in main()) add it to the system properties:

File gradleUserHome = gradleUserHome(options);
          addSystemProperties(gradleUserHome, rootDir);

Nevertheless, it doesn’t seem to be working in this case. Maybe there’s an ordering problem here, and the option just hasn’t been parsed yet when the native services are initializing? I’m just guessing, this is the limit of how far I’ve debugged this.

I initially saw this on older, released versions of gradle (1.3 and 1.7), and only tried the latest 1.9 rc to verify that it was still a bug before reporting it.

At first I thought my problem was that I was just seeing this bug (which was fixed long ago):

https://github.com/wolfs/gradle/commit/777479d541c78f570fd8ccb1b39dbbe0fd4d2dee

And that 1.3 was just too old, but it appears that that fix went in much earlier than 1.3.

I’m sorry for the horrible formatting. I’m not sure why it’s putting everything in a single code block. It doesn’t seem to be honoring my code close tags.

Apologies. If anyone knows how I can fix this, please share.

Thanks for the detailed report. Raised as GRADLE-2956.

Will endeavour to get this fixed for 1.10.