Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Support Play 2.2

Refactor Play framework to encapsulate the application-specific pieces
in a "PlayApp" abstraction defined by the BasePlayApp class. This
class has two subclasses: PlayAppPost22 for Play 2.2 and upwards and
PlayAppPre22 for Play 2.1.x and earlier (actually no earlier than 2.0
since older versions are not supported).

PlayAppPre22 is further subclassed by PlayAppPre22Dist and
PlayAppPre22Staged to represent the differences between Play 2.0/2.1
dist and staged applications, respectively.

PlayAppFactory isolates the using code (the Play container and some
associated frameworks) from the concrete subclasses of BasePlayApp.

Play version parsing and the naming requirements for the Play JAR are
both tightened up.

Play 2.2 support consists of:

1. Looking for a different style of start script. The start script is
now present in the bin directory and named after the application.

2. Updating the classpath variable in the start script (for both dist
and staged apps, which are now identical in structure in Play 2.2).

3. Supporting Play 2.2 style Java options by pre-pending '-J' to each
Java option.

4. Avoiding incompatible minimum and maximum heap sizes. Play 2.2 sets
-Xms to a large value by default and when this exceeds our calculated
-Xmx the JVM fails to initialise. Since we do not normally specify
-Xms, we set this to a low value (currently 2M since 1M is
insufficient for the JVM to initialise), but note that we do this for
Play 2.2 only.

[#58432326]
  • Loading branch information...
commit 4db158aaf2c0ca2a1540c120b0d74381b42c47f0 1 parent 6548d1e
Glyn Normington glyn authored

Showing 45 changed files with 1,183 additions and 370 deletions. Show diff stats Hide diff stats

  1. +1 1  docs/container-play.md
  2. +0 5 docs/util-other.md
  3. +9 1 lib/java_buildpack/base_component.rb
  4. +12 12 lib/java_buildpack/container/container_utils.rb
  5. +17 66 lib/java_buildpack/container/play.rb
  6. +2 2 lib/java_buildpack/framework/play_auto_reconfiguration.rb
  7. +7 9 lib/java_buildpack/framework/play_jpa_plugin.rb
  8. +176 0 lib/java_buildpack/util/base_play_app.rb
  9. +41 0 lib/java_buildpack/util/library_utils.rb
  10. +40 0 lib/java_buildpack/util/play_app_factory.rb
  11. +67 0 lib/java_buildpack/util/play_app_post22.rb
  12. +53 0 lib/java_buildpack/util/play_app_pre22.rb
  13. +61 0 lib/java_buildpack/util/play_app_pre22_dist.rb
  14. +46 0 lib/java_buildpack/util/play_app_pre22_staged.rb
  15. +0 105 lib/java_buildpack/util/play_utils.rb
  16. 0  ...ot/lib/play.play_0.0-0.0.0.jar → container_play_2.0_dist/application_root/lib/play.play_2.9.1-2.0.jar}
  17. 0  ...ication_root/lib/play.play_0.0-0.0.0.jar → container_play_2.0_dist/application_root/lib/some.test.jar}
  18. 0  spec/fixtures/{container_play_2.0 → container_play_2.0_dist}/application_root/start
  19. 0  ...ay_staged/staged/play_0.0.jar → container_play_2.1_dist/application_root/lib/play.play_2.10-2.1.4.jar}
  20. 0  ...application_root/lib/play.play_2.1.2.jar → container_play_2.1_dist/application_root/lib/some.test.jar}
  21. 0  spec/fixtures/{container_play → container_play_2.1_dist}/application_root/start
  22. 0  ...k_play_jpa_plugin_play20/staged/play_2.0.2.jar → container_play_2.1_staged/staged/play_2.10-2.1.4.jar}
  23. 0  ...amework_play_jpa_plugin_staged/staged/play_2.1.2.jar → container_play_2.1_staged/staged/some.test.jar}
  24. 0  spec/fixtures/{container_play_staged → container_play_2.1_staged}/start
  25. +4 0 spec/fixtures/container_play_2.2/bin/play-application
  26. 0  spec/fixtures/container_play_2.2/bin/play-application.bat
  27. 0  spec/fixtures/container_play_2.2/lib/com.typesafe.play.play_2.10-2.2.0.jar
  28. 0  spec/fixtures/container_play_2.2/lib/some.test.jar
  29. 0  spec/fixtures/container_play_2.2_ambiguous_start_script/bin/application1
  30. 0  spec/fixtures/container_play_2.2_ambiguous_start_script/bin/application2
  31. 0  spec/fixtures/container_play_2.2_ambiguous_start_script/lib/com.typesafe.play.play_2.10-2.2.0.jar
  32. 0  spec/fixtures/container_play_2.2_minus_bat_file/bin/play-application
  33. 0  spec/fixtures/container_play_2.2_minus_bat_file/lib/com.typesafe.play.play_2.10-2.2.0.jar
  34. 0  spec/fixtures/framework_play_jpa_plugin_dist/application_root/lib/play.play_2.10-2.1.2.jar
  35. 0  spec/fixtures/framework_play_jpa_plugin_play20/staged/play.play_2.9.1-2.0.jar
  36. 0  spec/fixtures/framework_play_jpa_plugin_staged/staged/play_2.10-2.1.2.jar
  37. +27 166 spec/java_buildpack/container/play_spec.rb
  38. +2 2 spec/java_buildpack/framework/play_auto_reconfiguration_spec.rb
  39. +1 1  spec/java_buildpack/framework/play_jpa_plugin_spec.rb
  40. +125 0 spec/java_buildpack/util/base_play_app_spec.rb
  41. +47 0 spec/java_buildpack/util/play_app_factory_spec.rb
  42. +127 0 spec/java_buildpack/util/play_app_post22_spec.rb
  43. +159 0 spec/java_buildpack/util/play_app_pre22_dist_spec.rb
  44. +50 0 spec/java_buildpack/util/play_app_pre22_spec.rb
  45. +109 0 spec/java_buildpack/util/play_app_pre22_staged_spec.rb
2  docs/container-play.md
Source Rendered
@@ -3,7 +3,7 @@ The Play Container allows Play applications to be run.
3 3
4 4 <table>
5 5 <tr>
6   - <td><strong>Detection Criteria</strong></td><td>The files <tt>start</tt> and <tt>lib/play.play_*.jar</tt> (or <tt>staged/play_*.jar</tt>) exist in the application
  6 + <td><strong>Detection Criteria</strong></td><td>The Play start script and the Play runtime JAR exist in the appropriate subdirectories of the application
7 7 directory or one of its immediate subdirectories (but not in both)</td>
8 8 </tr>
9 9 <tr>
5 docs/util-other.md
Source Rendered
... ... @@ -1,13 +1,9 @@
1 1 # Other Utiltities
2 2 The buildpack provides a number of other utilities that may help in implementing components.
3 3
4   -
5 4 ## [`JavaBuildpack::Util::GroovyUtils`][]
6 5 The `GroovyUtils` class provides a set of methods for finding groovy files and determing if they are of any special kind (e.g. they have a main method, they are a pogo, etc.).
7 6
8   -## [`JavaBuildpack::Util::PlayUtils`][]
9   -The `PlayUtils` class provides a set of methods for determing information about a Play Framework application.
10   -
11 7 ## [`JavaBuildpack::Util::Properties`][]
12 8 The `Properties` class provides a Ruby class that can read in a Java properties file and acts as a `Hash` with that data.
13 9
@@ -17,7 +13,6 @@ The `ResourceUtils` class provides an abstract around the `resources` directory
17 13 ## [`JavaBuildpack::Util::ServiceUtils`][]
18 14 The `ServiceUtils` class provides a set of methods for finding a given service in the `VCAP_SERVICES` payload.
19 15
20   -
21 16 [`JavaBuildpack::Util::GroovyUtils`]: ../lib/java_buildpack/util/groovy_utils.rb
22 17 [`JavaBuildpack::Util::PlayUtils`]: ../lib/java_buildpack/util/play_utils.rb
23 18 [`JavaBuildpack::Util::Properties`]: ../lib/java_buildpack/util/properties.rb
10 lib/java_buildpack/base_component.rb
@@ -16,6 +16,7 @@
16 16
17 17 require 'java_buildpack'
18 18 require 'java_buildpack/util/application_cache'
  19 +require 'java_buildpack/util/library_utils'
19 20 require 'java_buildpack/util/shell'
20 21
21 22 module JavaBuildpack
@@ -69,7 +70,7 @@ def compile
69 70 # are expected to read the +context+ values and take them into account when creating the command.
70 71 #
71 72 # @return [void, String] components other than containers are not expected to return any value. Container
72   - # compoonents are expected to return the command required to run the application.
  73 + # components are expected to return the command required to run the application.
73 74 def release
74 75 fail "Method 'release' must be defined"
75 76 end
@@ -105,6 +106,13 @@ def download_jar(version, uri, jar_name, target_directory = @lib_directory, desc
105 106 download(version, uri, description) { |file| shell "cp #{file.path} #{File.join(target_directory, jar_name)}" }
106 107 end
107 108
  109 + # Returns the additional libraries.
  110 + #
  111 + # @param [Array<String>] the paths of JARs in the additional libraries directory
  112 + def additional_libraries
  113 + JavaBuildpack::Util::LibraryUtils.lib_jars @lib_directory
  114 + end
  115 +
108 116 end
109 117
110 118 end
24 lib/java_buildpack/container/container_utils.rb
@@ -33,7 +33,7 @@ def self.to_java_opts_s(java_opts)
33 33 # Evaluates a value and if it is not +nil+ or empty, prepends it with a space. This can be used to create BASH
34 34 # command lines that do not have ugly extra spacing.
35 35 #
36   - # @param [String, nil] value the value to evalutate for extra spacing
  36 + # @param [String, nil] value the value to evaluate for extra spacing
37 37 # @return [String] an empty string if +value+ is +nil+ or empty, otherwise the value prepended with a space
38 38 def self.space(value)
39 39 value = value.to_s if value.respond_to?(:to_s)
@@ -47,18 +47,18 @@ def self.space(value)
47 47 # @param [String] lib_directory the directory that additional libraries are placed in
48 48 # @return [Array<String>] the relative paths of the JARs located in the additional libraries directory
49 49 def self.libs(root_dir, lib_directory)
50   - libs = []
51   -
52   - if lib_directory
53   - root_directory = Pathname.new(root_dir)
54   -
55   - libs = Pathname.new(lib_directory).children
56   - .select { |file| file.extname == '.jar' }
57   - .map { |file| file.relative_path_from(root_directory) }
58   - .sort
59   - end
  50 + relative_paths(root_dir, JavaBuildpack::Util::LibraryUtils.lib_jars(lib_directory))
  51 + end
60 52
61   - libs
  53 + # Returns an +Array+ containing the relative paths of the given files. The
  54 + # paths of these files are relative to the +root_dir+.
  55 + #
  56 + # @param [String] root_dir the directory relative to which the resultant are calculated
  57 + # @param [Array<String>] libs an array of file paths
  58 + # @return [Array<String>] the relative paths of the given file paths
  59 + def self.relative_paths(root_dir, libs)
  60 + root_directory = Pathname.new(root_dir)
  61 + libs.map { |lib| lib.relative_path_from(root_directory) }
62 62 end
63 63
64 64 end
83 lib/java_buildpack/container/play.rb
@@ -19,7 +19,7 @@
19 19 require 'java_buildpack/container/container_utils'
20 20 require 'java_buildpack/repository/configured_item'
21 21 require 'java_buildpack/util/application_cache'
22   -require 'java_buildpack/util/play_utils'
  22 +require 'java_buildpack/util/play_app_factory'
23 23 require 'pathname'
24 24
25 25 module JavaBuildpack::Container
@@ -30,95 +30,46 @@ class Play < JavaBuildpack::BaseComponent
30 30 def initialize(context)
31 31 super('Play Framework', context)
32 32
33   - @play_root = JavaBuildpack::Util::PlayUtils.root(@app_dir)
34   - @version = @play_root ? JavaBuildpack::Util::PlayUtils.version(@play_root) : nil
  33 + @play_app = JavaBuildpack::Util::PlayAppFactory.create @app_dir
35 34 end
36 35
37 36 def detect
38   - @version ? id(@version) : nil
  37 + if @play_app
  38 + version = @play_app.version
  39 + version ? id(version) : nil
  40 + else
  41 + nil
  42 + end
39 43 end
40 44
41 45 def compile
42   - shell "chmod +x #{JavaBuildpack::Util::PlayUtils.start_script @play_root}"
43   - add_libs_to_classpath
44   - replace_bootstrap @play_root
  46 + @play_app.set_executable
  47 + @play_app.add_libs_to_classpath additional_libraries
  48 + @play_app.replace_bootstrap BOOTSTRAP_CLASS_NAME
45 49 end
46 50
47 51 def release
48   - @java_opts << "-D#{KEY_HTTP_PORT}=$PORT"
  52 + java_opts = @java_opts.clone
  53 + java_opts << "-D#{KEY_HTTP_PORT}=$PORT"
49 54
50 55 path_string = "PATH=#{File.join @java_home, 'bin'}:$PATH"
51 56 java_home_string = ContainerUtils.space("JAVA_HOME=#{@java_home}")
52   - start_script_string = ContainerUtils.space(start_script_relative @play_root)
53   - java_opts_string = ContainerUtils.space(ContainerUtils.to_java_opts_s(@java_opts))
  57 + start_script_string = ContainerUtils.space(@play_app.start_script_relative)
  58 + java_opts_string = ContainerUtils.space(ContainerUtils.to_java_opts_s(@play_app.decorate_java_opts java_opts))
54 59
55 60 "#{path_string}#{java_home_string}#{start_script_string}#{java_opts_string}"
56 61 end
57 62
58 63 private
59 64
60   - KEY_HTTP_PORT = 'http.port'.freeze
61   -
62   - def add_libs_to_classpath
63   - if JavaBuildpack::Util::PlayUtils.lib_play_jar @play_root
64   - add_libs_to_dist_classpath
65   - else
66   - add_libs_to_staged_classpath
67   - end
68   - end
69   -
70   - def add_libs_to_staged_classpath
71   - # Staged applications add all the JARs in the staged directory to the classpath, so add symbolic links to the staged directory.
72   - # Note: for staged applications, @app_dir = @play_root
73   - link_libs_to_classpath_directory(JavaBuildpack::Util::PlayUtils.staged @play_root)
74   - end
  65 + BOOTSTRAP_CLASS_NAME = 'org.cloudfoundry.reconfiguration.play.Bootstrap'.freeze
75 66
76   - def link_libs_to_classpath_directory(classpath_directory)
77   - ContainerUtils.libs(@play_root, @lib_directory).each do |lib|
78   - shell "ln -nsf ../#{lib} #{classpath_directory}"
79   - end
80   - end
81   -
82   - def add_libs_to_dist_classpath
83   - # Dist applications either list JARs in a classpath variable (e.g. in Play 2.1.3) or on a -cp parameter (e.g. in Play 2.0),
84   - # so add to the appropriate list.
85   - # Note: for dist applications, @play_root is an immediate subdirectory of @app_dir, so @app_dir is equivalent to @play_root/..
86   - script_dir_relative_path = Pathname.new(@app_dir).relative_path_from(Pathname.new(@play_root)).to_s
87   -
88   - additional_classpath = ContainerUtils.libs(@app_dir, @lib_directory).map do |lib|
89   - "$scriptdir/#{script_dir_relative_path}/#{lib}"
90   - end
91   -
92   - result = update_file JavaBuildpack::Util::PlayUtils.start_script(@play_root), /^classpath=\"(.*)\"$/, "classpath=\"#{additional_classpath.join(':')}:\\1\""
93   - unless result
94   - link_libs_to_classpath_directory(JavaBuildpack::Util::PlayUtils.lib @play_root)
95   - end
96   - end
  67 + KEY_HTTP_PORT = 'http.port'.freeze
97 68
98 69 def id(version)
99 70 "#{@parsable_component_name}=#{version}"
100 71 end
101 72
102   - def replace_bootstrap(root)
103   - update_file JavaBuildpack::Util::PlayUtils.start_script(root), /play\.core\.server\.NettyServer/, 'org.cloudfoundry.reconfiguration.play.Bootstrap'
104   - end
105   -
106   - def start_script_relative(play_root)
107   - "./#{Pathname.new(JavaBuildpack::Util::PlayUtils.start_script(play_root)).relative_path_from(Pathname.new(@app_dir)).to_s}"
108   - end
109   -
110   - def update_file(file_name, pattern, replacement)
111   - content = File.open(file_name, 'r') { |file| file.read }
112   - result = content.gsub! pattern, replacement
113   -
114   - File.open(file_name, 'w') do |file|
115   - file.write content
116   - file.fsync
117   - end
118   -
119   - result
120   - end
121   -
122 73 end
123 74
124 75 end
4 lib/java_buildpack/framework/play_auto_reconfiguration.rb
@@ -17,7 +17,7 @@
17 17 require 'java_buildpack/framework'
18 18 require 'java_buildpack/repository/configured_item'
19 19 require 'java_buildpack/util/application_cache'
20   -require 'java_buildpack/util/play_utils'
  20 +require 'java_buildpack/util/play_app_factory'
21 21 require 'java_buildpack/versioned_dependency_component'
22 22
23 23 module JavaBuildpack::Framework
@@ -41,7 +41,7 @@ def release
41 41 protected
42 42
43 43 def supports?
44   - JavaBuildpack::Util::PlayUtils.root(@app_dir)
  44 + JavaBuildpack::Util::PlayAppFactory.create @app_dir
45 45 end
46 46
47 47 private
16 lib/java_buildpack/framework/play_jpa_plugin.rb
@@ -17,7 +17,7 @@
17 17 require 'java_buildpack/framework'
18 18 require 'java_buildpack/repository/configured_item'
19 19 require 'java_buildpack/util/application_cache'
20   -require 'java_buildpack/util/play_utils'
  20 +require 'java_buildpack/util/play_app_factory'
21 21 require 'java_buildpack/versioned_dependency_component'
22 22
23 23 module JavaBuildpack::Framework
@@ -44,8 +44,8 @@ def release
44 44 def supports?
45 45 candidate = false
46 46
47   - root = JavaBuildpack::Util::PlayUtils.root @app_dir
48   - candidate = uses_jpa?(root) || play20?(root) if root
  47 + play_app = JavaBuildpack::Util::PlayAppFactory.create @app_dir
  48 + candidate = uses_jpa?(play_app) || play20?(play_app.version) if play_app
49 49
50 50 candidate
51 51 end
@@ -58,14 +58,12 @@ def jar_name
58 58 "#{id @version}.jar"
59 59 end
60 60
61   - def play20?(root)
62   - JavaBuildpack::Util::PlayUtils.version(root) =~ /2.0.[\d]+/
  61 + def play20?(play_version)
  62 + play_version =~ /^2\.0(\.[\d]+)?$/
63 63 end
64 64
65   - def uses_jpa?(root)
66   - lib = File.join JavaBuildpack::Util::PlayUtils.lib(root), PLAY_JPA_PLUGIN_JAR
67   - staged = File.join JavaBuildpack::Util::PlayUtils.staged(root), PLAY_JPA_PLUGIN_JAR
68   - Dir[lib, staged].first
  65 + def uses_jpa?(play_app)
  66 + play_app.contains? PLAY_JPA_PLUGIN_JAR
69 67 end
70 68
71 69 end
176 lib/java_buildpack/util/base_play_app.rb
... ... @@ -0,0 +1,176 @@
  1 +# Encoding: utf-8
  2 +# Cloud Foundry Java Buildpack
  3 +# Copyright (c) 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 +require 'java_buildpack/util/shell'
  19 +
  20 +module JavaBuildpack::Util
  21 +
  22 + # Base class for Play application classes.
  23 + class BasePlayApp
  24 + include JavaBuildpack::Util::Shell
  25 +
  26 + # Returns the version of this Play application
  27 + #
  28 + # @return [String, nil] the version of the Play application
  29 + attr_reader :version
  30 +
  31 + # Determines whether the given application directory contains a Play application that this class recognizes.
  32 + #
  33 + # @param [String] app_dir the application directory
  34 + # @return [Boolean] +true+ if and only if this class recognizes a Play application
  35 + def self.recognizes?(app_dir)
  36 + find_root app_dir
  37 + end
  38 +
  39 + # Creates a Play application based on the given application directory.
  40 + #
  41 + # @param [String] app_dir the application directory
  42 + def initialize(app_dir)
  43 + @app_dir = app_dir
  44 + end
  45 +
  46 + # Ensures this Play application is executable.
  47 + def set_executable
  48 + shell "chmod +x #{start_script}"
  49 + end
  50 +
  51 + # Replaces the bootstrap class of this Play application.
  52 + #
  53 + # @param [String] bootstrap_class the replacement bootstrap class name
  54 + def replace_bootstrap(bootstrap_class)
  55 + update_file start_script, /play\.core\.server\.NettyServer/, bootstrap_class
  56 + end
  57 +
  58 + # Adds the given JARs to this Play application's classpath.
  59 + #
  60 + # @param [Array<String>] libs the JAR paths
  61 + def add_libs_to_classpath(libs)
  62 + fail "Method 'add_libs_to_classpath' must be defined"
  63 + end
  64 +
  65 + # Returns the path of the Play start script relative to the application directory.
  66 + #
  67 + # @return [String] the path of the Play start script relative to the application directory
  68 + def start_script_relative
  69 + "./#{Pathname.new(start_script).relative_path_from(Pathname.new(@app_dir)).to_s}"
  70 + end
  71 +
  72 + # Determines whether or not the Play application contains a JAR with the given, possibly wildcarded, name.
  73 + #
  74 + # @param [Object] jar_name a JAR name which may contain +*+ to match zero or more characters, e.g. +a*.jar+
  75 + # @return [Boolean] true if and only if at least one JAR was found matching the given name
  76 + def contains?(jar_name)
  77 + lib = File.join self.class.classpath_directory(play_root), jar_name
  78 + Dir[lib].first
  79 + end
  80 +
  81 + # Decorates the given Java options as appropriate to the version of Play.
  82 + #
  83 + # @param [Array<String>] java_opts the Java options to be decorated
  84 + # @return [Array<String] the decorated Java options
  85 + def decorate_java_opts(java_opts)
  86 + java_opts
  87 + end
  88 +
  89 + protected
  90 +
  91 + # Finds the Play application root directory, in the given application directory, containing a start script
  92 + # and a Play JAR in the appropriate directory. Also finds the Play application version.
  93 + #
  94 + # @param [String] app_dir the application directory
  95 + # @return [String, nil] the Play application root directory or +nil+ if no such directory was found
  96 + # @return [String, nil] the Play application version or +nil+ if no version is available
  97 + def self.root_and_version(app_dir)
  98 + play_root = find_root(app_dir)
  99 + fail "Unrecognized Play application in #{app_dir}" unless play_root
  100 + version = version(classpath_directory_play_jar(play_root))
  101 + fail "Unrecognized Play application version in #{app_dir}" unless version
  102 + return play_root, version # rubocop:disable RedundantReturn
  103 + end
  104 +
  105 + # The location of the directory containing the JARs of a Play application
  106 + #
  107 + # @param [String] root the root of the Play application
  108 + # @return [String] the path to the directory containing the JARs
  109 + def self.classpath_directory(root)
  110 + File.join root, 'lib'
  111 + end
  112 +
  113 + # The version of the Play application, as derived from the version number embedded in the name of the +play_+ JAR.
  114 + #
  115 + # @param [String] play_jar the path to the play JAR
  116 + # @return [String, nil] the version of the Play application
  117 + def self.version(play_jar)
  118 + play_jar.match(/.*play_.*-(.*)\.jar/)[1]
  119 + end
  120 +
  121 + # Returns the path of the start script.
  122 + #
  123 + # @return [String] the path of the start script
  124 + def start_script
  125 + self.class.start_script play_root
  126 + end
  127 +
  128 + # Returns the path of the start script.
  129 + #
  130 + # @param [String] app_dir the application root
  131 + # @return [String] the path of the start script
  132 + def self.start_script(app_dir)
  133 + fail "Method 'start_script' must be defined"
  134 + end
  135 +
  136 + private
  137 +
  138 + PLAY_JAR = '*play_*-*.jar'.freeze
  139 +
  140 + attr_reader :app_dir
  141 +
  142 + def self.find_root(app_dir)
  143 + roots = Dir[app_dir, File.join(app_dir, '*')].select do |file|
  144 + start_script(file) && classpath_directory_play_jar(file)
  145 + end
  146 +
  147 + fail "Play application detected in multiple directories: #{roots}" if roots.size > 1
  148 +
  149 + roots.first
  150 + end
  151 +
  152 + def self.play_jar(root)
  153 + Dir[File.join(root, PLAY_JAR)].first
  154 + end
  155 +
  156 + def self.classpath_directory_play_jar(root)
  157 + play_jar(classpath_directory(root))
  158 + end
  159 +
  160 + def update_file(file_name, pattern, replacement)
  161 + content = File.open(file_name, 'r') { |file| file.read }
  162 + result = content.gsub! pattern, replacement
  163 +
  164 + File.open(file_name, 'w') do |file|
  165 + file.write content
  166 + file.fsync
  167 + end
  168 +
  169 + result
  170 + end
  171 +
  172 + attr_reader :play_root
  173 +
  174 + end
  175 +
  176 +end
41 lib/java_buildpack/util/library_utils.rb
... ... @@ -0,0 +1,41 @@
  1 +# Encoding: utf-8
  2 +# Cloud Foundry Java Buildpack
  3 +# Copyright (c) 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::Util
  20 +
  21 + # Common utilities for manipulating libraries (i.e. JARs)
  22 + class LibraryUtils
  23 +
  24 + # Returns an +Array+ containing the paths of the JARs located in the given directory.
  25 + #
  26 + # @param [String] lib_directory the directory containing zero or more JARs
  27 + # @return [Array<String>] the paths of the JARs located in the given directory
  28 + def self.lib_jars(lib_directory)
  29 + libs = []
  30 +
  31 + if lib_directory
  32 + libs = Pathname.new(lib_directory).children
  33 + .select { |file| file.extname == '.jar' }
  34 + .sort
  35 + end
  36 +
  37 + libs
  38 + end
  39 + end
  40 +
  41 +end
40 lib/java_buildpack/util/play_app_factory.rb
... ... @@ -0,0 +1,40 @@
  1 +# Encoding: utf-8
  2 +# Cloud Foundry Java Buildpack
  3 +# Copyright (c) 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 +require 'java_buildpack/util/play_app_pre22_dist'
  19 +require 'java_buildpack/util/play_app_pre22_staged'
  20 +require 'java_buildpack/util/play_app_post22'
  21 +
  22 +module JavaBuildpack::Util
  23 +
  24 + # Create instances of PlayAppPre22.
  25 + class PlayAppFactory
  26 +
  27 + # Creates a Play application based on the given application directory.
  28 + #
  29 + # @param [String] app_dir the application directory
  30 + def self.create(app_dir)
  31 + recognizers = [PlayAppPre22Staged, PlayAppPre22Dist, PlayAppPost22].select do |play_app_class|
  32 + play_app_class if play_app_class.recognizes? app_dir
  33 + end
  34 + fail "Play application in #{app_dir} is recognized by more than one Play application class: #{recognizers}" if recognizers.size > 1
  35 + recognizers.empty? ? nil : recognizers[0].new(app_dir)
  36 + end
  37 +
  38 + end
  39 +
  40 +end
67 lib/java_buildpack/util/play_app_post22.rb
... ... @@ -0,0 +1,67 @@
  1 +# Encoding: utf-8
  2 +# Cloud Foundry Java Buildpack
  3 +# Copyright (c) 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/container/container_utils'
  18 +require 'java_buildpack/util'
  19 +require 'java_buildpack/util/base_play_app'
  20 +require 'java_buildpack/util/shell'
  21 +
  22 +module JavaBuildpack::Util
  23 +
  24 + # Encapsulate inspection and modification of Play applications from Play 2.2.0 onwards.
  25 + class PlayAppPost22 < BasePlayApp
  26 +
  27 + def initialize(app_dir)
  28 + super(app_dir)
  29 + @play_root, @version = self.class.root_and_version(app_dir)
  30 + end
  31 +
  32 + def add_libs_to_classpath(libs)
  33 + script_dir_relative_path = Pathname.new(app_dir).relative_path_from(Pathname.new(File.join(@play_root, 'bin'))).to_s
  34 +
  35 + additional_classpath = JavaBuildpack::Container::ContainerUtils.relative_paths(app_dir, libs).map do |lib|
  36 + "$app_home/#{script_dir_relative_path}/#{lib}"
  37 + end
  38 +
  39 + update_file start_script, /^declare -r app_classpath=\"(.*)\"$/, "declare -r app_classpath=\"#{additional_classpath.join(':')}:\\1\""
  40 + end
  41 +
  42 + def decorate_java_opts(java_opts)
  43 + decorated_java_opts = []
  44 + java_opts.each { |java_opt| decorated_java_opts << "-J#{java_opt}" }
  45 + decorated_java_opts << '-J-Xms2M'
  46 + end
  47 +
  48 + private
  49 +
  50 + def self.start_script(app_dir)
  51 + scripts = start_scripts app_dir
  52 + if scripts.size == 1
  53 + scripts[0]
  54 + else
  55 + scripts.find do |script|
  56 + File.exists?("#{script}.bat")
  57 + end
  58 + end
  59 + end
  60 +
  61 + def self.start_scripts(app_dir)
  62 + Dir[File.join(app_dir, 'bin', '*')]
  63 + end
  64 +
  65 + end
  66 +
  67 +end
53 lib/java_buildpack/util/play_app_pre22.rb
... ... @@ -0,0 +1,53 @@
  1 +# Encoding: utf-8
  2 +# Cloud Foundry Java Buildpack
  3 +# Copyright (c) 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/container/container_utils'
  18 +require 'java_buildpack/util'
  19 +require 'java_buildpack/util/base_play_app'
  20 +require 'java_buildpack/util/shell'
  21 +
  22 +module JavaBuildpack::Util
  23 +
  24 + # Base class for inspection and modification of Play applications up to and including Play 2.1.x.
  25 + class PlayAppPre22 < BasePlayApp
  26 + include JavaBuildpack::Util::Shell
  27 +
  28 + def initialize(app_dir)
  29 + super(app_dir)
  30 + end
  31 +
  32 + protected
  33 +
  34 + # Symbolically links to the given JARs from the classpath directory.
  35 + #
  36 + # @param [Array<String>] libs the JAR paths
  37 + def link_libs_from_classpath_dir(libs)
  38 + JavaBuildpack::Container::ContainerUtils.relative_paths(play_root, libs).each do |lib|
  39 + shell "ln -nsf ../#{lib} #{self.class.classpath_directory(play_root)}"
  40 + end
  41 + end
  42 +
  43 + private
  44 +
  45 + START_SCRIPT = 'start'.freeze
  46 +
  47 + def self.start_script(root)
  48 + Dir[File.join(root, START_SCRIPT)].first
  49 + end
  50 +
  51 + end
  52 +
  53 +end
61 lib/java_buildpack/util/play_app_pre22_dist.rb
... ... @@ -0,0 +1,61 @@
  1 +# Encoding: utf-8
  2 +# Cloud Foundry Java Buildpack
  3 +# Copyright (c) 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/container/container_utils'
  18 +require 'java_buildpack/util'
  19 +require 'java_buildpack/util/play_app_pre22'
  20 +
  21 +module JavaBuildpack::Util
  22 +
  23 + # Encapsulate inspection and modification of Play dist applications up to and including Play 2.1.x.
  24 + class PlayAppPre22Dist < PlayAppPre22
  25 +
  26 + def initialize(app_dir)
  27 + super(app_dir)
  28 + @play_root, @version = self.class.root_and_version(app_dir)
  29 + end
  30 +
  31 + def add_libs_to_classpath(libs)
  32 + # In Play 2.1.x dist applications, the start script contains a list of JARs which form the classpath. To add
  33 + # libraries to the classpath, the script is edited to extend the list of JARs.
  34 + #
  35 + # For Play Play 2.0.x dist applications, the start script builds a classpath dynamically
  36 + # from the set of JARs in the +lib+ directory. To add libraries to the classpath,
  37 + # the JARs are symbolically linked into the +lib+ directory.
  38 + add_libs_to_dist_classpath(libs)
  39 + end
  40 +
  41 + private
  42 +
  43 + def add_libs_to_dist_classpath(libs)
  44 + # Dist applications either list JARs in a classpath variable (e.g. in Play 2.1.3) or add all the JARs in the lib
  45 + # directory to the classpath using a -cp parameter (e.g. in Play 2.0).
  46 + script_dir_relative_path = Pathname.new(app_dir).relative_path_from(Pathname.new(@play_root)).to_s
  47 +
  48 + additional_classpath = JavaBuildpack::Container::ContainerUtils.relative_paths(app_dir, libs).map do |lib|
  49 + "$scriptdir/#{script_dir_relative_path}/#{lib}"
  50 + end
  51 +
  52 + result = update_file start_script, /^classpath=\"(.*)\"$/, "classpath=\"#{additional_classpath.join(':')}:\\1\""
  53 + unless result
  54 + # No classpath variable was found, so add symbolic links to the lib directory.
  55 + link_libs_from_classpath_dir(libs)
  56 + end
  57 + end
  58 +
  59 + end
  60 +
  61 +end
46 lib/java_buildpack/util/play_app_pre22_staged.rb
... ... @@ -0,0 +1,46 @@
  1 +# Encoding: utf-8
  2 +# Cloud Foundry Java Buildpack
  3 +# Copyright (c) 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/container/container_utils'
  18 +require 'java_buildpack/util'
  19 +require 'java_buildpack/util/play_app_pre22'
  20 +
  21 +module JavaBuildpack::Util
  22 +
  23 + # Encapsulate inspection and modification of Play staged applications up to and including Play 2.1.x.
  24 + class PlayAppPre22Staged < PlayAppPre22
  25 +
  26 + def initialize(app_dir)
  27 + super(app_dir)
  28 + @play_root, @version = self.class.root_and_version(app_dir)
  29 + end
  30 +
  31 + def add_libs_to_classpath(libs)
  32 + # For Play 2.0 and 2.1.x staged applications, the start script builds a classpath dynamically
  33 + # from the set of JARs in the +staged+ directory. To add libraries to the classpath,
  34 + # the JARs are symbolically linked into the +staged+ directory.
  35 + link_libs_from_classpath_dir(libs)
  36 + end
  37 +
  38 + private
  39 +
  40 + def self.classpath_directory(root)
  41 + File.join root, 'staged'
  42 + end
  43 +
  44 + end
  45 +
  46 +end
105 lib/java_buildpack/util/play_utils.rb
... ... @@ -1,105 +0,0 @@
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::Util
20   -
21   - # Utilities for dealing with Play Framework application
22   - class PlayUtils
23   -
24   - # Locate a Play application root directory in the given application directory.
25   - #
26   - # @param [String] app_dir the application directory
27   - # @return [Dir, nil] the located Play application directory or `nil` if there is no such
28   - # @raise if more than one Play application directory is located
29   - def self.root(app_dir)
30   -
31   - # A Play application may reside directly in the application directory or in a direct subdirectory of the
32   - # application directory.
33   - roots = Dir[app_dir, File.join(app_dir, '*')].select do |file|
34   - start_script(file) && (lib_play_jar(file) || staged_play_jar(file))
35   - end
36   -
37   - fail "Play application detected in multiple directories: #{roots}" if roots.size > 1
38   -
39   - roots.first
40   - end
41   -
42   - # The location of the start script in a Play application
43   - #
44   - # @param [String] root the root of the Play application
45   - # @return [String, nil] the path to the start script, or +nil+ if it does not exist
46   - def self.start_script(root)
47   - Dir[File.join(root, START_SCRIPT)].first
48   - end
49   -
50   - # The location of the lib directory in a dist Play application
51   - #
52   - # @param [String] root the root of the Play application
53   - # @return [String, nil] the path to the lib directory, or +nil+ if it does not exist
54   - def self.lib(root)
55   - File.join root, 'lib'
56   - end
57   -
58   - # The location of the play JAR in a dist Play application
59   - #
60   - # @param [String] root the root of the Play application
61   - # @return [String, nil] the path to the dist play JAR, or +nil+ if it does not exist
62   - def self.lib_play_jar(root)
63   - play_jar(lib(root))
64   - end
65   -
66   - # The location of the staged directory in a staged Play application
67   - #
68   - # @param [String] root the root of the Play application
69   - # @return [String, nil] the path to the staged directory, or +nil+ if it does not exist
70   - def self.staged(root)
71   - File.join root, 'staged'
72   - end
73   -
74   - # The location of the play JAR in a staged Play application
75   - #
76   - # @param [String] root the root of the Play application
77   - # @return [String, nil] the path to the staged play JAR, or +nil+ if it does not exist
78   - def self.staged_play_jar(root)
79   - play_jar(staged(root))
80   - end
81   -
82   - # The version of the Play application, as derived from the version number embedded in the name of the +play_+ JAR.
83   - #
84   - # @param [String] root the root of the Play application
85   - # @return [String, nil] the version of the Play application
86   - def self.version(root)
87   - play_jar = lib_play_jar(root) || staged_play_jar(root)
88   - play_jar.match(/.*play_(.*)\.jar/)[1]
89   - end
90   -
91   - private
92   -
93   - START_SCRIPT = 'start'.freeze
94   -
95   - PLAY_JAR = '*play_*.jar'.freeze
96   -
97   - def self.play_jar(root)
98   - Dir[File.join(root, PLAY_JAR)].first
99   - end
100   -
101   - private_class_method :new
102   -
103   - end
104   -
105   -end
0  ...play/application_root/lib/play.play_0.0-0.0.0.jar → ...dist/application_root/lib/play.play_2.9.1-2.0.jar
File renamed without changes
0  ..._2.0/application_root/lib/play.play_0.0-0.0.0.jar → ..._play_2.0_dist/application_root/lib/some.test.jar
File renamed without changes
0  ...ixtures/container_play_2.0/application_root/start → ...es/container_play_2.0_dist/application_root/start
File renamed without changes
0  ...ixtures/container_play_staged/staged/play_0.0.jar → ...ist/application_root/lib/play.play_2.10-2.1.4.jar
File renamed without changes
0  ...gin_dist/application_root/lib/play.play_2.1.2.jar → ..._play_2.1_dist/application_root/lib/some.test.jar
File renamed without changes
0  spec/fixtures/container_play/application_root/start → ...es/container_play_2.1_dist/application_root/start
File renamed without changes
0  ...work_play_jpa_plugin_play20/staged/play_2.0.2.jar → ...tainer_play_2.1_staged/staged/play_2.10-2.1.4.jar
File renamed without changes
0  ...work_play_jpa_plugin_staged/staged/play_2.1.2.jar → ...es/container_play_2.1_staged/staged/some.test.jar
File renamed without changes
0  spec/fixtures/container_play_staged/start → spec/fixtures/container_play_2.1_staged/start
File renamed without changes
4 spec/fixtures/container_play_2.2/bin/play-application
... ... @@ -0,0 +1,4 @@
  1 +
  2 +declare -r app_mainclass="play.core.server.NettyServer"
  3 +
  4 +declare -r app_classpath="$lib_dir/some-dependency.jar"
0  spec/fixtures/container_play_2.2/bin/play-application.bat
No changes.
0  spec/fixtures/container_play_2.2/lib/com.typesafe.play.play_2.10-2.2.0.jar
No changes.
0  spec/fixtures/container_play_2.2/lib/some.test.jar
No changes.
0  spec/fixtures/container_play_2.2_ambiguous_start_script/bin/application1
No changes.
0  spec/fixtures/container_play_2.2_ambiguous_start_script/bin/application2
No changes.
0  spec/fixtures/container_play_2.2_ambiguous_start_script/lib/com.typesafe.play.play_2.10-2.2.0.jar
No changes.
0  spec/fixtures/container_play_2.2_minus_bat_file/bin/play-application
No changes.
0  spec/fixtures/container_play_2.2_minus_bat_file/lib/com.typesafe.play.play_2.10-2.2.0.jar
No changes.
0  spec/fixtures/framework_play_jpa_plugin_dist/application_root/lib/play.play_2.10-2.1.2.jar
No changes.
0  spec/fixtures/framework_play_jpa_plugin_play20/staged/play.play_2.9.1-2.0.jar
No changes.
0  spec/fixtures/framework_play_jpa_plugin_staged/staged/play_2.10-2.1.2.jar
No changes.
193 spec/java_buildpack/container/play_spec.rb
@@ -16,186 +16,47 @@
16 16
17 17 require 'spec_helper'
18 18 require 'java_buildpack/container/play'
  19 +require 'java_buildpack/util/play_app_factory'
19 20
20 21 module JavaBuildpack::Container
21 22
22   - TEST_JAVA_HOME = 'test-java-home'
23   - TEST_JAVA_OPTS = ['test-java-opt']
24   - TEST_PLAY_APP = 'spec/fixtures/container_play'
25   -
26 23 describe Play do
27 24
28   - it 'should not detect an application without a start script' do
29   - detected = Play.new(
30   - app_dir: 'spec/fixtures/container_main',
31   - configuration: {}
32   - ).detect
33   -
34   - expect(detected).to be_nil
35   - end
36   -
37   - it 'should not detect an application with a start directory' do
38   - detected = Play.new(
39   - app_dir: 'spec/fixtures/container_play_invalid',
40   - configuration: {}
41   - ).detect
  25 + let(:play_instance) { double('PlayApp') }
42 26
43   - expect(detected).to be_nil
  27 + it 'should construct an instance using the PlayAppFactory' do
  28 + JavaBuildpack::Util::PlayAppFactory.stub(:create).with('test-app-dir').and_return(play_instance)
  29 + Play.new('app_dir' => 'test-app-dir')
44 30 end
45 31
46   - it 'should not detect an application which is too deeply nested in the application directory' do
47   - detected = Play.new(
48   - app_dir: 'spec/fixtures/container_play_too_deep',
49   - configuration: {}
50   - ).detect
51   -
52   - expect(detected).to be_nil
  32 + it 'should used nil returned by the PlayAppFactory to determine the version' do
  33 + JavaBuildpack::Util::PlayAppFactory.stub(:create).with('test-app-dir').and_return(nil)
  34 + play = Play.new('app_dir' => 'test-app-dir')
  35 + expect(play.detect).to be_nil
53 36 end
54 37
55   - it 'should fail if a Play application is in more than one directory' do
56   - expect do
57   - Play.new(
58   - app_dir: 'spec/fixtures/container_play_duplicate',
59   - configuration: {}
60   - )
61   - end.to raise_error(/multiple/)
  38 + it 'should use the PlayApp returned by the PlayAppFactory to determine the version' do
  39 + JavaBuildpack::Util::PlayAppFactory.stub(:create).with('test-app-dir').and_return(play_instance)
  40 + play_instance.should_receive(:version).and_return('test-version')
  41 + play = Play.new('app_dir' => 'test-app-dir')
  42 + expect(play.detect).to eq('play-framework=test-version')
62 43 end
63 44
64   - it 'should detect a dist application with a start script and a suitable Play JAR' do
65   - detected = Play.new(
66   - app_dir: 'spec/fixtures/container_play',
67   - configuration: {}
68   - ).detect
69   -
70   - expect(detected).to eq('play-framework=0.0-0.0.0')
  45 + it 'should use the PlayApp returned by the PlayAppFactory to perform compilation' do
  46 + JavaBuildpack::Util::PlayAppFactory.stub(:create).with('test-app-dir').and_return(play_instance)
  47 + play_instance.should_receive(:set_executable)
  48 + play_instance.should_receive(:add_libs_to_classpath)
  49 + play_instance.should_receive(:replace_bootstrap)
  50 + play = Play.new('app_dir' => 'test-app-dir')
  51 + play.compile
71 52 end
72 53
73   - it 'should detect a staged application with a start script and a suitable Play JAR' do
74   - detected = Play.new(
75   - app_dir: 'spec/fixtures/container_play_staged',
76   - configuration: {}
77   - ).detect
78   -
79   - expect(detected).to eq('play-framework=0.0')
80   - end
81   -
82   - it 'should not detect an application with a start script but no suitable Play JAR' do
83   - detected = Play.new(
84   - app_dir: 'spec/fixtures/container_play_like',
85   - configuration: {}
86   - ).detect
87   -
88   - expect(detected).to be_nil
89   - end
90   -
91   - it 'should make the start script executable in the compile step' do
92   - Dir.mktmpdir do |root|
93   - FileUtils.cp_r 'spec/fixtures/container_play/.', root
94   -
95   - play = Play.new(
96   - app_dir: root,
97   - configuration: {}
98   - )
99   -
100   - play.should_receive(:shell).with("chmod +x #{root}/application_root/start").and_return('')
101   -
102   - play.compile
103   - end
104   - end
105   -
106   - it 'should replace the server command in the start script' do
107   - Dir.mktmpdir do |root|
108   - start_script = File.join root, 'application_root', 'start'
109   - FileUtils.cp_r 'spec/fixtures/container_play/.', root
110   -
111   - Play.new(
112   - app_dir: root,
113   - configuration: {}
114   - ).compile
115   -
116   - actual = File.open(start_script, 'r') { |file| file.read }
117   -
118   - expect(actual).to_not match(/play.core.server.NettyServer/)
119   - expect(actual).to match(/org.cloudfoundry.reconfiguration.play.Bootstrap/)
120   - end
121   - end
122   -
123   - it 'should add additional libraries to classpath in (e.g. Play 2.1.3) dist application' do
124   - Dir.mktmpdir do |root|
125   - lib_directory = File.join root, '.lib'
126   - start_script = File.join root, 'application_root', 'start'
127   -
128   - FileUtils.cp_r 'spec/fixtures/container_play/.', root
129   - Dir.mkdir lib_directory
130   - FileUtils.cp 'spec/fixtures/additional_libs/test-jar-1.jar', lib_directory
131   -
132   - Play.new(
133   - app_dir: root,
134   - lib_directory: lib_directory,
135   - configuration: {}
136   - ).compile
137   -
138   - actual = File.open(start_script, 'r') { |file| file.read }
139   -
140   - expect(actual).to match(%r(classpath="\$scriptdir/.\./\.lib/test-jar-1\.jar:))
141   - end
142   - end
143   -
144   - it 'should add additional libraries to lib directory in Play 2.0 dist application' do
145   - Dir.mktmpdir do |root|
146   - lib_directory = File.join root, '.lib'
147   -