Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue with --daemon switch #12

Closed
purringpigeon opened this issue Jan 25, 2016 · 59 comments
Closed

Issue with --daemon switch #12

purringpigeon opened this issue Jan 25, 2016 · 59 comments

Comments

@purringpigeon
Copy link

I am not sure if this is an issue with the plug in - or gradle. However when I run like this:

gradle jfxNative

Everything works like a champ!

when I use it like this:
gradle jfxNative --daemon

It throws errors when attempting to copy the files to the lib folder:

Couldn't copy dependency commons-codec:commons-codec:1.6
java.nio.file.NoSuchFileException: C:\Users\user.m2\repository\commons-codec\commons-codec\1.6\commons-codec-1.6.jar -> build\jfx\app\lib\commons-codec-1.6.jar
at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:79)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
at sun.nio.fs.WindowsFileCopy.copy(WindowsFileCopy.java:205)
at sun.nio.fs.WindowsFileSystemProvider.copy(WindowsFileSystemProvider.java:278)
at java.nio.file.Files.copy(Files.java:1274)
at de.dynamicfiles.projects.gradle.plugins.javafx.tasks.JfxJarTask.lambda$null$1(JfxJarTask.java:123)
at java.lang.Iterable.forEach(Iterable.java:75)
at de.dynamicfiles.projects.gradle.plugins.javafx.tasks.JfxJarTask.lambda$jfxjar$2(JfxJarTask.java:119)
at java.lang.Iterable.forEach(Iterable.java:75)
at de.dynamicfiles.projects.gradle.plugins.javafx.tasks.JfxJarTask.jfxjar(JfxJarTask.java:117)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:75)
at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.doExecute(AnnotationProcessingTaskFactory.java:227)
at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:220)
at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:209)
etc....

Wondering if this a problem with Gradle, or something that needs to be addressed here? So I am posting it. Thanks!

It fails on every jar dependency.

(I have also posted on gradle).

@FibreFoX
Copy link
Owner

This looks pretty similar than this: #11 (comment)

@purringpigeon
Copy link
Author

Yes - these might be duplicate. I noticed this using Buildship for Eclipse which is the gradle plugin from Gradle themselves. It uses the --daemon and nothing we can do about that unfortunately.

I am not sure if this is because of the multi project or not, but I have noticed different behavior between the two ways of running the build.

This is what I have noticed:
gradle jfxNative --deamon

This creates the build folder in the root of the master project

master-project
---->build
--------->jfx
--------------->app
---------------------->app.jar

gradle jfxNative

This creates the build folder in the root of the master project

master-project
---->build
--------->jfx
--------------->app
---------------------->app.jar
---------------------->lib
---------------------------->.jar
---------------------->properties
---------------------------->
.* (custom files)
--------------->native
---------------------->appFolder
---------------------------->app (same structure as above - includes the exe, cfg, etc)
---------------------------->runtime

So it appears with the daemon flag, the folder structures are not being created correctly - and perhaps that is why the copy is not working?

@purringpigeon
Copy link
Author

This is a shot in the dark - but could it be possible that the --daemon doesn't run from the same directory and when it attempts to write the file, it can't locate the relative build directory?

Looking on stack overflow: http://stackoverflow.com/questions/14263725/java-files-write-nosuchfileexception asks why it throws this error on a write. This error is thrown when the directory isn't there. http://stackoverflow.com/questions/27335005/java-nio-files-createfile-fails-with-nosuchfileexception

Could you try using an absolute path in the copy, rather than the relative path? Perhaps that would address the issue when the --daemon option is used?

Thanks.

@purringpigeon
Copy link
Author

I noticed that when I ran with daemon this would fail:
String contents = new File( 'src/main/deploy/package/windows/file.template' ).getText( 'UTF-8' )

However, if I changed it to:
String contents = new File(new File("$rootDir"), 'src/main/deploy/package/windows/file.template' ).getText( 'UTF-8' )

It worked - so I am thinking that using absolute path at line 123 & 153 for the copy folder might solve the issue.

@FibreFoX
Copy link
Owner

Thank for your effort in debugging this yourself, maybe that will be solved by fixing issue #13

@purringpigeon
Copy link
Author

So I played with this a little more - created a simple java class to copy this file:

public static void main(String[] args) {

    try {
        Files.copy(new File("C:\\Users\\purringpigeon\\.m2\\repository\\org\\apache\\lucene\\lucene-core\\4.10.3\\lucene-core-4.10.3.jar").toPath(),
                new File("build\\jfx\\app\\lib\\lucene-core-4.10.3.jar").toPath(), StandardCopyOption.REPLACE_EXISTING);
    } catch (IOException ex) {
        Logger.getLogger(Playground.class.getName()).log(Level.SEVERE, null, ex);
    }
}

This throws the following error:
Jan 26, 2016 11:37:46 AM playground.Playground main
SEVERE: null
java.nio.file.NoSuchFileException: C:\Users\purringpigeon.m2\repository\org\apache\lucene\lucene-core\4.10.3\lucene-core-4.10.3.jar -> build\jfx\app\lib\lucene-core-4.10.3.jar
at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:79)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
at sun.nio.fs.WindowsFileCopy.copy(WindowsFileCopy.java:205)
at sun.nio.fs.WindowsFileSystemProvider.copy(WindowsFileSystemProvider.java:278)
at java.nio.file.Files.copy(Files.java:1274)
at playground.Playground.main(Playground.java:28)

If I change it to:
public static void main(String[] args) {

    try {
        Files.copy(new File("C:\\Users\\purringpigeon\\.m2\\repository\\org\\apache\\lucene\\lucene-core\\4.10.3\\lucene-core-4.10.3.jar").toPath(),
                new File("c:\\temp\\lucene-core-4.10.3.jar").toPath(), StandardCopyOption.REPLACE_EXISTING);
    } catch (IOException ex) {
        Logger.getLogger(Playground.class.getName()).log(Level.SEVERE, null, ex);
    }
}

it works just fine. Therefore I think the issue is definitely pathing. Thanks for your help!

@FibreFoX
Copy link
Owner

YES !! Found it!

Couldn't copy dependency com.google.code.gson:gson:2.3.1
java.nio.file.NoSuchFileException: C:\Users\FibreFoX\.gradle\caches\modules-2\files-2.1\com.google.code.gson\gson\2.3.1\ecb6e1f8e4b0e84c4b886c2f14a1500caf309757\gson-2.3.1.jar -> C:\Users\FibreFoX\.gr
adle\daemon\2.10\build\jfx\app\lib\gson-2.3.1.jar

thats the thing I wasn't aware of ! This will be changed with the bugfix for #13 i guess, but I will hold this open until I know this is really fixed.

The main-problem is the folder-structure and the "current"-path

@FibreFoX FibreFoX self-assigned this Jan 26, 2016
@purringpigeon
Copy link
Author

Sweet! Thank you again.

FibreFoX added a commit that referenced this issue Jan 26, 2016
* should fix issues #11 and #12
@FibreFoX FibreFoX added the bug label Jan 26, 2016
@FibreFoX
Copy link
Owner

@purringpigeon Could you check the current behaviour while using a local build SNAPSHOT-version?

@FibreFoX FibreFoX reopened this Jan 26, 2016
@purringpigeon
Copy link
Author

I am not sure how to run this locally? I would be more than happy to, but I haven't done something like that before. I tried changing the version to version: '1.0-SNAPSHOT' but that didn't work.

@FibreFoX
Copy link
Owner

@purringpigeon I uploaded a new SNAPSHOT-Version:

buildscript {
    repositories {
        maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
    }
    dependencies {
        classpath group: 'de.dynamicfiles.projects.gradle.plugins', name: 'javafx-gradle-plugin', version: '1.1-SNAPSHOT'
    }
}

@purringpigeon
Copy link
Author

This isn't working anymore. I don't get any errors but I am not getting the project setup or the exe installer.

I used to get the jfx set up and app under the:
master-project/build/jfx/...

Now when I run it (either with --daemon or not) I get the following:
master-project/build/jfx/app/app.jar (and that is all)
master-project/app-project/build/jfx/app/lib/*.jar (and that is all).

I am missing the rest of the structure and files. Nothing else created.

I get no errors now. It completes the build, just doesn't do everything. I am using :gradle jfxNative --daemon or gradle jfxNative

@FibreFoX
Copy link
Owner

Do you still have the fixed bundler = "windows.app"? There still is something not right regarding multi-project folders. I'll have a deeper look into it, thanks for testing.

@FibreFoX
Copy link
Owner

I used to get the jfx set up and app under the:
master-project/build/jfx/...

That was unwanted, the structure should be now:

master-project/app-project/build/jfx/app/app.jar
master-project/app-project/build/jfx/app/lib/*.jar

I uploaded a new SNAPSHOT-version (still being 1.1-SNAPSHOT), so you shouldn't have that wrong created folder below the root-project (I missed some File-constructor).

@purringpigeon
Copy link
Author

I think that fixed all the issues....
I needed to restructure my build scripts so that it worked within the correct folders - but now I am getting the folders in the:

master-project/app/build/jfx/*

I am getting the build working with both --daemon and without --daemon

I am reinstalling the gradle plugin in my eclipse and will test that out. But I think that this is working.

Here is my build.gradle:

buildscript {
    dependencies {
        //classpath group: 'de.dynamicfiles.projects.gradle.plugins', name: 'javafx-gradle-plugin', version: '1.0-SNAPSHOT'
        classpath group: 'de.dynamicfiles.projects.gradle.plugins', name: 'javafx-gradle-plugin', version: '1.1-SNAPSHOT'
    }
    repositories {
        //mavenCentral()
         maven { url "https://oss.sonatype.org/content/repositories/snapshots" }

    }
}

task setBuildNumber << {
    String contents = new File(new File("$projectDir"), 'src/main/deploy/package/windows/appname.template' ).getText( 'UTF-8' )
    contents = contents.replaceAll( 'BUILDNUMBER', version )
    new File(new File("$projectDir"),'src/main/deploy/package/windows/appname.iss' ).write( contents, 'UTF-8' )
}

task copyRequiredRuntimeConfiguration(type: Sync) {
    from 'properties'
    into 'build/additionalResources/properties'
    include '**/*'
}

apply plugin: 'java'

dependencies{
    compile project(':javafx-framework')
    compile project(':javafx-project1')
    compile project(':javafx-project2')
    compile project(':javafx-project3')
    compile project(':javafx-project4')
    compile project(':javafx-project5')
    copyRequiredRuntimeConfiguration
}

apply plugin: 'javafx-gradle-plugin'

copyRequiredRuntimeConfiguration.dependsOn(setBuildNumber)
jfxJar.dependsOn(tasks.copyRequiredRuntimeConfiguration)

jfx {

    //Since the path is within this project - need to provide absolute path to resolve it at build time.
    additionalAppResources = 'build/additionalResources'

    verbose = true
    mainClass = 'org.idahosif.application.appname'
    appName = 'appname'
    manifestAttributes = [
        version: "Build 1.0"
    ]
    jfxMainAppJarName = 'appname.jar'
    vendor = "My Company"

}

HOWEVER
When I ran without --daemon all when well BUT when I ran with --daemon, the location of the build is created as read only and it can not be cleaned.

* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':project-app:clean'.
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:69)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:46)
        at org.gradle.api.internal.tasks.execution.PostExecutionAnalysisTaskExecuter.execute(PostExecutionAnalysisTaskExecuter.java:35)
        at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:64)
        at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
        at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:52)
        at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
        at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:53)
        at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
        at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:203)
        at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:185)
        at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.processTask(AbstractTaskPlanExecutor.java:66)
        at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.run(AbstractTaskPlanExecutor.java:50)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor.process(DefaultTaskPlanExecutor.java:25)
        at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:110)
        at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:37)
        at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
        at org.gradle.execution.DefaultBuildExecuter.access$000(DefaultBuildExecuter.java:23)
        at org.gradle.execution.DefaultBuildExecuter$1.proceed(DefaultBuildExecuter.java:43)
        at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32)
        at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
        at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:30)
        at org.gradle.initialization.DefaultGradleLauncher$4.run(DefaultGradleLauncher.java:154)
        at org.gradle.internal.Factories$1.create(Factories.java:22)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:90)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:52)
        at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:151)
        at org.gradle.initialization.DefaultGradleLauncher.access$200(DefaultGradleLauncher.java:32)
        at org.gradle.initialization.DefaultGradleLauncher$1.create(DefaultGradleLauncher.java:99)
        at org.gradle.initialization.DefaultGradleLauncher$1.create(DefaultGradleLauncher.java:93)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:90)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:62)
        at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:93)
        at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:82)
        at org.gradle.launcher.exec.InProcessBuildActionExecuter$DefaultBuildController.run(InProcessBuildActionExecuter.java:94)
        at org.gradle.tooling.internal.provider.ExecuteBuildActionRunner.run(ExecuteBuildActionRunner.java:28)
        at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
        at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:43)
        at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:28)
        at org.gradle.launcher.exec.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:78)
        at org.gradle.launcher.exec.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:48)
        at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:52)
        at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:37)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:26)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:34)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:74)
        at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:72)
        at org.gradle.util.Swapper.swap(Swapper.java:38)
        at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:72)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.health.DaemonHealthTracker.execute(DaemonHealthTracker.java:47)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:66)
        at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:72)
        at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.health.HintGCAfterBuild.execute(HintGCAfterBuild.java:41)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:50)
        at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:246)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54)
        at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:40)
Caused by: org.gradle.api.file.UnableToDeleteFileException: Unable to delete directory: C:\workspace\workspace-name\master-project\project-app\build\jfx\native\appname\run
time
        at org.gradle.api.internal.file.copy.DeleteActionImpl.handleFailedDelete(DeleteActionImpl.java:90)
        at org.gradle.api.internal.file.copy.DeleteActionImpl.doDelete(DeleteActionImpl.java:66)
        at org.gradle.api.internal.file.copy.DeleteActionImpl.doDelete(DeleteActionImpl.java:61)
        at org.gradle.api.internal.file.copy.DeleteActionImpl.doDelete(DeleteActionImpl.java:61)
        at org.gradle.api.internal.file.copy.DeleteActionImpl.doDelete(DeleteActionImpl.java:61)
        at org.gradle.api.internal.file.copy.DeleteActionImpl.doDelete(DeleteActionImpl.java:61)
        at org.gradle.api.internal.file.copy.DeleteActionImpl.delete(DeleteActionImpl.java:46)
        at org.gradle.api.internal.file.DefaultFileOperations.delete(DefaultFileOperations.java:130)
        at org.gradle.api.internal.project.AbstractProject.delete(AbstractProject.java:690)
        at org.gradle.api.tasks.Delete.clean(Delete.java:38)
        at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:75)
        at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.doExecute(AnnotationProcessingTaskFactory.java:227)
        at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:220)
        at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:209)
        at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:585)
        at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:568)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:80)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:61)
        ... 68 more

The only way to clean the project is to run gradle --stop

I don't think we can do that from IDE plug ins.

@FibreFoX
Copy link
Owner

@purringpigeon so you are still getting the output to the wrong folder master-project/build/jfx/app/* (maybe I misunderstood)?

The resources for bundling to native bundles and the outcome of the java(fx)packager should result below that dedicated app-bundle-project. Can you confirm this is now where it should be?

@purringpigeon
Copy link
Author

No I am getting the correct folders now.

master-project
------>app-project
------------->build
------------------>jfx/*

So that is good. I am getting the correct structures and the installer. The only issue I have is that clean doesn't work when the daemon is running.

@FibreFoX
Copy link
Owner

Okay, in that case I would suggest to close this issue and #13 too, what do you think about this? The clean-issue might not have something to do with this gradle-plugin.

@purringpigeon
Copy link
Author

I think that this is an issue with the gradle-plug in actually. the clean worked before you made these changes.

The clean also works when the --daemon isn't used. It only affects the jfx folders, not the build folders in the other projects.

@FibreFoX
Copy link
Owner

let me tinker some dummy-multi-project buildscript, hopefully I can recreate that issue myself

@FibreFoX
Copy link
Owner

I can reproduce that issue now, seems that there is some handler open when running gradle jfxNative, there is a file-handler still open inside the daemon-process:

multi-project\app-project\build\jfx\native\appname\runtime\bin

I will look into the JDK, there is some magic regarding version-detection ....

@FibreFoX
Copy link
Owner

It smells like an issue from the JDK itself:

  • when launching normally, running jfxNative is okay, but running clean afterwards fails, because of some open file-handle
  • when specifying to NOT include the JRE, everything works nice for me:
jfx {
    verbose = true
    mainClass = 'org.company.application.appname'
    appName = 'appname'
    manifestAttributes = [
        version: "Build 1.0"
    ]
    jfxMainAppJarName = 'appname.jar'
    vendor = "My Company"
    bundler = "windows.app"
    bundleArguments = [
        runtime: null
    ]
}

I'll take a deeper look into the JDK .... again

@purringpigeon
Copy link
Author

It wouldn't be a big deal for me, but ALL IDE's use the --daemon to work with gradle unfortunately.

Glad you found what is going on, perhaps you'll figure out what will fix it.

@FibreFoX
Copy link
Owner

Just another case of "it's the JDK", I think I've found the spot where the file descriptor-leak exists:
http://hg.openjdk.java.net/openjfx/8u60/rt/file/996511a322b7/modules/fxpackager/src/main/java/com/oracle/tools/packager/windows/WinAppBundler.java#l325

As this stream is a DirectoryStream (as documented), this should have to be closed, mostly by using try(resouce){}-syntax.

Will try to report this issue, but I will release version 1.1 in the next minutes.

@FibreFoX
Copy link
Owner

For other visitors regarding Netbeans and Gradle: kelemen/netbeans-gradle-project#269

There is no way to stop it from the IDE at the moment because Gradle provides no way to do this through its API.

@FibreFoX
Copy link
Owner

FibreFoX commented Apr 19, 2016

@KorvinGump Hi, just a short note: when you are setting your build-file to NOT bundle some JRE, it is possible to call jfxNative-task within your IDE.

jfx{
    // ...
    bundleArguments = [
        // dont bundle JRE, by setting NULL (it is not recommended, but makes it callable with daemon-mode)
        runtime: null
    ]
}

@FibreFoX
Copy link
Owner

Current version (8.5.1) makes it possible to ignore the skipping-workaround.

@eskatos
Copy link

eskatos commented Jul 22, 2016

Please note that starting with Gradle 3.0, the daemon is enabled by default, not only for IDEs.
This may be a good reason to consider working around the jdk bug in this plugin somehow.

@FibreFoX
Copy link
Owner

FibreFoX commented Jul 22, 2016

@eskatos thanks for the update to gradle 3

Unfortunately this is not possible, I tried it with different ways, but I would need to "kill" some filehandle held open by the JVM. If someone knows a way, I would be happy to implement that kind of workaround. I've already created some pull-requests on the teamfx-repository, to get more attention about this, but it seems not as important...

Current workaround is to manually kill the daemon, or just exclude the bundled JRE, implemented workaround (which even can be disabled too) just does not generate on windows ... not much more I can do here :(

@eskatos
Copy link

eskatos commented Jul 22, 2016

@FibreFoX so one way to work around the issue would be to fork a process so that the leaked file handle does not disturb the Gradle daemon. I don't know the implementation details of this plugin, this may be a big chunk of work, or not.

Another way would be to go native and use Win32 CloseHandle function to force-close the file since the handle belong to our process.

@FibreFoX
Copy link
Owner

@eskatos this plugin uses the internal API of the javapackager, so no process itself is started anyway, which means no "process-fork" will get me to a nice result. I'm not creating the XML-file used by the javapackager as some "converter", this plugin uses the same API which is used by the javapackager itself.

As this is workaroundable by using no bundled JRE inside your IDE, and having JRE bundle on the build-system, any native workaround is way too much ... going "native" and use some closehandle ... might work ;) but it is messing too much with the system. As this is some bug in the JDK anyway, I hesitate to do any native action here.

Do you have any good source for force-closing filehandles inside java?

@eskatos
Copy link

eskatos commented Jul 23, 2016

As this is workaroundable by using no bundled JRE inside your IDE, and having JRE bundle on the build-system, any native workaround is way too much

The thing is, with Gradle 3 and the daemon enabled by default, users will have to explicitly disable the daemon to get things working, which is not so nice.

Do you have any good source for force-closing filehandles inside java?

Not really.
It won't be possible to do it in pure java as the offending unclosed stream is a local variable that can't even be accessed through reflection.
If I had to investigate how to list open handles and get enough data to find the offending ones I'd look into WIN32 apis and JNA. But I have the gut feeling this won't be a pleasant journey.

What about forking a JVM that do exactly what you do already, use the same API used by javapackager? You would have to pass some model to it somehow...

This situation is definitely not comfy. Let's hope this will be fixed in a JDK 8 update, not only on 9. It doesn't looks like so for now though ... https://bugs.openjdk.java.net/browse/JDK-8148717

@FibreFoX
Copy link
Owner

FibreFoX commented Jul 23, 2016

@eskatos
I know that JDK-bug ;) I found the bug and created that issue-entry ... I also created some bugfix-pull-requests (JDK 8 and JDK 9) to the dedicated teamfx-repository ... but this is still something which needs to get kicked into the openjfx-repo... but that's another story.

When Gradle 3 is there, maybe the chances are good for manually killing the daemons, the open file-handle created inside JVM is held by the gradle-daemon, killing that daemon might be a valid option ... but as I discussed on the netbeans-gradle-plugin, there is no nice way to manage these daemons.

I really don't want to create any native JNA-stuff ;) as it is nasty and doesn't feel right (but I am interestend to find some solution using that stuff, never did any hack like that before, which makes me interested even more into doing that stuff xD). Forking is NO option, as I rely on the loaded classpath by gradle (because of the ant-javafx.jar and possible other dependencies containing custom bundlers are already there), forking another process does not bring me anywhere near ... the overhead to workaround some JDK-bug isn't worth restructuring the whole plugin. The javapackager wasn't tested/created with long-living JVMs in mind, like the gradle-daemons introduce here ;) and that's why the guys/gals at oracle didn't make that as reproducable ....

@eskatos
Copy link

eskatos commented Jul 26, 2016

Yeah, I knew my suggestion to fork wouldn't please you :)
By the way, gradle --stop should work with its current limitation that is it will only stop Gradle daemons using the same Gradle version as the gradle command invoked. If it does not, then that's a bug.
To be continued.

@FibreFoX
Copy link
Owner

@eskatos thanks a lot for more suggestions to workaround this bug ;) but I would feel better when the bug would get fixed inside the JDK itself. As this is only problematic on windows-systems (as on linux/macosx there are no locking-issues), this might be a minor issue, but it's a nasty one.

As most jenkins-systems run on linux, this "only" hurts local development on windows-systems, where gradle-daemons are present, and not build-systems. Calling gradle --stop would not work, because you can't target the correct daemon (as you said because of the version-matching).

The more generic workaround is a manual gradle --stop-call for the right version, which might being mainainable via some adjustments inside the build.gradle instead of calling that inside the plugin. Maybe someone can write that part and publish it here?

@FibreFoX
Copy link
Owner

To sum up !

What's the problem:
Calling the clean-task does not work on Windows-systems, because the JDK contains some open/unclosed file-handle.

All current options:

  • bundling without JRE
  • bundling on linux/macosx
  • killing gradle-daemon manually before building
  • not calling clean-task

Possible solutions (on windows only) :

  • running inside separated process (aka fork) (requires heavy rework of this plugin)
  • hacking the current implementation via ASM (by changing that ant-method before bundling) (might be my second prefered solution, because I could learn a bit more of ASM here 😸 )
  • executing some "kill open-filehandle"-application like sysinternals handle.exe
  • praying to Oracle/OpenJDK to fix their stuff (by accepting the changes inside my pull-requests) (my prefered solution)

@FibreFoX FibreFoX self-assigned this Jul 29, 2016
@FibreFoX
Copy link
Owner

Just wanted to inform all visitors/watchers: I'm working on replacing the buggy method, first tries using ASM did not work out as expected, using BCEL now, but might still take some time. 😺 This is being worked on!

@Burtan
Copy link

Burtan commented Aug 21, 2016

I think, you have opted-out bundling on Linux/Mac as well? I get the following message on both: Gradle is in daemon-mode, skipped executing bundler, because this would result in some error on clean-task. (JDK-8148717)

@FibreFoX
Copy link
Owner

@Burtan you can disable that check, by setting skipDaemonModeCheck = true.

Yes, i disabled it by mistake on all platforms :( and with new gradle 3 behaviour of having that daemon by default, this will be more PITA than before. Currently I'm working on some other things, but I hope to provide a working fix soon™️

@toolforger
Copy link

Gradle's daemon mode is pretty much mandatory, Gradle's startup can take quite a while and daemon mode fixes that.
I.e. "killing gradle-daemon manually before building" is not a realistic option unless you can make sure that the jfx build is outside of any fast edit-compile-debug cycle.

Assuming that CI environments do not use daemon mode is, at best, a heuristic.

I have another stop-gap proposal: Restore the clean functionality, but when running in daemon mode and bundling for Windows, issue a warning that this will run into a resource leak.
("Bundling for Windows" may not be the same as "running on Windows" in the long term, BTW.)

@FibreFoX
Copy link
Owner

FibreFoX commented Aug 24, 2016

@toolforger I can't just "restore" the clean-functionality, because this is a different gradle-task which I'm not involved into. The proposed "solutions" are no real solutions, they are WORKAROUNDS. The real fix would have to be done by Oracle, not me.

This is no normal memory-leak, it is a file-handle lock! Welcome to the world of file-locking on windows-systems. The tooling provided by the JDK does NOT have permanent JVMs in mind, they think of process-termination after the bundling-process, this is a break-up with the paradigm introduced by gradle.

Personally I don't think the daemon mode does that much increase speedup, especially creating bundles should not be seen as "incremental normal development tasks", they are generating some output which has to be executed on the targeted systems after that normal development-phase.

Especially regarding the CI-environment: this is even proposed by the gradle-documentations, that CI-envs should not use daemon-mode.

@toolforger
Copy link

Well, somebody is suppressing the clean task and emitting a warning, I've been assuming that it's the javafx Gradle plugin.

Is this really a file locking scenario?
Not with that Files.list() call I'd assume: Windows' locking policy, while overly strict, is consistent; so if Files.list() places a lock, then one that prevents just writing, so future Files.list() and open-existing-file-for-reading calls should go through even if a lock from Files.list() leaks.
My (unvalidated) assumption is that Files.list() leaks file handles, which would get cleaned up during next GC but that might not happen soon enough.

WRT the speedup: Yes it is substantial. Even my minimal JavaFX test-drive project requires 8 seconds to build the model, and the times used to be much worse though I can't say how much of that is due to project size (those were life-size projects, not the toy I'm testing with right now) and much is because optimizations hadn't happened yet.
However, idiocy isn't the key merit of Gradle engineers, so if they think that daemon mode is the way to go, I'm assuming that they know use cases where model building takes a lot longer than 8 seconds, even with today's infrastructure. YMMV.

@FibreFoX
Copy link
Owner

@toolforger the clean-task is broken after the first jfxNative-build, because (as mentioned inside the reported and accepted bug and inside this "issue-thread") windows is holding some file-handle, which only will released on JVM-termination. This is even described inside Java-Docs:

A DirectoryStream is opened upon creation and is closed by invoking the close method. Closing a directory stream releases any resources associated with the stream. Failure to close the stream may result in a resource leak. The try-with-resources statement provides a useful construct to ensure that the stream is closed

To avoid false-positives (and to make CLEAN work), the current implementation inside my plugin simply does not work when daemon-mode is detected, because they are NOT target of the GC.

WRT the speedup: Yes it is substantial. Even my minimal JavaFX test-drive project requires 8 seconds to build the model, and the times used to be much worse though I can't say how much of that is due to project size (those were life-size projects, not the toy I'm testing with right now) and much is because optimizations hadn't happened yet.

Sorry to sound rude, but I don't care about this. Creating a DISTRIBUTION BUNDLE should not be part of the normal development-cycle, calling jfxJar-task should be used for development and jfxNative as the last part of the whole project-development. I'm just sitting between the contradicting paradigms of gradle vs javapackager, so please don't expect some holy-grail from me.

If you find something new I haven't mentioned inside #12 (comment) please don't hesitate to propose some pull-request.

@FibreFoX
Copy link
Owner

FibreFoX commented Aug 29, 2016

To all watchers: I might have finally beaten this DAEMON to the ground, and now can eat 🍰

Can you please retry using latest 8.5.3-SNAPSHOT? It should result in downloading javafx-gradle-plugin-8.5.3-20160829.142917-5.jar from sonatype.

Please make sure to have this inside your buildscript for using latest SNAPSHOT-versions:

buildscript {
    dependencies {
        classpath group: 'de.dynamicfiles.projects.gradle.plugins', name: 'javafx-gradle-plugin', version: '8.5.3-SNAPSHOT'
    }
    repositories {
        mavenCentral()
        maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
    }
}

This only works when using gradle daemon mode (which is default on gradle 3), and running on windows using some JDK above and including 1.8.0_60, but ONLY when NOT having runtime: null inside bundleArguments (because this was the use-case not working in the first place, so this is just to recap).

This version includes the adjustments required to fix #30 too.

(If working, I will push the required changes to github)

@FibreFoX
Copy link
Owner

@purringpigeon can you recheck this?

@FibreFoX
Copy link
Owner

The fixes provided for this will be released soon.

@FibreFoX
Copy link
Owner

I'm very happy to finally close this bug! Thanks for all people who supported me on this one !

@eskatos
Copy link

eskatos commented Sep 4, 2016

Awesome! 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants