Skip to content

Commit 3d833c2

Browse files
committed
distZip-style applications
This change adds support for distZip-style applications[1]. This means applications that are packaged as a start script in bin/ and classpath JARs in lib/ can be run. This package can be created with the Gradle application plugin, but also by the sbt-native-package plugin. [1]: http://www.gradle.org/docs/current/userguide/application_plugin.html [#69255612]
1 parent 5fc79a0 commit 3d833c2

File tree

17 files changed

+277
-36
lines changed

17 files changed

+277
-36
lines changed

.idea/.rakeTasks

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ To learn how to configure various properties of the buildpack, follow the "Confi
3232
* [Design](docs/design.md)
3333
* [Security](docs/security.md)
3434
* Standard Containers
35+
* [Dist ZIP](docs/container-dist_zip.md)
3536
* [Groovy](docs/container-groovy.md) ([Configuration](docs/container-groovy.md#configuration))
3637
* [Java Main](docs/container-java_main.md) ([Configuration](docs/container-java_main.md#configuration))
3738
* [Play Framework](docs/container-play_framework.md)

config/components.yml

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
# Configuration for components to use in the buildpack
1717
---
1818
containers:
19+
- "JavaBuildpack::Container::DistZip"
1920
- "JavaBuildpack::Container::Groovy"
2021
- "JavaBuildpack::Container::JavaMain"
2122
- "JavaBuildpack::Container::PlayFramework"

docs/container-dist_zip.md

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Dist Zip Container
2+
The Dist Zip Container allows applications packaged in [`distZip`-style][] to be run.
3+
4+
<table>
5+
<tr>
6+
<td><strong>Detection Criteria</strong></td>
7+
<td><ul>
8+
<li>A start script in the <tt>bin/</tt> subdirectory of the application directory or one of its immediate subdirectories (but not in both), and</li>
9+
<li>A JAR file in the <tt>lib/</tt> subdirectory of the application directory or one of its immediate subdirectories (but not in both), and</li>
10+
<li>Not a Play Framework application</li>
11+
</ul></td>
12+
</tr>
13+
<tr>
14+
<td><strong>Tags</strong></td>
15+
<td><tt>dist-zip</tt></td>
16+
</tr>
17+
</table>
18+
Tags are printed to standard output by the buildpack detect script
19+
20+
## Configuration
21+
The Dist Zip Container cannot be configured.
22+
23+
24+
[`distZip`-style]: http://www.gradle.org/docs/current/userguide/application_plugin.html

docs/container-play_framework.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ The Play Framework Container allows Play Framework applications to be run.
33

44
<table>
55
<tr>
6-
<td><strong>Detection Criteria</strong></td><td>The Play Framework start script and the Play Framework runtime JAR exist in the appropriate subdirectories of the application directory or one of its immediate subdirectories (but not in both)</td>
6+
<td><strong>Detection Criteria</strong></td>
7+
<td>The Play Framework start script and the Play Framework runtime JAR exist in the appropriate subdirectories of the application directory or one of its immediate subdirectories (but not in both)</td>
78
</tr>
89
<tr>
910
<td><strong>Tags</strong></td>
+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# Encoding: utf-8
2+
# Cloud Foundry Java Buildpack
3+
# Copyright 2013 the original author or authors.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
require 'java_buildpack/component/base_component'
18+
require 'java_buildpack/container'
19+
require 'java_buildpack/util/dash_case'
20+
require 'java_buildpack/util/find_single_directory'
21+
require 'java_buildpack/util/play/factory'
22+
require 'java_buildpack/util/qualify_path'
23+
require 'java_buildpack/util/start_script'
24+
25+
module JavaBuildpack
26+
module Container
27+
28+
# Encapsulates the detect, compile, and release functionality for +distZip+ style applications.
29+
class DistZip < JavaBuildpack::Component::BaseComponent
30+
include JavaBuildpack::Util
31+
32+
# Creates an instance
33+
#
34+
# @param [Hash] context a collection of utilities used the component
35+
def initialize(context)
36+
super(context)
37+
end
38+
39+
# (see JavaBuildpack::Component::BaseComponent#detect)
40+
def detect
41+
supports? ? DistZip.to_s.dash_case : nil
42+
end
43+
44+
# (see JavaBuildpack::Component::BaseComponent#compile)
45+
def compile
46+
start_script.chmod 0755
47+
augment_classpath
48+
end
49+
50+
# (see JavaBuildpack::Component::BaseComponent#release)
51+
def release
52+
[
53+
@droplet.java_home.as_env_var,
54+
@droplet.java_opts.as_env_var,
55+
'SERVER_PORT=$PORT',
56+
qualify_path(start_script, @droplet.root)
57+
].flatten.compact.join(' ')
58+
end
59+
60+
private
61+
62+
PATTERN_APP_CLASSPATH = /^declare -r app_classpath=\"(.*)\"$/
63+
64+
PATTERN_CLASSPATH = /^CLASSPATH=(.*)$/.freeze
65+
66+
def augment_classpath
67+
content = start_script.read
68+
69+
if content =~ PATTERN_CLASSPATH
70+
additional_classpath = @droplet.additional_libraries.sort.map do |additional_library|
71+
"$APP_HOME/#{additional_library.relative_path_from(root)}"
72+
end
73+
74+
update_file start_script, content,
75+
PATTERN_CLASSPATH, "CLASSPATH=#{additional_classpath.join(':')}:\\1"
76+
elsif content =~ PATTERN_APP_CLASSPATH
77+
additional_classpath = @droplet.additional_libraries.sort.map do |additional_library|
78+
"$app_home/#{additional_library.relative_path_from(start_script.dirname)}"
79+
end
80+
81+
update_file start_script, content,
82+
PATTERN_APP_CLASSPATH, "declare -r app_classpath=\"#{additional_classpath.join(':')}:\\1\""
83+
end
84+
end
85+
86+
def jars?
87+
(lib_dir + '*.jar').glob.any?
88+
end
89+
90+
def lib_dir
91+
root + 'lib'
92+
end
93+
94+
def root
95+
find_single_directory || @droplet.root
96+
end
97+
98+
def start_script
99+
JavaBuildpack::Util.start_script root
100+
end
101+
102+
def supports?
103+
start_script && start_script.exist? && jars? && !JavaBuildpack::Util::Play::Factory.create(@droplet)
104+
end
105+
106+
def update_file(path, content, pattern, replacement)
107+
path.open('w') do |f|
108+
f.write content.gsub pattern, replacement
109+
f.fsync
110+
end
111+
end
112+
113+
end
114+
115+
end
116+
end

lib/java_buildpack/container/java_main.rb

+3-3
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,12 @@ def release
4242
manifest_class_path.each { |path| @droplet.additional_libraries << path }
4343

4444
[
45+
port,
4546
"#{@droplet.java_home.root}/bin/java",
4647
@droplet.additional_libraries.as_classpath,
4748
@droplet.java_opts.join(' '),
4849
main_class,
49-
arguments,
50-
port
50+
arguments
5151
].flatten.compact.join(' ')
5252
end
5353

@@ -73,7 +73,7 @@ def manifest_class_path
7373
end
7474

7575
def port
76-
main_class =~ /^org\.springframework\.boot\.loader\.(?:[JW]ar|Properties)Launcher$/ ? '--server.port=$PORT' : nil
76+
main_class =~ /^org\.springframework\.boot\.loader\.(?:[JW]ar|Properties)Launcher$/ ? 'SERVER_PORT=$PORT' : nil
7777
end
7878

7979
end

lib/java_buildpack/container/spring_boot_cli.rb

+2-3
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,10 @@ def release
4949
[
5050
@droplet.java_home.as_env_var,
5151
@droplet.java_opts.as_env_var,
52+
'SERVER_PORT=$PORT',
5253
qualify_path(@droplet.sandbox + 'bin/spring', @droplet.root),
5354
'run',
54-
relative_groovy_files,
55-
'--',
56-
'--server.port=$PORT'
55+
relative_groovy_files
5756
].flatten.compact.join(' ')
5857
end
5958

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Encoding: utf-8
2+
# Cloud Foundry Java Buildpack
3+
# Copyright 2013 the original author or authors.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
require 'java_buildpack/util'
18+
19+
module JavaBuildpack
20+
module Util
21+
22+
# Find the single directory in the root of the droplet
23+
#
24+
# @return [Pathname, nil] the single directory in the root of the droplet, otherwise +nil+
25+
def find_single_directory
26+
roots = (@droplet.root + '*').glob.select { |child| child.directory? }
27+
roots.size == 1 ? roots.first : nil
28+
end
29+
30+
module_function :find_single_directory
31+
32+
end
33+
end

lib/java_buildpack/util/play/base.rb

+1-8
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
# limitations under the License.
1616

1717
require 'java_buildpack/util/play'
18+
require 'java_buildpack/util/find_single_directory'
1819
require 'java_buildpack/util/qualify_path'
1920

2021
module JavaBuildpack
@@ -80,14 +81,6 @@ def augment_classpath
8081
fail "Method 'augment_classpath' must be defined"
8182
end
8283

83-
# Find the single directory in the root of the droplet
84-
#
85-
# @return [Pathname, nil] the single directory in the root of the droplet, otherwise +nil+
86-
def find_single_directory
87-
roots = (@droplet.root + '*').glob.select { |child| child.directory? }
88-
roots.size == 1 ? roots.first : nil
89-
end
90-
9184
# Returns the +JAVA_OPTS+ in the form that they need to be added to the command line
9285
#
9386
# @return [Array<String>] the +JAVA_OPTS+ in the form that they need to be added to the command line
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
CLASSPATH=$APP_HOME/lib/dist-zip-application-1.0.0.BUILD-SNAPSHOT.jar:$APP_HOME/lib/h2-1.3.174.jar:$APP_HOME/lib/spring-boot-starter-jdbc-1.0.0.RELEASE.jar:$APP_HOME/lib/spring-boot-starter-web-1.0.0.RELEASE.jar:$APP_HOME/lib/spring-common-1.0.0.BUILD-SNAPSHOT.jar:$APP_HOME/lib/mysql-connector-java-5.1.28.jar:$APP_HOME/lib/spring-boot-starter-1.0.0.RELEASE.jar:$APP_HOME/lib/spring-jdbc-4.0.3.RELEASE.jar:$APP_HOME/lib/tomcat-jdbc-7.0.52.jar:$APP_HOME/lib/spring-tx-4.0.3.RELEASE.jar:$APP_HOME/lib/spring-boot-starter-tomcat-1.0.0.RELEASE.jar:$APP_HOME/lib/jackson-databind-2.3.2.jar:$APP_HOME/lib/spring-web-4.0.3.RELEASE.jar:$APP_HOME/lib/spring-webmvc-4.0.3.RELEASE.jar:$APP_HOME/lib/core-1.0.0.BUILD-SNAPSHOT.jar:$APP_HOME/lib/spring-boot-1.0.0.RELEASE.jar:$APP_HOME/lib/spring-boot-autoconfigure-1.0.0.RELEASE.jar:$APP_HOME/lib/spring-boot-starter-logging-1.0.0.RELEASE.jar:$APP_HOME/lib/snakeyaml-1.13.jar:$APP_HOME/lib/tomcat-juli-7.0.52.jar:$APP_HOME/lib/spring-beans-4.0.3.RELEASE.jar:$APP_HOME/lib/spring-core-4.0.3.RELEASE.jar:$APP_HOME/lib/tomcat-embed-core-7.0.52.jar:$APP_HOME/lib/tomcat-embed-el-7.0.52.jar:$APP_HOME/lib/tomcat-embed-logging-juli-7.0.52.jar:$APP_HOME/lib/jackson-annotations-2.3.0.jar:$APP_HOME/lib/jackson-core-2.3.2.jar:$APP_HOME/lib/spring-data-redis-1.1.1.RELEASE.jar:$APP_HOME/lib/spring-data-mongodb-1.4.0.RELEASE.jar:$APP_HOME/lib/spring-rabbit-1.2.1.RELEASE.jar:$APP_HOME/lib/jedis-2.1.0.jar:$APP_HOME/lib/jcl-over-slf4j-1.7.6.jar:$APP_HOME/lib/jul-to-slf4j-1.7.6.jar:$APP_HOME/lib/log4j-over-slf4j-1.7.6.jar:$APP_HOME/lib/logback-classic-1.1.1.jar:$APP_HOME/lib/spring-context-support-3.1.4.RELEASE.jar:$APP_HOME/lib/spring-data-commons-1.7.0.RELEASE.jar:$APP_HOME/lib/mongo-java-driver-2.11.4.jar:$APP_HOME/lib/amqp-client-3.1.3.jar:$APP_HOME/lib/spring-amqp-1.2.1.RELEASE.jar:$APP_HOME/lib/commons-pool-1.5.5.jar:$APP_HOME/lib/logback-core-1.1.1.jar:$APP_HOME/lib/commons-logging-1.1.3.jar:$APP_HOME/lib/spring-context-4.0.3.RELEASE.jar:$APP_HOME/lib/slf4j-api-1.7.6.jar:$APP_HOME/lib/spring-expression-4.0.3.RELEASE.jar:$APP_HOME/lib/spring-aop-4.0.3.RELEASE.jar:$APP_HOME/lib/aopalliance-1.0.jar

spec/fixtures/container_dist_zip/dist-zip-application/lib/dist-zip.jar

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
declare -r app_classpath="$lib_dir/com.wmg.eventprocessor-0.0.1-SNAPSHOT.jar:$lib_dir/org.scala-lang.scala-library-2.10.3.jar:$lib_dir/com.typesafe.akka.akka-actor_2.10-2.2.3.jar:$lib_dir/com.typesafe.config-1.0.2.jar:$lib_dir/com.rabbitmq.amqp-client-3.2.3.jar:$lib_dir/org.xerial.snappy.snappy-java-1.0.5.jar:$lib_dir/com.datastax.cassandra.cassandra-driver-core-1.0.0.jar:$lib_dir/io.netty.netty-3.6.3.Final.jar:$lib_dir/org.apache.cassandra.cassandra-thrift-1.2.3.jar:$lib_dir/commons-lang.commons-lang-2.4.jar:$lib_dir/org.slf4j.slf4j-api-1.7.2.jar:$lib_dir/org.apache.thrift.libthrift-0.7.0.jar:$lib_dir/javax.servlet.servlet-api-2.5.jar:$lib_dir/org.apache.httpcomponents.httpclient-4.0.1.jar:$lib_dir/org.apache.httpcomponents.httpcore-4.0.1.jar:$lib_dir/commons-logging.commons-logging-1.1.1.jar:$lib_dir/commons-codec.commons-codec-1.2.jar:$lib_dir/org.codehaus.jackson.jackson-core-asl-1.9.2.jar:$lib_dir/org.apache.cassandra.cassandra-all-1.2.3.jar:$lib_dir/net.jpountz.lz4.lz4-1.1.0.jar:$lib_dir/com.ning.compress-lzf-0.8.4.jar:$lib_dir/commons-cli.commons-cli-1.1.jar:$lib_dir/com.googlecode.concurrentlinkedhashmap.concurrentlinkedhashmap-lru-1.3.jar:$lib_dir/org.antlr.antlr-3.2.jar:$lib_dir/org.antlr.antlr-runtime-3.2.jar:$lib_dir/org.antlr.stringtemplate-3.2.1.jar:$lib_dir/antlr.antlr-2.7.7.jar:$lib_dir/org.apache.cassandra.deps.avro-1.4.0-cassandra-1.jar:$lib_dir/org.codehaus.jackson.jackson-mapper-asl-1.9.2.jar:$lib_dir/org.mortbay.jetty.jetty-6.1.22.jar:$lib_dir/org.mortbay.jetty.jetty-util-6.1.22.jar:$lib_dir/org.mortbay.jetty.servlet-api-2.5-20081211.jar:$lib_dir/jline.jline-1.0.jar:$lib_dir/com.googlecode.json-simple.json-simple-1.1.jar:$lib_dir/com.github.stephenc.high-scale-lib.high-scale-lib-1.1.2.jar:$lib_dir/org.yaml.snakeyaml-1.6.jar:$lib_dir/edu.stanford.ppl.snaptree-0.1.jar:$lib_dir/org.mindrot.jbcrypt-0.3m.jar:$lib_dir/com.yammer.metrics.metrics-core-2.0.3.jar:$lib_dir/log4j.log4j-1.2.16.jar:$lib_dir/com.github.stephenc.jamm-0.2.5.jar:$lib_dir/org.slf4j.slf4j-log4j12-1.7.2.jar:$lib_dir/com.fasterxml.jackson.module.jackson-module-scala_2.10-2.3.2.jar:$lib_dir/com.fasterxml.jackson.core.jackson-core-2.3.2.jar:$lib_dir/com.fasterxml.jackson.core.jackson-annotations-2.3.2.jar:$lib_dir/com.fasterxml.jackson.core.jackson-databind-2.3.2.jar:$lib_dir/com.thoughtworks.paranamer.paranamer-2.6.jar:$lib_dir/com.google.code.findbugs.jsr305-2.0.1.jar:$lib_dir/com.google.guava.guava-13.0.1.jar"

spec/fixtures/container_dist_zip_app_classpath/dist-zip-application/lib/dist-zip.jar

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Encoding: utf-8
2+
# Cloud Foundry Java Buildpack
3+
# Copyright 2013 the original author or authors.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
require 'spec_helper'
18+
require 'component_helper'
19+
require 'java_buildpack/container/dist_zip'
20+
21+
describe JavaBuildpack::Container::DistZip do
22+
include_context 'component_helper'
23+
24+
it 'should not recognize non-applications' do
25+
expect(component.detect).not_to be
26+
end
27+
28+
it 'should not recognize Play dist applications',
29+
app_fixture: 'container_play_2.2_dist' do
30+
31+
expect(component.detect).not_to be
32+
end
33+
34+
it 'should not recognize Play dist applications',
35+
app_fixture: 'container_play_2.2_staged' do
36+
37+
expect(component.detect).not_to be
38+
end
39+
40+
it 'should recognize distZip applications',
41+
app_fixture: 'container_dist_zip' do
42+
43+
expect(component.detect).to eq('dist-zip')
44+
end
45+
46+
it 'should correctly extend the CLASSPATH-style classpath',
47+
app_fixture: 'container_dist_zip' do
48+
49+
component.compile
50+
51+
expect((app_dir + 'dist-zip-application/bin/dist-zip-application').read)
52+
.to match 'CLASSPATH=\$APP_HOME/../.additional_libs/test-jar-1.jar:\$APP_HOME/../.additional_libs/test-jar-2.jar:'
53+
end
54+
55+
it 'should correctly extend the app_classpath-style classpath',
56+
app_fixture: 'container_dist_zip_app_classpath' do
57+
58+
component.compile
59+
60+
expect((app_dir + 'dist-zip-application/bin/dist-zip-application').read)
61+
.to match 'declare -r app_classpath="\$app_home/../../.additional_libs/test-jar-1.jar:\$app_home/../../.additional_libs/test-jar-2.jar:'
62+
end
63+
64+
it 'should return command',
65+
app_fixture: 'container_dist_zip' do
66+
67+
expect(component.release).to eq("#{java_home.as_env_var} JAVA_OPTS=\"test-opt-2 test-opt-1\" SERVER_PORT=$PORT " \
68+
'$PWD/dist-zip-application/bin/dist-zip-application')
69+
end
70+
71+
end

0 commit comments

Comments
 (0)