Skip to content
This repository was archived by the owner on May 19, 2019. It is now read-only.

Commit a3e17d6

Browse files
author
R. Tyler Croy
committed
Merge pull request #8 from ysb33r/oneJar
One jar with shadow
2 parents be27986 + bb60e9b commit a3e17d6

File tree

8 files changed

+376
-227
lines changed

8 files changed

+376
-227
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
= Changelog
2+
3+
== Roadmap (0.1.1)
4+
5+
* [Issue #2](https://github.com/jruby-gradle/jruby-gradle-jar-plugin/issues/2) - Executable JARs for Ruby GEMs.
6+
7+
== Version 0.1.0
8+
9+
* Initial release
10+
* [Issue #1](https://github.com/jruby-gradle/jruby-gradle-jar-plugin/issues/1) - Extension to build JARs containing GEMs.

README.md

Lines changed: 52 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ apply plugin: 'com.github.jrubygradle.jar'
3131

3232
This loads the following plugins if they are not already loaded:
3333
+ `com.github.jrubygradle.base`
34+
+ `java`
3435

3536
## Using the plugin
3637

@@ -63,47 +64,71 @@ task myJar (type :Jar) {
6364
6465
// All other JAR methods and properties are still valid
6566
}
67+
```
68+
69+
## Controlling the Ruby entry point script
70+
71+
If nothing is specified, then the bootstrap will look for a Ruby script `META-INF/init.rb`.
72+
It is also possible to set the entry script. This must be specified relative to the root of the created JAR.
6673

74+
```groovy
75+
jrubyJavaBootstrap {
76+
jruby {
77+
initScript = 'bin/asciidoctor'
78+
}
79+
}
6780
```
6881

82+
It is the user's responsibility to ensure that entry point script is created and added to the JAR, be it `META-INF/init.rb`
83+
or another specified script.
84+
85+
6986
## Executable JARs
7087

71-
Please note that executable JARs are still an incubating feature. At this point appropriate libs will be copied
72-
to the `META-INF/lib` directory, but a working `init.rb` is not available. It is still the responsibility of the
73-
the user to craft an appropriate `init.rb` and copy it to `META-INF` via the provided the [metaInf {}](http://www.gradle.org/docs/current/dsl/org.gradle.api.tasks.bundling.Jar.html) closure.
74-
75-
```groovy
76-
jar {
88+
**Please note that executable JARs are still an incubating feature**.
89+
90+
Executable JARs are indirectly supported via the [Gradle Shadow Jar plugin](http://plugins.gradle.org/plugin/com.github.johnrengelman.shadow).
91+
92+
93+
### Adding Shadow JAR
94+
```groovy
95+
buildscript {
96+
repositories {
97+
jcenter()
98+
}
99+
100+
dependencies {
101+
classpath 'com.github.jengelman.gradle.plugins:shadow:1.1.1'
102+
classpath group: 'com.github.jrubygradle:jruby-gradle-jar-plugin:0.1.1'
103+
}
104+
}
105+
106+
apply plugin: 'com.github.jrubygradle.jar'
107+
apply plugin: 'com.github.johnrengelman.shadow'
108+
109+
```
110+
111+
### Configuring Shadow JAR
112+
113+
Configuration is exactly the same as for a normal JAR class.
114+
115+
```groovy
116+
shadowJar {
77117
jruby {
78118
79-
// Make the JAR executable and use the default main class
119+
// Use the default bootstrap class
80120
defaultMainClass()
81121
82122
// Make the JAR executable by supplying your own main class
83-
mainClass 'my.own.main.'
123+
mainClass 'my.own.main'
84124
85125
// Equivalent to calling defaultMainClass()
86-
defaults 'mainClass'
126+
defaults 'gems', 'mainClass'
87127
88-
// Adds dependencies from this configuration into `META-INF/lib`
89-
// If none are specified, the plugin will default to 'jrubyJar','compile' & 'runtime'
90-
configurations 'myConfig'
91128
}
92129
}
93130
```
94131

95-
Using the default main class method `defaultMainClass()` will include class files from
96-
[warbler-bootstrap](https://github.com/jruby-gradle/warbler-bootstrap)
97-
98-
99-
## Controlling the version of warbler-bootstrap
100-
101-
By default the version is set to `1.+` meaning anything version 1.0 or beyond. If your project wants to lock
102-
down the specific version, then it can be set via
103-
104-
```groovy
105-
jruby {
106-
warblerBootstrapversion = '1.0.0'
107-
}
108-
```
109-
132+
See [Shadow JAR README](https://github.com/johnrengelman/shadow/blob/master/README.md) for configuration specifics.
133+
In a similar fashion to the `jar` task, the `shadowJar` task will make use of the `jrubyJavaBootstrap` task to
134+
create and compile a basic bootstrap class.

build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ dependencies {
3636
exclude module : 'groovy-all'
3737
}
3838

39+
testRuntime 'com.github.jengelman.gradle.plugins:shadow:1.+'
40+
3941
// For the testWarbler tests I am locking the versions, instead of a open version, as it makes
4042
// unit testing easier, This does not affect the final artifact.
4143
// If you change values here, you need to update JRubyJarPluginSpec as well.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package com.github.jrubygradle.jar
2+
3+
import groovy.transform.TupleConstructor
4+
import org.gradle.api.GradleException
5+
import org.gradle.api.Task
6+
7+
/**
8+
* @author Schalk W. Cronjé.
9+
*
10+
* @since 0.1.1
11+
*/
12+
@TupleConstructor
13+
class BootstrapClassExtension {
14+
15+
static final String BOOTSTRAP_TEMPLATE_PATH = 'META-INF/gradle-plugins/bootstrap.java.template'
16+
17+
/** The task this extension instance is attached to.
18+
*
19+
* @since 0.1.1
20+
*
21+
*/
22+
Task task
23+
24+
/** The location of the Ruby initialisation/bootstrap script.
25+
* The default bootstrap class will look for a file in this relative location.
26+
* It is the user's responsibility that this script is added to the Jar.
27+
*
28+
* @since 0.1.1
29+
*/
30+
String initScript = 'META-INF/init.rb'
31+
32+
/** This is the JRuby language compatibility mode.
33+
* @since 0.1.1
34+
*/
35+
String compatMode = '1.9'
36+
37+
Object source
38+
39+
Object getSource() {
40+
if(null == source) {
41+
setSourceFromResource()
42+
}
43+
this.source
44+
}
45+
46+
void setSourceFromResource() {
47+
Enumeration<URL> enumResources
48+
enumResources = this.class.classLoader.getResources( BOOTSTRAP_TEMPLATE_PATH)
49+
if(!enumResources.hasMoreElements()) {
50+
throw new GradleException ("Cannot find ${BOOTSTRAP_TEMPLATE_PATH} in classpath")
51+
} else {
52+
URI uri = enumResources.nextElement().toURI()
53+
String location = uri.getSchemeSpecificPart().replace('!/'+BOOTSTRAP_TEMPLATE_PATH,'')
54+
if(uri.scheme.startsWith('jar')) {
55+
location=location.replace('jar:file:','')
56+
source= task.project.zipTree(location)
57+
} else if(uri.scheme.startsWith('file')) {
58+
source= location.replace('file:','')
59+
} else {
60+
throw new GradleException("Cannot extract ${uri}")
61+
}
62+
}
63+
64+
}
65+
66+
}

src/main/groovy/com/github/jrubygradle/jar/JRubyJarConfigurator.groovy

Lines changed: 10 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@ package com.github.jrubygradle.jar
33
import groovy.transform.PackageScope
44
import org.gradle.api.Incubating
55
import org.gradle.api.Project
6-
import org.gradle.api.Task
7-
import org.gradle.api.artifacts.Configuration
8-
import org.gradle.api.file.FileCollection
96
import org.gradle.api.tasks.bundling.Jar
107
import com.github.jrubygradle.GemUtils
118

@@ -15,7 +12,8 @@ import com.github.jrubygradle.GemUtils
1512
*/
1613
class JRubyJarConfigurator {
1714

18-
static final String DEFAULT_MAIN_CLASS = 'com.lookout.jruby.JarMain'
15+
static final String DEFAULT_BOOTSTRAP_CLASS = 'com.github.jrubygradle.jar.bootstrap.JarMain'
16+
static final String SHADOW_JAR_TASK_CLASS = 'com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar'
1917

2018
// This is used by JRubyJarPlugin to configure Jar classes
2119
@PackageScope
@@ -29,15 +27,8 @@ class JRubyJarConfigurator {
2927
@PackageScope
3028
static void afterEvaluateAction( Project project ) {
3129
project.tasks.withType(Jar) { t ->
32-
if (t.manifest.attributes.containsKey('Main-Class')) {
33-
if (t.manifest.attributes.'Main-Class' == JRubyJarConfigurator.DEFAULT_MAIN_CLASS) {
34-
t.with {
35-
from({ project.configurations.jrubyEmbeds.collect { project.zipTree(it) } }) {
36-
include '**'
37-
exclude '**/WarMain.class'
38-
}
39-
}
40-
}
30+
if(t.class.superclass.name == SHADOW_JAR_TASK_CLASS && t.name=='shadowJar') {
31+
t.configurations.add(project.configurations.getByName('jrubyJar'))
4132
}
4233
}
4334
}
@@ -63,15 +54,10 @@ class JRubyJarConfigurator {
6354
*/
6455
@Incubating
6556
void mainClass(final String className) {
66-
maybeAddExtraManifest()
6757
archive.with {
6858
manifest {
6959
attributes 'Main-Class': className
7060
}
71-
metaInf {
72-
from { this.getDependencies() }
73-
into 'lib'
74-
}
7561
}
7662
}
7763

@@ -102,74 +88,20 @@ class JRubyJarConfigurator {
10288
*/
10389
@Incubating
10490
void defaultMainClass() {
105-
mainClass(DEFAULT_MAIN_CLASS)
106-
}
107-
108-
/** Adds a configuration to the list of dependencies that will be packed when creating an executable jar
109-
* This method is ignored if {@code mainClass} is not set.
110-
*
111-
* @param name Name of configuration
112-
*/
113-
@Incubating
114-
void configuration(String name) {
115-
this.configuration(archive.project.configurations.getByName(name))
91+
mainClass(DEFAULT_BOOTSTRAP_CLASS)
11692
}
11793

118-
/** Adds a configuration to the list of dependencies that will be packed when creating an executable jar
119-
* This method is ignored if {@code mainClass} is not set.
120-
*
121-
* @param name Configuration
122-
*/
123-
@Incubating
124-
void configuration(Configuration config) {
125-
if(this.configurations==null) {
126-
this.configurations = []
127-
}
128-
this.configurations.add(config)
94+
boolean isShadowJar() {
95+
shadowJar
12996
}
13097

13198
private JRubyJarConfigurator(Jar a) {
13299
archive = a
133-
}
134-
135-
private Set<File> getDependencies() {
136-
Set<File> tmp = []
137-
if(configurations == null) {
138-
archive.project.configurations.each { Configuration cfg ->
139-
if( ['jrubyJar','compile','runtime'].contains(cfg.name) ) {
140-
tmp.addAll(cfg.files)
141-
}
142-
}
143-
} else {
144-
configurations.each {
145-
tmp.addAll(it.files)
146-
}
147-
}
148-
return tmp
149-
}
150-
151-
private void maybeAddExtraManifest() {
152-
if(extraManifest == null) {
153-
extraManifest = new File(archive.project.buildDir,extraManifestName)
154-
String taskName = "${archive.name}ExtraManifest"
155-
Task task = archive.project.tasks.create(taskName)
156-
task << {
157-
String libs = task.inputs.files.collect { File f -> "lib/${f.name}" }.join(' ')
158-
extraManifest.parentFile.mkdirs()
159-
extraManifest.text = "Class-Path: ${libs}\n"
160-
}
161-
task.outputs.file(extraManifest)
162-
task.inputs.files({this.getDependencies()})
163-
archive.dependsOn task
164-
archive.manifest.from({task.outputs.files.singleFile})
100+
if (a.class.name == SHADOW_JAR_TASK_CLASS || a.class.superclass.name == SHADOW_JAR_TASK_CLASS) {
101+
shadowJar = true
165102
}
166103
}
167104

168-
private String getExtraManifestName() {
169-
"tmp/${archive.name}-extraManifest.mf"
170-
}
171-
172105
private Jar archive
173-
private List<Configuration> configurations
174-
private File extraManifest
106+
private boolean shadowJar = false
175107
}

0 commit comments

Comments
 (0)