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/03/14 00:46:42 UTC

svn commit: r636924 - in /incubator/buildr/trunk: Rakefile buildfile lib/core/addon.rb lib/core/package.rb lib/java/artifact.rb lib/java/nailgun.rb lib/java/org/apache/buildr/JavaTestFilter.class spec/artifact_spec.rb

Author: assaf
Date: Thu Mar 13 16:46:38 2008
New Revision: 636924

URL: http://svn.apache.org/viewvc?rev=636924&view=rev
Log:
Trust the package to know how to install/upload itself

Modified:
    incubator/buildr/trunk/Rakefile
    incubator/buildr/trunk/buildfile
    incubator/buildr/trunk/lib/core/addon.rb
    incubator/buildr/trunk/lib/core/package.rb
    incubator/buildr/trunk/lib/java/artifact.rb
    incubator/buildr/trunk/lib/java/nailgun.rb
    incubator/buildr/trunk/lib/java/org/apache/buildr/JavaTestFilter.class
    incubator/buildr/trunk/spec/artifact_spec.rb

Modified: incubator/buildr/trunk/Rakefile
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/Rakefile?rev=636924&r1=636923&r2=636924&view=diff
==============================================================================
--- incubator/buildr/trunk/Rakefile (original)
+++ incubator/buildr/trunk/Rakefile Thu Mar 13 16:46:38 2008
@@ -38,6 +38,7 @@
     spec.add_dependency 'rspec',                '~> 1.1'
     spec.add_dependency 'xml-simple',           '~> 1.0'
     spec.add_dependency 'archive-tar-minitar',  '~> 0.5'
+    spec.add_dependency 'rubyforge',            '~> 0.4'
     
     spec.platform = platform
     spec.add_dependency 'rjb', '~> 1.1' unless platform == 'java'
@@ -72,6 +73,16 @@
 end
 
 
+def ruby(*args)
+  options = Hash === args.last ? args.pop : {}
+  #options[:verbose] ||= false
+  cmd = []
+  cmd << 'sudo' if options.delete(:sudo) && !Gem.win_platform? && RUBY_PLATFORM !~ /java/
+  cmd << Config::CONFIG['ruby_install_name']
+  cmd << '-S' << options.delete(:command) if options[:command]
+  sh *cmd.push(*args.flatten).push(options)
+end
+
 # Setup environment for running this Rakefile (RSpec, Docter, etc).
 desc "If you're building from sources, run this task one to setup the necessary dependencies."
 task 'setup' do
@@ -82,7 +93,10 @@
   dependencies << Gem::Dependency.new('ultraviolet', '~>0.10') unless RUBY_PLATFORM =~ /java/
   dependencies << Gem::Dependency.new('rcov', '~>0.8') unless RUBY_PLATFORM =~ /java/ 
   dependencies.select { |dep| gems.search(dep.name, dep.version_requirements).empty? }.
-    each { |dep| install_gem dep.name, :version=>dep.version_requirements }
+    each do |dep|
+      ruby 'install', dep.name, '-v', dep.version_requirements.to_s, :command=>'gem', :sudo=>true
+    end
+    #each { |dep| install_gem dep.name, :version=>dep.version_requirements }
 end
 
 # Packaging and local installation.
@@ -93,32 +107,13 @@
 desc 'Install the package locally'
 task 'install'=>['clobber', 'package'] do |task|
   pkg = RUBY_PLATFORM =~ /java/ ? jruby_package : ruby_package
-  # install_gem File.expand_path(pkg.gem_file, pkg.package_dir)
   ruby 'install', File.expand_path(pkg.gem_file, pkg.package_dir), :command=>'gem', :sudo=>true
 end
 
-def ruby(*args)
-  options = Hash === args.last ? args.pop : {}
-  #options[:verbose] ||= false
-  cmd = []
-  cmd << 'sudo' if options.delete(:sudo) && !Gem.win_platform? && RUBY_PLATFORM !~ /java/
-  cmd << Config::CONFIG['ruby_install_name']
-  cmd << '-S' << options.delete(:command) if options[:command]
-  sh *cmd.push(*args.flatten).push(options)
-end
-
 desc 'Uninstall previously installed packaged'
 task 'uninstall' do |task|
   say "Uninstalling #{ruby_spec.name} ... "
   ruby 'install', name_or_path.to_s, :command=>'gem', :sudo=>true
-=begin
-  begin
-    require 'rubygems/uninstaller'
-  rescue LoadError # < rubygems 1.0.1
-    require 'rubygems/installer'
-  end
-  Gem::Uninstaller.new(ruby_spec.name, :executables=>true, :ignore=>true ).uninstall
-=end
   say 'Done'
 end
 

Modified: incubator/buildr/trunk/buildfile
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/buildfile?rev=636924&r1=636923&r2=636924&view=diff
==============================================================================
--- incubator/buildr/trunk/buildfile (original)
+++ incubator/buildr/trunk/buildfile Thu Mar 13 16:46:38 2008
@@ -1,65 +1,36 @@
 require 'buildr/jetty'
-
-def package_addon(project, *files)
-  legal = 'LICENSE', 'DISCLAIMER', 'NOTICE'
-  project.package(:gem).include(legal)
-  project.package(:gem).path('lib').tap do |lib|
-    files.each do |file|
-      lib.include(file, :as=>File.basename(file))
-    end
-  end
-  project.package(:gem).spec do |spec|
-    spec.author             = 'Apache Buildr'
-    spec.email              = 'buildr-user@incubator.apache.org'
-    spec.homepage           = "http://incubator.apache.org/buildr"
-    spec.rubyforge_project  = 'buildr'
-    spec.extra_rdoc_files   = legal
-    spec.rdoc_options << '--webcvs' << 'http://svn.apache.org/repos/asf/incubator/buildr/trunk/'
-    spec.add_dependency 'buildr', '~> 1.3'
-  end
-end
+$LOADED_FEATURES << 'jruby' unless RUBY_PLATFORM =~ /java/ # Pretend to have JRuby, keeps Nailgun happy.
+require 'java/nailgun'
 
 define 'buildr' do
   compile.using :source=>'1.4', :target=>'1.4', :debug=>false
 
   define 'java' do
-    require 'java/nailgun'
     compile.using(:javac).from(FileList['lib/java/**/*.java']).into('lib/java').with(Buildr::Nailgun.artifact)
   end
 
-  desc 'ANTLR grammar generation tasks.'
-  define 'antlr', :version=>'1.0' do
-    package_addon(self, 'lib/buildr/antlr.rb')
-  end
-
-  define 'cobertura', :version=>'1.0' do
-    package_addon(self, 'lib/buildr/cobertura.rb')
-  end
-
-  define 'hibernate', :version=>'1.0' do
-    package_addon(self, 'lib/buildr/hibernate.rb')
-  end
-
-  define 'javacc', :version=>'1.0' do
-    package_addon(self, 'lib/buildr/javacc.rb')
-  end
-
-  define 'jdepend', :version=>'1.0' do
-    package_addon(self, 'lib/buildr/jdepend.rb')
-  end
-
-  desc 'Provides a collection of tasks and methods for using Jetty, specifically as a server for testing your application.'
-  define 'jetty', :version=>'1.0' do
+  desc 'Buildr extra packages (Antlr, Cobertura, Hibernate, Javacc, JDepend, Jetty, OpenJPA, XmlBeans)'
+  define 'extra', :version=>'1.0' do
     compile.using(:javac).from(FileList['lib/buildr/**/*.java']).into('lib/buildr').with(Buildr::Jetty::REQUIRES)
-    package_addon(self, 'lib/buildr/jetty.rb')
-    package(:gem).path('lib/org/apache/buildr').include(:from=>'lib/buildr/org/apache/buildr/')
-  end
+    # Legals included in source code and show in RDoc.
+    legal = 'LICENSE', 'DISCLAIMER', 'NOTICE'
+    package(:gem).include(legal).path('lib').include('lib/buildr')
+    p package(:gem)
+    package(:gem).spec do |spec|
+      spec.author             = 'Apache Buildr'
+      spec.email              = 'buildr-user@incubator.apache.org'
+      spec.homepage           = "http://incubator.apache.org/buildr"
+      spec.rubyforge_project  = 'buildr'
+      spec.extra_rdoc_files   = legal
+      spec.rdoc_options << '--webcvs' << 'http://svn.apache.org/repos/asf/incubator/buildr/trunk/'
+      spec.add_dependency 'buildr', '~> 1.3'
+    end
 
-  define 'openjpa', :version=>'1.0' do
-    package_addon(self, 'lib/buildr/openjpa.rb')
-  end
+    install do
+      addon package(:gem)
+    end
 
-  define 'xmlbeans', :version=>'1.0' do
-    package_addon(self, 'lib/buildr/xmlbeans.rb')
+    upload do
+    end
   end
 end

Modified: incubator/buildr/trunk/lib/core/addon.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/core/addon.rb?rev=636924&r1=636923&r2=636924&view=diff
==============================================================================
--- incubator/buildr/trunk/lib/core/addon.rb (original)
+++ incubator/buildr/trunk/lib/core/addon.rb Thu Mar 13 16:46:38 2008
@@ -14,11 +14,13 @@
 # the License.
 
 
+require 'core/package'
 require 'tasks/zip'
-$LOADED_FEATURES << 'rubygems/open-uri.rb' # We already have open-uri
+$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
@@ -95,6 +97,26 @@
       @spec
     end
 
+    def install
+      cmd = Config::CONFIG['ruby_install_name'], '-S', 'gem', 'install', name
+      cmd .unshift 'sudo' unless Gem.win_platform? || RUBY_PLATFORM =~ /java/
+      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/
+      sh *cmd
+    end
+
+    def upload
+      rubyforge = RubyForge.new
+      rubyforge.login
+      #File.open('.changes', 'w'){|f| f.write(current)}
+      #rubyforge.userconfig.merge!('release_changes' => '.changes',  'preformatted' => true)
+      rubyforge.add_release spec.rubyforge_project.downcase, spec.name.downcase, spec.version, package(:gem).to_s
+    end
+
   private
 
     def create_from(file_map)
@@ -135,9 +157,10 @@
         end
       end
     end
+
   end
 
-  class Buildr::Project
+  class Project
     include PackageAsGem
   end
 

Modified: incubator/buildr/trunk/lib/core/package.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/core/package.rb?rev=636924&r1=636923&r2=636924&view=diff
==============================================================================
--- incubator/buildr/trunk/lib/core/package.rb (original)
+++ incubator/buildr/trunk/lib/core/package.rb Thu Mar 13 16:46:38 2008
@@ -136,8 +136,7 @@
       spec[:version] ||= self.version
       spec[:type] ||= type
 
-      packager = method("package_as_#{type}") rescue
-        fail("Don't know how to create a package of type #{type}")
+      packager = method("package_as_#{type}") rescue fail("Don't know how to create a package of type #{type}")
       if packager.arity == 1
         spec = send("package_as_#{type}_spec", spec) if respond_to?("package_as_#{type}_spec")
         file_name = path_to(:target, Artifact.hash_to_file_name(spec))
@@ -147,50 +146,38 @@
         file_name = path_to(:target, Artifact.hash_to_file_name(spec))
         package = packager.call(file_name, spec)
       end
-      unless packages.include?(package)
-        # Make it an artifact using the specifications, and tell it how to create a POM.
-        package.extend ActsAsArtifact
-        package.send :apply_spec, spec.only(*Artifact::ARTIFACT_ATTRIBUTES)
-        # Another task to create the POM file.
-        pom = package.pom
-        pom.enhance do
-          mkpath File.dirname(pom.name), :verbose=>false
-          File.open(pom.name, 'w') { |file| file.write pom.pom_xml }
-        end
 
+      # First time: prepare package for install, uninstall and upload tasks.
+      unless packages.include?(package)
         # We already run build before package, but we also need to do so if the package itself is
         # used as a dependency, before we get to run the package task.
         task 'package'=>package
         package.enhance [task('build')]
 
-        # Install the artifact along with its POM. Since the artifact (package task) is created
-        # in the target directory, we need to copy it into the local repository. However, the
-        # POM artifact (created by calling artifact on its spec) is already mapped to its right
-        # place in the local repository, so we only need to invoke it.
-        installed = file(Buildr.repositories.locate(package)=>package) { |task|
-          verbose(Rake.application.options.trace || false) do
-            mkpath File.dirname(task.name), :verbose=>false
-            cp package.name, task.name
-          end
-          puts "Installed #{task.name}" if verbose
-        }
-        task 'install'=>[installed, pom]
-        task 'uninstall' do |task|
-          verbose(Rake.application.options.trace || false) do
-            [ installed, pom ].map(&:to_s).each { |file| rm file if File.exist?(file) } 
+        unless package.respond_to?(:install)
+          # Make it an artifact using the specifications, and tell it how to create a POM.
+          package.extend ActsAsArtifact
+          package.send :apply_spec, spec.only(*Artifact::ARTIFACT_ATTRIBUTES)
+          # Another task to create the POM file.
+          pom = package.pom
+          pom.enhance do
+            mkpath File.dirname(pom.name), :verbose=>false
+            File.open(pom.name, 'w') { |file| file.write pom.pom_xml }
           end
-        end
-        task 'upload'=>[package.pom] do
-          package.pom.upload
-          package.upload
+          file(Buildr.repositories.locate(package)=>package) { package.install }
+
+          # Add the package to the list of packages created by this project, and
+          # register it as an artifact. The later is required so if we look up the spec
+          # we find the package in the project's target directory, instead of finding it
+          # in the local repository and attempting to install it.
+          Artifact.register package, pom
         end
 
-        # Add the package to the list of packages created by this project, and
-        # register it as an artifact. The later is required so if we look up the spec
-        # we find the package in the project's target directory, instead of finding it
-        # in the local repository and attempting to install it.
+        task('install')   { package.install if package.respond_to?(:install) }
+        task('uninstall') { package.uninstall if package.respond_to?(:uninstall) }
+        task('upload')    { package.upload if package.respond_to?(:upload) }
+
         packages << package
-        Artifact.register package, pom
       end
       package
     end
@@ -231,7 +218,6 @@
 
   end
 end
-
 
 class Buildr::Project
   include Buildr::Package

Modified: incubator/buildr/trunk/lib/java/artifact.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/java/artifact.rb?rev=636924&r1=636923&r2=636924&view=diff
==============================================================================
--- incubator/buildr/trunk/lib/java/artifact.rb (original)
+++ incubator/buildr/trunk/lib/java/artifact.rb Thu Mar 13 16:46:38 2008
@@ -14,14 +14,14 @@
 # the License.
 
 
-require "core/project"
-require "core/transports"
-require "builder"
+require 'core/project'
+require 'core/transports'
+require 'builder'
 
 module Buildr
 
-  desc "Download all artifacts"
-  task "artifacts"
+  desc 'Download all artifacts'
+  task 'artifacts'
 
   # Mixin with a task to make it behave like an artifact. Implemented by the packaging tasks.
   #
@@ -58,50 +58,50 @@
     end
 
     # :call-seq:
-    #   to_spec_hash() => Hash
+    #   to_spec_hash => Hash
     #
     # Returns the artifact specification as a hash. For example:
     #   com.example:app:jar:1.2
     # becomes:
-    #   { :group=>"com.example",
-    #     :id=>"app",
+    #   { :group=>'com.example',
+    #     :id=>'app',
     #     :type=>:jar,
-    #     :version=>"1.2" }
-    def to_spec_hash()
+    #     :version=>'1.2' }
+    def to_spec_hash
       base = { :group=>group, :id=>id, :type=>type, :version=>version }
       classifier.to_s.blank? ? base : base.merge(:classifier=>classifier)
     end
     alias_method :to_hash, :to_spec_hash
 
     # :call-seq:
-    #   to_spec() => String
+    #   to_spec => String
     #
     # Returns the artifact specification, in the structure:
     #   <group>:<artifact>:<type>:<version>
     # or
     #   <group>:<artifact>:<type>:<classifier><:version>
-    def to_spec()
+    def to_spec
       classifier.to_s.blank? ? "#{group}:#{id}:#{type}:#{version}" : "#{group}:#{id}:#{type}:#{classifier}:#{version}"
     end
 
     # :call-seq:
-    #   pom() => Artifact
+    #   pom => Artifact
     # 
     # Convenience method that returns a POM artifact.
-    def pom()
+    def pom
       return self if type == :pom
       Buildr.artifact(:group=>group, :id=>id, :version=>version, :type=>:pom)
     end
 
     # :call-seq:
-    #   pom_xml() => string
+    #   pom_xml => string
     #
     # Creates POM XML for this artifact.
-    def pom_xml()
+    def pom_xml
       xml = Builder::XmlMarkup.new(:indent=>2)
       xml.instruct!
       xml.project do
-        xml.modelVersion  "4.0.0"
+        xml.modelVersion  '4.0.0'
         xml.groupId       group
         xml.artifactId    id
         xml.version       version
@@ -109,8 +109,29 @@
       end
     end
 
+    def install
+      pom.install if pom && pom != self
+      invoke
+      installed = Buildr.repositories.locate(self)
+      unless installed == name # If not already in local repository.
+        verbose(Rake.application.options.trace || false) do
+          mkpath File.dirname(installed)
+          cp name, installed
+        end
+        puts "Installed #{installed}" if verbose
+      end
+    end
+
+    def uninstall
+      verbose(Rake.application.options.trace || false) do
+        installed = Buildr.repositories.locate(self)
+        rm installed if File.exist?(installed) 
+        pom.uninstall if pom && pom != self
+      end
+    end
+
     # :call-seq:
-    #   upload()
+    #   upload
     #   upload(url)
     #   upload(options)
     #
@@ -124,18 +145,22 @@
       # Where do we release to?
       upload_to ||= Buildr.repositories.release_to
       upload_to = { :url=>upload_to } unless Hash === upload_to
-      raise ArgumentError, "Don't know where to upload, perhaps you forgot to set repositories.release_to" if upload_to[:url].to_s.blank?
+      raise ArgumentError, 'Don\'t know where to upload, perhaps you forgot to set repositories.release_to' if upload_to[:url].to_s.blank?
+      invoke # Make sure we exist.
+
+      # Upload POM ahead of package, so we don't fail and find POM-less package (the horror!)
+      pom.upload(upload_to) if pom && pom != self
 
       # Set the upload URI, including mandatory slash (we expect it to be the base directory).
       # Username/password may be part of URI, or separate entities.
       uri = URI.parse(upload_to[:url].clone)
-      uri.path = uri.path + "/" unless uri.path[-1] == "/"
+      uri.path = uri.path + '/' unless uri.path[-1] == '/'
       uri.user = upload_to[:username] if upload_to[:username]
       uri.password = upload_to[:password] if upload_to[:password]
 
       # Upload artifact relative to base URL, need to create path before uploading.
       puts "Deploying #{to_spec}" if verbose
-      path = group.gsub(".", "/") + "/#{id}/#{version}/#{File.basename(name)}"
+      path = group.gsub('.', '/') + "/#{id}/#{version}/#{File.basename(name)}"
       URI.upload uri + path, name, :permissions=>upload_to[:permissions]
     end
 
@@ -149,7 +174,7 @@
     end
     
     def group_path
-      group.gsub(".", "/")
+      group.gsub('.', '/')
     end
 
   end
@@ -182,10 +207,10 @@
       end
 
       # :call-seq:
-      #   list() => specs
+      #   list => specs
       #
       # Returns an array of specs for all the registered artifacts. (Anything created from artifact, or package).
-      def list()
+      def list
         @artifacts.keys
       end
 
@@ -195,7 +220,7 @@
       # Register an artifact task(s) for later lookup (see #lookup).
       def register(*tasks)
         @artifacts ||= {}
-        fail "You can only register an artifact task, one of the arguments is not a Task that responds to to_spec()" unless
+        fail 'You can only register an artifact task, one of the arguments is not a Task that responds to to_spec' unless
           tasks.all? { |task| task.respond_to?(:to_spec) && task.respond_to?(:invoke) }
         tasks.each { |task| @artifacts[task.to_spec] = task }
         tasks
@@ -225,7 +250,7 @@
           spec[:type] = spec[:type].to_s.blank? ? DEFAULT_TYPE : spec[:type].to_sym
           spec
         elsif String === spec
-          group, id, type, version, *rest = spec.split(":")
+          group, id, type, version, *rest = spec.split(':')
           unless rest.empty?
             # Optional classifier comes before version.
             classifier, version = version, rest.shift
@@ -233,7 +258,7 @@
           end
           to_hash :group=>group, :id=>id, :type=>type, :version=>version, :classifier=>classifier
         else
-          fail "Expecting a String, Hash or object that responds to to_spec"
+          fail 'Expecting a String, Hash or object that responds to to_spec'
         end
       end
 
@@ -309,7 +334,7 @@
   protected
 
     # :call-seq:
-    #   download()
+    #   download
     # 
     # Downloads an artifact from one of the remote repositories, and stores it in the local
     # repository. Accepts a String or Hash artifact specification, and returns a path to the
@@ -317,11 +342,11 @@
     #
     # This method attempts to download the artifact from each repository in the order in
     # which they are returned from #remote, until successful. It always downloads the POM first.
-    def download()
+    def download
       puts "Downloading #{to_spec}" if Rake.application.options.trace
       remote = Buildr.repositories.remote.map { |repo_url| URI === repo_url ? repo_url : URI.parse(repo_url) }
-      remote = remote.each { |repo_url| repo_url.path += "/" unless repo_url.path[-1] == "/" }
-      fail "No remote repositories defined!" if remote.empty?
+      remote = remote.each { |repo_url| repo_url.path += '/' unless repo_url.path[-1] == '/' }
+      fail 'No remote repositories defined!' if remote.empty?
       exact_success = remote.find do |repo_url|
         begin
           path = "#{group_path}/#{id}/#{version}/#{File.basename(name)}"
@@ -366,8 +391,8 @@
         metadata_xml = StringIO.new
         URI.download repo_url + metadata_path, metadata_xml
         metadata = REXML::Document.new(metadata_xml.string).root
-        timestamp = REXML::XPath.first(metadata, "//timestamp").text
-        build_number = REXML::XPath.first(metadata, "//buildNumber").text
+        timestamp = REXML::XPath.first(metadata, '//timestamp').text
+        build_number = REXML::XPath.first(metadata, '//buildNumber').text
         snapshot_of = version[0, version.size - 9]
         repo_url + "#{group_path}/#{id}/#{version}/#{id}-#{snapshot_of}-#{timestamp}-#{build_number}.#{type}"
       rescue URI::NotFoundError
@@ -385,19 +410,19 @@
   #
   # You can access this object from the #repositories method. For example:
   #   puts repositories.local
-  #   repositories.remote << "http://example.com/repo"
-  #   repositories.release_to = "sftp://example.com/var/www/public/repo"
+  #   repositories.remote << 'http://example.com/repo'
+  #   repositories.release_to = 'sftp://example.com/var/www/public/repo'
   class Repositories
     include Singleton
 
     # :call-seq:
-    #   local() => path
+    #   local => path
     #
     # Returns the path to the local repository.
     #
     # The default path is .m2/repository relative to the home directory.
-    def local()
-      @local ||= File.expand_path(ENV['M2_REPO'] || ENV["local_repo"] || File.join(ENV['HOME'], ".m2/repository"))
+    def local
+      @local ||= File.expand_path(ENV['M2_REPO'] || ENV['local_repo'] || File.join(ENV['HOME'], '.m2/repository'))
     end
 
     # :call-seq:
@@ -419,22 +444,22 @@
     # a file path.
     #
     # For example:
-    #   locate :group=>"log4j", :id=>"log4j", :version=>"1.1"
+    #   locate :group=>'log4j', :id=>'log4j', :version=>'1.1'
     #     => ~/.m2/repository/log4j/log4j/1.1/log4j-1.1.jar
     def locate(spec)
       spec = Artifact.to_hash(spec)
-      File.join(local, spec[:group].split("."), spec[:id], spec[:version], Artifact.hash_to_file_name(spec))
+      File.join(local, spec[:group].split('.'), spec[:id], spec[:version], Artifact.hash_to_file_name(spec))
     end
 
     # :call-seq:
-    #   remote() => Array
+    #   remote => Array
     #
     # Returns an array of all the remote repository URLs.
     #
     # When downloading artifacts, repositories are accessed in the order in which they appear here.
     # The best way is to add repositories individually, for example:
-    #   repositories.remote << "http://example.com/repo"
-    def remote()
+    #   repositories.remote << 'http://example.com/repo'
+    def remote
       @remote ||= []
     end
 
@@ -469,39 +494,39 @@
     # Besides the URL, all other settings depend on the transport protocol in use.
     #
     # For example:
-    #   repositories.release_to = "sftp://john:secret@example.com/var/www/repo/"
-    #   repositories.release_to = { :url=>"sftp://example.com/var/www/repo/",
-    #                                :username="john", :password=>"secret" }
+    #   repositories.release_to = 'sftp://john:secret@example.com/var/www/repo/'
+    #   repositories.release_to = { :url=>'sftp://example.com/var/www/repo/',
+    #                                :username='john', :password=>'secret' }
     def release_to=(options)
       options = { :url=>options } unless Hash === options
       @release_to = options
     end
 
     # :call-seq:
-    #   release_to() => hash
+    #   release_to => hash
     #
     # Returns the current release server setting as a Hash. This is a more convenient way to
     # configure the settings, as it allows you to specify the settings progressively.
     #
     # For example, the Buildfile will contain the repository URL used by all developers:
-    #   repositories.release_to[:url] ||= "sftp://example.com/var/www/repo"
+    #   repositories.release_to[:url] ||= 'sftp://example.com/var/www/repo'
     # Your private buildr.rb will contain your credentials:
-    #   repositories.release_to[:username] = "john"
-    #   repositories.release_to[:password] = "secret"
-    def release_to()
+    #   repositories.release_to[:username] = 'john'
+    #   repositories.release_to[:password] = 'secret'
+    def release_to
       @release_to ||= {}
     end
 
   end
 
   # :call-seq:
-  #    repositories() => Repositories
+  #    repositories => Repositories
   #
   # Returns an object you can use for setting the local repository path, remote repositories
   # URL and release server settings.
   #
   # See Repositories.
-  def repositories()
+  def repositories
     Repositories.instance
   end
 
@@ -520,20 +545,20 @@
   # a different way of creating the artifact in the local repository. See Artifact for more details.
   #
   # For example, to specify an artifact:
-  #   artifact("log4j:log4j:jar:1.1")
+  #   artifact('log4j:log4j:jar:1.1')
   #
   # To use the artifact in a task:
-  #   compile.with artifact("log4j:log4j:jar:1.1")
+  #   compile.with artifact('log4j:log4j:jar:1.1')
   #
   # To specify an artifact and the means for creating it:
-  #   download(artifact("dojo:dojo-widget:zip:2.0")=>
-  #     "http://download.dojotoolkit.org/release-2.0/dojo-2.0-widget.zip")
+  #   download(artifact('dojo:dojo-widget:zip:2.0')=>
+  #     'http://download.dojotoolkit.org/release-2.0/dojo-2.0-widget.zip')
   def artifact(spec, &block) #:yields:task
     spec = Artifact.to_hash(spec)
     unless task = Artifact.lookup(spec)
       task = Artifact.define_task(repositories.locate(spec))
       task.send :apply_spec, spec
-      Rake::Task["rake:artifacts"].enhance [task]
+      Rake::Task['rake:artifacts'].enhance [task]
       Artifact.register(task)
     end
     task.enhance &block
@@ -559,8 +584,8 @@
   #   artifacts(xml, ws, db)
   #
   # Using artifacts created by a project:
-  #   artifact project("my-app")               # All packages
-  #   artifact project("mu-app").package(:war) # Only the WAR
+  #   artifact project('my-app')               # All packages
+  #   artifact project('mu-app').package(:war) # Only the WAR
   def artifacts(*specs)
     specs.flatten.inject([]) do |set, spec|
       case spec
@@ -614,9 +639,9 @@
   # * :version -- The version number
   #
   # For example:
-  #   group "xbean", "xbean_xpath", "xmlpublic", :under=>"xmlbeans", :version=>"2.1.0"
+  #   group 'xbean', 'xbean_xpath', 'xmlpublic', :under=>'xmlbeans', :version=>'2.1.0'
   # Or:
-  #   group %w{xbean xbean_xpath xmlpublic}, :under=>"xmlbeans", :version=>"2.1.0"
+  #   group %w{xbean xbean_xpath xmlpublic}, :under=>'xmlbeans', :version=>'2.1.0'
   def group(*args)
     hash = args.pop
     args.flatten.map { |id| artifact :group=>hash[:under], :version=>hash[:version], :id=>id }
@@ -655,11 +680,10 @@
   def upload(*args, &block)
     artifacts = artifacts(args)
     raise ArgumentError, 'This method can only upload artifacts' unless artifacts.all? { |f| f.respond_to?(:to_spec) }
-    all = (artifacts + artifacts.map { |artifact| artifact.pom }).uniq
     task('upload').tap do |task|
       task.enhance &block if block
-      task.enhance all do
-        all.each { |artifact| artifact.upload }
+      task.enhance artifacts do
+        artifacts.each { |artifact| artifact.upload }
       end
     end
   end

Modified: incubator/buildr/trunk/lib/java/nailgun.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/java/nailgun.rb?rev=636924&r1=636923&r2=636924&view=diff
==============================================================================
--- incubator/buildr/trunk/lib/java/nailgun.rb (original)
+++ incubator/buildr/trunk/lib/java/nailgun.rb Thu Mar 13 16:46:38 2008
@@ -19,7 +19,7 @@
 require 'jruby'
 require 'thread'
 require 'monitor'
-        require 'benchmark'
+require 'benchmark'
 
 module Buildr
 

Modified: incubator/buildr/trunk/lib/java/org/apache/buildr/JavaTestFilter.class
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/java/org/apache/buildr/JavaTestFilter.class?rev=636924&r1=636923&r2=636924&view=diff
==============================================================================
Binary files /tmp/tmpYbJAzs and /tmp/tmpdsZQD4 differ

Modified: incubator/buildr/trunk/spec/artifact_spec.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/spec/artifact_spec.rb?rev=636924&r1=636923&r2=636924&view=diff
==============================================================================
--- incubator/buildr/trunk/spec/artifact_spec.rb (original)
+++ incubator/buildr/trunk/spec/artifact_spec.rb Thu Mar 13 16:46:38 2008
@@ -19,219 +19,222 @@
 
 describe Artifact do
   before do
-    @spec = { :group=>"com.example", :id=>"library", :type=>:jar, :version=>"2.0" }
+    @spec = { :group=>'com.example', :id=>'library', :type=>:jar, :version=>'2.0' }
     @artifact = artifact(@spec)
-    @classified = artifact(@spec.merge(:classifier=>"all"))
-    @snapshot = artifact(@spec.merge({ :version=>"2.1-SNAPSHOT" }))
+    @classified = artifact(@spec.merge(:classifier=>'all'))
+    @snapshot = artifact(@spec.merge({ :version=>'2.1-SNAPSHOT' }))
   end
 
-  it "should act as one" do
+  it 'should act as one' do
     @artifact.should respond_to(:to_spec)
   end
 
-  it "should have an artifact identifier" do
-    @artifact.id.should eql("library")
+  it 'should have an artifact identifier' do
+    @artifact.id.should eql('library')
   end
 
-  it "should have a group identifier" do
-    @artifact.group.should eql("com.example")
+  it 'should have a group identifier' do
+    @artifact.group.should eql('com.example')
   end
 
-  it "should have a version number" do
-    @artifact.version.should eql("2.0")
+  it 'should have a version number' do
+    @artifact.version.should eql('2.0')
   end
 
-  it "should know if it is a snapshot" do
+  it 'should know if it is a snapshot' do
     @artifact.should_not be_snapshot
     @classified.should_not be_snapshot
     @snapshot.should be_snapshot
   end
 
-  it "should have a file type" do
+  it 'should have a file type' do
     @artifact.type.should eql(:jar)
   end
 
-  it "should understand classifier" do
+  it 'should understand classifier' do
     @artifact.classifier.should be_nil
-    @classified.classifier.should eql("all")
+    @classified.classifier.should eql('all')
   end
 
-  it "should return hash specification" do
+  it 'should return hash specification' do
     @artifact.to_hash.should == @spec
     @artifact.to_spec_hash.should == @spec
-    @classified.to_hash.should == @spec.merge(:classifier=>"all")
+    @classified.to_hash.should == @spec.merge(:classifier=>'all')
   end
 
-  it "should return string specification" do
-    @artifact.to_spec.should eql("com.example:library:jar:2.0")
-    @classified.to_spec.should eql("com.example:library:jar:all:2.0")
+  it 'should return string specification' do
+    @artifact.to_spec.should eql('com.example:library:jar:2.0')
+    @classified.to_spec.should eql('com.example:library:jar:all:2.0')
   end
 
-  it "should have associated POM artifact" do
+  it 'should have associated POM artifact' do
     @artifact.pom.to_hash.should == @artifact.to_hash.merge(:type=>:pom)
+  end
+
+  it 'should have one artifact for all classifiers' do
     @classified.pom.to_hash.should == @classified.to_hash.merge(:type=>:pom).except(:classifier)
   end
 
-  it "should download file if file does not exist" do
+  it 'should download file if file does not exist' do
     lambda { @artifact.invoke }.should raise_error(Exception, /No remote repositories/)
     lambda { @classified.invoke }.should raise_error(Exception, /No remote repositories/)
   end
 
-  it "should not download file if file exists" do
+  it 'should not download file if file exists' do
     write repositories.locate(@artifact)
     lambda { @artifact.invoke }.should_not raise_error
     write repositories.locate(@classified)
     lambda { @classified.invoke }.should_not raise_error
   end
 
-  it "should handle lack of POM gracefully" do
-    repositories.remote = "http://example.com"
-    URI.should_receive(:download).twice { |uri, target, options| raise URI::NotFoundError if uri.to_s.ends_with(".pom") }
+  it 'should handle lack of POM gracefully' do
+    repositories.remote = 'http://example.com'
+    URI.should_receive(:download).twice { |uri, target, options| raise URI::NotFoundError if uri.to_s.ends_with('.pom') }
     lambda { @artifact.invoke }.should_not raise_error
   end
 
-  it "should pass if POM provided" do
-    repositories.remote = "http://example.com"
+  it 'should pass if POM provided' do
+    repositories.remote = 'http://example.com'
     @artifact.pom.enhance { |task| write task.name, @artifact.pom_xml }
     write repositories.locate(@artifact)
     lambda { @artifact.invoke }.should_not raise_error
   end
 
-  it "should pass if POM not required" do
-    repositories.remote = "http://example.com"
+  it 'should pass if POM not required' do
+    repositories.remote = 'http://example.com'
     class << @artifact ; def pom() ; end ; end
     write repositories.locate(@artifact)
     lambda { @artifact.invoke }.should_not raise_error
   end
 
-  it "should not download file if dry-run" do
+  it 'should not download file if dry-run' do
     dryrun do 
       lambda { @artifact.invoke }.should_not raise_error
       lambda { @classified.invoke }.should_not raise_error
     end
   end
 
-  it "should resolve to path in local repository" do
-    @artifact.to_s.should == File.join(repositories.local, "com/example/library/2.0/library-2.0.jar")
-    @classified.to_s.should == File.join(repositories.local, "com/example/library/2.0/library-2.0-all.jar")
+  it 'should resolve to path in local repository' do
+    @artifact.to_s.should == File.join(repositories.local, 'com/example/library/2.0/library-2.0.jar')
+    @classified.to_s.should == File.join(repositories.local, 'com/example/library/2.0/library-2.0-all.jar')
   end
 
-  it "should return a list of all registered artifact specifications" do
-    define("foo", :version=>"1.0") { package :jar }
+  it 'should return a list of all registered artifact specifications' do
+    define('foo', :version=>'1.0') { package :jar }
     Artifact.list.should include(@artifact.to_spec)
     Artifact.list.should include(@classified.to_spec)
-    Artifact.list.should include("foo:foo:jar:1.0")
+    Artifact.list.should include('foo:foo:jar:1.0')
   end
 end
 
 
-describe "repositories.local" do
-  it "should default to .m2 path" do
+describe 'repositories.local' do
+  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'))
   end
 
-  it "should be settable" do
-    repositories.local = ".m2/local"
-    repositories.local.should eql(File.expand_path(".m2/local"))
+  it 'should be settable' do
+    repositories.local = '.m2/local'
+    repositories.local.should eql(File.expand_path('.m2/local'))
   end
 
-  it "should reset to default" do
-    repositories.local = ".m2/local"
+  it 'should reset to default' do
+    repositories.local = '.m2/local'
     repositories.local = nil
-    repositories.local.should eql(File.expand_path("~/.m2/repository"))
+    repositories.local.should eql(File.expand_path('~/.m2/repository'))
   end
 
-  it "should locate file from string specification" do
+  it 'should locate file from string specification' do
     repositories.local = nil
-    repositories.locate("com.example:library:jar:2.0").should eql(
-      File.expand_path("~/.m2/repository/com/example/library/2.0/library-2.0.jar"))
+    repositories.locate('com.example:library:jar:2.0').should eql(
+      File.expand_path('~/.m2/repository/com/example/library/2.0/library-2.0.jar'))
   end
 
-  it "should locate file from hash specification" do
+  it 'should locate file from hash specification' do
     repositories.local = nil
-    repositories.locate(:group=>"com.example", :id=>"library", :version=>"2.0").should eql(
-      File.expand_path("~/.m2/repository/com/example/library/2.0/library-2.0.jar"))
+    repositories.locate(:group=>'com.example', :id=>'library', :version=>'2.0').should eql(
+      File.expand_path('~/.m2/repository/com/example/library/2.0/library-2.0.jar'))
   end
 end
 
 
-describe "repositories.remote" do
+describe 'repositories.remote' do
   before do
-    @repos = [ "http://www.ibiblio.org/maven2", "http://repo1.maven.org/maven2" ]
+    @repos = [ 'http://www.ibiblio.org/maven2', 'http://repo1.maven.org/maven2' ]
   end
 
-  it "should be empty initially" do
+  it 'should be empty initially' do
     repositories.remote.should be_empty
   end
 
-  it "should be settable" do
+  it 'should be settable' do
     repositories.remote = @repos.first
     repositories.remote.should eql([@repos.first])
   end
 
-  it "should be settable from array" do
+  it 'should be settable from array' do
     repositories.remote = @repos
     repositories.remote.should eql(@repos)
   end
 
-  it "should add and return repositories in order" do
+  it 'should add and return repositories in order' do
     @repos.each { |url| repositories.remote << url }
     repositories.remote.should eql(@repos)
   end
 
-  it "should be used to download artifact" do
-    repositories.remote = "http://example.com"
+  it 'should be used to download artifact' do
+    repositories.remote = 'http://example.com'
     URI.should_receive(:download).twice.and_return { |uri, target, options| write target }
-    lambda { artifact("com.example:library:jar:2.0").invoke }.
-      should change { File.exist?(File.join(repositories.local, "com/example/library/2.0/library-2.0.jar")) }.to(true)
+    lambda { artifact('com.example:library:jar:2.0').invoke }.
+      should change { File.exist?(File.join(repositories.local, 'com/example/library/2.0/library-2.0.jar')) }.to(true)
   end
 
-  it "should lookup in array order" do
-    repositories.remote = [ "http://example.com", "http://example.org" ]
-    order = ["com", "org"]
+  it 'should lookup in array order' do
+    repositories.remote = [ 'http://example.com', 'http://example.org' ]
+    order = ['com', 'org']
     URI.should_receive(:download).any_number_of_times do |uri, target, options|
       order.shift if order.first && uri.to_s[order.first]
       fail URI::NotFoundError unless order.empty?
       write target
     end
-    lambda { artifact("com.example:library:jar:2.0").invoke }.should change { order.empty? }
+    lambda { artifact('com.example:library:jar:2.0').invoke }.should change { order.empty? }
   end
 
-  it "should fail if artifact not found" do
-    repositories.remote = "http://example.com"
+  it 'should fail if artifact not found' do
+    repositories.remote = 'http://example.com'
     URI.should_receive(:download).once.ordered.and_return { fail URI::NotFoundError }
-    lambda { artifact("com.example:library:jar:2.0").invoke }.should raise_error(RuntimeError, /Failed to download/)
-    File.exist?(File.join(repositories.local, "com/example/library/2.0/library-2.0.jar")).should be_false
+    lambda { artifact('com.example:library:jar:2.0').invoke }.should raise_error(RuntimeError, /Failed to download/)
+    File.exist?(File.join(repositories.local, 'com/example/library/2.0/library-2.0.jar')).should be_false
   end
 
-  it "should support artifact classifier" do
-    repositories.remote = "http://example.com"
+  it 'should support artifact classifier' do
+    repositories.remote = 'http://example.com'
     URI.should_receive(:download).twice.and_return { |uri, target, options| write target }
-    lambda { artifact("com.example:library:jar:all:2.0").invoke }.
-      should change { File.exist?(File.join(repositories.local, "com/example/library/2.0/library-2.0-all.jar")) }.to(true)
+    lambda { artifact('com.example:library:jar:all:2.0').invoke }.
+      should change { File.exist?(File.join(repositories.local, 'com/example/library/2.0/library-2.0-all.jar')) }.to(true)
   end
 
-  it "should deal well with repositories URL that lack the last slash" do
-    repositories.remote = "http://example.com/base"
+  it 'should deal well with repositories URL that lack the last slash' do
+    repositories.remote = 'http://example.com/base'
     uri = nil
     URI.should_receive(:download).twice.and_return { |uri, target, options| }
-    artifact("group:id:jar:1.0").invoke
-    uri.to_s.should eql("http://example.com/base/group/id/1.0/id-1.0.pom")
+    artifact('group:id:jar:1.0').invoke
+    uri.to_s.should eql('http://example.com/base/group/id/1.0/id-1.0.pom')
   end
 
-  it "should deal well with repositories URL that have the last slash" do
-    repositories.remote = "http://example.com/base/"
+  it 'should deal well with repositories URL that have the last slash' do
+    repositories.remote = 'http://example.com/base/'
     uri = nil
     URI.should_receive(:download).twice.and_return { |uri, target, options| }
-    artifact("group:id:jar:1.0").invoke
-    uri.to_s.should eql("http://example.com/base/group/id/1.0/id-1.0.pom")
+    artifact('group:id:jar:1.0').invoke
+    uri.to_s.should eql('http://example.com/base/group/id/1.0/id-1.0.pom')
   end
   
-  it "should resolve m2-style deployed snapshots" do
+  it 'should resolve m2-style deployed snapshots' do
     metadata = <<-XML
-    <?xml version="1.0" encoding="UTF-8"?>
+    <?xml version='1.0' encoding='UTF-8'?>
     <metadata>
       <groupId>com.example</groupId>
       <artifactId>library</artifactId>
@@ -245,30 +248,30 @@
       </versioning>
     </metadata>
     XML
-    repositories.remote = "http://example.com"
+    repositories.remote = 'http://example.com'
     URI.should_receive(:download).twice.with(uri(/2.1-SNAPSHOT\/library-2.1-SNAPSHOT.(jar|pom)$/), anything()).
       and_return { fail URI::NotFoundError }
     URI.should_receive(:download).twice.with(uri(/2.1-SNAPSHOT\/maven-metadata.xml$/), duck_type(:write)).
       and_return { |uri, target, options| target.write(metadata) }
     URI.should_receive(:download).twice.with(uri(/2.1-SNAPSHOT\/library-2.1-20071012.190008-8.(jar|pom)$/), /2.1-SNAPSHOT\/library-2.1-SNAPSHOT.(jar|pom)$/).
       and_return { |uri, target, options| write target }
-    lambda { artifact("com.example:library:jar:2.1-SNAPSHOT").invoke }.
-      should change { File.exist?(File.join(repositories.local, "com/example/library/2.1-SNAPSHOT/library-2.1-SNAPSHOT.jar")) }.to(true)
+    lambda { artifact('com.example:library:jar:2.1-SNAPSHOT').invoke }.
+      should change { File.exist?(File.join(repositories.local, 'com/example/library/2.1-SNAPSHOT/library-2.1-SNAPSHOT.jar')) }.to(true)
   end
   
-  it "should handle missing maven metadata by reporting the artifact unavailable" do
-    repositories.remote = "http://example.com"
+  it 'should handle missing maven metadata by reporting the artifact unavailable' do
+    repositories.remote = 'http://example.com'
     URI.should_receive(:download).with(uri(/2.1-SNAPSHOT\/library-2.1-SNAPSHOT.jar$/), anything()).
       and_return { fail URI::NotFoundError }
     URI.should_receive(:download).with(uri(/2.1-SNAPSHOT\/maven-metadata.xml$/), duck_type(:write)).
       and_return { fail URI::NotFoundError }
-    lambda { artifact("com.example:library:jar:2.1-SNAPSHOT").invoke }.should raise_error(RuntimeError, /Failed to download/)
-    File.exist?(File.join(repositories.local, "com/example/library/2.1-SNAPSHOT/library-2.1-SNAPSHOT.jar")).should be_false
+    lambda { artifact('com.example:library:jar:2.1-SNAPSHOT').invoke }.should raise_error(RuntimeError, /Failed to download/)
+    File.exist?(File.join(repositories.local, 'com/example/library/2.1-SNAPSHOT/library-2.1-SNAPSHOT.jar')).should be_false
   end
   
-  it "should handle missing m2 snapshots by reporting the artifact unavailable" do
+  it 'should handle missing m2 snapshots by reporting the artifact unavailable' do
     metadata = <<-XML
-    <?xml version="1.0" encoding="UTF-8"?>
+    <?xml version='1.0' encoding='UTF-8'?>
     <metadata>
       <groupId>com.example</groupId>
       <artifactId>library</artifactId>
@@ -282,151 +285,151 @@
       </versioning>
     </metadata>
     XML
-    repositories.remote = "http://example.com"
+    repositories.remote = 'http://example.com'
     URI.should_receive(:download).with(uri(/2.1-SNAPSHOT\/library-2.1-SNAPSHOT.jar$/), anything()).
       and_return { fail URI::NotFoundError }
     URI.should_receive(:download).with(uri(/2.1-SNAPSHOT\/maven-metadata.xml$/), duck_type(:write)).
       and_return { |uri, target, options| target.write(metadata) }
     URI.should_receive(:download).with(uri(/2.1-SNAPSHOT\/library-2.1-20071012.190008-8.jar$/), anything()).
       and_return { fail URI::NotFoundError }
-    lambda { artifact("com.example:library:jar:2.1-SNAPSHOT").invoke }.should raise_error(RuntimeError, /Failed to download/)
-    File.exist?(File.join(repositories.local, "com/example/library/2.1-SNAPSHOT/library-2.1-SNAPSHOT.jar")).should be_false
+    lambda { artifact('com.example:library:jar:2.1-SNAPSHOT').invoke }.should raise_error(RuntimeError, /Failed to download/)
+    File.exist?(File.join(repositories.local, 'com/example/library/2.1-SNAPSHOT/library-2.1-SNAPSHOT.jar')).should be_false
   end
 end
 
 
-describe "repositories.release_to" do
-  it "should accept URL as first argument" do
-    repositories.release_to = "http://example.com"
-    repositories.release_to.should == { :url=>"http://example.com" }
+describe 'repositories.release_to' do
+  it 'should accept URL as first argument' do
+    repositories.release_to = 'http://example.com'
+    repositories.release_to.should == { :url=>'http://example.com' }
   end
 
-  it "should accept hash with options" do
-    repositories.release_to = { :url=>"http://example.com", :username=>"john" }
-    repositories.release_to.should == { :url=>"http://example.com", :username=>"john" }
+  it 'should accept hash with options' do
+    repositories.release_to = { :url=>'http://example.com', :username=>'john' }
+    repositories.release_to.should == { :url=>'http://example.com', :username=>'john' }
   end
 
-  it "should allow the hash to be manipulated" do
-    repositories.release_to = "http://example.com"
-    repositories.release_to.should == { :url=>"http://example.com" }
-    repositories.release_to[:username] = "john"
-    repositories.release_to.should == { :url=>"http://example.com", :username=>"john" }
+  it 'should allow the hash to be manipulated' do
+    repositories.release_to = 'http://example.com'
+    repositories.release_to.should == { :url=>'http://example.com' }
+    repositories.release_to[:username] = 'john'
+    repositories.release_to.should == { :url=>'http://example.com', :username=>'john' }
   end
 end
 
 
-describe Buildr, "#artifact" do
-  before { @spec = { :group=>"com.example", :id=>"library", :type=>"jar", :version=>"2.0" } }
+describe Buildr, '#artifact' do
+  before { @spec = { :group=>'com.example', :id=>'library', :type=>'jar', :version=>'2.0' } }
 
-  it "should accept hash specification" do
-    artifact(:group=>"com.example", :id=>"library", :type=>"jar", :version=>"2.0").should respond_to(:invoke)
+  it 'should accept hash specification' do
+    artifact(:group=>'com.example', :id=>'library', :type=>'jar', :version=>'2.0').should respond_to(:invoke)
   end
 
-  it "should reject partial hash specifier" do
+  it 'should reject partial hash specifier' do
     lambda { artifact(@spec.merge(:group=>nil)) }.should raise_error
     lambda { artifact(@spec.merge(:id=>nil)) }.should raise_error
     lambda { artifact(@spec.merge(:version=>nil)) }.should raise_error
   end
 
-  it "should complain about invalid key" do
+  it 'should complain about invalid key' do
     lambda { artifact(@spec.merge(:error=>true)) }.should raise_error(ArgumentError, /no such option/i)
   end
   
-  it "should use JAR type by default" do
+  it 'should use JAR type by default' do
     artifact(@spec.merge(:type=>nil)).should respond_to(:invoke)
   end
 
-  it "should accept string specification" do
-    artifact("com.example:library:jar:2.0").should respond_to(:invoke)
+  it 'should accept string specification' do
+    artifact('com.example:library:jar:2.0').should respond_to(:invoke)
   end
 
-  it "should reject partial string specifier" do
-    lambda { artifact("com.example:library:jar") }.should raise_error
-    lambda { artifact("com.example:library:jar:") }.should raise_error
-    lambda { artifact("com.example:library::2.0") }.should_not raise_error
-    lambda { artifact("com.example::jar:2.0") }.should raise_error
-    lambda { artifact(":library:jar:2.0") }.should raise_error
+  it 'should reject partial string specifier' do
+    lambda { artifact('com.example:library:jar') }.should raise_error
+    lambda { artifact('com.example:library:jar:') }.should raise_error
+    lambda { artifact('com.example:library::2.0') }.should_not raise_error
+    lambda { artifact('com.example::jar:2.0') }.should raise_error
+    lambda { artifact(':library:jar:2.0') }.should raise_error
   end
 
-  it "should create a task naming the artifact in the local repository" do
-    file = File.join(repositories.local, "com", "example", "library", "2.0", "library-2.0.jar")
+  it 'should create a task naming the artifact in the local repository' do
+    file = File.join(repositories.local, 'com', 'example', 'library', '2.0', 'library-2.0.jar')
     Rake::Task.task_defined?(file).should be_false
-    artifact("com.example:library:jar:2.0").name.should eql(file)
+    artifact('com.example:library:jar:2.0').name.should eql(file)
   end
 
-  it "should use from method to install artifact from existing file" do
-    write "test.jar"
-    artifact = artifact("group:id:jar:1.0").from("test.jar")
+  it 'should use from method to install artifact from existing file' do
+    write 'test.jar'
+    artifact = artifact('group:id:jar:1.0').from('test.jar')
     lambda { artifact.invoke }.should change { File.exist?(artifact.to_s) }.to(true)
   end
 end
 
 
-describe Buildr, "#artifacts" do
-  it "should return a list of artifacts from all its arguments" do
-    specs = [ "saxon:saxon:jar:8.4", "saxon:saxon-dom:jar:8.4", "saxon:saxon-xpath:jar:8.4" ]
+describe Buildr, '#artifacts' do
+  it 'should return a list of artifacts from all its arguments' do
+    specs = [ 'saxon:saxon:jar:8.4', 'saxon:saxon-dom:jar:8.4', 'saxon:saxon-xpath:jar:8.4' ]
     artifacts(*specs).should eql(specs.map { |spec| artifact(spec) })
   end
 
-  it "should accept nested arrays" do
-    specs = [ "saxon:saxon:jar:8.4", "saxon:saxon-dom:jar:8.4", "saxon:saxon-xpath:jar:8.4" ]
+  it 'should accept nested arrays' do
+    specs = [ 'saxon:saxon:jar:8.4', 'saxon:saxon-dom:jar:8.4', 'saxon:saxon-xpath:jar:8.4' ]
     artifacts([[specs[0]]], [[specs[1]], specs[2]]).should eql(specs.map { |spec| artifact(spec) })
   end
 
-  it "should accept struct" do
-    specs = struct(:main=>"saxon:saxon:jar:8.4", :dom=>"saxon:saxon-dom:jar:8.4", :xpath=>"saxon:saxon-xpath:jar:8.4")
+  it 'should accept struct' do
+    specs = struct(:main=>'saxon:saxon:jar:8.4', :dom=>'saxon:saxon-dom:jar:8.4', :xpath=>'saxon:saxon-xpath:jar:8.4')
     artifacts(specs).should eql(specs.values.map { |spec| artifact(spec) })
   end
 
-  it "should ignore duplicates" do
-    artifacts("saxon:saxon:jar:8.4", "saxon:saxon:jar:8.4").size.should be(1)
+  it 'should ignore duplicates' do
+    artifacts('saxon:saxon:jar:8.4', 'saxon:saxon:jar:8.4').size.should be(1)
   end
 
-  it "should accept and return existing tasks" do
-    artifacts(task("foo"), task("bar")).should eql([task("foo"), task("bar")])
+  it 'should accept and return existing tasks' do
+    artifacts(task('foo'), task('bar')).should eql([task('foo'), task('bar')])
   end
 
-  it "should accept filenames and expand them" do
-    artifacts("test").map(&:to_s).should eql([File.expand_path("test")])
+  it 'should accept filenames and expand them' do
+    artifacts('test').map(&:to_s).should eql([File.expand_path('test')])
   end
 
-  it "should accept filenames and return filenames" do
-    artifacts("c:test").first.should be_kind_of(String)
+  it 'should accept filenames and return filenames' do
+    artifacts('c:test').first.should be_kind_of(String)
   end
 
-  it "should accept project and return all its packaging tasks" do
-    define "foobar", :group=>"group", :version=>"1.0" do
-      package :jar, :id=>"code"
-      package :war, :id=>"webapp"
+  it 'should accept project and return all its packaging tasks' do
+    define 'foobar', :group=>'group', :version=>'1.0' do
+      package :jar, :id=>'code'
+      package :war, :id=>'webapp'
     end
-    foobar = project("foobar")
+    foobar = project('foobar')
     artifacts(foobar).should eql([
-      task(foobar.path_to("target/code-1.0.jar")),
-      task(foobar.path_to("target/webapp-1.0.war"))
+      task(foobar.path_to('target/code-1.0.jar')),
+      task(foobar.path_to('target/webapp-1.0.war'))
     ])
   end
 
-  it "should complain about an invalid specification" do
+  it 'should complain about an invalid specification' do
     lambda { artifacts(5) }.should raise_error
-    lambda { artifacts("group:no:version:") }.should raise_error
+    lambda { artifacts('group:no:version:') }.should raise_error
   end
 end
 
 
-describe Buildr, "#group" do
-  it "should accept list of artifact identifiers" do
-    list = group("saxon", "saxon-dom", "saxon-xpath", :under=>"saxon", :version=>"8.4")
-    list.should include(artifact("saxon:saxon:jar:8.4"))
-    list.should include(artifact("saxon:saxon-dom:jar:8.4"))
-    list.should include(artifact("saxon:saxon-xpath:jar:8.4"))
+describe Buildr, '#group' do
+  it 'should accept list of artifact identifiers' do
+    list = group('saxon', 'saxon-dom', 'saxon-xpath', :under=>'saxon', :version=>'8.4')
+    list.should include(artifact('saxon:saxon:jar:8.4'))
+    list.should include(artifact('saxon:saxon-dom:jar:8.4'))
+    list.should include(artifact('saxon:saxon-xpath:jar:8.4'))
     list.size.should be(3)
   end
 
-  it "should accept array with artifact identifiers" do
-    list = group(%w{saxon saxon-dom saxon-xpath}, :under=>"saxon", :version=>"8.4")
-    list.should include(artifact("saxon:saxon:jar:8.4"))
-    list.should include(artifact("saxon:saxon-dom:jar:8.4"))
-    list.should include(artifact("saxon:saxon-xpath:jar:8.4"))
+  it 'should accept array with artifact identifiers' do
+    list = group(%w{saxon saxon-dom saxon-xpath}, :under=>'saxon', :version=>'8.4')
+    list.should include(artifact('saxon:saxon:jar:8.4'))
+    list.should include(artifact('saxon:saxon-dom:jar:8.4'))
+    list.should include(artifact('saxon:saxon-xpath:jar:8.4'))
     list.size.should be(3)
   end
 end
@@ -489,69 +492,81 @@
 end
 
 
-describe ActsAsArtifact, "#upload" do
-  it "should be used to upload artifact" do
-    test_upload artifact("com.example:library:jar:2.0"), "com/example/library/2.0/library-2.0.jar"
-  end
-
-  it "should support artifact classifier" do
-    test_upload artifact("com.example:library:jar:all:2.0"), "com/example/library/2.0/library-2.0-all.jar"
+describe ActsAsArtifact, '#upload' do
+  it 'should be used to upload artifact' do
+    artifact = artifact('com.example:library:jar:2.0')
+    # Prevent artifact from downloading anything.
+    write repositories.locate(artifact)
+    write repositories.locate(artifact.pom)
+    URI.should_receive(:upload).once.
+      with(URI.parse('sftp://example.com/base/com/example/library/2.0/library-2.0.pom'), artifact.pom.to_s, anything)
+    URI.should_receive(:upload).once.
+      with(URI.parse('sftp://example.com/base/com/example/library/2.0/library-2.0.jar'), artifact.to_s, anything)
+    verbose(false) { artifact.upload(:url=>'sftp://example.com/base') }
   end
 
-  def test_upload(artifact, path)
+  it 'should support artifact classifier' do
+    artifact = artifact('com.example:library:jar:all:2.0')
     # Prevent artifact from downloading anything.
     write repositories.locate(artifact)
-    URI.should_receive(:upload).once.with(URI.parse("sftp://example.com/base/#{path}"), artifact.to_s, anything)
-    verbose(false) { artifact.upload(:url=>"sftp://example.com/base") }
+    write repositories.locate(artifact.pom)
+    URI.should_receive(:upload).at_least(:once).
+      with(URI.parse('sftp://example.com/base/com/example/library/2.0/library-2.0.pom'), artifact.pom.to_s, anything)
+    URI.should_receive(:upload).at_least(:once).
+      with(URI.parse('sftp://example.com/base/com/example/library/2.0/library-2.0-all.jar'), artifact.to_s, anything)
+    verbose(false) { artifact.upload(:url=>'sftp://example.com/base') }
   end
 
-  it "should complain without any repository configuration" do
-    artifact = artifact("com.example:library:jar:2.0")
+  it 'should complain without any repository configuration' do
+    artifact = artifact('com.example:library:jar:2.0')
     # Prevent artifact from downloading anything.
     write repositories.locate(artifact)
+    write repositories.locate(artifact.pom)
     lambda { artifact.upload }.should raise_error(Exception, /where to upload/)
   end
 
-  it "should accept repositories.upload setting" do
-    artifact = artifact("com.example:library:jar:2.0")
+  it 'should accept repositories.upload setting' do
+    artifact = artifact('com.example:library:jar:2.0')
     # Prevent artifact from downloading anything.
     write repositories.locate(artifact)
-    URI.should_receive(:upload).once
-    repositories.release_to = "sftp://example.com/base"
+    write repositories.locate(artifact.pom)
+    URI.should_receive(:upload).at_least(:once)
+    repositories.release_to = 'sftp://example.com/base'
+    artifact.upload
     lambda { artifact.upload }.should_not raise_error
   end
 end
 
 
-describe Rake::Task, " artifacts" do
-  it "should download all specified artifacts" do
-    artifact "group:id:jar:1.0"
-    repositories.remote = "http://example.com"
+describe Rake::Task, ' artifacts' do
+  it 'should download all specified artifacts' do
+    artifact 'group:id:jar:1.0'
+    repositories.remote = 'http://example.com'
     URI.should_receive(:download).twice.and_return { |uri, target, options| write target }
-    task("artifacts").invoke
+    task('artifacts').invoke
   end
 
-  it "should fail if failed to download an artifact" do
-    artifact "group:id:jar:1.0"
-    lambda { task("artifacts").invoke }.should raise_error(RuntimeError, /No remote repositories/)
+  it 'should fail if failed to download an artifact' do
+    artifact 'group:id:jar:1.0'
+    lambda { task('artifacts').invoke }.should raise_error(RuntimeError, /No remote repositories/)
   end
 
-  it "should succeed if artifact already exists" do
-    write repositories.locate(artifact("group:id:jar:1.0"))
+  it 'should succeed if artifact already exists' do
+    write repositories.locate(artifact('group:id:jar:1.0'))
     suppress_stdout do
-      lambda { task("artifacts").invoke }.should_not raise_error
+      lambda { task('artifacts').invoke }.should_not raise_error
     end
   end
 end
 
 
-describe Buildr, "#transitive" do
+describe Buildr, '#transitive' do
   before do
-    repositories.remote = "http://example.com"
-    @simple = [ "saxon:saxon:jar:8.4", "saxon:saxon-dom:jar:8.4", "saxon:saxon-xpath:jar:8.4" ]
+    repositories.remote = 'http://example.com'
+    @simple = [ 'saxon:saxon:jar:8.4', 'saxon:saxon-dom:jar:8.4', 'saxon:saxon-xpath:jar:8.4' ]
     @simple.map { |spec| artifact(spec).pom }.each { |task| write task.name, task.pom_xml }
     @provided = @simple.first
-    @complex = "group:app:jar:1.0"
+    @complex = 'group:app:jar:1.0'
     write artifact(@complex).pom.to_s, <<-XML
 <project>
   <artifactId>app</artifactId>
@@ -583,7 +598,7 @@
   </dependencies>
 </project>
 XML
-    @transitive = "master:app:war:1.0"
+    @transitive = 'master:app:war:1.0'
     write artifact(@transitive).pom.to_s, <<-XML
 <project>
   <artifactId>app</artifactId>
@@ -599,63 +614,63 @@
 XML
   end
 
-  it "should return a list of artifacts from all its arguments" do
-    specs = [ "saxon:saxon:jar:8.4", "saxon:saxon-dom:jar:8.4", "saxon:saxon-xpath:jar:8.4" ]
+  it 'should return a list of artifacts from all its arguments' do
+    specs = [ 'saxon:saxon:jar:8.4', 'saxon:saxon-dom:jar:8.4', 'saxon:saxon-xpath:jar:8.4' ]
     transitive(*specs).should eql(specs.map { |spec| artifact(spec) })
   end
 
-  it "should accept nested arrays" do
-    specs = [ "saxon:saxon:jar:8.4", "saxon:saxon-dom:jar:8.4", "saxon:saxon-xpath:jar:8.4" ]
+  it 'should accept nested arrays' do
+    specs = [ 'saxon:saxon:jar:8.4', 'saxon:saxon-dom:jar:8.4', 'saxon:saxon-xpath:jar:8.4' ]
     transitive([[specs[0]]], [[specs[1]], specs[2]]).should eql(specs.map { |spec| artifact(spec) })
   end
 
-  it "should accept struct" do
-    specs = struct(:main=>"saxon:saxon:jar:8.4", :dom=>"saxon:saxon-dom:jar:8.4", :xpath=>"saxon:saxon-xpath:jar:8.4")
+  it 'should accept struct' do
+    specs = struct(:main=>'saxon:saxon:jar:8.4', :dom=>'saxon:saxon-dom:jar:8.4', :xpath=>'saxon:saxon-xpath:jar:8.4')
     transitive(specs).should eql(specs.values.map { |spec| artifact(spec) })
   end
 
-  it "should ignore duplicates" do
-    transitive("saxon:saxon:jar:8.4", "saxon:saxon:jar:8.4").size.should be(1)
+  it 'should ignore duplicates' do
+    transitive('saxon:saxon:jar:8.4', 'saxon:saxon:jar:8.4').size.should be(1)
   end
 
-  it "should accept and return existing tasks" do
-    transitive(task("foo"), task("bar")).should eql([task("foo"), task("bar")])
+  it 'should accept and return existing tasks' do
+    transitive(task('foo'), task('bar')).should eql([task('foo'), task('bar')])
   end
 
-  it "should accept filenames and expand them" do
-    transitive("test").map(&:to_s).should eql([File.expand_path("test")])
+  it 'should accept filenames and expand them' do
+    transitive('test').map(&:to_s).should eql([File.expand_path('test')])
   end
 
-  it "should accept filenames and return file task" do
-    transitive("c:test").first.should be_kind_of(Rake::FileTask)
+  it 'should accept filenames and return file task' do
+    transitive('c:test').first.should be_kind_of(Rake::FileTask)
   end
 
-  it "should accept project and return all its packaging tasks" do
-    define "foobar", :group=>"group", :version=>"1.0" do
-      package :jar, :id=>"code"
-      package :war, :id=>"webapp"
+  it 'should accept project and return all its packaging tasks' do
+    define 'foobar', :group=>'group', :version=>'1.0' do
+      package :jar, :id=>'code'
+      package :war, :id=>'webapp'
     end
-    foobar = project("foobar")
+    foobar = project('foobar')
     transitive(foobar).should eql([
-      task(foobar.path_to("target/code-1.0.jar")),
-      task(foobar.path_to("target/webapp-1.0.war"))
+      task(foobar.path_to('target/code-1.0.jar')),
+      task(foobar.path_to('target/webapp-1.0.war'))
     ])
   end
 
-  it "should complain about an invalid specification" do
+  it 'should complain about an invalid specification' do
     lambda { transitive(5) }.should raise_error
-    lambda { transitive("group:no:version:") }.should raise_error
+    lambda { transitive('group:no:version:') }.should raise_error
   end
 
-  it "should bring artifact and its dependencies" do
+  it 'should bring artifact and its dependencies' do
     transitive(@complex).should eql(artifacts(@complex, @simple))
   end
 
-  it "should bring dependencies of POM without artifact itself" do
-    transitive(@complex.sub(/jar/, "pom")).should eql(artifacts(@simple))
+  it 'should bring dependencies of POM without artifact itself' do
+    transitive(@complex.sub(/jar/, 'pom')).should eql(artifacts(@simple))
   end
 
-  it "should bring artifact and transitive depenencies" do
+  it 'should bring artifact and transitive depenencies' do
     transitive(@transitive).should eql(artifacts(@transitive, @complex, @simple - [@provided]))
   end
 end