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 2007/11/14 00:44:17 UTC
svn commit: r594720 [7/9] - in /incubator/buildr/trunk: ./ bin/ doc/
doc/css/ doc/images/ doc/pages/ lib/ lib/buildr/ lib/buildr/jetty/
lib/core/ lib/java/ lib/tasks/ test/
Added: incubator/buildr/trunk/lib/tasks/zip.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/tasks/zip.rb?rev=594720&view=auto
==============================================================================
--- incubator/buildr/trunk/lib/tasks/zip.rb (added)
+++ incubator/buildr/trunk/lib/tasks/zip.rb Tue Nov 13 15:44:11 2007
@@ -0,0 +1,671 @@
+require "zip/zip"
+require "zip/zipfilesystem"
+
+
+module Buildr
+
+ # Base class for ZipTask, TarTask and other archives.
+ class ArchiveTask < Rake::FileTask
+
+ # Which files go where. All the rules for including, excluding and merging files
+ # are handled by this object.
+ class Path #:nodoc:
+
+ # Returns the archive from this path.
+ attr_reader :root
+
+ def initialize(root, path)
+ @root = root
+ @path = path.blank? ? path : "#{path}/"
+ @includes = FileList[]
+ @excludes = []
+ # Expand source files added to this path.
+ expand_src = proc { @includes.map{ |file| file.to_s }.uniq }
+ @sources = [ expand_src ]
+ # Add files and directories added to this path.
+ @actions = [] << proc do |file_map|
+ expand_src.call.each do |path|
+ unless excluded?(path)
+ if File.directory?(path)
+ in_directory path do |file, rel_path|
+ dest = "#{@path}#{rel_path}"
+ puts "Adding #{dest}" if Rake.application.options.trace
+ file_map[dest] = file
+ end
+ else
+ puts "Adding #{@path}#{File.basename(path)}" if Rake.application.options.trace
+ file_map["#{@path}#{File.basename(path)}"] = path
+ end
+ end
+ end
+ end
+ end
+
+ # :call-seq:
+ # include(*files) => self
+ # include(*files, :path=>path) => self
+ # include(file, :as=>name) => self
+ # include(:from=>path) => self
+ # include(*files, :merge=>true) => self
+ def include(*args)
+ options = args.pop if Hash === args.last
+ files = args.flatten
+
+ if options.nil? || options.empty?
+ @includes.include *files.flatten
+ elsif options[:path]
+ sans_path = options.reject { |k,v| k == :path }
+ path(options[:path]).include *files + [sans_path]
+ elsif options[:as]
+ raise "You can only use the :as option in combination with the :path option" unless options.size == 1
+ raise "You can only use one file with the :as option" unless files.size == 1
+ include_as files.first.to_s, options[:as]
+ elsif options[:from]
+ raise "You can only use the :from option in combination with the :path option" unless options.size == 1
+ raise "You canont use the :from option with file names" unless files.empty?
+ [options[:from]].flatten.each { |path| include_as path.to_s, "." }
+ elsif options[:merge]
+ raise "You can only use the :merge option in combination with the :path option" unless options.size == 1
+ files.each { |file| merge file }
+ else
+ raise "Unrecognized option #{options.keys.join(", ")}"
+ end
+ self
+ end
+ alias :add :include
+
+ # :call-seq:
+ # exclude(*files) => self
+ def exclude(*files)
+ files = files.flatten.map(&:to_s)
+ @excludes |= files
+ @excludes |= files.reject { |f| f =~ /\*$/ }.map { |f| "#{f}/*" }
+ self
+ end
+
+ # :call-seq:
+ # merge(*files) => Merge
+ # merge(*files, :path=>name) => Merge
+ def merge(*args)
+ options = args.pop if Hash === args.last
+ files = args.flatten
+
+ if options.nil? || options.empty?
+ files.collect do |file|
+ @sources << proc { file.to_s }
+ expander = ZipExpander.new(file)
+ @actions << proc { |file_map| expander.expand(file_map, @path) }
+ expander
+ end.first
+ elsif options[:path]
+ sans_path = options.reject { |k,v| k == :path }
+ path(options[:path]).merge *files + [sans_path]
+ self
+ else
+ raise "Unrecognized option #{options.keys.join(", ")}"
+ end
+ end
+
+ # Returns a Path relative to this one.
+ def path(path)
+ return self if path.blank?
+ return root.path(path[1..-1]) if path[0] == ?/
+ root.path("#{@path}#{path}")
+ end
+
+ # Returns all the source files.
+ def sources() #:nodoc:
+ @sources.map{ |source| source.call }.flatten
+ end
+
+ def add_files(file_map) #:nodoc:
+ @actions.each { |action| action.call(file_map) }
+ end
+
+ def to_s()
+ @path
+ end
+
+ protected
+
+ def include_as(source, as)
+ @sources << proc { source }
+ @actions << proc do |file_map|
+ file = source.to_s
+ unless excluded?(file)
+ if File.directory?(file)
+ in_directory file do |file, rel_path|
+ path = rel_path.split("/")[1..-1]
+ path.unshift as unless as == "."
+ dest = "#{@path}#{path.join('/')}"
+ puts "Adding #{dest}" if Rake.application.options.trace
+ file_map[dest] = file
+ end
+ else
+ puts "Adding #{@path}#{as}" if Rake.application.options.trace
+ file_map["#{@path}#{as}"] = file
+ end
+ end
+ end
+ end
+
+ def in_directory(dir)
+ prefix = Regexp.new("^" + Regexp.escape(File.dirname(dir) + File::SEPARATOR))
+ FileList.recursive(dir).reject { |file| excluded?(file) }.
+ each { |file| yield file, file.sub(prefix, "") }
+ end
+
+ def excluded?(file)
+ @excludes.any? { |exclude| File.fnmatch(exclude, file) }
+ end
+
+ end
+
+
+ # Extend one Zip file into another.
+ class ZipExpander #:nodoc:
+
+ def initialize(zip_file)
+ @zip_file = zip_file.to_s
+ @includes = []
+ @excludes = []
+ end
+
+ def include(*files)
+ @includes |= files
+ self
+ end
+
+ def exclude(*files)
+ @excludes |= files
+ self
+ end
+
+ def expand(file_map, path)
+ @includes = ["*"] if @includes.empty?
+ Zip::ZipFile.open(@zip_file) do |source|
+ source.entries.reject { |entry| entry.directory? }.each do |entry|
+ if @includes.any? { |pattern| File.fnmatch(pattern, entry.name) } &&
+ !@excludes.any? { |pattern| File.fnmatch(pattern, entry.name) }
+ dest = "#{path}#{entry.name}"
+ puts "Adding #{dest}" if Rake.application.options.trace
+ file_map[dest] = lambda { |output| output.write source.read(entry) }
+ end
+ end
+ end
+ end
+
+ end
+
+
+ def initialize(*args) #:nodoc:
+ super
+ @paths = { ""=>Path.new(self, "") }
+ @prepares = []
+
+ # Make sure we're the last enhancements, so other enhancements can add content.
+ enhance do
+ @file_map = {}
+ enhance do
+ send "create" if respond_to?(:create)
+ # We're here because the archive file does not exist, or one of the files is newer than the archive contents;
+ # we need to make sure the archive doesn't exist (e.g. opening an existing Zip will add instead of create).
+ # We also want to protect against partial updates.
+ rm name, :verbose=>false rescue nil
+ mkpath File.dirname(name), :verbose=>false
+ begin
+ @paths.each do |name, object|
+ @file_map[name] = nil unless name.blank?
+ object.add_files(@file_map)
+ end
+ create_from @file_map
+ rescue
+ rm name, :verbose=>false rescue nil
+ raise
+ end
+ end
+ end
+ end
+
+ # :call-seq:
+ # include(*files) => self
+ # include(*files, :path=>path) => self
+ # include(file, :as=>name) => self
+ # include(:from=>path) => self
+ # include(*files, :merge=>true) => self
+ #
+ # Include files in this archive, or when called on a path, within that path. Returns self.
+ #
+ # The first form accepts a list of files, directories and glob patterns and adds them to the archive.
+ # For example, to include the file foo, directory bar (including all files in there) and all files under baz:
+ # zip(..).include("foo", "bar", "baz/*")
+ #
+ # The second form is similar but adds files/directories under the specified path. For example,
+ # to add foo as bar/foo:
+ # zip(..).include("foo", :path=>"bar")
+ # The :path option is the same as using the path method:
+ # zip(..).path("bar").include("foo")
+ # All other options can be used in combination with the :path option.
+ #
+ # The third form adds a file or directory under a different name. For example, to add the file foo under the
+ # name bar:
+ # zip(..).include("foo", :as=>"bar")
+ #
+ # The fourth form adds the contents of a directory using the directory as a prerequisite:
+ # zip(..).include(:from=>"foo")
+ # Unlike <code>include("foo")</code> it includes the contents of the directory, not the directory itself.
+ # Unlike <code>include("foo/*")</code>, it uses the directory timestamp for dependency management.
+ #
+ # The fifth form includes the contents of another archive by expanding it into this archive. For example:
+ # zip(..).include("foo.zip", :merge=>true).include("bar.zip")
+ # You can also use the method #merge.
+ def include(*files)
+ @paths[""].include *files
+ self
+ end
+ alias :add :include
+
+ # :call-seq:
+ # exclude(*files) => self
+ #
+ # Excludes files and returns self. Can be used in combination with include to prevent some files from being included.
+ def exclude(*files)
+ @paths[""].exclude *files
+ self
+ end
+
+ # :call-seq:
+ # merge(*files) => Merge
+ # merge(*files, :path=>name) => Merge
+ #
+ # Merges another archive into this one by including the individual files from the merged archive.
+ #
+ # Returns an object that supports two methods: include and exclude. You can use these methods to merge
+ # only specific files. For example:
+ # zip(..).merge("src.zip").include("module1/*")
+ def merge(*files)
+ @paths[""].merge *files
+ end
+
+ # :call-seq:
+ # path(name) => Path
+ #
+ # Returns a path object. Use the path object to include files under a path, for example, to include
+ # the file "foo" as "bar/foo":
+ # zip(..).path("bar").include("foo")
+ #
+ # Returns a Path object. The Path object implements all the same methods, like include, exclude, merge
+ # and so forth. It also implements path and root, so that:
+ # path("foo").path("bar") == path("foo/bar")
+ # path("foo").root == root
+ def path(name)
+ return @paths[""] if name.blank?
+ normalized = name.split("/").inject([]) do |path, part|
+ case part
+ when ".", nil, ""
+ path
+ when ".."
+ path[0...-1]
+ else
+ path << part
+ end
+ end.join("/")
+ @paths[normalized] ||= Path.new(self, normalized)
+ end
+
+ # :call-seq:
+ # root() => ArchiveTask
+ #
+ # Call this on an archive to return itself, and on a path to return the archive.
+ def root()
+ self
+ end
+
+ # :call-seq:
+ # with(options) => self
+ #
+ # Passes options to the task and returns self. Some tasks support additional options, for example,
+ # the WarTask supports options like :manifest, :libs and :classes.
+ #
+ # For example:
+ # package(:jar).with(:manifest=>"MANIFEST_MF")
+ def with(options)
+ options.each do |key, value|
+ begin
+ send "#{key}=", value
+ rescue NameError
+ if respond_to?(:[]=) # Backward compatible with Buildr 1.1.
+ warn_deprecated "The []= method is deprecated, please use attribute accessors instead."
+ self[key] = value
+ else
+ raise ArgumentError, "This task does not support the option #{key}."
+ end
+ end
+ end
+ self
+ end
+
+ def invoke_prerequisites() #:nodoc:
+ @prepares.each { |prepare| prepare.call(self) }
+ @prepares.clear
+ @prerequisites |= @paths.collect { |name, path| path.sources }.flatten
+ super
+ end
+
+ def needed?() #:nodoc:
+ return true unless File.exist?(name)
+ # You can do something like:
+ # include("foo", :path=>"foo").exclude("foo/bar", path=>"foo").
+ # include("foo/bar", :path=>"foo/bar")
+ # This will play havoc if we handled all the prerequisites together
+ # under the task, so instead we handle them individually for each path.
+ #
+ # We need to check that any file we include is not newer than the
+ # contents of the Zip. The file itself but also the directory it's
+ # coming from, since some tasks touch the directory, e.g. when the
+ # content of target/classes is included into a WAR.
+ most_recent = @paths.collect { |name, path| path.sources }.flatten.
+ each { |src| File.directory?(src) ? FileList.recursive(src) | [src] : src }.flatten.
+ select { |file| File.exist?(file) }.collect { |file| File.stat(file).mtime }.max
+ File.stat(name).mtime < (most_recent || Rake::EARLY) || super
+ end
+
+ protected
+
+ # Adds a prepare block. These blocks are called early on for adding more content to
+ # the archive, before invoking prerequsities. Anything you add here will be invoked
+ # as a prerequisite and used to determine whether or not to generate this archive.
+ # In contrast, enhance blocks are evaluated after it was decided to create this archive.
+ def prepare(&block)
+ @prepares << block
+ end
+
+ def []=(key, value) #:nodoc:
+ raise ArgumentError, "This task does not support the option #{key}."
+ end
+
+ end
+
+ # The ZipTask creates a new Zip file. You can include any number of files and and directories,
+ # use exclusion patterns, and include files into specific directories.
+ #
+ # For example:
+ # zip("test.zip").tap do |task|
+ # task.include "srcs"
+ # task.include "README", "LICENSE"
+ # end
+ #
+ # See Buildr#zip and ArchiveTask.
+ class ZipTask < ArchiveTask
+
+ private
+
+ def create_from(file_map)
+ Zip::ZipOutputStream.open name do |zip|
+ seen = {}
+ mkpath = lambda do |dir|
+ unless dir == "." || seen[dir]
+ mkpath.call File.dirname(dir)
+ zip.put_next_entry dir + '/'
+ seen[dir] = true
+ end
+ end
+
+ file_map.each do |path, content|
+ mkpath.call File.dirname(path)
+ if content.respond_to?(:call)
+ zip.put_next_entry path
+ content.call zip
+ elsif content.nil? || File.directory?(content.to_s)
+ mkpath.call path
+ else
+ zip.put_next_entry path
+ File.open content.to_s, "rb" do |is|
+ while data = is.read(4096)
+ zip << data
+ end
+ end
+ end
+ end
+ end
+ end
+
+ end
+
+
+ # :call-seq:
+ # zip(file) => ZipTask
+ #
+ # The ZipTask creates a new Zip file. You can include any number of files and
+ # and directories, use exclusion patterns, and include files into specific
+ # directories.
+ #
+ # For example:
+ # zip("test.zip").tap do |task|
+ # task.include "srcs"
+ # task.include "README", "LICENSE"
+ # end
+ def zip(file)
+ ZipTask.define_task(file)
+ end
+
+
+ # An object for unzipping a file into a target directory. You can tell it to include
+ # or exclude only specific files and directories, and also to map files from particular
+ # paths inside the zip file into the target directory. Once ready, call #extract.
+ #
+ # Usually it is more convenient to create a file task for extracting the zip file
+ # (see #unzip) and pass this object as a prerequisite to other tasks.
+ #
+ # See Buildr#unzip.
+ class Unzip
+
+ # The zip file to extract.
+ attr_accessor :zip_file
+ # The target directory to extract to.
+ attr_accessor :target
+
+ # Initialize with hash argument of the form target=>zip_file.
+ def initialize(args)
+ @target, @zip_file = Rake.application.resolve_args(args)
+ @paths = {}
+ end
+
+ # :call-seq:
+ # extract()
+ #
+ # Extract the zip file into the target directory.
+ #
+ # You can call this method directly. However, if you are using the #unzip method,
+ # it creates a file task for the target directory: use that task instead as a
+ # prerequisite. For example:
+ # build unzip(dir=>zip_file)
+ # Or:
+ # unzip(dir=>zip_file).target.invoke
+ def extract()
+ # If no paths specified, then no include/exclude patterns
+ # specified. Nothing will happen unless we include all files.
+ if @paths.empty?
+ @paths[nil] = FromPath.new(self, nil)
+ @paths[nil].include "*"
+ end
+
+ # Otherwise, empty unzip creates target as a file when touching.
+ mkpath target.to_s, :verbose=>false
+ Zip::ZipFile.open(zip_file.to_s) do |zip|
+ entries = zip.collect
+ @paths.each do |path, patterns|
+ patterns.map(entries).each do |dest, entry|
+ next if entry.directory?
+ dest = File.expand_path(dest, target.to_s)
+ puts "Extracting #{dest}" if Rake.application.options.trace
+ mkpath File.dirname(dest), :verbose=>false rescue nil
+ entry.extract(dest) { true }
+ end
+ end
+ end
+ # Let other tasks know we updated the target directory.
+ touch target.to_s, :verbose=>false
+ end
+
+ # :call-seq:
+ # include(*files) => self
+ # include(*files, :path=>name) => self
+ #
+ # Include all files that match the patterns and returns self.
+ #
+ # Use include if you only want to unzip some of the files, by specifying
+ # them instead of using exclusion. You can use #include in combination
+ # with #exclude.
+ def include(*files)
+ if Hash === files.last
+ from_path(files.pop[:path]).include *files
+ else
+ from_path(nil).include *files
+ end
+ self
+ end
+ alias :add :include
+
+ # :call-seq:
+ # exclude(*files) => self
+ #
+ # Exclude all files that match the patterns and return self.
+ #
+ # Use exclude to unzip all files except those that match the pattern.
+ # You can use #exclude in combination with #include.
+ def exclude(*files)
+ if Hash === files.last
+ from_path(files.pop[:path]).exclude *files
+ else
+ from_path(nil).exclude *files
+ end
+ self
+ end
+
+ # :call-seq:
+ # from_path(name) => Path
+ #
+ # Allows you to unzip from a path. Returns an object you can use to
+ # specify which files to include/exclude relative to that path.
+ # Expands the file relative to that path.
+ #
+ # For example:
+ # unzip(Dir.pwd=>"test.jar").from_path("etc").include("LICENSE")
+ # will unzip etc/LICENSE into ./LICENSE.
+ #
+ # This is different from:
+ # unzip(Dir.pwd=>"test.jar").include("etc/LICENSE")
+ # which unzips etc/LICENSE into ./etc/LICENSE.
+ def from_path(name)
+ @paths[name] ||= FromPath.new(self, name)
+ end
+ alias :path :from_path
+
+ # :call-seq:
+ # root() => Unzip
+ #
+ # Returns the root path, essentially the Unzip object itself. In case you are wondering
+ # down paths and want to go back.
+ def root()
+ self
+ end
+
+ # Returns the path to the target directory.
+ def to_s()
+ target.to_s
+ end
+
+ class FromPath #:nodoc:
+
+ def initialize(unzip, path)
+ @unzip = unzip
+ if path
+ @path = path[-1] == ?/ ? path : path + "/"
+ else
+ @path = ""
+ end
+ end
+
+ # See UnzipTask#include
+ def include(*files) #:doc:
+ @include ||= []
+ @include |= files
+ self
+ end
+
+ # See UnzipTask#exclude
+ def exclude(*files) #:doc:
+ @exclude ||= []
+ @exclude |= files
+ self
+ end
+
+ def map(entries)
+ includes = @include || ["*"]
+ excludes = @exclude || []
+ entries.inject({}) do |map, entry|
+ short = entry.name.sub(@path, "")
+ if includes.any? { |pat| File.fnmatch(pat, short) } &&
+ !excludes.any? { |pat| File.fnmatch(pat, short) }
+ map[short] = entry
+ end
+ map
+ end
+ end
+
+ # Documented in Unzip.
+ def root()
+ @unzip
+ end
+
+ # The target directory to extract to.
+ def target()
+ @unzip.target
+ end
+
+ end
+
+ end
+
+ # :call-seq:
+ # unzip(to_dir=>zip_file) => Zip
+ #
+ # Creates a task that will unzip a file into the target directory. The task name
+ # is the target directory, the prerequisite is the file to unzip.
+ #
+ # This method creates a file task to expand the zip file. It returns an Unzip object
+ # that specifies how the file will be extracted. You can include or exclude specific
+ # files from within the zip, and map to different paths.
+ #
+ # The Unzip object's to_s method return the path to the target directory, so you can
+ # use it as a prerequisite. By keeping the Unzip object separate from the file task,
+ # you overlay additional work on top of the file task.
+ #
+ # For example:
+ # unzip("all"=>"test.zip")
+ # unzip("src"=>"test.zip").include("README", "LICENSE")
+ # unzip("libs"=>"test.zip").from_path("libs")
+ def unzip(args)
+ target, zip_file = Rake.application.resolve_args(args)
+ task = file(File.expand_path(target.to_s)=>zip_file)
+ Unzip.new(task=>zip_file).tap do |setup|
+ task.enhance { setup.extract }
+ end
+ end
+
+end
+
+
+module Zip #:nodoc:
+
+ class ZipCentralDirectory #:nodoc:
+ # Patch to add entries in alphabetical order.
+ def write_to_stream(io)
+ offset = io.tell
+ @entrySet.sort { |a,b| a.name <=> b.name }.each { |entry| entry.write_c_dir_entry(io) }
+ write_e_o_c_d(io, offset)
+ end
+ end
+
+end
Added: incubator/buildr/trunk/test/archive.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/test/archive.rb?rev=594720&view=auto
==============================================================================
--- incubator/buildr/trunk/test/archive.rb (added)
+++ incubator/buildr/trunk/test/archive.rb Tue Nov 13 15:44:11 2007
@@ -0,0 +1,427 @@
+require File.join(File.dirname(__FILE__), 'sandbox')
+
+
+describe "ArchiveTask", :shared=>true do
+ before do
+ @dir = File.expand_path("test")
+ @files = %w{Test1.txt Text2.html}.map { |file| File.expand_path(file, @dir) }.
+ each { |file| write file, content_for(file) }
+ end
+
+ # Not too smart, we just create some content based on file name to make sure you read what you write.
+ def content_for(file)
+ "Content for #{File.basename(file)}"
+ end
+
+ # Create an archive not using the archive task, this way we do have a file in existence, but we don't
+ # have an already invoked task. Yield an archive task to the block which can use it to include files,
+ # set options, etc.
+ def create_without_task()
+ archive(@archive + ".tmp").tap do |task|
+ yield task if block_given?
+ task.invoke
+ mv task.name, @archive
+ end
+ end
+
+ def create_for_merge()
+ zip(@archive + ".src").include(@files).tap do |task|
+ task.invoke
+ yield task
+ end
+ end
+
+ it "should point to archive file" do
+ archive(@archive).name.should eql(@archive)
+ end
+
+ it "should create file" do
+ lambda { archive(@archive).invoke }.should change { File.exist?(@archive) }.to(true)
+ end
+
+ it "should create empty archive if no files included" do
+ archive(@archive).invoke
+ inspect_archive { |archive| archive.should be_empty }
+ end
+
+ it "should archive all included files" do
+ archive(@archive).include(@files).invoke
+ inspect_archive { |archive| @files.each { |f| archive[File.basename(f)].should eql(content_for(f)) } }
+ inspect_archive.size.should eql(@files.size)
+ end
+
+ it "should include entry for directory" do
+ archive(@archive).include(@dir).invoke
+ inspect_archive { |archive| @files.each { |f| archive["test/" + File.basename(f)].should eql(content_for(f)) } }
+ end
+
+ it "should not archive any excluded files" do
+ archive(@archive).include(@files).exclude(@files.last).invoke
+ inspect_archive do |archive|
+ archive.keys.should include(File.basename(@files.first))
+ archive.keys.should_not include(File.basename(@files.last))
+ end
+ end
+
+ it "should not archive any excluded files in included directories" do
+ archive(@archive).include(@dir).exclude(@files.last).invoke
+ inspect_archive do |archive|
+ archive.keys.should include("test/" + File.basename(@files.first))
+ archive.keys.should_not include("test/" + File.basename(@files.last))
+ end
+ end
+
+ it "should not archive any excluded files when using :from/:as" do
+ archive(@archive).include(:from=>@dir).exclude(@files.last).invoke
+ inspect_archive do |archive|
+ archive.keys.should include(File.basename(@files.first))
+ archive.keys.should_not include(File.basename(@files.last))
+ end
+ end
+
+ it "should exclude entire directory and all its children" do
+ mkpath "#{@dir}/sub"
+ write "#{@dir}/sub/test"
+ archive(@archive).include(@dir).exclude("#{@dir}/sub").invoke
+ inspect_archive do |archive|
+ archive.keys.select { |file| file =~ /sub/ }.should be_empty
+ end
+ end
+
+ it "should archive files into specified path" do
+ archive(@archive).include(@files, :path=>"code").invoke
+ inspect_archive { |archive| @files.each { |f| archive["code/" + File.basename(f)].should eql(content_for(f)) } }
+ end
+
+ it "should include entry for directory" do
+ archive(@archive).include(@dir).invoke
+ inspect_archive { |archive| @files.each { |f| archive["test/" + File.basename(f)].should eql(content_for(f)) } }
+ end
+
+ it "should archive files into specified path" do
+ archive(@archive).include(@files, :path=>"code").invoke
+ inspect_archive { |archive| @files.each { |f| archive["code/" + File.basename(f)].should eql(content_for(f)) } }
+ end
+
+ it "should archive directories into specified path" do
+ archive(@archive).include(@dir, :path=>"code").invoke
+ inspect_archive { |archive| @files.each { |f| archive["code/test/" + File.basename(f)].should eql(content_for(f)) } }
+ end
+
+ it "should understand . in path" do
+ archive(@archive).path(".").should == archive(@archive).path("")
+ archive(@archive).path("foo").path(".").should == archive(@archive).path("foo")
+ end
+
+ it "should understand .. in path" do
+ archive(@archive).path("..").should == archive(@archive).path("")
+ archive(@archive).path("foo").path("..").should == archive(@archive).path("")
+ archive(@archive).path("foo/bar").path("..").should == archive(@archive).path("foo")
+ end
+
+ it "should understand leading / in path" do
+ archive(@archive).path("/").should == archive(@archive).path("")
+ archive(@archive).path("foo/bar").path("/").should == archive(@archive).path("")
+ end
+
+ it "should archive file into specified name" do
+ archive(@archive).include(@files.first, :as=>"test/sample").invoke
+ inspect_archive { |archive| @files.each { |f| archive["test/sample"].should eql(content_for(@files.first)) } }
+ end
+
+ it "should archive file into specified name/path" do
+ archive(@archive).include(@files.first, :as=>"test/sample", :path=>"path").invoke
+ inspect_archive { |archive| @files.each { |f| archive["path/test/sample"].should eql(content_for(@files.first)) } }
+ end
+
+ it "should archive files starting with dot" do
+ write "test/.config", "# configuration"
+ archive(@archive).include("test").invoke
+ inspect_archive { |archive| @files.each { |f| archive["test/.config"].should eql("# configuration") } }
+ end
+
+ it "should archive directory into specified name" do
+ archive(@archive).include(@dir, :as=>"code").invoke
+ inspect_archive { |archive| @files.each { |f| archive["code/" + File.basename(f)].should eql(content_for(f)) } }
+ end
+
+ it "should archive directory into specified name/path" do
+ archive(@archive).include(@dir, :as=>"code", :path=>"path").invoke
+ inspect_archive { |archive| @files.each { |f| archive["path/code/" + File.basename(f)].should eql(content_for(f)) } }
+ end
+
+ it "should archive directory contents" do
+ archive(@archive).include(@dir, :as=>".").invoke
+ inspect_archive { |archive| @files.each { |f| archive[File.basename(f)].should eql(content_for(f)) } }
+ end
+
+ it "should archive directory contents into specified path" do
+ archive(@archive).include(@dir, :as=>".", :path=>"path").invoke
+ inspect_archive { |archive| @files.each { |f| archive["path/" + File.basename(f)].should eql(content_for(f)) } }
+ end
+
+ it "should not allow two files with the :as argument" do
+ lambda { archive(@archive).include(@files.first, @files.last, :as=>"test/sample") }.should raise_error(RuntimeError, /one file/)
+ end
+
+ it "should expand another archive file" do
+ create_for_merge do |src|
+ archive(@archive).merge(src)
+ archive(@archive).invoke
+ inspect_archive { |archive| @files.each { |f| archive[File.basename(f)].should eql(content_for(f)) } }
+ end
+ end
+
+ it "should expand another archive file with include pattern" do
+ create_for_merge do |src|
+ archive(@archive).merge(src).include(File.basename(@files.first))
+ archive(@archive).invoke
+ inspect_archive { |archive| archive[File.basename(@files.first)].should eql(content_for(@files.first)) }
+ end
+ end
+
+ it "should expand another archive file with exclude pattern" do
+ create_for_merge do |src|
+ archive(@archive).merge(src).exclude(File.basename(@files.first))
+ archive(@archive).invoke
+ inspect_archive { |archive| @files[1..-1].each { |f| archive[File.basename(f)].should eql(content_for(f)) } }
+ end
+ end
+
+ it "should expand another archive file into path" do
+ create_for_merge do |src|
+ archive(@archive).path("test").merge(src)
+ archive(@archive).invoke
+ inspect_archive { |archive| @files.each { |f| archive["test/" + File.basename(f)].should eql(content_for(f)) } }
+ end
+ end
+
+ it "should expand another archive file into path with merge option" do
+ create_for_merge do |src|
+ archive(@archive).include(src, :merge=>true)
+ archive(@archive).invoke
+ inspect_archive { |archive| @files.each { |f| archive[File.basename(f)].should eql(content_for(f)) } }
+ end
+ end
+
+ it "should update if one of the files is recent" do
+ create_without_task { |archive| archive.include(@files) }
+ # Touch archive file to some point in the past. This effectively makes
+ # all included files newer.
+ File.utime Time.now - 100, Time.now - 100, @archive
+ archive(@archive).include(@files).invoke
+ File.stat(@archive).mtime.should be_close(Time.now, 10)
+ end
+
+ it "should do nothing if all files are uptodate" do
+ create_without_task { |archive| archive.include(@files) }
+ # By touching all files in the past, there's nothing new to update.
+ (@files + [@archive]).each { |f| File.utime Time.now - 100, Time.now - 100, f }
+ archive(@archive).include(@files).invoke
+ File.stat(@archive).mtime.should be_close(Time.now - 100, 10)
+ end
+
+ it "should update if one of the files is recent" do
+ create_without_task { |archive| archive.include(@files) }
+ # Change files, we expect to see new content.
+ write @files.first, "/* Refreshed */"
+ File.utime(Time.now - 100, Time.now - 100, @archive) # Touch archive file to some point in the past.
+ archive(@archive).include(@files).invoke
+ inspect_archive { |archive| archive[File.basename(@files.first)].should eql("/* Refreshed */") }
+ end
+
+ it "should create new archive when updating" do
+ create_without_task { |archive| archive.include(@files) }
+ File.utime(Time.now - 100, Time.now - 100, @archive) # Touch archive file to some point in the past.
+ archive(@archive).include(@files[1..-1]).invoke
+ inspect_archive.size.should be(@files.size - 1)
+ end
+
+ it "should not accept invalid options" do
+ archive(@archive).include(@files)
+ lambda { archive(@archive).with :option=>true }.should raise_error
+ end
+end
+
+
+describe TarTask do
+ it_should_behave_like "ArchiveTask"
+ before { @archive = File.expand_path("test.tar") }
+ define_method(:archive) { |file| tar(file) }
+
+ def inspect_archive()
+ entries = {}
+ Archive::Tar::Minitar.open @archive, "r" do |reader|
+ reader.each { |entry| entries[entry.directory ? "#{entry.name}/" : entry.name] = entry.read }
+ end
+ yield entries if block_given?
+ entries
+ end
+end
+
+
+describe TarTask, " gzipped" do
+ it_should_behave_like "ArchiveTask"
+ before { @archive = File.expand_path("test.tgz") }
+ define_method(:archive) { |file| tar(file) }
+
+ def inspect_archive()
+ entries = {}
+ Zlib::GzipReader.open @archive do |gzip|
+ Archive::Tar::Minitar.open gzip, "r" do |reader|
+ reader.each { |entry| entries[entry.directory ? "#{entry.name}/" : entry.name] = entry.read }
+ end
+ end
+ yield entries if block_given?
+ entries
+ end
+end
+
+
+describe ZipTask do
+ it_should_behave_like "ArchiveTask"
+ before { @archive = File.expand_path("test.zip") }
+ define_method(:archive) { |file| zip(file) }
+
+ def inspect_archive()
+ entries = {}
+ Zip::ZipFile.open @archive do |zip|
+ zip.entries.each do |entry|
+ entries[entry.to_s] = zip.read(entry)
+ end
+ end
+ yield entries if block_given?
+ entries
+ end
+
+ it "should work with path object" do
+ archive(@archive).path("code").include(@files)
+ archive(@archive).invoke
+ inspect_archive { |archive| archive.keys.should include("code/") }
+ end
+end
+
+
+describe Unzip do
+ before do
+ @zip = File.expand_path("test.zip")
+ @dir = File.expand_path("test")
+ @files = %w{Test1.txt Text2.html}.map { |file| File.join(@dir, file) }.
+ each { |file| write file, content_for(file) }
+ @target = File.expand_path("target")
+ end
+
+ # Not too smart, we just create some content based on file name to
+ # make sure you read what you write.
+ def content_for(file)
+ "Content for #{File.basename(file)}"
+ end
+
+ def with_zip(*args)
+ zip(@zip).include(*args.empty? ? @files : args).invoke
+ yield
+ end
+
+ it "should touch target directory" do
+ with_zip do
+ mkdir @target
+ File.utime(Time.now - 100, Time.now - 100, @target)
+ unzip(@target=>@zip).target.invoke
+ end
+ File.stat(@target).mtime.should be_close(Time.now, 5)
+ end
+
+ it "should expand files" do
+ with_zip do
+ unzip(@target=>@zip).target.invoke
+ @files.each { |f| File.read(File.join(@target, File.basename(f))).should eql(content_for(f)) }
+ end
+ end
+
+ it "should expand all files" do
+ with_zip do
+ unzip(@target=>@zip).target.invoke
+ FileList[File.join(@target, "*")].size.should be(@files.size)
+ end
+ end
+
+ it "should expand only included files" do
+ with_zip do
+ only = File.basename(@files.first)
+ unzip(@target=>@zip).include(only).target.invoke
+ FileList[File.join(@target, "*")].should include(File.expand_path(only, @target))
+ FileList[File.join(@target, "*")].size.should be(1)
+ end
+ end
+
+ it "should expand all but excluded files" do
+ with_zip do
+ except = File.basename(@files.first)
+ unzip(@target=>@zip).exclude(except).target.invoke
+ FileList[File.join(@target, "*")].should_not include(File.expand_path(except, @target))
+ FileList[File.join(@target, "*")].size.should be(@files.size - 1)
+ end
+ end
+
+ it "should include with nested path patterns" do
+ with_zip @files, :path=>"test/path" do
+ only = File.basename(@files.first)
+ unzip(@target=>@zip).include(only).target.invoke
+ FileList[File.join(@target, "*")].should be_empty
+
+ Rake::Task.clear ; rm_rf @target
+ unzip(@target=>@zip).include("test/path/" + only).target.invoke
+ FileList[File.join(@target, "test/path/*")].size.should be(1)
+
+ Rake::Task.clear ; rm_rf @target
+ unzip(@target=>@zip).include("test/**").target.invoke
+ FileList[File.join(@target, "test/path/*")].size.should be(2)
+ end
+ end
+
+ it "should include with relative path" do
+ with_zip @files, :path=>"test/path" do
+ only = File.basename(@files.first)
+ unzip(@target=>@zip).tap { |unzip| unzip.from_path("test").include(only) }.target.invoke
+ FileList[File.join(@target, "*")].should be_empty
+
+ Rake::Task.clear ; rm_rf @target
+ unzip(@target=>@zip).tap { |unzip| unzip.from_path("test").include("test/*") }.target.invoke
+ FileList[File.join(@target, "path/*")].should be_empty
+
+ Rake::Task.clear ; rm_rf @target
+ unzip(@target=>@zip).tap { |unzip| unzip.from_path("test").include("path/*" + only) }.target.invoke
+ FileList[File.join(@target, "path/*")].size.should be(1)
+
+ Rake::Task.clear ; rm_rf @target
+ unzip(@target=>@zip).tap { |unzip| unzip.from_path("test").include("path/*") }.target.invoke
+ FileList[File.join(@target, "path/*")].size.should be(2)
+ end
+ end
+
+ it "should exclude with relative path" do
+ with_zip @files, :path=>"test" do
+ except = File.basename(@files.first)
+ unzip(@target=>@zip).tap { |unzip| unzip.from_path("test").exclude(except) }.target.invoke
+ FileList[File.join(@target, "*")].should include(File.join(@target, File.basename(@files[1])))
+ FileList[File.join(@target, "*")].size.should be(@files.size - 1)
+ end
+ end
+
+ it "should return itself from root method" do
+ task = unzip(@target=>@zip)
+ task.root.should be(task)
+ task.from_path("foo").root.should be(task)
+ end
+
+ it "should return target task from target method" do
+ task = unzip(@target=>@zip)
+ task.target.should be(file(@target))
+ task.from_path("foo").target.should be(file(@target))
+ end
+
+ it "should alias from_path as path" do
+ task = unzip(@target=>@zip)
+ task.from_path("foo").should be(task.path("foo"))
+ end
+end
Added: incubator/buildr/trunk/test/artifact.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/test/artifact.rb?rev=594720&view=auto
==============================================================================
--- incubator/buildr/trunk/test/artifact.rb (added)
+++ incubator/buildr/trunk/test/artifact.rb Tue Nov 13 15:44:11 2007
@@ -0,0 +1,681 @@
+require File.join(File.dirname(__FILE__), 'sandbox')
+
+
+describe Artifact do
+ before do
+ @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" }))
+ end
+
+ 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")
+ end
+
+ 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")
+ end
+
+ 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
+ @artifact.type.should eql(:jar)
+ end
+
+ it "should understand classifier" do
+ @artifact.classifier.should be_nil
+ @classified.classifier.should eql("all")
+ end
+
+ 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")
+ 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")
+ end
+
+ it "should have associated POM artifact" do
+ @artifact.pom.to_hash.should == @artifact.to_hash.merge(:type=>:pom)
+ @classified.pom.to_hash.should == @classified.to_hash.merge(:type=>:pom)
+ end
+
+ 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
+ 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") }
+ lambda { @artifact.invoke }.should_not raise_error
+ end
+
+ 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"
+ 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
+ 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")
+ end
+
+ 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")
+ end
+end
+
+
+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"))
+ end
+
+ 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"
+ repositories.local = nil
+ repositories.local.should eql(File.expand_path("~/.m2/repository"))
+ end
+
+ 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"))
+ end
+
+ 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"))
+ end
+end
+
+
+describe "repositories.remote" do
+ before do
+ @repos = [ "http://www.ibiblio.org/maven2", "http://repo1.maven.org/maven2" ]
+ end
+
+ it "should be empty initially" do
+ repositories.remote.should be_empty
+ end
+
+ it "should be settable" do
+ repositories.remote = @repos.first
+ repositories.remote.should eql([@repos.first])
+ end
+
+ 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
+ @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"
+ 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)
+ end
+
+ 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? }
+ end
+
+ 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
+ end
+
+ 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)
+ end
+
+ 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")
+ end
+
+ 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")
+ end
+
+ it "should resolve m2-style deployed snapshots" do
+ metadata = <<-XML
+ <?xml version="1.0" encoding="UTF-8"?>
+ <metadata>
+ <groupId>com.example</groupId>
+ <artifactId>library</artifactId>
+ <version>2.1-SNAPSHOT</version>
+ <versioning>
+ <snapshot>
+ <timestamp>20071012.190008</timestamp>
+ <buildNumber>8</buildNumber>
+ </snapshot>
+ <lastUpdated>20071012190008</lastUpdated>
+ </versioning>
+ </metadata>
+ XML
+ 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)
+ end
+
+ 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
+ end
+
+ it "should handle missing m2 snapshots by reporting the artifact unavailable" do
+ metadata = <<-XML
+ <?xml version="1.0" encoding="UTF-8"?>
+ <metadata>
+ <groupId>com.example</groupId>
+ <artifactId>library</artifactId>
+ <version>2.1-SNAPSHOT</version>
+ <versioning>
+ <snapshot>
+ <timestamp>20071012.190008</timestamp>
+ <buildNumber>8</buildNumber>
+ </snapshot>
+ <lastUpdated>20071012190008</lastUpdated>
+ </versioning>
+ </metadata>
+ XML
+ 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
+ end
+end
+
+
+describe "repositories.proxy" do
+ before do
+ repositories.remote = "http://example.com"
+ end
+
+ it "should be empty initially" do
+ repositories.proxy.should be_nil
+ end
+
+ it "should be used when downloading" do
+ repositories.proxy = "http://myproxy:8080"
+ Net::HTTP.should_receive(:start).with(anything, 80, "myproxy", 8080, nil, nil).twice
+ artifact("com.example:library:jar:all:2.0").invoke
+ 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" }
+ 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" }
+ 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" }
+ end
+end
+
+
+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)
+ end
+
+ 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
+ lambda { artifact(@spec.merge(:error=>true)) }.should raise_error(ArgumentError, /no such option/i)
+ end
+
+ 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)
+ 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
+ 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")
+ Rake::Task.task_defined?(file).should be_false
+ 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")
+ 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" ]
+ 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" ]
+ 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")
+ 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)
+ end
+
+ 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")])
+ end
+
+ 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"
+ end
+ 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"))
+ ])
+ end
+
+ it "should complain about an invalid specification" do
+ lambda { artifacts(5) }.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"))
+ 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"))
+ list.size.should be(3)
+ end
+end
+
+
+describe Builder, '#install' do
+ before do
+ @spec = 'group:id:jar:1.0'
+ write @file = 'test.jar'
+ end
+
+ it 'should return the install task' do
+ install.should be(task('install'))
+ end
+
+ it 'should accept artifacts to install' do
+ install artifact(@spec)
+ lambda { install @file }.should raise_error(ArgumentError)
+ end
+
+ it 'should install artifact when install task is run' do
+ write @file
+ install artifact(@spec).from(@file)
+ lambda { install.invoke }.should change { File.exist?(artifact(@spec).to_s) }.to(true)
+ end
+
+ it 'should install POM alongside artifact' do
+ write @file
+ install artifact(@spec).from(@file)
+ lambda { install.invoke }.should change { File.exist?(artifact(@spec).pom.to_s) }.to(true)
+ end
+end
+
+
+describe Builder, '#upload' do
+ before do
+ @spec = 'group:id:jar:1.0'
+ write @file = 'test.jar'
+ repositories.deploy_to = 'sftp://example.com/base'
+ end
+
+ it 'should return the upload task' do
+ upload.should be(task('upload'))
+ end
+
+ it 'should accept artifacts to upload' do
+ upload artifact(@spec)
+ lambda { upload @file }.should raise_error(ArgumentError)
+ end
+
+ it 'should upload artifact when upload task is run' do
+ write @file
+ upload artifact(@spec).from(@file)
+ URI.should_receive(:upload).once.
+ with(URI.parse('sftp://example.com/base/group/id/1.0/id-1.0.jar'), artifact(@spec).to_s, anything)
+ URI.should_receive(:upload).once.
+ with(URI.parse('sftp://example.com/base/group/id/1.0/id-1.0.pom'), artifact(@spec).pom.to_s, anything)
+ upload.invoke
+ end
+end
+
+
+describe Buildr, "#deploy" do
+ before do
+ repositories.deploy_to = "sftp://example.com/base"
+ @file = file("README")
+ write @file.to_s
+ end
+
+ it "should deploy a file to a path using its basename" do
+ URI.should_receive(:upload).once.with(URI.parse("sftp://example.com/base/README"), @file.to_s, anything)
+ deploy @file
+ end
+
+ it "should deploy a file to specified path and basename" do
+ URI.should_receive(:upload).once.with(URI.parse("sftp://example.com/base/foo/bar/README"), @file.to_s, anything)
+ deploy @file, :path=>"foo/bar"
+ end
+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"
+ end
+
+ def test_upload(artifact, path)
+ # 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") }
+ end
+
+ 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)
+ 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")
+ # Prevent artifact from downloading anything.
+ write repositories.locate(artifact)
+ URI.should_receive(:upload).once
+ repositories.release_to = "sftp://example.com/base"
+ 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"
+ URI.should_receive(:download).twice.and_return { |uri, target, options| write target }
+ 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/)
+ end
+
+ 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
+ end
+ end
+end
+
+
+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" ]
+ @simple.map { |spec| artifact(spec).pom }.each { |task| write task.name, task.pom_xml }
+ @provided = @simple.first
+ @complex = "group:app:jar:1.0"
+ write artifact(@complex).pom.to_s, <<-XML
+<project>
+ <artifactId>app</artifactId>
+ <groupId>group</groupId>
+ <dependencies>
+ <dependency>
+ <artifactId>saxon</artifactId>
+ <groupId>saxon</groupId>
+ <version>8.4</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <artifactId>saxon-dom</artifactId>
+ <groupId>saxon</groupId>
+ <version>8.4</version>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <artifactId>saxon-xpath</artifactId>
+ <groupId>saxon</groupId>
+ <version>8.4</version>
+ </dependency>
+ <dependency>
+ <artifactId>saxon-nosuch</artifactId>
+ <groupId>saxon</groupId>
+ <version>8.4</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
+XML
+ @transitive = "master:app:war:1.0"
+ write artifact(@transitive).pom.to_s, <<-XML
+<project>
+ <artifactId>app</artifactId>
+ <groupId>group</groupId>
+ <dependencies>
+ <dependency>
+ <artifactId>app</artifactId>
+ <groupId>group</groupId>
+ <version>1.0</version>
+ </dependency>
+ </dependencies>
+</project>
+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" ]
+ 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" ]
+ 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")
+ 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)
+ end
+
+ 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")])
+ end
+
+ 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"
+ end
+ 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"))
+ ])
+ end
+
+ it "should complain about an invalid specification" do
+ lambda { transitive(5) }.should raise_error
+ lambda { transitive("group:no:version:") }.should raise_error
+ end
+
+ 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))
+ end
+
+ it "should bring artifact and transitive depenencies" do
+ transitive(@transitive).should eql(artifacts(@transitive, @complex, @simple - [@provided]))
+ end
+end
Added: incubator/buildr/trunk/test/build.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/test/build.rb?rev=594720&view=auto
==============================================================================
--- incubator/buildr/trunk/test/build.rb (added)
+++ incubator/buildr/trunk/test/build.rb Tue Nov 13 15:44:11 2007
@@ -0,0 +1,33 @@
+require File.join(File.dirname(__FILE__), 'sandbox')
+
+
+describe "Local directory build task" do
+ it "should execute build task for current project" do
+ define "foobar"
+ lambda { task("build").invoke }.should run_task("foobar:build")
+ end
+
+ it "should not execute build task for other projects" do
+ define "foobar", :base_dir=>"elsewhere"
+ lambda { task("build").invoke }.should_not run_task("foobar:build")
+ end
+end
+
+
+describe Project, " build task" do
+ it "should execute build task for sub-project" do
+ define("foo") { define "bar" }
+ lambda { task("foo:build").invoke }.should run_task("foo:bar:build")
+ end
+
+ it "should not execute build task of other projects" do
+ define "foo"
+ define "bar"
+ lambda { task("foo:build").invoke }.should_not run_task("bar:build")
+ end
+
+ it "should be accessible as build method" do
+ define "boo"
+ project("boo").build.should be(task("boo:build"))
+ end
+end
Added: incubator/buildr/trunk/test/checks.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/test/checks.rb?rev=594720&view=auto
==============================================================================
--- incubator/buildr/trunk/test/checks.rb (added)
+++ incubator/buildr/trunk/test/checks.rb Tue Nov 13 15:44:11 2007
@@ -0,0 +1,545 @@
+require File.join(File.dirname(__FILE__), 'sandbox')
+
+
+module BuildChecks
+ def should_pass()
+ lambda { check }.should_not raise_error
+ end
+
+ def should_fail()
+ lambda { check }.should raise_error(RuntimeError, /Checks failed/)
+ end
+
+ def check()
+ project("foo").task("package").invoke
+ end
+end
+
+
+describe Project, " check task" do
+ include BuildChecks
+
+ it "should execute last thing from package task" do
+ task "action"
+ define "foo", :version=>"1.0" do
+ package :jar
+ task("package").enhance { task("action").invoke }
+ end
+ lambda { check }.should run_tasks(["foo:package", "action", "foo:check"])
+ end
+
+ it "should execute all project's expectations" do
+ task "expectation"
+ define "foo", :version=>"1.0" do
+ check { task("expectation").invoke }
+ end
+ lambda { check }.should run_task("expectation")
+ end
+
+ it "should succeed if there are no expectations" do
+ define "foo", :version=>"1.0"
+ should_pass
+ end
+
+ it "should succeed if all expectations passed" do
+ define "foo", :version=>"1.0" do
+ check { true }
+ check { false }
+ end
+ should_pass
+ end
+
+ it "should fail if any expectation failed" do
+ define "foo", :version=>"1.0" do
+ check
+ check { fail "sorry" }
+ check
+ end
+ should_fail
+ end
+end
+
+
+describe Project, "#check" do
+ include BuildChecks
+
+ it "should add expectation" do
+ define "foo" do
+ expectations.should be_empty
+ check
+ expectations.size.should be(1)
+ end
+ end
+
+ it "should treat no arguments as expectation against project" do
+ define "foo" do
+ subject = self
+ check do
+ it.should be(subject)
+ description.should eql(subject.to_s)
+ end
+ end
+ should_pass
+ end
+
+ it "should treat single string argument as description, expectation against project" do
+ define "foo" do
+ subject = self
+ check "should be project" do
+ it.should be(subject)
+ description.should eql("#{subject} should be project")
+ end
+ end
+ should_pass
+ end
+
+ it "should treat single object argument as subject" do
+ define "foo" do
+ subject = Object.new
+ check subject do
+ it.should be(subject)
+ description.should eql(subject.to_s)
+ end
+ end
+ should_pass
+ end
+
+ it "should treat first object as subject, second object as description" do
+ define "foo" do
+ subject = Object.new
+ check subject, "should exist" do
+ it.should be(subject)
+ description.should eql("#{subject} should exist")
+ end
+ end
+ should_pass
+ end
+
+ it "should work without block" do
+ define "foo" do
+ check "implement later"
+ end
+ should_pass
+ end
+end
+
+
+describe BuildChecks::Expectation, " matchers" do
+ include BuildChecks
+
+ it "should include Buildr matchers exist and contain" do
+ define "foo" do
+ check do
+ self.should respond_to(:exist)
+ self.should respond_to(:contain)
+ end
+ end
+ should_pass
+ end
+
+ it "should include RSpec matchers like be and eql" do
+ define "foo" do
+ check do
+ self.should respond_to(:be)
+ self.should respond_to(:eql)
+ end
+ end
+ should_pass
+ end
+
+ it "should include RSpec predicates like be_nil and be_empty" do
+ define "foo" do
+ check do
+ nil.should be_nil
+ [].should be_empty
+ end
+ end
+ should_pass
+ end
+end
+
+
+describe BuildChecks::Expectation, " exist" do
+ include BuildChecks
+
+ it "should pass if file exists" do
+ define "foo" do
+ build file("test") { |task| write task.name }
+ check(file("test")) { it.should exist }
+ end
+ should_pass
+ end
+
+ it "should fail if file does not exist" do
+ define "foo" do
+ check(file("test")) { it.should exist }
+ end
+ should_fail
+ end
+
+ it "should not attempt to invoke task" do
+ define "foo" do
+ file("test") { |task| write task.name }
+ check(file("test")) { it.should exist }
+ end
+ should_fail
+ end
+
+ it "should pass if ZIP path exists" do
+ write "resources/test"
+ define "foo", :version=>"1.0" do
+ package(:jar).include("resources")
+ check(package(:jar).path("resources")) { it.should exist }
+ end
+ should_pass
+ end
+
+ it "should fail if ZIP path does not exist" do
+ mkpath "resources"
+ define "foo", :version=>"1.0" do
+ package(:jar).include("resources")
+ check(package(:jar)) { it.path("not-resources").should exist }
+ end
+ should_fail
+ end
+
+ it "should pass if ZIP entry exists" do
+ write "resources/test"
+ define "foo", :version=>"1.0" do
+ package(:jar).include("resources")
+ check(package(:jar).entry("resources/test")) { it.should exist }
+ check(package(:jar).path("resources").entry("test")) { it.should exist }
+ end
+ should_pass
+ end
+
+ it "should fail if ZIP path does not exist" do
+ mkpath "resources"
+ define "foo", :version=>"1.0" do
+ package(:jar).include("resources")
+ check(package(:jar).entry("resources/test")) { it.should exist }
+ end
+ should_fail
+ end
+end
+
+
+describe BuildChecks::Expectation, " exist" do
+ include BuildChecks
+
+ it "should pass if file has no content" do
+ define "foo" do
+ build file("test") { write "test" }
+ check(file("test")) { it.should be_empty }
+ end
+ should_pass
+ end
+
+ it "should fail if file has content" do
+ define "foo" do
+ build file("test") { write "test", "something" }
+ check(file("test")) { it.should be_empty }
+ end
+ should_fail
+ end
+
+ it "should fail if file does not exist" do
+ define "foo" do
+ check(file("test")) { it.should be_empty }
+ end
+ should_fail
+ end
+
+ it "should pass if directory is empty" do
+ define "foo" do
+ build file("test") { mkpath "test" }
+ check(file("test")) { it.should be_empty }
+ end
+ should_pass
+ end
+
+ it "should fail if directory has any files" do
+ define "foo" do
+ build file("test") { write "test/file" }
+ check(file("test")) { it.should be_empty }
+ end
+ should_fail
+ end
+
+ it "should pass if ZIP path is empty" do
+ mkpath "resources"
+ define "foo", :version=>"1.0" do
+ package(:jar).include("resources")
+ check(package(:jar).path("resources")) { it.should be_empty }
+ end
+ should_pass
+ end
+
+ it "should fail if ZIP path has any entries" do
+ write "resources/test"
+ define "foo", :version=>"1.0" do
+ package(:jar).include("resources")
+ check(package(:jar).path("resources")) { it.should be_empty }
+ end
+ should_fail
+ end
+
+ it "should pass if ZIP entry has no content" do
+ write "resources/test"
+ define "foo", :version=>"1.0" do
+ package(:jar).include("resources")
+ check(package(:jar).entry("resources/test")) { it.should be_empty }
+ check(package(:jar).path("resources").entry("test")) { it.should be_empty }
+ end
+ should_pass
+ end
+
+ it "should fail if ZIP entry has content" do
+ write "resources/test", "something"
+ define "foo", :version=>"1.0" do
+ package(:jar).include("resources")
+ check(package(:jar).entry("resources/test")) { it.should be_empty }
+ end
+ should_fail
+ end
+
+ it "should fail if ZIP entry does not exist" do
+ mkpath "resources"
+ define "foo", :version=>"1.0" do
+ package(:jar).include("resources")
+ check(package(:jar).entry("resources/test")) { it.should be_empty }
+ end
+ should_fail
+ end
+end
+
+
+describe BuildChecks::Expectation, " contain(file)" do
+ include BuildChecks
+
+ it "should pass if file content matches string" do
+ define "foo" do
+ build file("test") { write "test", "something" }
+ check(file("test")) { it.should contain("thing") }
+ end
+ should_pass
+ end
+
+ it "should pass if file content matches pattern" do
+ define "foo" do
+ build file("test") { write "test", "something\nor\nanother" }
+ check(file("test")) { it.should contain(/or/) }
+ end
+ should_pass
+ end
+
+ it "should pass if file content matches all arguments" do
+ define "foo" do
+ build file("test") { write "test", "something\nor\nanother" }
+ check(file("test")) { it.should contain(/or/, /other/) }
+ end
+ should_pass
+ end
+
+ it "should fail unless file content matchs all arguments" do
+ define "foo" do
+ build file("test") { write "test", "something" }
+ check(file("test")) { it.should contain(/some/, /other/) }
+ end
+ should_fail
+ end
+
+ it "should fail if file content does not match" do
+ define "foo" do
+ build file("test") { write "test", "something" }
+ check(file("test")) { it.should contain(/other/) }
+ end
+ should_fail
+ end
+
+ it "should fail if file does not exist" do
+ define "foo" do
+ check(file("test")) { it.should contain(/anything/) }
+ end
+ should_fail
+ end
+end
+
+
+describe BuildChecks::Expectation, " contain(directory)" do
+ include BuildChecks
+
+ it "should pass if directory contains file" do
+ write "resources/test"
+ define "foo" do
+ check(file("resources")) { it.should contain("test") }
+ end
+ should_pass
+ end
+
+ it "should pass if directory contains glob pattern" do
+ write "resources/with/test"
+ define "foo" do
+ check(file("resources")) { it.should contain("**/t*st") }
+ end
+ should_pass
+ end
+
+ it "should pass if directory contains all arguments" do
+ write "resources/with/test"
+ define "foo" do
+ check(file("resources")) { it.should contain("**/test", "**/*") }
+ end
+ should_pass
+ end
+
+ it "should fail unless directory contains all arguments" do
+ write "resources/test"
+ define "foo" do
+ check(file("resources")) { it.should contain("test", "or-not") }
+ end
+ should_fail
+ end
+
+ it "should fail if directory is empty" do
+ mkpath "resources"
+ define "foo" do
+ check(file("resources")) { it.should contain("test") }
+ end
+ should_fail
+ end
+
+ it "should fail if directory does not exist" do
+ define "foo" do
+ check(file("resources")) { it.should contain }
+ end
+ should_fail
+ end
+end
+
+
+describe BuildChecks::Expectation, " contain(zip.entry)" do
+ include BuildChecks
+
+ it "should pass if ZIP entry content matches string" do
+ write "resources/test", "something"
+ define "foo", :version=>"1.0" do
+ package(:jar).include("resources")
+ check(package(:jar).entry("resources/test")) { it.should contain("thing") }
+ #check(package(:jar)) { it.entry("resources/test").should contain("thing") }
+ end
+ should_pass
+ end
+
+ it "should pass if ZIP entry content matches pattern" do
+ write "resources/test", "something\nor\another"
+ define "foo", :version=>"1.0" do
+ package(:jar).include("resources")
+ check(package(:jar).entry("resources/test")) { it.should contain(/or/) }
+ #check(package(:jar)) { it.entry("resources/test").should contain(/or/) }
+ end
+ should_pass
+ end
+
+ it "should pass if ZIP entry content matches all arguments" do
+ write "resources/test", "something\nor\nanother"
+ define "foo", :version=>"1.0" do
+ package(:jar).include("resources")
+ check(package(:jar).entry("resources/test")) { it.should contain(/or/, /other/) }
+ #check(package(:jar)) { it.entry("resources/test").should contain(/or/, /other/) }
+ end
+ should_pass
+ end
+
+ it "should fail unless ZIP path contains all arguments" do
+ write "resources/test", "something"
+ define "foo", :version=>"1.0" do
+ package(:jar).include("resources")
+ check(package(:jar).entry("resources/test")) { it.should contain(/some/, /other/) }
+ #check(package(:jar)) { it.entry("resources/test").should contain(/some/, /other/) }
+ end
+ should_fail
+ end
+
+ it "should fail if ZIP entry content does not match" do
+ write "resources/test", "something"
+ define "foo", :version=>"1.0" do
+ package(:jar).include("resources")
+ check(package(:jar).entry("resources/test")) { it.should contain(/other/) }
+ #check(package(:jar)) { it.entry("resources/test").should contain(/other/) }
+ end
+ should_fail
+ end
+
+ it "should fail if ZIP entry does not exist" do
+ mkpath "resources"
+ define "foo", :version=>"1.0" do
+ package(:jar).include("resources")
+ check(package(:jar).entry("resources/test")) { it.should contain(/anything/) }
+ #check(package(:jar)) { it.entry("resources/test").should contain(/anything/) }
+ end
+ should_fail
+ end
+end
+
+
+describe BuildChecks::Expectation, " contain(zip.path)" do
+ include BuildChecks
+
+ it "should pass if ZIP path contains file" do
+ write "resources/test"
+ define "foo", :version=>"1.0" do
+ package(:jar).include("resources")
+ check(package(:jar).path("resources")) { it.should contain("test") }
+ end
+ should_pass
+ end
+
+ it "should handle deep nesting" do
+ write "resources/test/test2.efx"
+ define "foo", :version=>"1.0" do
+ package(:jar).include("*")
+ check(package(:jar)) { it.should contain("resources/test/test2.efx") }
+ check(package(:jar).path("resources")) { it.should contain("test/test2.efx") }
+ check(package(:jar).path("resources/test")) { it.should contain("test2.efx") }
+ end
+ should_pass
+ end
+
+
+ it "should pass if ZIP path contains pattern" do
+ write "resources/with/test"
+ define "foo", :version=>"1.0" do
+ package(:jar).include("resources")
+ check(package(:jar).path("resources")) { it.should contain("**/t*st") }
+ end
+ should_pass
+ end
+
+ it "should pass if ZIP path contains all arguments" do
+ write "resources/with/test"
+ define "foo", :version=>"1.0" do
+ package(:jar).include("resources")
+ check(package(:jar).path("resources")) { it.should contain("**/test", "**/*") }
+ end
+ should_pass
+ end
+
+ it "should fail unless ZIP path contains all arguments" do
+ write "resources/test"
+ define "foo", :version=>"1.0" do
+ package(:jar).include("resources")
+ check(package(:jar).path("resources")) { it.should contain("test", "or-not") }
+ end
+ should_fail
+ end
+
+ it "should fail if ZIP path is empty" do
+ mkpath "resources"
+ define "foo", :version=>"1.0" do
+ package(:jar).include("resources")
+ check(package(:jar).path("resources")) { it.should contain("test") }
+ end
+ should_fail
+ end
+end