You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@buildr.apache.org by as...@apache.org on 2008/02/25 23:47:22 UTC
svn commit: r631024 - in /incubator/buildr/trunk: DISCLAIMER Rakefile
doc/pages/download.textile doc/web.toc.yaml lib/core/application.rb
Author: assaf
Date: Mon Feb 25 14:47:20 2008
New Revision: 631024
URL: http://svn.apache.org/viewvc?rev=631024&view=rev
Log:
Now with new and improved release task
Modified:
incubator/buildr/trunk/DISCLAIMER
incubator/buildr/trunk/Rakefile
incubator/buildr/trunk/doc/pages/download.textile
incubator/buildr/trunk/doc/web.toc.yaml
incubator/buildr/trunk/lib/core/application.rb
Modified: incubator/buildr/trunk/DISCLAIMER
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/DISCLAIMER?rev=631024&r1=631023&r2=631024&view=diff
==============================================================================
--- incubator/buildr/trunk/DISCLAIMER (original)
+++ incubator/buildr/trunk/DISCLAIMER Mon Feb 25 14:47:20 2008
@@ -1 +1,7 @@
-Apache Buildr is an effort undergoing incubation at The Apache Software Foundation (ASF), sponsored by the Apache Incubator. Incubation is required of all newly accepted projects until a further review indicates that the infrastructure, communications, and decision making process have stabilized in a manner consistent with other successful ASF projects. While incubation status is not necessarily a reflection of the completeness or stability of the code, it does indicate that the project has yet to be fully endorsed by the ASF.
+Apache Buildr is an effort undergoing incubation at The Apache Software
+Foundation (ASF), sponsored by the Apache Incubator. Incubation is required of
+all newly accepted projects until a further review indicates that the
+infrastructure, communications, and decision making process have stabilized in
+a manner consistent with other successful ASF projects. While incubation status
+is not necessarily a reflection of the completeness or stability of the code,
+it does indicate that the project has yet to be fully endorsed by the ASF.
Modified: incubator/buildr/trunk/Rakefile
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/Rakefile?rev=631024&r1=631023&r2=631024&view=diff
==============================================================================
--- incubator/buildr/trunk/Rakefile (original)
+++ incubator/buildr/trunk/Rakefile Mon Feb 25 14:47:20 2008
@@ -82,6 +82,8 @@
# Testing is everything.
#
+task('clobber') { rm 'failing' rescue nil }
+
desc 'Run all specs'
Spec::Rake::SpecTask.new('spec') do |task|
task.spec_files = FileList['spec/**/*_spec.rb']
@@ -94,15 +96,18 @@
task.spec_opts << '--options' << 'spec/spec.opts' << '--format' << 'failing_examples:failing' << '--example' << 'failing'
end
+
namespace 'spec' do
- desc 'Run all specs and generate test/coverage reports in html directory'
- Spec::Rake::SpecTask.new('report') do |task|
- mkpath 'html'
+ directory('reports')
+ Rake::Task['rake:clobber'].enhance { rm_rf 'reports' }
+
+ desc 'Run all specs and generate specification and test coverage reports in html directory'
+ Spec::Rake::SpecTask.new('full'=>'reports') do |task|
task.spec_files = FileList['spec/**/*_spec.rb']
- task.spec_opts << '--format' << 'html:html/report.html' << '--backtrace'
+ task.spec_opts << '--format' << 'html:reports/specs.html' << '--backtrace'
task.rcov = true
- task.rcov_dir = 'html/coverage'
+ task.rcov_dir = 'reports/coverage'
task.rcov_opts = ['--exclude', 'spec,bin']
end
@@ -119,7 +124,7 @@
#
desc 'Generate RDoc documentation'
rdoc = Rake::RDocTask.new(:rdoc) do |rdoc|
- rdoc.rdoc_dir = 'html/rdoc'
+ rdoc.rdoc_dir = 'rdoc'
rdoc.title = ruby_spec.name
rdoc.options = ruby_spec.rdoc_options + ['--promiscuous']
rdoc.rdoc_files.include('lib/**/*.rb')
@@ -143,7 +148,7 @@
:collection => Docter.collection('Buildr').using('doc/web.toc.yaml').
include('doc/pages', 'LICENSE', 'CHANGELOG'),
:template => Docter.template('doc/web.haml').
- include('doc/css', 'doc/images', 'doc/scripts', 'html/report.html', 'html/coverage', 'html/rdoc')
+ include('doc/css', 'doc/images', 'doc/scripts', 'reports/specs.html', 'reports/coverage', 'rdoc')
}
print_docs = {
:collection => Docter.collection('Buildr').using('doc/print.toc.yaml').
@@ -157,6 +162,8 @@
desc 'Generate HTML documentation'
html = Docter::Rake.generate('html', web_docs[:collection], web_docs[:template])
+ html.enhance ['spec:full']
+
desc 'Run Docter server'
Docter::Rake.serve 'docter', web_docs[:collection], web_docs[:template], :port=>3000
task('docs').enhance [html]
@@ -181,143 +188,202 @@
end
-# Commit to SVN, upload and do the release cycle.
-#
-namespace :svn do
- task :clean? do |task|
- status = `svn status`.reject { |line| line =~ /\s(pkg|html)$/ }
+namespace 'release' do
+ require 'highline'
+ require 'highline/import'
+ Kernel.def_delegators :$terminal, :color
+
+ # This task does all prerequisites checks before starting the release, for example,
+ # that we have Groovy and Scala to run all the test cases, or that we have Allison
+ # and PrinceXML to generate the full documentation.
+ task 'check'
+ # This task does all the preparation work before making a release and also checks
+ # that we generate all the right material, for example, that we compiled Java sources,
+ # created the PDF, have coverage report.
+ task 'prepare'=>['clobber', 'check']
+
+ # Does CHANGELOG reflects current release?
+ task 'check' do
+ say 'Checking that CHANGELOG indicates most recent version and today\'s date ... '
+ expecting = "#{ruby_spec.version} (#{Time.now.strftime('%Y-%m-%d')})"
+ header = File.readlines('CHANGELOG').first
+ fail "Expecting CHANGELOG to start with #{expecting}, but found #{header} instead" unless expecting == header
+ say 'OK'
+ end
+
+ # License requirement.
+ task 'check' do
+ say 'Checking that files contain the Apache license ... '
+ directories = 'lib', 'spec', 'docs', 'bin'
+ ignore = 'class', 'opts'
+ FileList['lib/**/*', 'spec/**/*', 'bin/**', 'doc/css/*', 'doc/scripts/*'].
+ exclude('doc/css/eiffel.css').reject { |file| File.directory?(file) || ignore.include?(file[/[^.]*$/]) }.each do |file|
+ comments = File.read(file).scan(/(\/\*(.*?)\*\/)|^#\s+(.*?)$|<!--(.*?)-->/m).
+ map { |match| match.reject(&:nil?) }.flatten.join("\n")
+ fail "File #{file} missing Apache License, please add it before making a release!" unless
+ comments =~ /Licensed to the Apache Software Foundation/ && comments =~ /http:\/\/www.apache.org\/licenses\/LICENSE-2.0/
+ end
+ say 'OK'
+ end
+
+ # No local changes.
+ task 'check' do
+ status = `svn status`
fail "Cannot release unless all local changes are in SVN:\n#{status}" unless status.empty?
end
-
- task :tag do |task|
- cur_url = `svn info`.scan(/URL: (.*)/)[0][0]
- new_url = cur_url.sub(/(trunk$)|(branches\/\w*)$/, "tags/#{ruby_spec.version.to_s}")
- system 'svn', 'copy', cur_url, new_url, '-m', "Release #{ruby_spec.version.to_s}"
+
+ # Compile Java libraries.
+ task 'prepare' do
+ say 'Compiling Java libraries ... '
+ FileList['lib/**/*.class'].each { |file| rm file }
+ `buildr compile`
+ FileList['lib/**/*.java'].each { |src| fail "Can't find .class file for #{src}!" unless File.exist?(src.ext('class')) }
+ say 'OK'
end
-end
-namespace :upload do
- task :docs=>'rake:docs' do |task|
- sh %{rsync -r --del --progress html/* people.apache.org:/www/incubator.apache.org/#{ruby_spec.rubyforge_project.downcase}/}
+ # Tests, specs and coverage reports.
+ task 'check' do
+ say 'Checking that we have JRuby, Scala and Groovy available ... '
+ fail 'Full testing requires JRuby!' if `which jruby`.empty?
+ fail 'Full testing requires Scala!' if `which scalac`.empty? || ENV['SCALA_HOME'].to_s.empty?
+ fail 'Full testing requires Groovy!' if `which groovyc`.empty?
+ say 'OK'
+ end
+ task 'prepare' do
+ say 'Running test suite using JRuby ...'
+ task('spec:jruby').invoke
+ say 'Running test suite using Ruby ...'
+ task('spec:ruby').invoke
+ say 'Done'
end
- task :packages=>['rake:docs', 'rake:package'] do |task|
- require 'rubyforge'
+ # Documentation (derived from above).
+ task 'check' do
+ say 'Checking that we can use Allison and PrinceXML ... '
+ fail 'Release requires the Allison RDoc template, please gem install allison!' unless rdoc.template =~ /allison.rb/
+ fail 'Release requires PrinceXML to generate PDF documentation!' if `which prince`.empty?
+ say 'OK'
+ end
+ task 'prepare'=>'spec:full' do
+ say 'Generating RDocs and PDF ...'
+ task('docs').invoke
+ say 'Done'
- # Read the changes for this release.
- pattern = /(^(\d+\.\d+(?:\.\d+)?)\s+\(\d{4}-\d{2}-\d{2}\)\s*((:?^[^\n]+\n)*))/
- changelog = File.read(__FILE__.pathmap('%d/CHANGELOG'))
- changes = changelog.scan(pattern).inject({}) { |hash, set| hash[set[1]] = set[2] ; hash }
- current = changes[ruby_spec.version.to_s]
- if !current && ruby_spec.version.to_s =~ /\.0$/
- current = changes[ruby_spec.version.to_s.split('.')[0..-2].join('.')]
+ say 'Checking that we have PDF, RDoc, specs and coverage report ... '
+ fail 'No RDocs if html/rdoc!' unless File.exist?('html/rdoc/files/lib/buildr_rb.html')
+ fail 'No PDF generated, you need to install PrinceXML!' unless File.exist?('html/buildr.pdf')
+ fail 'No specifications in html directory!' unless File.exist?('html/specs.html')
+ fail 'No coverage reports in html/coverage directory!' unless File.exist?('html/coverage/index.html')
+ say 'OK'
+ end
+
+ task 'check' do
+ require 'rubyforge' rescue fail 'RubyForge required, please gem install rubyforge!'
+ fail 'GnuPG required to create signatures!' if `which gpg`.empty?
+ gpg_user = ENV['GPG_USER'] or fail 'Please set GPG_USER (--local-user) environment variable so we know which key to use.'
+ sh('gpg', '--list-key', gpg_user) { |ok, res| ok or fail "No key matches for GPG_USER=#{gpg_user}" }
+ end
+
+
+ # Cut the release: upload Gem to RubyForge before updating site (fail safe).
+ task 'cut'=>['upload:rubyforge', 'upload:site']
+
+
+ namespace 'upload' do
+ # Upload site (html directory) to Apache.
+ task 'site'=>'rake:docs' do
+ say 'Uploading Web site to people.apache.org ... '
+ args = Dir.glob('html/*') + ['people.apache.org:/www/incubator.apache.org/' + ruby_spec.rubyforge_project.downcase]
+ verbose(false) { sh 'rsync ', '-r', '--del', '--progress', *files }
+ say 'Done'
end
- fail "No changeset found for version #{ruby_spec.version}" unless current
- puts "Uploading #{ruby_spec.name} #{ruby_spec.version}"
- files = Dir.glob('pkg/*.{gem,tgz,zip}')
- rubyforge = RubyForge.new
- rubyforge.login
- File.open('.changes', 'w'){|f| f.write(current)}
- rubyforge.userconfig.merge!('release_changes' => '.changes', 'preformatted' => true)
- rubyforge.add_release ruby_spec.rubyforge_project.downcase, ruby_spec.name.downcase, ruby_spec.version, *files
- rm '.changes'
- puts "Release #{ruby_spec.version} uploaded"
- end
-end
+ # Upload Gems to RubyForge.
+ task 'rubyforge'=>['rake:docs', 'rake:package'] do
+ require 'rubyforge'
+
+ # Read the changes for this release.
+ say 'Looking for changes between this release and previous one ... '
+ pattern = /(^(\d+\.\d+(?:\.\d+)?)\s+\(\d{4}-\d{2}-\d{2}\)\s*((:?^[^\n]+\n)*))/
+ changelog = File.read(__FILE__.pathmap('%d/CHANGELOG'))
+ changes = changelog.scan(pattern).inject({}) { |hash, set| hash[set[1]] = set[2] ; hash }
+ current = changes[ruby_spec.version.to_s]
+ current = changes[ruby_spec.version.to_s.split('.')[0..-2].join('.')] if !current && ruby_spec.version.to_s =~ /\.0$/
+ fail "No changeset found for version #{ruby_spec.version}" unless current
+ say 'OK'
+
+ say "Uploading #{ruby_spec.version} to RubyForge ... "
+ files = Dir.glob('pkg/*.{gem,tgz,zip}')
+ rubyforge = RubyForge.new
+ rubyforge.login
+ File.open('.changes', 'w'){|f| f.write(current)}
+ rubyforge.userconfig.merge!('release_changes' => '.changes', 'preformatted' => true)
+ rubyforge.add_release ruby_spec.rubyforge_project.downcase, ruby_spec.name.downcase, ruby_spec.version, *files
+ rm '.changes'
+ say 'Done'
+ end
-namespace :release do
+ task 'apache'=>['rake:package'] do
+ require 'md5'
+ require 'sha1'
+
+ gpg_user = ENV['GPG_USER'] or fail 'Please set GPG_USER (--local-user) environment variable so we know which key to use.'
+ say 'Creating -incubating packages ... '
+ rm_rf 'incubating'
+ mkpath 'incubating'
+ packages = FileList['pkg/*.{gem,zip,tgz}'].map do |package|
+ package.pathmap('incubating/%n-incubating%x').tap do |incubating|
+ cp package, incubating
+ end
+ end
+ say 'Done'
- # TODO: Check that we're using allison.
- # TODO: Check that we can generate PDFs.
+ say 'Signing -incubating packages ... '
+ files = packages.each do |package|
+ binary = File.read(package)
+ File.open(package + '.md5', 'w') { |file| file.write MD5.hexdigest(binary) << ' ' << package }
+ File.open(package + '.sha1', 'w') { |file| file.write SHA1.hexdigest(binary) << ' ' << package }
+ sh 'gpg', '--local-user', gpg_user, '--armor', '--output', package + '.asc', '--detach-sig', package, :verbose=>true
+ [package, package + '.md5', package + '.sha1', package + '.asc']
+ end
+ say 'Done'
+
+ say 'Uploading packages to Apache dist ... '
+ args = files.flatten << 'KEYS' << 'people.apache.org:/www.apache.org/dist/incubator/buildr/'
+ verbose(false) { sh 'rsync', '-progress', *args }
+ say 'Done'
+ end
+ Rake::Task['rake:clobber'].enhance { rm_rf 'incubating' }
+
+ end
- task :ready? do
- require 'highline'
- require 'highline/import'
- puts "This version: #{ruby_spec.version}"
- puts
- puts "Top 4 lines form CHANGELOG:'
- puts File.readlines('CHANGELOG')[0..3].map { |l| " #{l}" }
- puts
- ask('Top-entry in CHANGELOG file includes today\'s date?') =~ /yes/i or
- fail 'Please update CHANGELOG to include the right date'
+ # Tag this release in SVN.
+ task 'tag' do
+ say "Tagging release as tags/#{ruby_spec.version} ... "
+ cur_url = `svn info`.scan(/URL: (.*)/)[0][0]
+ new_url = cur_url.sub(/(trunk$)|(branches\/\w*)$/, "tags/#{ruby_spec.version.to_s}")
+ sh 'svn', 'copy', cur_url, new_url, '-m', "Release #{ruby_spec.version.to_s}", :verbose=>false
+ say "OK"
end
- task :post do
+ # Update lib/buildr.rb to next vesion number, add new entry in CHANGELOG.
+ task 'next_version'=>'tag' do
next_version = ruby_spec.version.to_ints.zip([0, 0, 1]).map { |a| a.inject(0) { |t,i| t + i } }.join('.')
- puts "Updating lib/buildr.rb to next version number: #{next_version}"
+ say "Updating lib/buildr.rb to next version number (#{next_version}) ... "
buildr_rb = File.read(__FILE__.pathmap('%d/lib/buildr.rb')).
sub(/(VERSION\s*=\s*)(['"])(.*)\2/) { |line| "#{$1}#{$2}#{next_version}#{$2}" }
File.open(__FILE__.pathmap('%d/lib/buildr.rb'), 'w') { |file| file.write buildr_rb }
- puts 'Adding entry to CHANGELOG'
+ say "OK"
+
+ say 'Adding new entry to CHANGELOG ... '
changelog = File.read(__FILE__.pathmap('%d/CHANGELOG'))
File.open(__FILE__.pathmap('%d/CHANGELOG'), 'w') { |file| file.write "#{next_version} (Pending)\n\n#{changelog}" }
+ say "OK"
end
- task :meat=>['clobber', 'svn:clean?', 'spec:jruby', 'spec:report', 'upload:packages', 'upload:docs', 'svn:tag']
-end
-
-desc 'Upload release to RubyForge including docs, tag SVN'
-task :release=>[ 'release:ready?', 'release:meat', 'release:post' ]
-
-
-# Handles Java libraries that are part of Buildr.
-#
-task 'compile' do
- $LOAD_PATH.unshift File.expand_path('lib')
- require 'buildr'
- require 'buildr/jetty'
-
- # RJB, JUnit and friends.
- Dir.chdir 'lib/java' do
- `javac -source 1.4 -target 1.4 -Xlint:all org/apache/buildr/*.java`
- end
-
- # Jetty server.
- cp = artifacts(Buildr::Jetty::REQUIRES).each { |task| task.invoke }.map(&:name).join(File::PATH_SEPARATOR)
- Dir.chdir 'lib/buildr' do
- `javac -source 1.4 -target 1.4 -Xlint:all -cp #{cp} org/apache/buildr/*.java`
- end
+ # Wrapup comes after cut, and does things like tagging in SVN, updating Buildr version number, etc.
+ task 'wrapup'=>['tag', 'next_version']
end
-
-# Apache release:
-# - Create MD5/SHA1/PGP signatures
-# - Upload to people.apache.org:/www/www.apache.org/dist/incubator/buildr
-#
-namespace 'release' do
-
- task 'prepare'=>'clobber'
-
- # Check that all source files have licenses.
- task 'prepare' do
- puts 'Checking that files contain the Apache license'
- directories = 'lib', 'spec', 'docs', 'bin'
- ignore = 'class', 'opts'
- FileList['lib/**/*', 'spec/**/*', 'bin/**', 'doc/css/*', 'doc/scripts/*'].
- exclude('doc/css/eiffel.css').reject { |file| File.directory?(file) || ignore.include?(file[/[^.]*$/]) }.each do |file|
- comments = File.read(file).scan(/(\/\*(.*?)\*\/)|^#\s+(.*?)$|<!--(.*?)-->/m).
- map { |match| match.reject(&:nil?) }.flatten.join("\n")
- fail "File #{file} missing Apache License, please add it before making a release!" unless
- comments =~ /Licensed to the Apache Software Foundation/ && comments =~ /http:\/\/www.apache.org\/licenses\/LICENSE-2.0/
- end
- end
-
- # Compile Java libraries.
- task 'prepare'=>'compile' do
- FileList['lib/**/*.java'].each { |src| fail "Can't find .class file for #{src}!" unless File.exist?(src.ext('class')) }
- end
-
- # Make sure we have RDoc template, Docter and PDF genereation.
- task 'prepare'=>[rdoc.template, pdf] do
- fail 'Release requires the Allison RDoc template, please gem install allison!' unless rdoc.template =~ /allison.rb/
- fail 'No PDF generated, you need to install PrinceXML!' unless File.exist?('html/buildr.pdf')
- end
-
- # Run specs on Ruby and JRuby, make sure we generate test/coverage reports.
- task 'prepare'=>['spec:jruby', 'spec:report'] do
- fail 'No test reports in html directory!' unless File.exist?('html/report.html')
- fail 'No coverage reports in html directory!' unless File.exist?('html/coverage/index.html')
- end
-end
+task 'release'=>['release:prepare', 'release:cut', 'release:wrapup']
Modified: incubator/buildr/trunk/doc/pages/download.textile
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/doc/pages/download.textile?rev=631024&r1=631023&r2=631024&view=diff
==============================================================================
--- incubator/buildr/trunk/doc/pages/download.textile (original)
+++ incubator/buildr/trunk/doc/pages/download.textile Mon Feb 25 14:47:20 2008
@@ -3,11 +3,12 @@
h2. Installing Buildr
-The easiest way to install Buildr is using the fabulous RubyGems package manager. Of course,
-you will need either Ruby or JRuby, and we recommend a recent version of RubyGems and
-if this sounds foreign to you, don't worry. We'll show you how to install Buildr on Linux,
-OS/X, Windows and JRuby in the "Getting Started guide":getting_started.html, we even provide
-automated installation scripts.
+The easiest way to install Buildr is using the fabulous RubyGems package
+manager. Of course, you will need either Ruby or JRuby, and we recommend a
+recent version of RubyGems and if this sounds foreign to you, don't worry.
+We'll show you how to install Buildr on Linux, OS/X, Windows and JRuby in the
+"Getting Started guide":getting_started.html, we even provide automated
+installation scripts.
h2. Binaries and Source Code
@@ -15,3 +16,13 @@
At the moment we do not make offical Apache binary and source distributions.
Unofficial binary and source distributions are available form
"RubyForge":http://rubyforge.org/projects/buildr.
+
+p(note). When downloading from a mirror please check the
+"md5sum":http://www.apache.org/dev/release-signing#md5 and verify the
+"OpenPGP":http://www.apache.org/dev/release-signing#openpgp compatible
+signature from the main Apache site. This
+"KEYS":http://www.apache.org/dist/incubator/buildr/KEYS file contains the
+public keys used for signing releases. It is recommended that (when possible) a
+web of trust is used to confirm the identity of these keys. For more
+information, please see the "Apache Release
+FAQ":http://www.apache.org/dev/release.html.
Modified: incubator/buildr/trunk/doc/web.toc.yaml
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/doc/web.toc.yaml?rev=631024&r1=631023&r2=631024&view=diff
==============================================================================
--- incubator/buildr/trunk/doc/web.toc.yaml (original)
+++ incubator/buildr/trunk/doc/web.toc.yaml Mon Feb 25 14:47:20 2008
@@ -26,5 +26,5 @@
- Project Status:
- License: license.html
- Change Log: changelog.html
- - Test Report: report.html
- - Test Coverage: coverage
+ - Specs: specs.html
+ - Coverage: coverage
Modified: incubator/buildr/trunk/lib/core/application.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/core/application.rb?rev=631024&r1=631023&r2=631024&view=diff
==============================================================================
--- incubator/buildr/trunk/lib/core/application.rb (original)
+++ incubator/buildr/trunk/lib/core/application.rb Mon Feb 25 14:47:20 2008
@@ -13,6 +13,27 @@
# License for the specific language governing permissions and limitations under
# the License.
+# Portion of this file derived from Rake.
+# Copyright (c) 2003, 2004 Jim Weirich
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
require 'benchmark'