lib/tasks/zip.rb in buildr-0.15.0 vs lib/tasks/zip.rb in buildr-0.16.0
- old
+ new
@@ -7,15 +7,140 @@
# 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.
class ZipTask < Rake::FileTask
+ # :nodoc:
+ module IncludeFiles
+
+ # Include the specified files or directories.
+ def include(*files)
+ if Hash === files.last
+ options = files.pop
+ else
+ options = {}
+ end
+
+ if options[:path]
+ path(options[:path]).include *files +[ options.reject { |k,v| k == :path } ]
+ elsif options[:as]
+ raise "You can only use the :as option in combination with the :path option" unless options.keys.size == 1
+ raise "You can only use one file with the :as option" unless files.size == 1
+ include_as(files.first, options[:as])
+ elsif options[:merge]
+ raise "You can only use the :merge option in combination with the :path option" unless options.keys.size == 1
+ files.each { |file| merge file }
+ elsif options.keys.empty?
+ (@files ||= FileList[]).include *files
+ else
+ raise "Unrecognized option #{options.keys.join(", ")}"
+ end
+ self
+ end
+
+ # Exclude the specified file or directories.
+ def exclude(*files)
+ (@files ||= FileList[]).exclude *files
+ self
+ end
+ alias :add :include
+
+ def merge(*files)
+ if Hash === files.last
+ options = files.pop
+ else
+ options = {}
+ end
+
+ if options[:path]
+ path(options[:path]).merge *files +[ options.reject { |k,v| k == :path } ]
+ elsif options.keys.empty?
+ files.collect do |file|
+ @expand_sources << proc { artifacts(file).map(&:to_s) }
+ expander = ZipExpander.new(file)
+ @add_files << proc { |zip| expander.expand(zip, @path) }
+ expander
+ end.first
+ else
+ raise "Unrecognized option #{options.keys.join(", ")}"
+ end
+ end
+
+ protected
+
+ def setup_path(path = nil)
+ @path = "#{path}/" if path
+ expand_src = proc { artifacts(*@files || []).map(&:to_s) }
+ @expand_sources = [ expand_src ]
+ @add_files = [] << proc do |zip|
+ expand_src.call.each do |file|
+ if File.directory?(file)
+ in_directory(file, @files) do |file, rel_path|
+ puts "Adding #{@path}#{rel_path}" if Rake.application.options.trace
+ zip.add "#{@path}#{rel_path}", file
+ end
+ else
+ puts "Adding #{@path}#{File.basename(file)}" if Rake.application.options.trace
+ zip.add "#{@path}#{File.basename(file)}", file
+ end
+ end
+ end
+ end
+
+ def include_as(source, as)
+ @expand_sources << proc { artifacts(source).map(&:to_s) }
+ @add_files << proc do |zip|
+ file = artifacts(source).first.to_s
+ if File.directory?(file)
+ in_directory(file) do |file, rel_path|
+ puts "Adding #{@path}#{as}/#{rel_path}" if Rake.application.options.trace
+ zip.add file, "#{@path}#{as}/#{rel_path}"
+ end
+ else
+ puts "Adding #{@path}#{as}" if Rake.application.options.trace
+ zip.add "#{@path}#{as}", file
+ end
+ end
+ end
+
+ def in_directory(dir, excludes = nil)
+ prefix = Regexp.new("^" + Regexp.escape(File.dirname(dir) + File::SEPARATOR))
+ Dir[File.join(dir, "**", "*")].
+ reject { |file| File.directory?(file) || (excludes && excludes.exclude?(file)) }.
+ each { |file| yield file, file.sub(prefix, "") }
+ end
+
+ def expand_sources()
+ @expand_sources.map(&:call).flatten
+ end
+
+ def add_file(zip)
+ @add_files.each { |action| action.call zip }
+ end
+
+ end
+
+
+ # Which files go where.
+ class Path
+
+ include IncludeFiles
+
+ def initialize(path)
+ setup_path path
+ end
+
+ end
+
+ include IncludeFiles
+
def initialize(*args)
super
- @paths = {}
+ @paths = { nil=>self }
+ setup_path
enhance do |task|
- verbose { puts "Creating #{task.name}" }
+ puts "Creating #{task.name}" if verbose
# We're here because the Zip file does not exist, or one of the files is
# newer than the Zip contents; in the later case, opening the Zip file
# will add to its contents instead of replacing it, so we want the Zip
# gone before we change it. We also don't want to see any partial updates.
rm task.name, :verbose=>false rescue nil
@@ -27,42 +152,54 @@
raise
end
end
end
- # Include the specified files and directories. Returns self.
- #
- # You can specify a path for inclusion by passing :path=> as the
- # last argument. For example:
- # task.include "src" # Include the src directory
- # task.include foobar, :path=>"libs" # Include under /libs/
- def include(*files)
- if Hash === files.last
- path = files.pop[:path]
+
+ class ZipExpander
+
+ def initialize(zip_file)
+ @zip_file = zip_file
end
- (@paths[path] ||= FileList[]).include *files
- self
- end
- alias :add :include
- # Excludes the specified files and directories. Returns self. Use this
- # in combination with include; make sure to use the same path.
- def exclude(*files)
- if Hash === files.last
- path = files.pop[:path]
+ def include(*files)
+ (@includes ||= [])
+ @includes |= files
+ self
end
- (@paths[path] ||= FileList[]).exclude *files
- self
+
+ def exclude(*files)
+ (@excludes ||= [])
+ @excludes |= files
+ self
+ end
+
+ def expand(zip, path)
+ @includes ||= ["*"]
+ @excludes ||= []
+ Zip::ZipFile.open(artifacts(@zip_file).map(&:to_s).first) 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) }
+ puts "Adding #{path}#{entry.name}" if Rake.application.options.trace
+ zip.get_output_stream("#{path}#{entry.name}") { |output| output.write source.read(entry) }
+ # TODO: read and write file
+ end
+ end
+ end
+ end
+
end
+
# Returns a path to which you can include/exclude files.
#
# zip(..).include("foo", :path=>"bar")
# is equivalen to:
# zip(..).path("bar").include("foo")
def path(path)
- @paths[path] ||= FileList[]
+ path.blank? ? @paths[nil] : (@paths[path] ||= Path.new(path))
end
# Pass options to the task. Returns self.
def with(options)
options.each do |key, value|
@@ -75,38 +212,35 @@
fail "#{self.class} does not support the attribute #{key}"
end
def invoke_prerequisites()
super
- @paths.each { |p, files| artifacts(*files).each { |f| file(f).invoke } }
+ @paths.collect { |name, path| path.expand_sources }.flatten.each { |src| file(src).invoke }
end
def needed?()
+ 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.
- #@paths.collect{ |p, files| files }.flatten.each { |f| file(f).invoke }
- return true unless File.exist?(name)
+ #
# 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.
- files = @paths.collect { |path, files| files.map(&:to_s) }.flatten
- files = files.collect { |f| File.directory?(f) ? FileList[File.join(f, "**", "*")].collect | [f] : f }.flatten
- most_recent = files.select { |f| File.exist?(f) }.collect { |f| File.stat(f).mtime }.max
+ most_recent = @paths.collect { |name, path| path.expand_sources }.flatten.
+ each { |src| File.directory?(src) ? FileList[File.join(src, "**", "*")] | [src] : src }.flatten.
+ select { |file| File.exist?(file) }.collect { |file| File.stat(file).mtime }.max
File.stat(name).mtime < (most_recent || Rake::EARLY)
end
protected
def create(zip)
- zip_map.keys.sort.each do |path|
- puts "Adding #{path}" if Rake.application.options.trace
- zip.add path, zip_map[path]
- end
+ @paths.each { |name, obj| obj.add_file zip }
end
def zip_map()
unless @zip_map
args = @paths.collect do |path, files|
@@ -242,12 +376,13 @@
def from_path(path)
@paths[path] ||= FromPath.new(path)
end
def needed?()
- return true unless target && File.exist?(target)
- return true if prerequisites.any? { |prereq| File.stat(prereq).mtime > File.stat(target).mtime }
- false
+ #return true unless target && File.exist?(target)
+ #return true if prerequisites.any? { |prereq| File.stat(prereq).mtime > File.stat(target).mtime }
+ #false
+ true
end
# :nodoc:
class FromPath