Return-Path: Delivered-To: apmail-incubator-buildr-commits-archive@locus.apache.org Received: (qmail 72052 invoked from network); 5 Apr 2008 02:41:37 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 5 Apr 2008 02:41:37 -0000 Received: (qmail 15143 invoked by uid 500); 5 Apr 2008 02:41:38 -0000 Delivered-To: apmail-incubator-buildr-commits-archive@incubator.apache.org Received: (qmail 15132 invoked by uid 500); 5 Apr 2008 02:41:37 -0000 Mailing-List: contact buildr-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: buildr-dev@incubator.apache.org Delivered-To: mailing list buildr-commits@incubator.apache.org Received: (qmail 15123 invoked by uid 99); 5 Apr 2008 02:41:37 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 04 Apr 2008 19:41:37 -0700 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO eris.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 05 Apr 2008 02:40:52 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 18E021A9832; Fri, 4 Apr 2008 19:41:05 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r645019 - in /incubator/buildr/trunk: ./ lib/ lib/buildr/core/ lib/buildr/java/ spec/ Date: Sat, 05 Apr 2008 02:41:03 -0000 To: buildr-commits@incubator.apache.org From: assaf@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20080405024105.18E021A9832@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: assaf Date: Fri Apr 4 19:41:01 2008 New Revision: 645019 URL: http://svn.apache.org/viewvc?rev=645019&view=rev Log: Added experimental support for YAML configuration files: - settings.yaml found in ~/.buildr for user settings (username, password, etc) - build.yaml file found next to buildfile for project settings (dependencies, defaults, etc) - profiles.yaml file found next to buildfile for profile-specific settings You can use build.yaml to force a Gem to be loaded before buildfile, e.g.: gems: - extra-stuff - other-features ~> 2.1 Buildr will offer to install these gems when running interactively. Added: incubator/buildr/trunk/spec/application_spec.rb Modified: incubator/buildr/trunk/CHANGELOG incubator/buildr/trunk/lib/buildr.rb incubator/buildr/trunk/lib/buildr/core/addon.rb incubator/buildr/trunk/lib/buildr/core/application.rb incubator/buildr/trunk/lib/buildr/core/common.rb incubator/buildr/trunk/lib/buildr/core/environment.rb incubator/buildr/trunk/lib/buildr/java/bdd_frameworks.rb incubator/buildr/trunk/spec/artifact_spec.rb incubator/buildr/trunk/spec/common_spec.rb incubator/buildr/trunk/spec/project_spec.rb incubator/buildr/trunk/spec/sandbox.rb incubator/buildr/trunk/spec/spec_helpers.rb Modified: incubator/buildr/trunk/CHANGELOG URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/CHANGELOG?rev=645019&r1=645018&r2=645019&view=diff ============================================================================== --- incubator/buildr/trunk/CHANGELOG (original) +++ incubator/buildr/trunk/CHANGELOG Fri Apr 4 19:41:01 2008 @@ -24,6 +24,10 @@ * Added: JRuby 1.1 support (Victor Hugo Borja, Nick Sieger). * Added: IDEA 7 task: use buildr idea7x (Shane Witbeck). * Added: Experimental support for addons. +* Added: Experimental support for YAML configurtion files settings.yaml (in +~/.buildr), build.yaml (next to buildfile) and profiles.yaml. +* Added: Ability to create a package that is not an artifact and specify the +target file using the :file argument. * Changed: JUnit/TestNG test cases are selected by superClass or annotations, not by class-name pattern. * Changed: Upgraded to Antwrap 0.7.0, thanks to Caleb Powell for relicensing Modified: incubator/buildr/trunk/lib/buildr.rb URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/buildr.rb?rev=645019&r1=645018&r2=645019&view=diff ============================================================================== --- incubator/buildr/trunk/lib/buildr.rb (original) +++ incubator/buildr/trunk/lib/buildr.rb Fri Apr 4 19:41:01 2008 @@ -29,6 +29,7 @@ VERSION = '1.3.0'.freeze # unless const_defined?(:VERSION) end + require 'buildr/core' require 'buildr/tasks' require 'buildr/java' Modified: incubator/buildr/trunk/lib/buildr/core/addon.rb URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/buildr/core/addon.rb?rev=645019&r1=645018&r2=645019&view=diff ============================================================================== --- incubator/buildr/trunk/lib/buildr/core/addon.rb (original) +++ incubator/buildr/trunk/lib/buildr/core/addon.rb Fri Apr 4 19:41:01 2008 @@ -16,83 +16,11 @@ require 'buildr/core/package' require 'buildr/tasks/zip' -$LOADED_FEATURES << 'rubygems/open-uri.rb' # We already have open-uri, RubyGems loads a different one -require 'rubygems/source_info_cache' -require 'rubygems/doc_manager' -require 'rubygems/format' require 'rubyforge' module Buildr - # :call-seq: - # addon(name, version?) - # addon(task) - # - # Use the specified addon, downloading and install it, if necessary. - # - # Addons are essentially Ruby gems, but installed and loaded differently: - # * The addon method downloads and installs the gem, if necessary. - # * It requires a Ruby file with the same name as the gem, if it finds one. - # * It imports all .rake files found in the Gem's tasks directory. - # - # The first form takes the gem's name and optional version requirement. The default - # version requirement is '>= 0' (see RubyGem's gem method for more information). - # For example: - # addon 'buildr-java', '~> 1.0' - # - # The second form takes a file task that points to the Gem file. - def addon(name_or_path, version = nil) - case name_or_path - when Rake::FileTask - path = name_or_path.to_s - spec = Gem::Format.from_file_by_path(path).spec - when String - dep = Gem::Dependency.new(name_or_path, version) - #spec = Gem::SourceIndex.from_installed_gems.search(dep).last || Gem::SourceInfoCache.search(dep).last - unless spec = Gem::SourceIndex.from_installed_gems.search(dep).last - Gem::SourceInfoCache.search(dep).last - Gem::SourceInfoCache.cache.flush - fail Gem::LoadError, "Could not find #{name_or_path} locally or in remote repository." unless spec - end - else fail "First argument must be Gem name or File task." - end - - if Gem::SourceIndex.from_installed_gems.search(spec.name, spec.version).empty? - say "Installing #{spec.full_name} ... " if verbose - cmd = Config::CONFIG['ruby_install_name'], '-S', 'gem', 'install', name_or_path.to_s - cmd << '-v' << spec.version.to_s - cmd.unshift 'sudo' unless Gem.win_platform? || RUBY_PLATFORM =~ /java/ - sh *cmd.push(:verbose=>false) - Gem.source_index.load_gems_in Gem::SourceIndex.installed_spec_directories - # NOTE: The nice thing would be to do a Gem install from the process, - # but installing the documenation requires RDoc, and RDoc defines - # one too many top-level classes which mess with our stuff. -=begin - require 'rubygems/dependency_installer' - installer = Gem::DependencyInstaller.new(path || name, version.to_s).tap do |installer| - installer.install - say 'Installed' - installer.installed_gems.each do |spec| - # NOTE: RI documentation must be generated before RDoc. - Gem::DocManager.new(spec, nil).generate_ri - Gem::DocManager.new(spec, nil).generate_rdoc - Gem.source_index.add_spec spec - end - end -=end - end - - Gem.activate(spec.name, true, spec.version).tap do - FileList[spec.require_paths.map { |path| File.expand_path("#{path}/*.rb", spec.full_gem_path) }]. - map { |path| File.basename(path) }.each { |file| require file } - FileList[File.expand_path('tasks/*.rake', spec.full_gem_path)].each do |file| - Rake.application.add_import file - end - end - end - - class PackageGemTask < ArchiveTask def initialize(*args) @@ -107,13 +35,13 @@ def install cmd = Config::CONFIG['ruby_install_name'], '-S', 'gem', 'install', name - cmd .unshift 'sudo' unless Gem.win_platform? || RUBY_PLATFORM =~ /java/ + cmd .unshift 'sudo' unless Gem.win_platform? sh *cmd end def uninstall cmd = Config::CONFIG['ruby_install_name'], '-S', 'gem', 'uninstall', spec.name, '-v', spec.version.to_s - cmd .unshift 'sudo' unless Gem.win_platform? || RUBY_PLATFORM =~ /java/ + cmd .unshift 'sudo' unless Gem.win_platform? sh *cmd end Modified: incubator/buildr/trunk/lib/buildr/core/application.rb URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/buildr/core/application.rb?rev=645019&r1=645018&r2=645019&view=diff ============================================================================== --- incubator/buildr/trunk/lib/buildr/core/application.rb (original) +++ incubator/buildr/trunk/lib/buildr/core/application.rb Fri Apr 4 19:41:01 2008 @@ -36,97 +36,205 @@ require 'benchmark' +require 'rake' +require 'rubygems/source_info_cache' +require 'buildr/core/application_cli' + + +# Gem::user_home is nice, but ENV['HOME'] lets you override from the environment. +ENV["HOME"] ||= File.expand_path(Gem::user_home) +ENV['BUILDR_ENV'] ||= 'development' + +# Add a touch of colors (red) to warnings. +HighLine.use_color = !Gem.win_platform? module Buildr - # Gem::user_home is nice, but ENV['HOME'] lets you override from the environment. - ENV["HOME"] ||= File.expand_path(Gem::user_home) + class Application < Rake::Application #:nodoc: - # When running from +rake+, we already have an Application setup and must plug into it, - # since the top-level tasks come from there. When running from +buildr+, we get to load - # Rake and set everything up, and we use our own Application full of cool Buildr features. - if defined?(Rake) - Rake.application.top_level_tasks.unshift task('buildr:initialize') - else - - require 'rake' - - class Application < Rake::Application #:nodoc: - - DEFAULT_BUILDFILES = ['buildfile', 'Buildfile'] + DEFAULT_RAKEFILES - - require 'buildr/core/application_cli' - include CommandLineInterface - - attr_reader :rakefiles, :requires - private :rakefiles, :requires - - def initialize() - super - @rakefiles = DEFAULT_BUILDFILES - @name = 'Buildr' - @requires = [] - @top_level_tasks = [] - parse_options - collect_tasks - top_level_tasks.unshift 'buildr:initialize' - end - - def run() - times = Benchmark.measure do - standard_exception_handling do - find_buildfile - load_buildfile - top_level - end - end - if verbose - real = [] - real << ("%ih" % (times.real / 3600)) if times.real >= 3600 - real << ("%im" % ((times.real / 60) % 60)) if times.real >= 60 - real << ("%.3fs" % (times.real % 60)) - puts "Completed in #{real.join}" - end + DEFAULT_BUILDFILES = ['buildfile', 'Buildfile'] + DEFAULT_RAKEFILES + + include CommandLineInterface + + attr_reader :rakefiles, :requires + private :rakefiles, :requires + + def initialize + super + @rakefiles = DEFAULT_BUILDFILES + @name = 'Buildr' + @requires = [] + @top_level_tasks = [] + @home_dir = File.expand_path('.buildr', ENV['HOME']) + @environment = ENV['BUILDR_ENV'] + parse_options + collect_tasks + top_level_tasks.unshift 'buildr:initialize' + mkpath @home_dir unless File.exist?(@home_dir) + end + + # Returns list of Gems associated with this buildfile, as listed in build.yaml. + # Each entry is of type Gem::Specification. + attr_reader :gems + + # Buildr home directory, .buildr under user's home directory. + attr_reader :home_dir + + # Copied from BUILD_ENV. + attr_reader :environment + + # User settings loaded from settings.yaml (Hash). + def settings + unless @settings + file_name = ['settings.yaml', 'settings.yml'].map { |fn| File.expand_path(fn, home_dir) }.find { |fn| File.exist?(fn) } + @settings = file_name && YAML.load(File.read(file_name)) || {} + fail "Expecting #{file_name} to be a hash!" unless Hash === @settings end + @settings + end - def find_buildfile() - here = Dir.pwd - while ! have_rakefile - Dir.chdir('..') - if Dir.pwd == here || options.nosearch - error = "No Buildfile found (looking for: #{@rakefiles.join(', ')})" - if STDIN.isatty - chdir(original_dir) { task('generate').invoke } - exit 1 - else - raise error - end - end - here = Dir.pwd - end + # Configuration loaded from build.yaml (Hash). + def configuration + unless @config + file_name = ['build.yaml', 'build.yml'].map { |fn| File.expand_path(fn, File.dirname(buildfile)) }.find { |fn| File.exist?(fn) } + @config = file_name && YAML.load(File.read(file_name)) || {} + fail "Expecting #{file_name} to be a hash!" unless Hash === @config end + @config + end + + # :call-seq: + # profile => hash + # + # Returns the profile for the current environment. + def profile + profiles[environment] ||= {} + end - def load_buildfile() - @requires.each { |name| require name } - puts Buildr.environment ? "(in #{Dir.pwd}, #{Buildr.environment})" : "(in #{Dir.pwd})" - load File.expand_path(@rakefile) if @rakefile != '' - load_imports + # :call-seq: + # profiles => hash + # + # Returns all the profiles loaded from the profiles.yaml file. + def profiles + unless @profiles + file_name = ['profiles.yaml', 'profiles.yml'].map { |fn| File.expand_path(fn, File.dirname(buildfile)) }.find { |fn| File.exist?(fn) } + @profiles = file_name && YAML.load(File.read(file_name)) || {} + fail "Expecting #{file_name} to be a hash!" unless Hash === @profiles + @profiles = profiles.inject({}) { |hash, (name, value)| value ||= {} + raise 'Each profile must be empty or contain name/value pairs.' unless Hash === value + hash.merge(name=>(value || {})) } end + @profiles + end + + # :call-seq: + # buildfile + def buildfile + rakefile + end + # :call-seq: + # build_files => files + # + # Returns a list of build files. These are files used by the build, + def build_files + [buildfile].compact + Array(@build_files) end - Rake.application = Buildr::Application.new - end + # Returns Gem::Specification for every listed and installed Gem, Gem::Dependency + # for listed and uninstalled Gem, which is the installed before loading the buildfile. + def listed_gems #:nodoc: + Array(configuration['gems']).map do |dep| + name, trail = dep.scan(/^\s*(\S*)\s*(.*)\s*$/).first + versions = trail.scan(/[=><~!]{0,2}\s*[\d\.]+/) + versions = ['>= 0'] if versions.empty? + dep = Gem::Dependency.new(name, versions) + Gem::SourceIndex.from_installed_gems.search(dep).last || dep + end + end + private :listed_gems + def run + times = Benchmark.measure do + standard_exception_handling do + find_buildfile + load_gems + load_buildfile + top_level + load_tasks + end + end + if verbose + real = [] + real << ("%ih" % (times.real / 3600)) if times.real >= 3600 + real << ("%im" % ((times.real / 60) % 60)) if times.real >= 60 + real << ("%.3fs" % (times.real % 60)) + puts "Completed in #{real.join}" + end + end - class << self + # Load/install all Gems specified in build.yaml file. + def load_gems #:nodoc: + missing_deps, installed = listed_gems.partition { |gem| gem.is_a?(Gem::Dependency) } + unless missing_deps.empty? + remote = missing_deps.map { |dep| Gem::SourceInfoCache.search(dep).last || dep } + not_found_deps, install = remote.partition { |gem| gem.is_a?(Gem::Dependency) } + fail Gem::LoadError, "Build requires the gems #{not_found_deps.join(', ')}, which cannot be found in local or remote repository." unless not_found_deps.empty? + uses = "This build requires the gems #{install.map(&:full_name).join(', ')}:" + fail Gem::LoadError, "#{uses} to install, run Buildr interactively." unless $stdout.isatty + unless agree("#{uses} do you want me to install them? [Y/n]", true) + fail Gem::LoadError, 'Cannot build without these gems.' + end + install.each do |spec| + say "Installing #{spec.full_name} ... " if verbose + cmd = Config::CONFIG['ruby_install_name'], '-S', 'gem', 'install', spec.name, '-v', spec.version.to_s + cmd.unshift 'sudo' unless Gem.win_platform? || RUBY_PLATFORM =~ /java/ + sh *cmd.push(:verbose=>false) + Gem.source_index.load_gems_in Gem::SourceIndex.installed_spec_directories + end + installed += install + end + + installed.each do |spec| + if gem(spec.name, spec.version.to_s) + # FileList[spec.require_paths.map { |path| File.expand_path("#{path}/*.rb", spec.full_gem_path) }]. + # map { |path| File.basename(path) }.each { |file| require file } + # FileList[File.expand_path('tasks/*.rake', spec.full_gem_path)].each do |file| + # Rake.application.add_import file + # end + end + end + @gems = installed + end + + def find_buildfile + here = Dir.pwd + while ! have_rakefile + Dir.chdir('..') + if Dir.pwd == here || options.nosearch + error = "No Buildfile found (looking for: #{@rakefiles.join(', ')})" + if STDIN.isatty + chdir(original_dir) { task('generate').invoke } + exit 1 + else + raise error + end + end + here = Dir.pwd + end + end + + def load_buildfile + @requires.each { |name| require name } + puts "(in #{Dir.pwd}, #{environment})" + load File.expand_path(@rakefile) if @rakefile != '' + load_imports + end # Loads buildr.rake files from users home directory and project directory. # Loads custom tasks from .rake files in tasks directory. - def load_tasks_and_local_files() #:nodoc: - return false if @build_files - # Load the settings files. + def load_tasks #:nodoc: @build_files = [ File.expand_path('buildr.rb', ENV['HOME']), 'buildr.rb' ].select { |file| File.exist?(file) } @build_files += [ File.expand_path('buildr.rake', ENV['HOME']), File.expand_path('buildr.rake') ]. select { |file| File.exist?(file) }.each { |file| warn "Please use '#{file.ext('rb')}' instead of '#{file}'" } @@ -140,19 +248,30 @@ end true end + private :load_tasks + + end + + + class << self # :call-seq: - # build_files() => files + # build_files => files # # Returns a list of build files. These are files used by the build, - def build_files() - [Rake.application.rakefile].compact + @build_files + def build_files + Buildr.application.build_files end task 'buildr:initialize' do Buildr.load_tasks_and_local_files end + # Returns the Buildr::Application object. + attr_accessor :application + end + + Buildr.application = Rake.application = Buildr::Application.new end Modified: incubator/buildr/trunk/lib/buildr/core/common.rb URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/buildr/core/common.rb?rev=645019&r1=645018&r2=645019&view=diff ============================================================================== --- incubator/buildr/trunk/lib/buildr/core/common.rb (original) +++ incubator/buildr/trunk/lib/buildr/core/common.rb Fri Apr 4 19:41:01 2008 @@ -309,8 +309,6 @@ end -# Add a touch of colors (red) to warnings. -HighLine.use_color = !Gem.win_platform? module Kernel #:nodoc: alias :warn_without_color :warn Modified: incubator/buildr/trunk/lib/buildr/core/environment.rb URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/buildr/core/environment.rb?rev=645019&r1=645018&r2=645019&view=diff ============================================================================== --- incubator/buildr/trunk/lib/buildr/core/environment.rb (original) +++ incubator/buildr/trunk/lib/buildr/core/environment.rb Fri Apr 4 19:41:01 2008 @@ -117,50 +117,8 @@ Buildr.options end - # :call-seq: - # environment => string or nil - # - # Returns the environment name. Use this when your build depends on the environment, - # for example, development, production, etc. The value comes from the BUILDR_ENV - # environment variable, and defaults to 'development'. - # - # For example: - # buildr -e production - def environment - ENV['BUILDR_ENV'] ||= 'development' - end - - # :call-seq: - # environment(env) - # - # Sets the environment name. - def environment=(env) - ENV['BUILDR_ENV'] = env - end - - # :call-seq: - # profile => hash - # - # Returns the profile for the current environment. def profile - profiles[environment] ||= {} - end - - # :call-seq: - # profiles => hash - # - # Returns all the profiles loaded from the profiles.yaml file. - def profiles - unless @profiles - filename = ['Profiles.yaml', 'profiles.yaml'].map { |fn| File.expand_path(fn, File.dirname(Rake.application.rakefile)) }. - detect { |filename| File.exist?(filename) } - profiles = filename && YAML::load(File.read(filename)) || {} - raise 'Profiles file must be a YAML file with a name: structure map.' unless Hash === profiles - @profiles = profiles.inject({}) { |hash, (name, value)| value ||= {} - raise 'Each profile must be empty or contain name/value pairs.' unless Hash === value - hash.merge(name=>(value || {})) } - end - @profiles + application.profile end end Modified: incubator/buildr/trunk/lib/buildr/java/bdd_frameworks.rb URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/buildr/java/bdd_frameworks.rb?rev=645019&r1=645018&r2=645019&view=diff ============================================================================== --- incubator/buildr/trunk/lib/buildr/java/bdd_frameworks.rb (original) +++ incubator/buildr/trunk/lib/buildr/java/bdd_frameworks.rb Fri Apr 4 19:41:01 2008 @@ -78,14 +78,16 @@ def run(tests, dependencies) #:nodoc: cmd_options = task.options.only(:properties, :java_args) cmd_options.update :classpath => dependencies, :project => task.project - install_gems(cmd_options) + # TODO: Setting up JRuby is something to do before running Buildr. + #install_gems(cmd_options) report_dir = task.report_to.to_s FileUtils.rm_rf report_dir ENV['CI_REPORTS'] = report_dir jruby("-Ilib", "-S", "spec", - "--require", gem_path(task.project, "ci_reporter", "lib/ci/reporter/rake/rspec_loader"), + #"--require", gem_path(task.project, "ci_reporter", "lib/ci/reporter/rake/rspec_loader"), + "--require", "ci/reporter/rake/rspec_loader", "--format", "CI::Reporter::RSpecDoc", tests, cmd_options.merge({:name => "RSpec"})) tests @@ -124,13 +126,13 @@ Java::Commands.java(*java_args) end - def install_gems(options) - unless required_gems(options).all? {|g| gem_path(options[:project], g)} - args = ["-S", "maybe_install_gems", *required_gems(options)] - args << {:name => "JRuby Setup"}.merge(options) - jruby(*args) - end - end + #def install_gems(options) + # unless required_gems(options).all? {|g| gem_path(options[:project], g)} + # args = ["-S", "maybe_install_gems", *required_gems(options)] + # args << {:name => "JRuby Setup"}.merge(options) + # jruby(*args) + # end + #end end Added: incubator/buildr/trunk/spec/application_spec.rb URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/spec/application_spec.rb?rev=645019&view=auto ============================================================================== --- incubator/buildr/trunk/spec/application_spec.rb (added) +++ incubator/buildr/trunk/spec/application_spec.rb Fri Apr 4 19:41:01 2008 @@ -0,0 +1,286 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with this +# work for additional information regarding copyright ownership. The ASF +# licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + + +require File.join(File.dirname(__FILE__), 'spec_helpers') + + +describe Buildr::Application do + before :each do + @app = Buildr.application + end + + + describe 'home_dir' do + it 'should point to ~/.buildr' do + @app.home_dir.should eql(File.expand_path('.buildr', ENV['HOME'])) + end + + it 'should point to existing directory' do + File.directory?(@app.home_dir).should be_true + end + end + + + describe 'settings' do + it 'should be empty hash if no settings.yaml file' do + @app.settings.should == {} + end + + it 'should return loaded settings.yaml file' do + write 'home/.buildr/settings.yaml', 'foo: bar' + @app.settings.should == { 'foo'=>'bar' } + end + + it 'should fail if settings.yaml file is not a hash' do + write 'home/.buildr/settings.yaml', 'foo bar' + lambda { @app.settings }.should raise_error(RuntimeError, /expecting.*settings.yaml/i) + end + + it 'should be empty hash if settings.yaml file is empty' do + write 'home/.buildr/settings.yaml' + @app.settings.should == {} + end + end + + + describe 'configuration' do + it 'should be empty hash if no build.yaml file' do + @app.configuration.should == {} + end + + it 'should return loaded build.yaml file' do + write 'build.yaml', 'foo: bar' + @app.configuration.should == { 'foo'=>'bar' } + end + + it 'should fail if build.yaml file is not a hash' do + write 'build.yaml', 'foo bar' + lambda { @app.configuration }.should raise_error(RuntimeError, /expecting.*build.yaml/i) + end + + it 'should be empty hash if build.yaml file is empty' do + write 'build.yaml' + @app.configuration.should == {} + end + end + + + describe 'profiles' do + it 'should be empty hash if no profiles.yaml file' do + @app.profiles.should == {} + end + + it 'should return loaded profiles.yaml file' do + write 'profiles.yaml', <<-YAML + development: + foo: bar + YAML + @app.profiles.should == { 'development'=> { 'foo'=>'bar' } } + end + + it 'should fail if profiles.yaml file is not a hash' do + write 'profiles.yaml', 'foo bar' + lambda { @app.profiles }.should raise_error(RuntimeError, /expecting.*profiles.yaml/i) + end + + it 'should be empty hash if profiles.yaml file is empty' do + write 'profiles.yaml' + @app.profiles.should == {} + end + end + + + describe 'profile' do + it 'should be empty hash if no profiles.yaml' do + @app.profile.should == {} + end + + it 'should be empty hash if no matching profile' do + write 'profiles.yaml', <<-YAML + test: + foo: bar + YAML + @app.profile.should == {} + end + + it 'should return profile matching environment name' do + write 'profiles.yaml', <<-YAML + development: + foo: bar + test: + foo: baz + YAML + @app.profile.should == { 'foo'=>'bar' } + end + + end + + + describe 'gems' do + + def load_with_yaml + write 'build.yaml', <<-YAML + gems: + - rspec + - rake >= 0.8 + YAML + @app.load_gems + end + + it 'should return empty array if no gems specified' do + @app.load_gems + @app.gems.should be_empty + end + + it 'should return one entry for each gem specified in buildr.yaml' do + load_with_yaml + @app.gems.size.should be(2) + end + + it 'should return a Gem::Specification for each installed gem' do + load_with_yaml + @app.gems.each { |gem| gem.should be_kind_of(Gem::Specification) } + end + + it 'should parse Gem name correctly' do + load_with_yaml + @app.gems.map(&:name).should include('rake', 'rspec') + end + + it 'should find installed version of Gem' do + load_with_yaml + @app.gems.each { |gem| gem.version.should eql(Gem.loaded_specs[gem.name].version) } + end + end + + + describe 'load_gems' do + before do + @spec = Gem::Specification.new do |spec| + spec.name = 'foo' + spec.version = '1.2' + end + end + + it 'should do nothing if no gems specified' do + lambda { @app.load_gems }.should_not raise_error + end + + it 'should install nothing if specified gems already installed' do + @app.should_receive(:listed_gems).and_return([Gem.loaded_specs['rspec']]) + @app.should_not_receive(:sh) + lambda { @app.load_gems }.should_not raise_error + end + + it 'should fail if required gem not found in remote repository' do + @app.should_receive(:listed_gems).and_return([Gem::Dependency.new('foo', '>=1.1')]) + Gem::SourceInfoCache.should_receive(:search).and_return([]) + lambda { @app.load_gems }.should raise_error(LoadError, /cannot be found/i) + end + + it 'should fail if need to install gem and not running in interactive mode' do + @app.should_receive(:listed_gems).and_return([Gem::Dependency.new('foo', '>=1.1')]) + Gem::SourceInfoCache.should_receive(:search).and_return([@spec]) + $stdout.should_receive(:isatty).and_return(false) + lambda { @app.load_gems }.should raise_error(LoadError, /this build requires the gems/i) + end + + it 'should ask permission before installing required gems' do + @app.should_receive(:listed_gems).and_return([Gem::Dependency.new('foo', '>=1.1')]) + Gem::SourceInfoCache.should_receive(:search).and_return([@spec]) + $terminal.should_receive(:agree).with(/install/, true) + lambda { @app.load_gems }.should raise_error + end + + it 'should fail if permission not granted to install gem' do + @app.should_receive(:listed_gems).and_return([Gem::Dependency.new('foo', '>=1.1')]) + Gem::SourceInfoCache.should_receive(:search).and_return([@spec]) + $terminal.should_receive(:agree).and_return(false) + lambda { @app.load_gems }.should raise_error(LoadError, /cannot build without/i) + end + + it 'should install gem if permission granted' do + @app.should_receive(:listed_gems).and_return([Gem::Dependency.new('foo', '>=1.1')]) + Gem::SourceInfoCache.should_receive(:search).and_return([@spec]) + $terminal.should_receive(:agree).and_return(true) + @app.should_receive(:sh) do |*args| + args.should include('-S', 'gem', 'install', 'foo', '-v', '1.2') + end + @app.should_receive(:gem).and_return(false) + @app.load_gems + end + + it 'should reload gem cache after installing required gems' do + @app.should_receive(:listed_gems).and_return([Gem::Dependency.new('foo', '>=1.1')]) + Gem::SourceInfoCache.should_receive(:search).and_return([@spec]) + $terminal.should_receive(:agree).and_return(true) + @app.should_receive(:sh) + Gem.source_index.should_receive(:load_gems_in).with(Gem::SourceIndex.installed_spec_directories) + @app.should_receive(:gem).and_return(false) + @app.load_gems + end + + it 'should load previously installed gems' do + @app.should_receive(:listed_gems).and_return([Gem.loaded_specs['rspec']]) + @app.should_receive(:gem).with('rspec', Gem.loaded_specs['rspec'].version.to_s) + @app.load_gems + end + + it 'should load newly installed gems' do + @app.should_receive(:listed_gems).and_return([Gem::Dependency.new('foo', '>=1.1')]) + Gem::SourceInfoCache.should_receive(:search).and_return([@spec]) + $terminal.should_receive(:agree).and_return(true) + @app.should_receive(:sh) + @app.should_receive(:gem).with('foo', @spec.version.to_s) + @app.load_gems + end + + it 'should default to >=0 version requirement if not specified' do + write 'build.yaml', 'gems: foo' + Gem::SourceInfoCache.should_receive(:search).with(Gem::Dependency.new('foo', '>=0')).and_return([]) + lambda { @app.load_gems }.should raise_error + end + + it 'should parse exact version requirement' do + write 'build.yaml', 'gems: foo 2.5' + Gem::SourceInfoCache.should_receive(:search).with(Gem::Dependency.new('foo', '=2.5')).and_return([]) + lambda { @app.load_gems }.should raise_error + end + + it 'should parse range version requirement' do + write 'build.yaml', 'gems: foo ~>2.3' + Gem::SourceInfoCache.should_receive(:search).with(Gem::Dependency.new('foo', '~>2.3')).and_return([]) + lambda { @app.load_gems }.should raise_error + end + + it 'should parse multiple version requirements' do + write 'build.yaml', 'gems: foo >=2.0 !=2.1' + Gem::SourceInfoCache.should_receive(:search).with(Gem::Dependency.new('foo', ['>=2.0', '!=2.1'])).and_return([]) + lambda { @app.load_gems }.should raise_error + end + end + +end + + +describe ENV do + + describe 'BUILDR_ENV' do + it 'should default to development' do + ENV['BUILDR_ENV'].should eql('development') + end + end +end Modified: incubator/buildr/trunk/spec/artifact_spec.rb URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/spec/artifact_spec.rb?rev=645019&r1=645018&r2=645019&view=diff ============================================================================== --- incubator/buildr/trunk/spec/artifact_spec.rb (original) +++ incubator/buildr/trunk/spec/artifact_spec.rb Fri Apr 4 19:41:01 2008 @@ -132,7 +132,7 @@ it 'should default to .m2 path' do # For convenience, sandbox actually sets the local repository to a temp directory repositories.local = nil - repositories.local.should eql(File.expand_path('~/.m2/repository')) + repositories.local.should eql(File.expand_path('.m2/repository', ENV['HOME'])) end it 'should be settable' do Modified: incubator/buildr/trunk/spec/common_spec.rb URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/spec/common_spec.rb?rev=645019&r1=645018&r2=645019&view=diff ============================================================================== --- incubator/buildr/trunk/spec/common_spec.rb (original) +++ incubator/buildr/trunk/spec/common_spec.rb Fri Apr 4 19:41:01 2008 @@ -577,80 +577,3 @@ props.split("\n").should include("name3=double\\\\hash") end end - - -describe Buildr, 'environment' do - it 'should default to development' do - environment.should eql('development') - end - - it 'should come from BUILDR_ENV environment variable' do - ENV['BUILDR_ENV'] = 'buildr-test' - environment.should eql('buildr-test') - end - - it 'should change the environment variable' do - Buildr.environment = 'buildr-test' - ENV['BUILDR_ENV'].should eql('buildr-test') - end -end - - -describe Buildr, 'profiles' do - it 'should return empty hash if no profiles file' do - Buildr.profiles.should == {} - end - - it 'should load profiles from profiles.yaml file' do - write 'profiles.yaml', <<-YAML -dev: - foo: bar -test: - bar: baz - YAML - Buildr.profiles.should == { 'dev'=> { 'foo'=>'bar' }, 'test'=>{ 'bar'=>'baz' } } - end - - it 'should load profiles from Profiles.yaml file' do - write 'Profiles.yaml', <<-YAML -dev: - foo: bar -test: - bar: baz - YAML - Buildr.profiles.should == { 'dev'=> { 'foo'=>'bar' }, 'test'=>{ 'bar'=>'baz' } } - end - - it 'should accept empty profiles file' do - write 'Profiles.yaml', "# comment\n\n" - Buildr.profiles.should == {} - end - - it 'should complain if profiles file is not a map' do - write 'Profiles.yaml', 'not_a_map' - lambda { Buildr.profiles }.should raise_error - end -end - - -describe Buildr, 'profile' do - it 'should return profile for current environment' do - Buildr.environment = 'qa' - Buildr.profiles['qa'] = { 'foo'=>'bar' } - Buildr.profile.should == { 'foo'=>'bar' } - end - - it 'should return empty hash if no proflie available' do - Buildr.profile.should == {} - end - - it 'should accept empty profile' do - write 'Profiles.yaml', "development:\n" - Buildr.profile.should == {} - end - - it 'should complain if profile is not a map' do - write 'Profiles.yaml', 'development: not_a_map' - lambda { Buildr.profile }.should raise_error - end -end Modified: incubator/buildr/trunk/spec/project_spec.rb URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/spec/project_spec.rb?rev=645019&r1=645018&r2=645019&view=diff ============================================================================== --- incubator/buildr/trunk/spec/project_spec.rb (original) +++ incubator/buildr/trunk/spec/project_spec.rb Fri Apr 4 19:41:01 2008 @@ -701,6 +701,8 @@ end +=begin +# TODO: how do we test this? describe Rake::Task, 'buildr:initialize' do it 'should be ready to run as the first task' do Rake.application.top_level_tasks.first.should eql('buildr:initialize') @@ -712,3 +714,4 @@ lambda { task('buildr:initialize').invoke }.should change { defined }.to(true) end end +=end Modified: incubator/buildr/trunk/spec/sandbox.rb URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/spec/sandbox.rb?rev=645019&r1=645018&r2=645019&view=diff ============================================================================== --- incubator/buildr/trunk/spec/sandbox.rb (original) +++ incubator/buildr/trunk/spec/sandbox.rb Fri Apr 4 19:41:01 2008 @@ -20,64 +20,69 @@ repositories.remote << 'http://repo1.maven.org/maven2' Java.load # Anything added to the classpath. artifacts(TestFramework.frameworks.map(&:dependencies).flatten).each { |a| file(a).invoke } -task('buildr:initialize').invoke -# We need to run all tests inside a sandbox, tacking a snapshot of Rake/Buildr before the test, +ENV['HOME'] = File.expand_path('tmp/home') + +# We need to run all tests inside a _sandbox, tacking a snapshot of Buildr before the test, # and restoring everything to its previous state after the test. Damn state changes. module Sandbox - def self.included(spec) - spec.before(:each) { sandbox } - spec.after(:each) { reset } + class << self + attr_reader :tasks, :rules + + def included(spec) + spec.before(:each) { sandbox } + spec.after(:each) { reset } + end end - def sandbox - @sandbox = {} - # During teardown we get rid of all the tasks and start with a clean slate. - # Unfortunately, we also get rid of tasks we need, like build, clean, etc. - # Here we capture them in their original form, recreated during teardown. - @sandbox[:tasks] = Rake.application.tasks.collect do |original| - prerequisites = original.prerequisites.clone - actions = original.instance_eval { @actions }.clone - lambda do - original.class.send(:define_task, original.name=>prerequisites).tap do |task| - task.comment = original.comment - actions.each { |action| task.enhance &action } - end + @tasks = Buildr.application.tasks.collect do |original| + prerequisites = original.send(:prerequisites).map(&:to_s) + actions = original.instance_eval { @actions }.clone + lambda do + original.class.send(:define_task, original.name=>prerequisites).tap do |task| + task.comment = original.comment + actions.each { |action| task.enhance &action } end end - @sandbox[:rules] = Rake.application.instance_variable_get(:@rules).clone + end + @rules = Buildr.application.instance_variable_get(:@rules) + def sandbox # Create a temporary directory where we can create files, e.g, # for projects, compilation. We need a place that does not depend # on the current directory. - @test_dir = File.expand_path('../tmp', File.dirname(__FILE__)) - FileUtils.mkpath @test_dir - # Move to the work directory and make sure Rake thinks of it as the Rakefile directory. - @sandbox[:pwd] = Dir.pwd - Dir.chdir @test_dir - @sandbox[:load_path] = $LOAD_PATH.clone - @sandbox[:loaded_features] = $LOADED_FEATURES.clone - @sandbox[:original_dir] = Rake.application.original_dir - Rake.application.instance_eval { @original_dir = Dir.pwd } - Rake.application.instance_eval { @rakefile = File.expand_path('buildfile') } + temp = File.join(File.dirname(__FILE__), '../tmp') + FileUtils.mkpath temp + Dir.chdir temp + + @_sandbox = {} + Buildr.application = Rake.application = Buildr::Application.new + Sandbox.tasks.each { |block| block.call } + Buildr.application.instance_variable_set :@rules, Sandbox.rules.clone + Buildr.application.instance_eval { @rakefile = File.expand_path('buildfile') } + + @_sandbox[:load_path] = $LOAD_PATH.clone + @_sandbox[:loaded_features] = $LOADED_FEATURES.clone # Later on we'll want to lose all the on_define created during the test. - @sandbox[:on_define] = Project.class_eval { (@on_define || []).dup } - @sandbox[:layout] = Layout.default.clone + @_sandbox[:on_define] = Project.class_eval { (@on_define || []).dup } + @_sandbox[:layout] = Layout.default.clone # Create a local repository we can play with. However, our local repository will be void # of some essential artifacts (e.g. JUnit artifacts required by build task), so we create # these first (see above) and keep them across test cases. - @sandbox[:artifacts] = Artifact.class_eval { @artifacts }.clone - Buildr.repositories.local = File.join(@test_dir, 'repository') + @_sandbox[:artifacts] = Artifact.class_eval { @artifacts }.clone + Buildr.repositories.local = File.expand_path('repository') + ENV['HOME'] = File.expand_path('home') - @sandbox[:env_keys] = ENV.keys + @_sandbox[:env_keys] = ENV.keys ['DEBUG', 'TEST', 'HTTP_PROXY', 'USER'].each { |k| ENV.delete(k) ; ENV.delete(k.downcase) } # Don't output crap to the console. trace false verbose false + task('buildr:initialize').invoke end # Call this from teardown. @@ -91,29 +96,20 @@ # Get rid of all the projects and the on_define blocks we used. Project.clear - on_define = @sandbox[:on_define] + on_define = @_sandbox[:on_define] Project.class_eval { @on_define = on_define } - Layout.default = @sandbox[:layout].clone + Layout.default = @_sandbox[:layout].clone - # Switch back Rake directory. - Dir.chdir @sandbox[:pwd] - original_dir = @sandbox[:original_dir] - $LOAD_PATH.replace @sandbox[:load_path] - $LOADED_FEATURES.replace @sandbox[:loaded_features] - Rake.application.instance_eval { @original_dir = original_dir } - FileUtils.rm_rf @test_dir - - # Get rid of all the tasks and restore the default tasks. - Rake::Task.clear - @sandbox[:tasks].each { |block| block.call } - Rake.application.instance_variable_set :@rules, @sandbox[:rules] + $LOAD_PATH.replace @_sandbox[:load_path] + $LOADED_FEATURES.replace @_sandbox[:loaded_features] + FileUtils.rm_rf Dir.pwd # Get rid of all artifacts. - @sandbox[:artifacts].tap { |artifacts| Artifact.class_eval { @artifacts = artifacts } } + @_sandbox[:artifacts].tap { |artifacts| Artifact.class_eval { @artifacts = artifacts } } # Restore options. Buildr.options.test = nil - (ENV.keys - @sandbox[:env_keys]).each { |key| ENV.delete key } + (ENV.keys - @_sandbox[:env_keys]).each { |key| ENV.delete key } end end Modified: incubator/buildr/trunk/spec/spec_helpers.rb URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/spec/spec_helpers.rb?rev=645019&r1=645018&r2=645019&view=diff ============================================================================== --- incubator/buildr/trunk/spec/spec_helpers.rb (original) +++ incubator/buildr/trunk/spec/spec_helpers.rb Fri Apr 4 19:41:01 2008 @@ -223,43 +223,43 @@ end def dryrun - Rake.application.options.dryrun = true + Buildr.application.options.dryrun = true begin suppress_stdout { yield } ensure - Rake.application.options.dryrun = false + Buildr.application.options.dryrun = false end end # We run tests with tracing off. Then things break. And we need to figure out what went wrong. # So just use trace() as you would use verbose() to find and squash the bug. def trace(value = nil) - old_value = Rake.application.options.trace - Rake.application.options.trace = value unless value.nil? + old_value = Buildr.application.options.trace + Buildr.application.options.trace = value unless value.nil? if block_given? begin yield ensure - Rake.application.options.trace = old_value + Buildr.application.options.trace = old_value end end - Rake.application.options.trace + Buildr.application.options.trace end - # Change the Rakefile original directory, faking invocation from a different directory. + # Change the Buildr original directory, faking invocation from a different directory. def in_original_dir(dir) begin - original_dir = Rake.application.original_dir - Rake.application.instance_eval { @original_dir = File.expand_path(dir) } + original_dir = Buildr.application.original_dir + Buildr.application.instance_eval { @original_dir = File.expand_path(dir) } yield ensure - Rake.application.instance_eval { @original_dir = original_dir } + Buildr.application.instance_eval { @original_dir = original_dir } end end # Buildr's define method creates a project definition but does not evaluate it - # (that happens once the Rakefile is loaded), and we include Buildr's define in + # (that happens once the buildfile is loaded), and we include Buildr's define in # the test context so we can use it without prefixing with Buildr. This just patches # define to evaluate the project definition before returning it. def define(name, properties = nil, &block) #:yields:project @@ -279,7 +279,7 @@ # Make all Buildr methods accessible from test cases, and add various helper methods. config.include Buildr, SpecHelpers - # Sanbdox Rake/Buildr for each test. + # Sanbdox Buildr for each test. config.include Sandbox end