fjc-warbler 0.9.12

Sign up to get free protection for your applications and to get access to all the features.
@@ -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