jruby-gradle / jruby-gradle-jar-plugin Goto Github PK
View Code? Open in Web Editor NEWPlugin for creating JRuby-based java archives
Plugin for creating JRuby-based java archives
JRubyPluginSpec.groovy
: For now they have been marked with @IgnoreIf
to work around the problem when offline. However they should be refactored to work correctly when offline.
We need to do the following before releasing 0.1.4
@Incubating
1.0
maven { url 'http://dl.bintray.com/rtyler/jruby' }
0.2.0
in JRubyJarPlugin
- https://github.com/jruby-gradle/jruby-gradle-jar-plugin/pull/38/files#diff-0db12cd653b5b3468ac21351b2bf8466R73Right now it's pinned to 0.1.2, which is fine but 0.1.3 contains important fixes that we should include by default
the META-INF/init.rb is something which comes from jruby-rack and is meant as way to setup the ENV used by jruby-rack. warbler uses it as well in the same manner for runnable jars., i.e. when it detects a rack application it will include ENV['RACK_ENV']='production'
whether the warbler defaults and magic makes sense I do not know, but if there is no such init.rb file, just do nothing and continue launching.
Much of this behavior I think should be consolidated into a JRubyJar
task type which inherits from Jar
and provides all the necessary "fat jar" functionality that we need.
I would like to be abler to extend this functionality, e.g.:
task serviceJar(type: JRubyFatJar) {
dependsOn myOtherCustomTasks
archiveName 'foobar'
from('special/dir')
}
To where the .jrubydir
and other fat-jar magic are applied when my "foobar.jar" is created.
That'd be nice.
due to some existing duplicates between the .jrubydir files generated by the base plugin and the JRubyJar
task the strategy is set to EXCLUDE
.
it almost looks like the base plugin does not need to generate those '.jrubydir' files and this could solve this problem.
Stacktrace:
runUserAcceptanceTests task with environment: development
Snapshot Version: 1.0.0-SNAPSHOT
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jrubyPrepareGems UP-TO-DATE
:jrubyPrepareJars UP-TO-DATE
:jrubyPrepare UP-TO-DATE
:shadowJar
FAILURE: Build failed with an exception.
* What went wrong:
there is no initScript configured
* Try:
Run with --info or --debug option to get more log output.
* Exception is:
org.gradle.api.tasks.StopExecutionException: there is no initScript configured
at com.github.jrubygradle.jar.JRubyJarConfigurator.applyConfig(JRubyJarConfigurator.groovy:164)
at com.github.jrubygradle.jar.JRubyJarConfigurator.this$dist$invoke$1(JRubyJarConfigurator.groovy)
at com.github.jrubygradle.jar.JRubyJarConfigurator$1.methodMissing(JRubyJarConfigurator.groovy)
at com.github.jrubygradle.jar.JRubyJarConfigurator$1.beforeExecute(JRubyJarConfigurator.groovy:215)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.listener.BroadcastDispatch.dispatch(BroadcastDispatch.java:83)
at org.gradle.listener.BroadcastDispatch.dispatch(BroadcastDispatch.java:31)
at org.gradle.messaging.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
at com.sun.proxy.$Proxy10.beforeExecute(Unknown Source)
at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.executeTask(AbstractTaskPlanExecutor.java:76)
at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.processTask(AbstractTaskPlanExecutor.java:63)
at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.run(AbstractTaskPlanExecutor.java:51)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor.process(DefaultTaskPlanExecutor.java:23)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:88)
at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:29)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:62)
at org.gradle.execution.DefaultBuildExecuter.access$200(DefaultBuildExecuter.java:23)
at org.gradle.execution.DefaultBuildExecuter$2.proceed(DefaultBuildExecuter.java:68)
at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:62)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:55)
at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:149)
at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:106)
at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:86)
at org.gradle.launcher.exec.InProcessBuildActionExecuter$DefaultBuildController.run(InProcessBuildActionExecuter.java:80)
at org.gradle.launcher.cli.ExecuteBuildAction.run(ExecuteBuildAction.java:33)
at org.gradle.launcher.cli.ExecuteBuildAction.run(ExecuteBuildAction.java:24)
at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:36)
at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:26)
at org.gradle.launcher.cli.RunBuildAction.run(RunBuildAction.java:51)
at org.gradle.internal.Actions$RunnableActionAdapter.execute(Actions.java:171)
at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:237)
at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:210)
at org.gradle.launcher.cli.JavaRuntimeValidationAction.execute(JavaRuntimeValidationAction.java:35)
at org.gradle.launcher.cli.JavaRuntimeValidationAction.execute(JavaRuntimeValidationAction.java:24)
at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:206)
at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:169)
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:33)
at org.gradle.launcher.bootstrap.EntryPoint.run(EntryPoint.java:45)
at org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBootstrap.java:54)
at org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.java:35)
at org.gradle.launcher.GradleMain.main(GradleMain.java:23)
build.gradle
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "com.github.jruby-gradle:jruby-gradle-plugin:0.1.17"
classpath "com.github.jengelman.gradle.plugins:shadow:1.2.1"
classpath "com.github.jruby-gradle:jruby-gradle-jar-plugin:0.2.1"
classpath "org.ajoberstar:gradle-git:0.13.0"
}
}
jrubyJar {
jruby {
initScript "bin/my-executable"
}
}
Environment Details:
> gradle --version
------------------------------------------------------------
Gradle 2.2.1
------------------------------------------------------------
Build time: 2014-11-24 09:45:35 UTC
Build number: none
Revision: 6fcb59c06f43a4e6b1bcb401f7686a8601a1fb4a
Groovy: 2.3.6
Ant: Apache Ant(TM) version 1.9.3 compiled on December 23 2013
JVM: 1.8.0_05 (Oracle Corporation 25.5-b02)
OS: Mac OS X 10.9.5 x86_64
> java -version
java version "1.8.0_05"
Java(TM) SE Runtime Environment (build 1.8.0_05-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.5-b02, mixed mode)
I mis-typed the initScript
in my jrubyJavaBootstrap
closure and when I went to rebuild (./gradlew shadowJar
) the jrubyJavaBootstrap
task showed "UP-TO-DATE" and created a broken jar.
Basically changes to anything in that closure requires a clean build :(
Formerly issue #2
Some gems include jar files within their codebases which they require to function correctly.
Setting aside whether or not I think this is a "good idea" or not, the jar plugin should not futz with the contents of gems that are being included in the shadow jar.
See johnrengelman/shadow#111 for the upstream question about how to accomplish this
All configuration that has to deal with the creation of a self-contained executable JRuby jar artifact should be managed under the jrubyJar
task, e.g.
jrubyJar {
initScript 'app.rb'
defaultMain() /* optional, present unless otherwise specified */
defaultGems() /* optional, present unless otherwise specified */
configuration configurations.compile /* dependencies in this configuraiton are shaded in */
}
This task would take the ruby files added to the main
sourceset and pull them into the jar
Expected java -jar build/libs/example.jar -T
to output a list of rake tasks inside the .jar, instead rake appears to be running from and searching for tasks in the current directory.
Rakefile
puts File.expand_path(File.dirname(__FILE__) + '/tasks')
# Load all our tasks from the tasks directory
Dir[File.expand_path(File.dirname(__FILE__) + '/tasks/*.rake')].each do |f|
load f
end
In my codebase, .rake
files are located inside lib
lib/tasks/
lib/tasks/example_task.rake
Rakefile
In the .jar the tasks directory is in the root...
29 tasks/
30 tasks/example_task.rake
31 Rakefile
When I run java -jar build/libs/example.jar -T
any tasks I have locally (outside the .jar) are output instead of tasks bundled into the .jar
Remove last remnants from code and unittests.
When using the jar plugin with the 'java' plugin applied there are two archives in the artifacts
list, one for the default 'jar' and one for the 'shadowJar' that would be generated.
If you want to use uploadArchives
the task will fail unless you have existing Java code that would go into the default 'jar' task
I've disabled this behavior with:
'''
jar.enabled = false
configurations.archives.artifacts.removeAll { it.archiveTask.is jar }
'''
But wonder if the jar plugin should handle this in some form or fashion
Moved here from jruby-gradle/jruby-gradle-plugin#67
when embedding gems in jar they need the directory info for each directory (mydir) in a file mydir/.jrubydir which is just the directory listing, each entry in one line. see https://github.com/jruby/jruby/blob/master/core/src/main/ruby/jruby/commands.rb#L16 and jruby/warbler#299
only then those gems can be used by fancy j2ee containers or osgi framework.
With @mkristian's recent changes being merged, it is now impossible to build a jrubyJar
(fat jar) without also producing a jar artifact.
:jar SKIPPED
:jrubyJar
FAILURE: Build failed with an exception.
* What went wrong:
Cannot expand ZIP '/home/tyler/source/lookout/metron/build/libs/metron-3.0+0fd969d.jar' as it does not exist.
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
This dependency link should be broken and the jrubyJar
task should be able to contruct its tree on its own without requiring that the jar
task also execute.
In effect, I should be able to disable the jar
task and still execute jrubyJar
Instead of making it such that the default JRubyBootstrap class is recompiled across different projects, why don't we just package it up as a jar (like warbler-bootstrap
) and specify it as a dependency?
jruby has two classloaders:
so jar-dependencies and jbundler uses require 'some.jar'
which loads this jar into the jruby-classloader
this is a dynamic process and completely inside the realm of ruby code.
this allows the ruby code to decide which jars to load and which one not to load. this is something I used yesterday for a workaround:
https://github.com/lookout/leafy/blob/master/leafy-metrics/leafy-metrics.gemspec
declares slf4j-simple which is never used during runtime:
https://github.com/lookout/leafy/blob/master/leafy-metrics/lib/leafy-metrics_jars.rb
currently it is used only when running tests.
now the gem-artifacts from the torquebox maven repository can have jar dependencies and jruby-gradle-jar-plugin readme basically says to use shadowJar to bundle them into a uberjar. this changes the classloader semantic drastically since all the jars are part of the main-classloader now and this one is static and outside the control of the ruby code.
with my example of leafy-metrics this means slf4j-simple is always part of the main-classloader and the ruby code can NOT decide to NOT use the jar.
so the proper way to bundle jar-dependencies would to build a local maven repository at the root of the jar: i.e. the org.slf4j:slf4j-api:1.7.7 artifact should be located org/slf4j/slf4-api/1.7.7/slf4j-api-1.7.7.jar and let jar-dependencies load it - let the ruby code decide whether when to load it ;)
This is with the current HEAD (4b8de17
). I'm able to create a fat jar artifact that is executable, but I do not have initScript 'foo.rb'
defined, nor have I created a jar-bootstrap.rb
.
Currently the plugin happily creates the artfact, when it should really stop execution because this is an invalid artifact.
When I remove the line pulling in shadowjar from the plugins repository, my gradlefile fails now.
FAILURE: Build failed with an exception.
* Where:
Build file '/usr/home/tyler/source/github/blick/build.gradle' line: 36
* What went wrong:
A problem occurred evaluating root project 'blick'.
> Could not find method shadowJar() for arguments [build_53hpiloh3ahr8sdm93qjclshj9$_run_closure5@4d3c6593] on root project 'blick'.
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
BUILD FAILED
Total time: 17.618 secs
IMHO, since we need shadowjar to build jars properly, it should be an explicit dependency, what do you think @ysb33r ?
I'm not familiar with the proper practice for plugins that depend on other plugins, but shouldn't the jar
plugin specify a dependency on the base
plugin?
The source code which would be included in the library jar would be sourced from the main
sourceSet.
The jar
task would otherwise function as per usual under the java
or groovy
plugin
currently the JRubyJar
task depends on jrubyPrepare
from the base plugin and defaultGems()
does use it.
you can supply and alternative gems directory - in this case the dependency to jrubyPrepare
should be dropped. not sure what happens with the jars directory . . . the code feels half baked here.
task missing(type :JRubyJar) {
into('tasks') { from('rakes') }
}
the produced jar will have directory "tasks" but without .jrubydir file thus jruby can use directory globs for this directory.
From this code
[8:52:40] tyler:jruby-gradle-example git:(master) $ ./gradlew jar
:jrubyJavaBootstrap UP-TO-DATE
:compileJava
/usr/home/tyler/source/github/javaone-jruby-demo/jruby-gradle-example/build/generated/java/META-INF/gradle-plugins/bootstrap.java:3: error: package org.jruby.embed does not exist
import org.jruby.embed.ScriptingContainer;
^
/usr/home/tyler/source/github/javaone-jruby-demo/jruby-gradle-example/build/generated/java/META-INF/gradle-plugins/bootstrap.java:4: error: package org.jruby.embed does not exist
import static org.jruby.embed.PathType.*;
^
/usr/home/tyler/source/github/javaone-jruby-demo/jruby-gradle-example/build/generated/java/META-INF/gradle-plugins/bootstrap.java:5: error: package org.jruby does not exist
import org.jruby.CompatVersion;
^
/usr/home/tyler/source/github/javaone-jruby-demo/jruby-gradle-example/build/generated/java/META-INF/gradle-plugins/bootstrap.java:40: error: cannot find symbol
private ScriptingContainer container;
^
symbol: class ScriptingContainer
location: class JarMain
/usr/home/tyler/source/github/javaone-jruby-demo/jruby-gradle-example/build/generated/java/META-INF/gradle-plugins/bootstrap.java:10: error: cannot find symbol
container = new ScriptingContainer();
^
symbol: class ScriptingContainer
location: class JarMain
5 errors
:compileJava FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':compileJava'.
> Compilation failed; see the compiler error output for details.
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
BUILD FAILED
Total time: 28.611 secs
[8:53:13] tyler:jruby-gradle-example git:(master) $
Related to #42, in the use case of something like asciidoctorj, we would want to be able to include gems packed into the library jar, e.g.:
jar {
jruby {
includeGems() /* takes optional gemInstallDir */
}
}
the nature of using version ranges in dependencies is that the transitive dependency hull of the project can/will change over time. this means it is NOT possible or very difficult to reproduce a build from the past. for a library this is probably less a problem since there you want to keep the version ranges open (and/or hope semantic versioning works). for other projects like a rails-app or a sinatra-app I want to be able to rerun the build which went into production anytime in future.
in ruby world there is bundler which helps to address the problem by locking down the version of ALL dependencies.
to use gradle + bundler side by side is probably the way to go:
currently the jrubyJar
task and the extension to Jar
just adds a from "${archive.project.projectDir}/src/main/ruby"
to task. which is not quite the same as far I understand sourceSets
with https://github.com/mkristian/jruby-mains I created a few "Main" classes which do execute the jar as is without unpacking it. this requires jruby-1.7.19 since the CWD (or PWD) needs to be inside the jar for tools like rake to find the right Rakefile.
it really reduces the startup time by 2-3 sec on my machine not to extract the jar.
Using META-INF/init.rb
seem to have some complicatiosn related to other parts of the Ruby universe.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.