require "zipper/version" require "zipper/fileEntryType" require "zipper/fileEntry" require "zipper/zipEntry" require "zipper/JsonConfigKey" require "zip" module Zipper class ZipFileGenerator # Initialize with the json config. def initialize(json_config) @entries = json_config[JsonConfigKey::Entries] @ignore_entries = json_config[JsonConfigKey::IgnoreEntries] @output_file = json_config[JsonConfigKey::Name] end # Zip the input entries. def write buffer = create_zip(@entries, @ignore_entries) puts "\nwrite file #{@output_file}" File.open(@output_file, "wb") {|f| f.write buffer.string } end private # True if +fileEntry+ isn't included into +ignore_entries+ array # Params: # +file_entry_name+:: name of the entry # +file_entry_type+:: type of the entry # +ignore_entries+:: array of entries for which should be excluded (false returned) def filter_entries(file_entry_name, file_entry_type, ignore_entries) return true if ignore_entries == nil ignore_entries.each do |entry| return false if (file_entry_type.casecmp(FileEntryType::FILE) == 0) && (file_entry_name.include? entry) end return true end # Creates +FileEntry+ for file or array of entries for directory and subdirectories # Params: # +directory_or_file+:: path to directory or file # +entry_path+:: path with which the entry should be put into zip def get_entries(directory_or_file, entry_path, ignore_entries) if File.directory? directory_or_file get_dir_entries_recursively(directory_or_file, entry_path, ignore_entries) else FileEntry.new(directory_or_file, FileEntryType::FILE, false, entry_path) end end # Collects all files from directory recursively # Params: # +dir+:: start directory # +entry_path+:: path with which file should be placed into zip # +replace_path+:: part of path which is being replaced by +entry_path+ def get_dir_entries_recursively(dir, entry_path, ignore_entries, replace_path = nil) replace_path = dir.clone if replace_path.nil? (Dir.entries(dir) - %w(. ..)).map { |v| File.join(dir, v) }.select { |path| filter_entries path, FileEntryType::FILE, ignore_entries }.map { |path| if File.directory? path get_dir_entries_recursively(path, entry_path, ignore_entries, replace_path) else entry_path_in_zip = (entry_path.nil? ? path : path.sub(replace_path, entry_path)).gsub(/^[\/\\]+/, "") FileEntry.new(path, FileEntryType::FILE, false, entry_path_in_zip) end } end # Creates zip file in memory from passed +FileEntry+ array, returns StringIO as result # Params: # +entries+:: array of +FileEntry+ and +ZipEntry+ objects def compress(entries) puts "\nadding the following entries into zip package" puts "#{ entries.map{ |x| x.name + ", " + x.path.to_s + ", " + x.type.to_s }.join("\n")}" buffer = Zip::File.add_buffer do |zio| entries.each do |file| if file.is_a FileEntry zio.add(file.path == nil ? file.name : file.path, file.name) else zio.get_output_stream(file.name) { |os| os.write file.buffer.string } end end end end # Creates from json array of entries # Params: # +entries+:: input entries to compress # +ignore_entries+:: entries which should be ignored def create_zip(entries, ignore_entries) compress(entries.map { |x| if x.is_a? String get_entries(x, nil, ignore_entries) elsif x[JsonConfigKey::Type].nil? || x[JsonConfigKey::Type].casecmp(FileEntryType::FILE) == 0 get_entries(x[JsonConfigKey::Name], x[JsonConfigKey::Path], ignore_entries) elsif x[JsonConfigKey::Type].casecmp(FileEntryType::ZIP) == 0 ZipEntry.new(x[JsonConfigKey::Name], create_zip(x[JsonConfigKey::Entries], x[JsonConfigKey::IgnoreEntries])) end }.flatten.select{ |f| filter_entries(f.name, f.type, ignore_entries) }.uniq{ |f| f.name }) end end end