Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
- #583: fix: Create config dir if it's missing for simpler usage
- #588: fix: NullPointerException during shutdown with executable war files
- #589: fix: Jetty wars don't have console logging enabled by default
- #617: fix: correct ability to configure/override/force specific traits via Config.new(forced_traits: [...])
- #591: chore: clean up obsolete & deprecated code from 2.0.x and old Bundler versions
- #592: chore: relax rubyzip requirement to allow rubyzip 2.x
- #593: chore: relax jruby-rack requirement to allow compatibility with upcoming 1.3.x
Expand Down
5 changes: 2 additions & 3 deletions README.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -185,12 +185,11 @@ of how to configure Warbler to package Camping and Sinatra apps.

If the default settings are not appropriate for your application, you can
customize Warbler's behavior. To customize files, libraries, and gems included
in the .war file, you'll need a config/warble.rb file. There a two ways of
doing this. With the gem, simply run
in the .war file, you'll need a +config/warble.rb+ file. To generate one:

warble config

Finally, edit the +config/warble.rb+ to your taste. The generated file is
Edit the +config/warble.rb+ to your taste. The generated file is
fully-documented with the available options and default values.

=== Archive Layout
Expand Down
9 changes: 5 additions & 4 deletions lib/warbler/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ class Config

# Traits: an array of trait classes corresponding to
# characteristics of the project that are either auto-detected or
# configured.
attr_accessor :traits
# forced enabled during `Config.new(forced_traits: [...]) do |config|`
attr_reader :traits

# Directory where the war file will be written. Can be used to direct
# Warbler to place your war file directly in your application server's
Expand Down Expand Up @@ -182,8 +182,9 @@ class Config
attr_reader :warbler_templates
attr_reader :warbler_scripts

def initialize(warbler_home = WARBLER_HOME)
super()
# @param forced_traits [Array<Class>, nil] optional array of Warbler::Trait types to force rather than auto-detecting them
def initialize(warbler_home = WARBLER_HOME, forced_traits: nil)
super(forced_traits)

@warbler_home = warbler_home
@warbler_templates = "#{WARBLER_HOME}/lib/warbler/templates"
Expand Down
1 change: 1 addition & 0 deletions lib/warbler/jar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ def create(config_or_path)

# Invoke a hook to allow the project traits to add or modify the archive contents.
def apply_traits(config)
puts "Applying traits #{config.traits}" unless silent?
Comment thread
chadlwilson marked this conversation as resolved.
config.update_archive(self)
end

Comment thread
chadlwilson marked this conversation as resolved.
Expand Down
34 changes: 29 additions & 5 deletions lib/warbler/traits.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
# See the file LICENSE.txt for details.
#++

require 'set'
require 'stringio'
require 'tsort'

Expand All @@ -15,10 +16,13 @@ module Warbler
# the kind of project and how it should be packed into the jar or
# war file.
module Traits
attr_accessor :traits

def initialize
@traits = auto_detect_traits
# @param forced_traits [Array<Class>, nil] array of Warbler::Trait types to force rather than auto-detecting them
def initialize(forced_traits)
@traits = if forced_traits.nil? || forced_traits.empty?
auto_detect_traits
else
validate_traits(forced_traits)
end
Comment thread
chadlwilson marked this conversation as resolved.
end

def auto_detect_traits
Expand All @@ -45,6 +49,18 @@ def dump_traits
@trait_objects = nil
@traits.collect! {|t| t.name }
end

private
def validate_traits(requested_traits)
conflicts = Set.new
requested_traits.each do |trait|
Comment thread
chadlwilson marked this conversation as resolved.
trait.conflicts.each do |conflict|
conflicts += [trait, conflict] if requested_traits.include?(conflict)
end
end
raise "Some forced traits declare conflicts with each other: #{conflicts.to_a}" unless conflicts.empty?
TraitsDependencyArray.new(requested_traits).tsort
end
Comment thread
chadlwilson marked this conversation as resolved.
end

# Each trait class includes this module to receive shared functionality.
Expand All @@ -53,6 +69,14 @@ module ClassMethods
def requirements
[]
end

def conflicts
[]
end

def detect_any_conflicts?
conflicts.any? { |c| c.detect? }
end
end

def self.included(base)
Expand Down Expand Up @@ -108,7 +132,7 @@ class TraitsDependencyArray < Array

alias tsort_each_node each
def tsort_each_child(node, &block)
node.requirements.each(&block)
node.requirements.select { |r| include?(r) }.each(&block)
end
end

Expand Down
4 changes: 4 additions & 0 deletions lib/warbler/traits/gemspec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ def self.detect?
!Dir['*.gemspec'].empty?
end

def self.conflicts
[ Traits::NoGemspec ]
end

def before_configure; require 'yaml'
@spec_file = Dir['*.gemspec'].first
@spec = File.open(@spec_file) { |f| Gem::Specification.from_yaml(f) } rescue Gem::Specification.load(@spec_file)
Expand Down
6 changes: 5 additions & 1 deletion lib/warbler/traits/jar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ class Jar
include Trait

def self.detect?
!War.detect?
!detect_any_conflicts?
end

def self.conflicts
[ Traits::War ]
end

def before_configure
Expand Down
6 changes: 5 additions & 1 deletion lib/warbler/traits/nogemspec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ class NoGemspec
include ExecutableHelper

def self.detect?
Jar.detect? && !Gemspec.detect?
Jar.detect? && !detect_any_conflicts?
end

def self.conflicts
[ Traits::Gemspec ]
end

def before_configure
Expand Down
6 changes: 5 additions & 1 deletion lib/warbler/traits/rack.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ class Rack
include Trait

def self.detect?
!Rails.detect? && (File.exist?("config.ru") || !Dir['*/config.ru'].empty?)
(File.exist?("config.ru") || !Dir['*/config.ru'].empty?) && !detect_any_conflicts?
end

def self.conflicts
[ Traits::Rails ]
end

def self.requirements
Expand Down
4 changes: 4 additions & 0 deletions lib/warbler/traits/rails.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ def self.detect?
File.exist?('config/environment.rb')
end

def self.conflicts
[ Traits::Rack ]
end

def self.requirements
[ Traits::War ]
end
Expand Down
4 changes: 4 additions & 0 deletions lib/warbler/traits/war.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ def self.detect?
Traits::Rails.detect? || Traits::Rack.detect?
end

def self.conflicts
[ Traits::Jar ]
end

def before_configure
config.gem_path = DEFAULT_GEM_PATH
config.pathmaps = default_pathmaps
Expand Down
32 changes: 18 additions & 14 deletions spec/warbler/bundler_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ def bundle_install(*args)
let(:config) { drbclient.config(@extra_config) }
let(:jar) { drbclient.jar }

def apply_silently
silence { jar.apply(config) }
end

context "in a war project" do
run_in_directory "spec/sample_war"
cleanup_temp_files
Expand All @@ -49,15 +53,15 @@ def bundle_install(*args)
use_config do |config|
config.gems << "rake"
end
jar.apply(config)
apply_silently
expect(file_list(%r{WEB-INF/Gemfile})).to_not be_empty
expect(file_list(%r{WEB-INF/gems/specifications/rspec})).to_not be_empty
expect(file_list(%r{WEB-INF/gems/specifications/rake})).to be_empty
end

it "copies Gemfiles into the war" do
File.open("Gemfile.lock", "w") {|f| f << "GEM"}
jar.apply(config)
apply_silently
expect(file_list(%r{WEB-INF/Gemfile})).to_not be_empty
expect(file_list(%r{WEB-INF/Gemfile.lock})).to_not be_empty
end
Expand All @@ -66,7 +70,7 @@ def bundle_install(*args)
use_config do |config|
config.gem_path = '/WEB-INF/jewels'
end
jar.apply(config)
apply_silently
expect(file_list(%r{WEB-INF/jewels/specifications/rspec})).to_not be_empty
end

Expand All @@ -76,15 +80,15 @@ def bundle_install(*args)
it "works with :git entries in Gemfiles" do
File.open("Gemfile", "w") {|f| f << "source 'file://#{@gem_dir}'\ngem 'tester', :git => '#{@gem_dir}'\n"}
bundle_install '--local'
jar.apply(config)
apply_silently
expect(file_list(%r{WEB-INF/gems/bundler/gems/tester[^/]*/lib/tester/version\.rb})).to_not be_empty
expect(file_list(%r{WEB-INF/gems/bundler/gems/tester[^/]*/tester.gemspec})).to_not be_empty
end

it "bundles only the gemspec for :git entries that are excluded" do
File.open("Gemfile", "w") {|f| f << "source 'https://rubygems.org'\ngem 'rake'\ngroup :test do\ngem 'tester', :git => '#{@gem_dir}'\nend\n"}
bundle_install '--local'
jar.apply(config)
apply_silently
expect(file_list(%r{WEB-INF/gems/bundler/gems/tester[^/]*/lib/tester/version\.rb})).to be_empty
expect(file_list(%r{WEB-INF/gems/bundler/gems/tester[^/]*/tester.gemspec})).to_not be_empty
end
Expand All @@ -99,7 +103,7 @@ def bundle_install(*args)
@gem_dir = generate_gem('tester', Dir.mktmpdir("gems-#{Time.now.to_i}"))
File.open("Gemfile", "w") {|f| f << "source 'file://#{@gem_dir}'\ngem 'tester', :path => '#{@gem_dir}'\n"}
bundle_install '--local'
silence { jar.apply(config) }
apply_silently
expect(file_list(%r{tester})).to be_empty
end

Expand All @@ -110,7 +114,7 @@ def bundle_install(*args)
@gem_dir = generate_gem('tester', 'gems/tester') # spec/sample_war/gems
File.open("Gemfile", "w") {|f| f << "source 'https://rubygems.org'\ngem 'rake'\ngem 'tester', :path => 'gems/tester'\n"}
bundle_install '--local'
jar.apply(config)
apply_silently
expect(file_list(%r{tester})).to_not be_empty # included from :path as is
expect(file_list(%r{WEB-INF/gems/bundler/gems/tester[^/]*/lib/tester/version\.rb})).to be_empty
expect(file_list(%r{WEB-INF/gems/bundler/gems/tester[^/]*/tester.gemspec})).to be_empty
Expand All @@ -123,7 +127,7 @@ def bundle_install(*args)

it "does not bundle dependencies in the test group by default" do
File.open("Gemfile", "w") {|f| f << "source 'https://rubygems.org'\ngem 'rake'\ngroup :test do\ngem 'rspec'\nend\n"}
jar.apply(config)
apply_silently
expect(file_list(%r{WEB-INF/gems/gems/rake[^/]*/})).to_not be_empty
expect(file_list(%r{WEB-INF/gems/gems/rspec[^/]*/})).to be_empty
expect(file_list(%r{WEB-INF/gems/specifications/rake})).to_not be_empty
Expand Down Expand Up @@ -160,7 +164,7 @@ def bundle_install(*args)
it "works with :git entries in Gemfiles" do
File.open("Gemfile", "w") {|f| f << "source 'file://#{@gem_dir}'\ngem 'tester', :git => '#{@gem_dir}'\n"}
bundle_install '--local'
jar.apply(config)
apply_silently
expect(file_list(%r{^bundler/gems/tester[^/]*/lib/tester/version\.rb})).to_not be_empty
expect(file_list(%r{^bundler/gems/tester[^/]*/tester.gemspec})).to_not be_empty
jar.add_init_file(config)
Expand All @@ -182,18 +186,18 @@ def bundle_install(*args)

it "includes the bundler gem" do
bundle_install
jar.apply(config)
apply_silently
expect(config.gems.detect{|k,v| k.name == 'bundler'}).to_not be nil
expect(file_list(/bundler-/)).to_not be_empty
end

it "does not include the bundler cache directory" do
jar.apply(config)
apply_silently
expect(file_list(%r{vendor/bundle})).to be_empty
end

it "includes ENV['BUNDLE_FROZEN'] in init.rb" do
jar.apply(config)
apply_silently
contents = jar.contents('META-INF/init.rb')
expect(contents.split("\n").grep(/ENV\['BUNDLE_FROZEN'\] = '1'/)).to_not be_empty
end
Expand All @@ -211,7 +215,7 @@ def bundle_install(*args)
use_config do |config|
config.features = %w{runnable}
end
jar.apply(config)
apply_silently
end

after do
Expand Down Expand Up @@ -247,7 +251,7 @@ def bundle_install(*args)

it "includes the bundler gem" do
bundle_install
jar.apply(config)
apply_silently
expect(file_list(%r{gems/rake-13.3.0/lib})).to_not be_empty
expect(file_list(%r{gems/bundler-})).to_not be_empty
expect(file_list(%r{gems/bundler-.*/exe})).to_not be_empty
Expand Down
Loading