Adding aggregate method to allow concatenating file contents when merging archives
authorAntoine Toulme <antoine@lunar-ocean.com>
Sat, 29 Jul 2017 08:13:51 +0000 (01:13 -0700)
committerAntoine Toulme <antoine@lunar-ocean.com>
Sat, 29 Jul 2017 08:13:51 +0000 (01:13 -0700)
CHANGELOG
lib/buildr/packaging/archive.rb
lib/buildr/packaging/tar.rb
lib/buildr/packaging/ziptask.rb
spec/packaging/archive_spec.rb

index 70388a0..91b01e4 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,7 @@
 1.5.4 (Pending)
 * Added: Support to compiling Kotlin
 * Fixed: Remove section on development builds in the Contributing section.
+* Added: New way to concatenate file contents when merging several archives together.
 
 1.5.3 (2017-05-17)
 * Change: Add support for gwt 2.8.1 to gwt addon.
index d710b8c..59e2f61 100644 (file)
@@ -267,6 +267,11 @@ module Buildr #:nodoc:
         @expanders.each { |expander| expander.exclude(*files) }
         self
       end
+      
+      def aggregate(*files)
+        @expanders.each { |expander| expander.aggregate(*files) }
+        self
+      end
     end
 
 
@@ -277,6 +282,7 @@ module Buildr #:nodoc:
         @zip_file = zip_file.to_s
         @includes = []
         @excludes = []
+        @aggregates = []
       end
 
       def include(*files)
@@ -289,6 +295,11 @@ module Buildr #:nodoc:
         @excludes |= files
         self
       end
+      
+      def aggregate(*files)
+        @aggregates |= files
+        self
+      end
 
       def expand(file_map, path)
         @includes = ['*'] if @includes.empty?
@@ -298,7 +309,11 @@ module Buildr #:nodoc:
                !@excludes.any? { |pattern| File.fnmatch(pattern, entry.name) }
               dest = path =~ /^\/?$/ ? entry.name : Util.relative_path(path + "/" + entry.name)
               trace "Adding #{dest}"
-              file_map[dest] = ZipEntryData.new(source, entry)
+              if @aggregates.any? { |pattern| File.fnmatch(pattern, entry.name) }
+                file_map[dest] << ZipEntryData.new(source, entry)
+              else
+                file_map[dest] = ZipEntryData.new(source, entry)
+              end
             end
           end
         end
@@ -327,7 +342,7 @@ module Buildr #:nodoc:
 
       # Make sure we're the last enhancements, so other enhancements can add content.
       enhance do
-        @file_map = {}
+        @file_map = Hash.new {|h,k| h[k]=[]}
         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;
@@ -485,7 +500,7 @@ module Buildr #:nodoc:
       @prepares.each { |prepare| prepare.call(self) }
       @prepares.clear
 
-      file_map = {}
+      file_map = Hash.new {|h,k| h[k]=[]}
       @paths.each do |name, path|
         path.add_files(file_map)
       end
index fe1da78..8e094a4 100644 (file)
@@ -72,7 +72,7 @@ module Buildr #:nodoc:
       end
     end
 
-  private
+    private
 
     def create_from(file_map)
       if gzip
@@ -90,22 +90,38 @@ module Buildr #:nodoc:
       Archive::Tar::Minitar::Writer.open(out) do |tar|
         options = { :mode=>mode || '0755', :mtime=>Time.now }
 
-        file_map.each do |path, content|
-          if content.respond_to?(:call)
-            tar.add_file(path, content.respond_to?(:mode) ? options.merge(:mode => content.mode) : options) { |os, _| content.call os }
-          elsif content.nil?
-          elsif File.directory?(content.to_s)
-            stat = File.stat(content.to_s)
+        file_map.each do |path, contents|
+          if contents.nil?
+          elsif File.directory?(contents.to_s)
+            stat = File.stat(contents.to_s)
             tar.mkdir(path, options.merge(:mode=>stat.mode, :mtime=>stat.mtime, :uid=>stat.uid, :gid=>stat.gid))
           else
-            File.open content.to_s, 'rb' do |is|
-              tar.add_file path, options.merge(:mode=>is.stat.mode, :mtime=>is.stat.mtime, :uid=>is.stat.uid, :gid=>is.stat.gid) do |os, opts|
-                while data = is.read(4096)
-                  os.write(data)
+            contents = [contents].flatten
+            
+            combined_options = options
+            if File.exists?(contents.first.to_s)
+              stat = File.stat(contents.first.to_s)
+              combined_options = options.merge(:mode=> stat.mode, :mtime=> stat.mtime, :uid=>stat.uid, :gid=> stat.gid)
+            elsif contents.first.respond_to?(:mode)
+              combined_options = combined_options.merge(:mode => contents.first.mode)
+            end
+              
+            
+            tar.add_file path, combined_options do |os, opts|
+              [contents].flatten.each do |content|
+                if content.respond_to?(:call)
+                  content.call os
+                else
+                  File.open content.to_s, 'rb' do |is| 
+                    while data = is.read(4096)
+                      os.write(data)
+                    end
+                  end
                 end
               end
             end
           end
+          
         end
       end
     end
@@ -128,7 +144,7 @@ module Buildr #:nodoc:
     def contain?(*patterns)
       content = read_content_from_tar
       patterns.map { |pattern| Regexp === pattern ? pattern : Regexp.new(Regexp.escape(pattern.to_s)) }.
-        all? { |pattern| content =~ pattern }
+      all? { |pattern| content =~ pattern }
     end
 
     # :call-seq:
index 8fe9d51..3b9f97d 100644 (file)
@@ -49,7 +49,7 @@ module Buildr #:nodoc:
       @entries ||= Zip::File.open(name) { |zip| zip.entries }
     end
 
-  private
+    private
 
     def create_from(file_map)
       Zip::OutputStream.open name do |zip|
@@ -65,21 +65,32 @@ module Buildr #:nodoc:
 
         paths = file_map.keys.sort
         paths.each do |path|
-          content = file_map[path]
+          contents = file_map[path]
           warn "Warning:  Path in zipfile #{name} contains backslash: #{path}" if path =~ /\\/
-          mkpath.call File.dirname(path)
-          if content.respond_to?(:call)
-            entry = zip.put_next_entry(path, compression_level)
-            entry.unix_perms = content.mode & 07777 if content.respond_to?(:mode)
-            content.call zip
-          elsif content.nil? || File.directory?(content.to_s)
-            mkpath.call path
-          else
-            entry = zip.put_next_entry(path, compression_level)
-            File.open content.to_s, 'rb' do |is|
-              entry.unix_perms = is.stat.mode & 07777
-              while data = is.read(4096)
-                zip << data
+          
+          entry_created = false
+          [contents].flatten.each do |content|
+            if content.respond_to?(:call)
+              unless entry_created
+                entry = zip.put_next_entry(path, compression_level) unless entry_created
+                entry.unix_perms = content.mode & 07777 if content.respond_to?(:mode)
+                entry_created = true
+              end
+              content.call zip
+            elsif content.nil? || File.directory?(content.to_s)
+              mkpath.call path
+            else
+              File.open content.to_s, 'rb' do |is|
+                unless entry_created
+                  entry = zip.put_next_entry(path, compression_level)
+                  entry.unix_perms = is.stat.mode & 07777
+                  entry_created = true
+                end
+                
+                
+                while data = is.read(4096)
+                  zip << data
+                end
               end
             end
           end
@@ -304,7 +315,7 @@ module Buildr #:nodoc:
           if entry.name =~ /^#{@path}/
             short = entry.name.sub(@path, '')
             if includes.any? { |pat| File.fnmatch(pat, short) } &&
-               !excludes.any? { |pat| File.fnmatch(pat, short) }
+              !excludes.any? { |pat| File.fnmatch(pat, short) }
               map[short] = entry
             end
           end
index d7121b5..73ba1ba 100644 (file)
@@ -306,6 +306,20 @@ shared_examples_for 'ArchiveTask' do
       inspect_archive.should be_empty
     end
   end
+  
+  it 'should merge archives, aggregating file contents' do
+    @files = %w{foo1 foo2}.map { |folder| File.join(@dir, folder) }.
+      map do |dir|
+        txt_file = File.join(dir, 'test1.txt')
+        write txt_file, content_for('test1.txt')
+        zip(File.join(dir, 'test1.zip')).include(txt_file)
+      end
+    archive(@archive).merge(@files).aggregate("test1.txt")
+    archive(@archive).invoke
+    inspect_archive do |archive|
+      archive['test1.txt'].should eql(content_for('test1.txt') * @files.size)
+    end
+  end
 
   it 'should expand another archive file into path' do
     create_for_merge do |src|