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

Commit 69d9e4f

Browse files
committed
Working prototype of extending both Jar and ShadowJar task types
1 parent be27986 commit 69d9e4f

File tree

6 files changed

+305
-200
lines changed

6 files changed

+305
-200
lines changed

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

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
}
Lines changed: 103 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,144 @@
11
package com.github.jrubygradle.jar
22

3-
import com.github.jrubygradle.internal.WarblerBootstrap
3+
import com.github.jrubygradle.JRubyPlugin
4+
import groovy.transform.PackageScope
45
import org.gradle.api.Plugin
56
import org.gradle.api.Project
67
import org.gradle.api.Task
8+
import org.gradle.api.tasks.Copy
79
import org.gradle.api.tasks.bundling.Jar
10+
import org.gradle.api.tasks.compile.JavaCompile
811
import org.gradle.api.tasks.testing.Test
912

1013
/**
1114
* @author Schalk W. Cronjé
1215
*/
1316
class JRubyJarPlugin implements Plugin<Project> {
17+
18+
static final String BOOTSTRAP_TASK_NAME = 'jrubyJavaStub'
19+
1420
void apply(Project project) {
1521

1622
project.apply plugin : 'com.github.jruby-gradle.base'
23+
project.apply plugin : 'java-base'
1724
project.configurations.maybeCreate('jrubyEmbeds')
1825
project.configurations.maybeCreate('jrubyJar')
1926

20-
// In order to update the testing cycle we need to tell unit tests where to
21-
// find GEMs. We are assuming that if someone includes this plugin, that they
22-
// will be writing tests that includes jruby and that they might need some
23-
// GEMs as part of the tests.
24-
def testConfiguration = { Task t ->
25-
environment GEM_HOME : project.extensions.getByName('jruby').gemInstallDir
26-
dependsOn 'jrubyPrepareGems'
27+
updateTestTask(project)
28+
addCodeGenerationTask(project)
29+
addDependentTasks(project)
30+
addJrubyExtensionToJar(project)
31+
addAfterEvaluateHooks(project)
32+
}
33+
34+
@PackageScope
35+
void addCodeGenerationTask(Project project) {
36+
37+
Task stubTask = project.tasks.create( name: BOOTSTRAP_TASK_NAME, type : Copy )
38+
stubTask.extensions.create(
39+
'jruby',
40+
BootstrapClassExtension,
41+
stubTask
42+
)
43+
44+
project.configure(stubTask) {
45+
group JRubyPlugin.TASK_GROUP_NAME
46+
description 'Generates a JRuby Java bootstrap class'
47+
48+
from({extensions.jruby.getSource()})
49+
into new File(project.buildDir,'generated/java')
50+
51+
52+
filter { String line ->
53+
line.replaceAll('%%LAUNCH_SCRIPT%%',extensions.jruby.initScript)
54+
}
55+
56+
rename '(.+)\\.java\\.template','$1.java'
57+
2758
}
28-
try {
29-
Task t = project.tasks.getByName('test')
30-
if( t instanceof Test) {
31-
project.configure(t,testConfiguration)
59+
60+
project.sourceSets {
61+
main {
62+
java {
63+
srcDir new File(project.buildDir,'generated/java')
64+
}
3265
}
33-
} catch(UnknownTaskException) {
34-
project.tasks.whenTaskAdded { Task t ->
35-
if(t.name == 'test' && t instanceof Test) {
36-
project.configure(t,testConfiguration)
66+
}
67+
}
68+
@PackageScope
69+
void addDependentTasks(Project project) {
70+
['jar','shadowJar'].each { taskName ->
71+
try {
72+
Task t = project.tasks.getByName(taskName)
73+
if( t instanceof Jar) {
74+
t.dependsOn 'jrubyPrepareGems'
75+
}
76+
} catch(UnknownTaskException) {
77+
project.tasks.whenTaskAdded { Task t ->
78+
if (t.name == taskName && t instanceof Jar) {
79+
t.dependsOn 'jrubyPrepareGems'
80+
}
3781
}
3882
}
3983
}
84+
4085
try {
41-
Task t = project.tasks.getByName('jar')
42-
if( t instanceof Jar) {
43-
t.dependsOn 'jrubyPrepareGems'
86+
Task t = project.tasks.getByName('compileJava')
87+
if( t instanceof JavaCompile) {
88+
t.dependsOn BOOTSTRAP_TASK_NAME
4489
}
4590
} catch(UnknownTaskException) {
4691
project.tasks.whenTaskAdded { Task t ->
47-
if (t.name == 'jar' && t instanceof Jar) {
48-
t.dependsOn 'jrubyPrepareGems'
92+
if (t.name == 'compileJava' && t instanceof JavaCompile) {
93+
t.dependsOn BOOTSTRAP_TASK_NAME
4994
}
5095
}
5196
}
5297

53-
if(!Jar.metaClass.respondsTo(Jar.class,'jruby',Closure)) {
54-
Jar.metaClass.jruby = { Closure extraConfig ->
55-
JRubyJarConfigurator.configureArchive(delegate,extraConfig)
56-
}
57-
}
98+
}
5899

59-
project.afterEvaluate {
60-
WarblerBootstrap.addDependency(project)
61-
JRubyJarConfigurator.afterEvaluateAction(project)
100+
@PackageScope
101+
void addJrubyExtensionToJar(Project project) {
102+
if(!Jar.metaClass.respondsTo(Jar.class,'jruby',Closure)) {
103+
Jar.metaClass.jruby = { Closure extraConfig ->
104+
JRubyJarConfigurator.configureArchive(delegate,extraConfig)
105+
}
106+
}
107+
}
62108

109+
@PackageScope
110+
void addAfterEvaluateHooks(Project project) {
111+
project.afterEvaluate {
63112
project.dependencies {
64113
jrubyJar group: 'org.jruby', name: 'jruby-complete', version: project.jruby.defaultVersion
65114
}
66-
67-
115+
// WarblerBootstrap.addDependency(project)
116+
JRubyJarConfigurator.afterEvaluateAction(project)
68117
}
69118
}
70119

120+
@PackageScope
121+
void updateTestTask(Project project) {
122+
// In order to update the testing cycle we need to tell unit tests where to
123+
// find GEMs. We are assuming that if someone includes this plugin, that they
124+
// will be writing tests that includes jruby and that they might need some
125+
// GEMs as part of the tests.
126+
def testConfiguration = { Task t ->
127+
environment GEM_HOME : project.extensions.getByName('jruby').gemInstallDir
128+
dependsOn 'jrubyPrepareGems'
129+
}
71130

131+
try {
132+
Task t = project.tasks.getByName('test')
133+
if( t instanceof Test) {
134+
project.configure(t,testConfiguration)
135+
}
136+
} catch(UnknownTaskException) {
137+
project.tasks.whenTaskAdded { Task t ->
138+
if(t.name == 'test' && t instanceof Test) {
139+
project.configure(t,testConfiguration)
140+
}
141+
}
142+
}
143+
}
72144
}

0 commit comments

Comments
 (0)