fjc-warbler 0.9.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,19 @@
1
+ #--
2
+ # (c) Copyright 2007-2008 Sun Microsystems, Inc.
3
+ # See the file LICENSES.txt included with the distribution for
4
+ # software license details.
5
+ #++
6
+
7
+ class WarbleGenerator < Rails::Generator::Base
8
+ def manifest
9
+ record do |m|
10
+ m.directory 'config'
11
+ m.template 'warble.rb', File.join('config', 'warble.rb')
12
+ end
13
+ end
14
+
15
+ protected
16
+ def banner
17
+ "Usage: #{$0} warble"
18
+ end
19
+ end
Binary file
Binary file
data/lib/warbler.rb ADDED
@@ -0,0 +1,16 @@
1
+ #--
2
+ # (c) Copyright 2007-2008 Sun Microsystems, Inc.
3
+ # See the file LICENSES.txt included with the distribution for
4
+ # software license details.
5
+ #++
6
+
7
+ # Warbler is a lightweight, flexible, Rake-based system for packaging your Rails apps
8
+ # into .war files.
9
+ module Warbler
10
+ WARBLER_HOME = File.expand_path(File.dirname(__FILE__) + '/..') unless defined?(WARBLER_HOME)
11
+ end
12
+
13
+ require 'warbler/gems'
14
+ require 'warbler/config'
15
+ require 'warbler/task'
16
+ require 'warbler/version'
@@ -0,0 +1,238 @@
1
+ #--
2
+ # (c) Copyright 2007-2008 Sun Microsystems, Inc.
3
+ # See the file LICENSES.txt included with the distribution for
4
+ # software license details.
5
+ #++
6
+
7
+ require 'ostruct'
8
+
9
+ module Warbler
10
+ # Warbler assembly configuration.
11
+ class Config
12
+ TOP_DIRS = %w(app config lib log vendor)
13
+ FILE = "config/warble.rb"
14
+ BUILD_GEMS = %w(warbler rake rcov)
15
+
16
+ # Directory where files will be staged, defaults to tmp/war
17
+ attr_accessor :staging_dir
18
+
19
+ # Directory where the war file will be written. Can be used to direct
20
+ # Warbler to place your war file directly in your application server's
21
+ # autodeploy directory. Defaults to the root of the Rails directory.
22
+ attr_accessor :autodeploy_dir
23
+
24
+ # Top-level directories to be copied into WEB-INF. Defaults to
25
+ # names in TOP_DIRS
26
+ attr_accessor :dirs
27
+
28
+ # Additional files beyond the top-level directories to include in the
29
+ # WEB-INF directory
30
+ attr_accessor :includes
31
+
32
+ # Files to exclude from the WEB-INF directory
33
+ attr_accessor :excludes
34
+
35
+ # Java classes and other files to copy to WEB-INF/classes
36
+ attr_accessor :java_classes
37
+
38
+ # Java libraries to copy to WEB-INF/lib
39
+ attr_accessor :java_libs
40
+
41
+ # Rubygems to install into the webapp at WEB-INF/gems
42
+ attr_accessor :gems
43
+
44
+ # Whether to include dependent gems (default true)
45
+ attr_accessor :gem_dependencies
46
+
47
+ # Whether to exclude **/*.log files (default is true)
48
+ attr_accessor :exclude_logs
49
+
50
+ # Public HTML directory file list, to be copied into the root of the war
51
+ attr_accessor :public_html
52
+
53
+ # Container of pathmaps used for specifying source-to-destination transformations
54
+ # under various situations (<tt>public_html</tt> and <tt>java_classes</tt> are two
55
+ # entries in this structure).
56
+ attr_accessor :pathmaps
57
+
58
+ # Name of war file (without the .war), defaults to the directory name containing
59
+ # the Rails application
60
+ attr_accessor :war_name
61
+
62
+ # Name of the MANIFEST.MF template. Defaults to the MANIFEST.MF normally generated
63
+ # by jar -cf....
64
+ attr_accessor :manifest_file
65
+
66
+ # Extra configuration for web.xml. Controls how the dynamically-generated web.xml
67
+ # file is generated.
68
+ #
69
+ # * <tt>webxml.jndi</tt> -- the name of one or more JNDI data sources name to be
70
+ # available to the application. Places appropriate &lt;resource-ref&gt; entries
71
+ # in the file.
72
+ # * <tt>webxml.ignored</tt> -- array of key names that will be not used to
73
+ # generate a context param. Defaults to ['jndi', 'booter']
74
+ #
75
+ # Any other key/value pair placed in the open structure will be dumped as a
76
+ # context parameter in the web.xml file. Some of the recognized values are:
77
+ #
78
+ # * <tt>webxml.rails.env</tt> -- the Rails environment to use for the
79
+ # running application, usually either development or production (the
80
+ # default).
81
+ # * <tt>webxml.jruby.min.runtimes</tt> -- minimum number of pooled runtimes to
82
+ # keep around during idle time
83
+ # * <tt>webxml.jruby.max.runtimes</tt> -- maximum number of pooled Rails
84
+ # application runtimes
85
+ #
86
+ # Note that if you attempt to access webxml configuration keys in a conditional,
87
+ # you might not obtain the result you want. For example:
88
+ # <%= webxml.maybe.present.key || 'default' %>
89
+ # doesn't yield the right result. Instead, you need to generate the context parameters:
90
+ # <%= webxml.context_params['maybe.present.key'] || 'default' %>
91
+ attr_accessor :webxml
92
+
93
+ def initialize(warbler_home = WARBLER_HOME)
94
+ @staging_dir = File.join("tmp", "war")
95
+ @dirs = TOP_DIRS.select {|d| File.directory?(d)}
96
+ @includes = FileList[]
97
+ @excludes = FileList[]
98
+ @java_libs = FileList["#{warbler_home}/lib/*.jar"]
99
+ @java_classes = FileList[]
100
+ @gems = Warbler::Gems.new
101
+ @gem_dependencies = true
102
+ @exclude_logs = true
103
+ @public_html = FileList["public/**/*"]
104
+ @pathmaps = default_pathmaps
105
+ @webxml = default_webxml_config
106
+ @rails_root = File.expand_path(defined?(RAILS_ROOT) ? RAILS_ROOT : Dir.getwd)
107
+ @war_name = File.basename(@rails_root)
108
+ auto_detect_frameworks
109
+ yield self if block_given?
110
+ @excludes += warbler_vendor_excludes(warbler_home)
111
+ @excludes += FileList["**/*.log"] if @exclude_logs
112
+ @excludes << @staging_dir
113
+ end
114
+
115
+ def gems=(value)
116
+ @gems = Warbler::Gems.new(value)
117
+ end
118
+
119
+ private
120
+ def warbler_vendor_excludes(warbler_home)
121
+ warbler = File.expand_path(warbler_home)
122
+ if warbler =~ %r{^#{@rails_root}/(.*)}
123
+ FileList["#{$1}"]
124
+ else
125
+ []
126
+ end
127
+ end
128
+
129
+ def default_pathmaps
130
+ p = OpenStruct.new
131
+ p.public_html = ["%{public/,}p"]
132
+ p.java_libs = ["WEB-INF/lib/%f"]
133
+ p.java_classes = ["WEB-INF/classes/%p"]
134
+ p.application = ["WEB-INF/%p"]
135
+ p.gemspecs = ["WEB-INF/gems/specifications/%f"]
136
+ p.gems = ["WEB-INF/gems/gems/%n"]
137
+ p
138
+ end
139
+
140
+ def default_webxml_config
141
+ c = WebxmlOpenStruct.new
142
+ c.rails.env = ENV['RAILS_ENV'] || 'production'
143
+ c.public.root = '/'
144
+ c.jndi = nil
145
+ c.ignored = %w(jndi booter)
146
+ c
147
+ end
148
+
149
+ def auto_detect_frameworks
150
+ !Warbler.framework_detection || auto_detect_rails || auto_detect_merb || auto_detect_rackup
151
+ end
152
+
153
+ def auto_detect_rails
154
+ return false unless task = Warbler.project_application.lookup("environment")
155
+ task.invoke rescue nil
156
+ return false unless defined?(::Rails)
157
+ @dirs << "tmp" if File.directory?("tmp")
158
+ @webxml.booter = :rails
159
+ unless (defined?(Rails.vendor_rails?) && Rails.vendor_rails?) || File.directory?("vendor/rails")
160
+ @gems["rails"] = Rails::VERSION::STRING
161
+ end
162
+ if defined?(Rails.configuration.gems)
163
+ Rails.configuration.gems.each do |g|
164
+ @gems[g.name] = g.respond_to?(:version) ? g.version : g.specification.version
165
+ end
166
+ end
167
+ @webxml.jruby.max.runtimes = 1 if defined?(Rails.configuration.threadsafe!)
168
+ true
169
+ end
170
+
171
+ def auto_detect_merb
172
+ return false unless task = Warbler.project_application.lookup("merb_env")
173
+ task.invoke rescue nil
174
+ return false unless defined?(::Merb)
175
+ @webxml.booter = :merb
176
+ @gems["merb-core"] = Merb::VERSION # TODO: what should this be?
177
+ true
178
+ end
179
+
180
+ def auto_detect_rackup
181
+ return false unless File.exist?("config.ru")
182
+ @webxml.booter = :rack
183
+ @webxml.rackup = File.read("config.ru")
184
+ end
185
+ end
186
+
187
+ class WebxmlOpenStruct < OpenStruct
188
+ %w(java com org javax).each {|name| undef_method name if Object.methods.include?(name) }
189
+
190
+ def initialize(key = 'webxml')
191
+ @key = key
192
+ @table = Hash.new {|h,k| h[k] = WebxmlOpenStruct.new(k) }
193
+ end
194
+
195
+ def servlet_context_listener
196
+ case self.booter
197
+ when :rack
198
+ "org.jruby.rack.RackServletContextListener"
199
+ when :merb
200
+ "org.jruby.rack.merb.MerbServletContextListener"
201
+ else # :rails, default
202
+ "org.jruby.rack.rails.RailsServletContextListener"
203
+ end
204
+ end
205
+
206
+ def [](key)
207
+ new_ostruct_member(key)
208
+ send(key)
209
+ end
210
+
211
+ def []=(key, value)
212
+ new_ostruct_member(key)
213
+ send("#{key}=", value)
214
+ end
215
+
216
+ def context_params
217
+ require 'cgi'
218
+ params = {}
219
+ @table.each do |k,v|
220
+ case v
221
+ when WebxmlOpenStruct
222
+ nested_params = v.context_params
223
+ nested_params.each do |nk,nv|
224
+ params["#{CGI::escapeHTML(k.to_s)}.#{nk}"] = nv
225
+ end
226
+ else
227
+ params[CGI::escapeHTML(k.to_s)] = CGI::escapeHTML(v.to_s)
228
+ end
229
+ end
230
+ params.delete_if {|k,v| ['ignored', *ignored].include?(k.to_s) }
231
+ params
232
+ end
233
+
234
+ def to_s
235
+ "No value for '#@key' found"
236
+ end
237
+ end
238
+ end
@@ -0,0 +1,36 @@
1
+ #--
2
+ # (c) Copyright 2007-2008 Sun Microsystems, Inc.
3
+ # See the file LICENSES.txt included with the distribution for
4
+ # software license details.
5
+ #++
6
+
7
+ module Warbler
8
+ # A set of gems. This only exists to allow expected operations
9
+ # to be used to add gems, and for backwards compatibility.
10
+ # It would be easier to just use a hash.
11
+ class Gems < Hash
12
+ ANY_VERSION = nil
13
+
14
+ def initialize(gems = nil)
15
+ if gems.is_a?(Hash)
16
+ self.merge!(gems)
17
+ elsif gems.is_a?(Array)
18
+ gems.each {|gem| self << gem }
19
+ end
20
+ end
21
+
22
+ def <<(gem)
23
+ self[gem] ||= ANY_VERSION
24
+ end
25
+
26
+ def +(other)
27
+ other.each {|g| self[g] ||= ANY_VERSION }
28
+ self
29
+ end
30
+
31
+ def -(other)
32
+ other.each {|g| self.delete(g)}
33
+ self
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,339 @@
1
+ #--
2
+ # (c) Copyright 2007-2008 Sun Microsystems, Inc.
3
+ # See the file LICENSES.txt included with the distribution for
4
+ # software license details.
5
+ #++
6
+
7
+ require 'rake'
8
+ require 'rake/tasklib'
9
+
10
+ module Warbler
11
+ class << self
12
+ attr_writer :project_application
13
+ def project_application
14
+ @project_application || Rake.application
15
+ end
16
+
17
+ attr_accessor :framework_detection
18
+ end
19
+ self.framework_detection = true
20
+
21
+ # Warbler Rake task. Allows defining multiple configurations inside the same
22
+ # Rakefile by using different task names.
23
+ class Task < Rake::TaskLib
24
+ COPY_PROC = proc {|t| cp t.prerequisites.last, t.name }
25
+
26
+ # Task name
27
+ attr_accessor :name
28
+
29
+ # Warbler::Config
30
+ attr_accessor :config
31
+
32
+ # Whether to print a line when a file or directory task is declared; helps
33
+ # to see what is getting included
34
+ attr_accessor :verbose
35
+
36
+ def initialize(name = :war, config = nil, tasks = :define_tasks)
37
+ @name = name
38
+ @config = config
39
+ if @config.nil? && File.exists?(Config::FILE)
40
+ @config = eval(File.open(Config::FILE) {|f| f.read})
41
+ end
42
+ @config ||= Config.new
43
+ unless @config.kind_of? Config
44
+ warn "War::Config not provided by override in initializer or #{Config::FILE}; using defaults"
45
+ @config = Config.new
46
+ end
47
+ yield self if block_given?
48
+ send tasks
49
+ end
50
+
51
+ private
52
+ def define_tasks
53
+ define_main_task
54
+ define_clean_task
55
+ define_public_task
56
+ define_gems_task
57
+ define_webxml_task
58
+ define_app_task
59
+ define_jar_task
60
+ define_exploded_task
61
+ define_debug_task
62
+ end
63
+
64
+ def define_main_task
65
+ desc "Create #{@config.war_name}.war"
66
+ task @name => ["#{@name}:app", "#{@name}:public", "#{@name}:webxml", "#{@name}:jar"]
67
+ end
68
+
69
+ def define_clean_task
70
+ with_namespace_and_config do |name, config|
71
+ desc "Clean up the .war file and the staging area"
72
+ task "clean" do
73
+ rm_rf config.staging_dir
74
+ rm_f "#{config.war_name}.war"
75
+ end
76
+ task "clear" => "#{name}:clean"
77
+ end
78
+ end
79
+
80
+ def define_public_task
81
+ public_target_files = define_public_file_tasks
82
+ with_namespace_and_config do
83
+ desc "Copy all public HTML files to the root of the .war"
84
+ task "public" => public_target_files
85
+ task "debug:public" do
86
+ puts "", "public files:"
87
+ puts *public_target_files
88
+ end
89
+ end
90
+ end
91
+
92
+ def define_gems_task
93
+ directory "#{config.staging_dir}/#{apply_pathmaps("sources-0.0.1.gem", :gems).pathmap("%d")}"
94
+ targets = define_copy_gems_tasks
95
+ with_namespace_and_config do
96
+ desc "Unpack all gems into WEB-INF/gems"
97
+ task "gems" => targets
98
+ task "debug:gems" do
99
+ puts "", "gems files:"
100
+ puts *targets
101
+ end
102
+ end
103
+ end
104
+
105
+ def define_webxml_task
106
+ with_namespace_and_config do |name, config|
107
+ desc "Generate a web.xml file for the webapp"
108
+ task "webxml" do
109
+ mkdir_p "#{config.staging_dir}/WEB-INF"
110
+ if File.exist?("config/web.xml")
111
+ cp "config/web.xml", "#{config.staging_dir}/WEB-INF"
112
+ else
113
+ erb = if File.exist?("config/web.xml.erb")
114
+ "config/web.xml.erb"
115
+ else
116
+ "#{WARBLER_HOME}/web.xml.erb"
117
+ end
118
+ require 'erb'
119
+ erb = ERB.new(File.open(erb) {|f| f.read })
120
+ File.open("#{config.staging_dir}/WEB-INF/web.xml", "w") do |f|
121
+ f << erb.result(erb_binding(config.webxml))
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+
128
+ def define_java_libs_task
129
+ target_files = @config.java_libs.map do |lib|
130
+ define_file_task(lib,
131
+ "#{@config.staging_dir}/#{apply_pathmaps(lib, :java_libs)}")
132
+ end
133
+ with_namespace_and_config do |name, config|
134
+ desc "Copy all java libraries into the .war"
135
+ task "java_libs" => target_files
136
+ task "debug:java_libs" do
137
+ puts "", "java_libs files:"
138
+ puts *target_files
139
+ end
140
+ end
141
+ target_files
142
+ end
143
+
144
+ def define_java_classes_task
145
+ target_files = @config.java_classes.map do |f|
146
+ define_file_task(f,
147
+ "#{@config.staging_dir}/#{apply_pathmaps(f, :java_classes)}")
148
+ end
149
+ with_namespace_and_config do |name, config|
150
+ desc "Copy java classes into the .war"
151
+ task "java_classes" => target_files
152
+ task "debug:java_classes" do
153
+ puts "", "java_classes files:"
154
+ puts *target_files
155
+ end
156
+ end
157
+ target_files
158
+ end
159
+
160
+ def define_app_task
161
+ webinf_target_files = define_webinf_file_tasks
162
+ with_namespace_and_config do |name, config|
163
+ desc "Copy all application files into the .war"
164
+ task "app" => ["#{name}:gems", *webinf_target_files]
165
+ task "debug:app" do
166
+ puts "", "app files:"
167
+ puts *webinf_target_files
168
+ end
169
+ end
170
+ end
171
+
172
+ def define_jar_task
173
+ with_namespace_and_config do |name, config|
174
+ desc "Run the jar command to create the .war"
175
+ task "jar" do
176
+ war_path = "#{config.war_name}.war"
177
+ war_path = File.join(config.autodeploy_dir, war_path) if config.autodeploy_dir
178
+ flags, manifest = config.manifest_file ? ["cfm", config.manifest_file] : ["cf", ""]
179
+ sh "jar #{flags} #{war_path} #{manifest} -C #{config.staging_dir} ."
180
+ end
181
+ end
182
+ end
183
+
184
+ def define_exploded_task
185
+ with_namespace_and_config do |name,config|
186
+ libs = define_java_libs_task
187
+ desc "Create an exploded war in the app's public directory"
188
+ task "exploded" => ["webxml", "java_classes", "gems", *libs] do
189
+ cp "#{@config.staging_dir}/WEB-INF/web.xml", "."
190
+ cp File.join(WARBLER_HOME, "sun-web.xml"), "." unless File.exists?("sun-web.xml")
191
+ ln_sf "#{@config.staging_dir}/WEB-INF/gems", "."
192
+ if File.directory?("#{@config.staging_dir}/WEB-INF/classes")
193
+ ln_sf "#{@config.staging_dir}/WEB-INF/classes", "."
194
+ end
195
+ mkdir_p "lib"
196
+ libs.each {|l| ln_sf l, "lib/#{File.basename(l)}"}
197
+ ln_sf "..", "public/WEB-INF"
198
+ end
199
+
200
+ task "clean:exploded" do
201
+ (libs.map {|l| "lib/#{File.basename(l)}" } +
202
+ ["gems", "public/WEB-INF", "classes"]).each do |l|
203
+ rm_f l if File.exist?(l) && File.symlink?(l)
204
+ end
205
+ rm_f "*web.xml"
206
+ end
207
+ end
208
+ end
209
+
210
+ def define_debug_task
211
+ with_namespace_and_config do |name, config|
212
+ task "debug" do
213
+ require 'yaml'
214
+ puts YAML::dump(config)
215
+ end
216
+ all_debug_tasks = %w(: app java_libs java_classes gems public includes excludes).map do |n|
217
+ n.sub(/^:?/, "#{name}:debug:").sub(/:$/, '')
218
+ end
219
+ task "debug:all" => all_debug_tasks
220
+ end
221
+ end
222
+
223
+ def define_public_file_tasks
224
+ @config.public_html.map do |f|
225
+ define_file_task(f, "#{@config.staging_dir}/#{apply_pathmaps(f, :public_html)}")
226
+ end
227
+ end
228
+
229
+ def define_webinf_file_tasks
230
+ target_files = @config.dirs.map do |d|
231
+ define_file_task(d, "#{@config.staging_dir}/#{apply_pathmaps(d, :application)}")
232
+ end
233
+ files = FileList[*(@config.dirs.map{|d| "#{d}/**/*"})]
234
+ files.include *(@config.includes.to_a)
235
+ files.exclude *(@config.excludes.to_a)
236
+ target_files += files.map do |f|
237
+ define_file_task(f,
238
+ "#{@config.staging_dir}/#{apply_pathmaps(f, :application)}")
239
+ end
240
+ target_files += define_java_libs_task
241
+ target_files += define_java_classes_task
242
+ task "#@name:debug:includes" do
243
+ puts "", "included files:"
244
+ puts *files.include
245
+ end
246
+ task "#@name:debug:excludes" do
247
+ puts "", "excluded files:"
248
+ puts *files.exclude
249
+ end
250
+ target_files
251
+ end
252
+
253
+ def define_file_task(source, target)
254
+ if File.directory?(source)
255
+ directory target
256
+ puts %{directory "#{target}"} if verbose
257
+ else
258
+ directory File.dirname(target)
259
+ file(target => [File.dirname(target), source], &COPY_PROC)
260
+ puts %{file "#{target}" => "#{source}"} if verbose
261
+ end
262
+ target
263
+ end
264
+
265
+ def with_namespace_and_config
266
+ name, config = @name, @config
267
+ namespace name do
268
+ yield name, config
269
+ end
270
+ end
271
+
272
+ def define_copy_gems_tasks
273
+ targets = []
274
+ @config.gems.each do |gem, version|
275
+ define_single_gem_tasks(gem, targets, version)
276
+ end
277
+ targets
278
+ end
279
+
280
+ def define_single_gem_tasks(gem_pattern, targets, version = nil)
281
+ gem = case gem_pattern
282
+ when Gem::Dependency
283
+ gem_pattern
284
+ else
285
+ Gem::Dependency.new(gem_pattern, version)
286
+ end
287
+ matched = Gem.source_index.search(gem)
288
+ fail "gem '#{gem}' not installed" if matched.empty?
289
+ spec = matched.last
290
+
291
+ gem_name = "#{spec.name}-#{spec.version}"
292
+ unless spec.platform.nil? || spec.platform == Gem::Platform::RUBY
293
+ [spec.platform, spec.original_platform].each do |p|
294
+ name = "#{gem_name}-#{p}"
295
+ if File.exist?(File.join(Gem.dir, 'cache', "#{name}.gem"))
296
+ gem_name = name
297
+ break
298
+ end
299
+ end
300
+ end
301
+
302
+ gem_unpack_task_name = "gem:#{gem_name}"
303
+ return if Rake::Task.task_defined?(gem_unpack_task_name)
304
+
305
+ targets << define_file_task(spec.loaded_from,
306
+ "#{@config.staging_dir}/#{apply_pathmaps(spec.loaded_from, :gemspecs)}")
307
+
308
+ task targets.last do
309
+ Rake::Task[gem_unpack_task_name].invoke
310
+ end
311
+
312
+ src = File.join(Gem.dir, 'cache', "#{gem_name}.gem")
313
+ dest = "#{config.staging_dir}/#{apply_pathmaps(src, :gems)}"
314
+
315
+ task gem_unpack_task_name => [dest.pathmap("%d")] do |t|
316
+ require 'rubygems/installer'
317
+ Gem::Installer.new(src).unpack(dest)
318
+ end
319
+
320
+ if @config.gem_dependencies
321
+ spec.dependencies.each do |dep|
322
+ define_single_gem_tasks(dep.name, targets, dep.version_requirements)
323
+ end
324
+ end
325
+ end
326
+
327
+ def erb_binding(webxml)
328
+ binding
329
+ end
330
+
331
+ def apply_pathmaps(file, pathmaps)
332
+ pathmaps = @config.pathmaps.send(pathmaps)
333
+ pathmaps.each do |p|
334
+ file = file.pathmap(p)
335
+ end if pathmaps
336
+ file
337
+ end
338
+ end
339
+ end