require 'fileutils' require 'SecureRandom' class Wix def self.install_path=(value) raise "WIX path '#{value}' does not exist" unless(Dir.exists?(value)) @install_path = value end def self.install_path @install_path = ENV['WIX'] if(@install_path.nil?) return @install_path end def self.make_mergemodule(output, input) gem_dir = File.dirname(__FILE__) apply_wix_template(output, input, "#{gem_dir}/templates/mergemodule.wxs") end def self.make_installation(output, input) gem_dir = File.dirname(__FILE__) apply_wix_template(output, input, "#{gem_dir}/templates/Install.wxs") end def self.create_mergemodule_wixfile(output_wixfile, input) gem_dir = File.dirname(__FILE__) create_wix_file(output_wixfile, input, "#{gem_dir}/templates/mergemodule.wxs") end def self.create_installation_wixfile(output_wixfile, input) gem_dir = File.dirname(__FILE__) create_wix_file(output_wixfile, input, "#{gem_dir}/templates/mergemodule.wxs") end private def self.create_wix_file(wix_file, input, template) product_name = File.basename(wix_file, '.wxs') product_name = input[:product_name] if(input.kind_of?(Hash) && input.has_key?(:product_name)) wxs_text = File.read(template) files = input files = input[:files] if(input.kind_of?(Hash)) wxs_text = manage_files(wxs_text, files) wxs_text = wxs_text.gsub(/PRODUCT_NAME/) { |s| s = product_name } wxs_text = wxs_text.gsub(/MODULE_NAME/) { |s| s = product_name } product_code = "{#{SecureRandom.uuid}}" product_code = input[:product_code] if(input.kind_of?(Hash) && input.has_key?(:product_code)) wxs_text = wxs_text.gsub(/PRODUCT_CODE/) { |s| s = product_code } upgrade_code = "{#{SecureRandom.uuid}}" upgrade_code = input[:upgrade_code] if(input.kind_of?(Hash) && input.has_key?(:upgrade_code)) wxs_text = wxs_text.gsub(/UPGRADE_CODE/) { |s| s = upgrade_code } product_version = '0.0.0.0' product_version = input[:version] if(input.kind_of?(Hash) && input.has_key?(:version)) wxs_text = wxs_text.gsub(/VERSION/) { |s| s = product_version } manufacturer = '' manufacturer = input[:manufacturer] if(input.kind_of?(Hash) && input.has_key?(:manufacturer)) dir_xml = "" dir_xml = "#{dir_xml}" if(manufacturer.length > 0) wxs_text = wxs_text.gsub(/MANUFACTURER/) { |s| s = manufacturer } unless(manufacturer.empty?) wxs_text = wxs_text.gsub(/INSTALL_DIR/) { |s| s = dir_xml } #puts wxs_text File.open(wix_file, 'w') { |f| f.puts(wxs_text) } end def self.apply_wix_template(output, input, template) ext = File.extname(output) basename = File.basename(output, ext) FileUtils.rm(output) if(File.exists?(output)) output_path = File.dirname(output) wix_file = "#{File.dirname(output)}/#{basename}.wxs" create_wix_file(wix_file, input, template) raise 'WIX path is not set!' if(install_path.nil?) stdout = %x[\"#{install_path}\\bin\\candle.exe\" -out \"#{output_path}/#{basename}.wixobj\" \"#{wix_file}\"] raise "#{stdout}\nFailed to generate .wixobj file" unless(File.exists?("#{output_path}/#{basename}.wixobj")) stdout = %x[\"#{install_path}\\bin\\light.exe\" -nologo -out \"#{output}\" \"#{output_path}/#{basename}.wixobj\"] raise "#{stdout}\nFailed to generate #{output} file" unless(File.exists?(output)) Dir.glob("#{output_path}/#{basename}.{wxs,wixobj,wixpdb}") { |file| FileUtils.rm(file) } end def self.wix_id(file) id = "id_#{file}".gsub(/[^a-zA-Z0-9_\.]/) { |s| s = '_' } max_id_length = 72 - 2 id = id.slice(id.length-max_id_length, max_id_length) unless(id.length <= max_id_length) id = "id#{id}" return id end def self.files_to_xml(files) xml = '' files.each do |file| if(File.extname(file) == ".msm") file_xml = "" else file_xml = "\n" end xml = "#{xml}#{file_xml}" end return xml end def self.files_xml(dir_files_hash) xml = '' dir_files_hash.each do |directory, value| if(value.is_a?(Hash)) xml = "#{xml}\n" unless(directory == '.') xml = "#{xml}#{files_to_xml(value[:files])}" if(value.has_key?(:files)) xml = "#{xml}#{files_xml(value)}" xml = "#{xml}\n" unless(directory == '.') end end return xml end def self.component_refs_xml(dir_files_hash) xml = '' dir_files_hash.each do |directory, value| if(value.is_a?(Hash)) if(value.has_key?(:files)) value[:files].each do |file| if(File.extname(file) == ".msm") xml = "#{xml}\n" else xml = "#{xml}\n" end end end xml = "#{xml}#{component_refs_xml(value)}" end end return xml end def self.manage_files(wxs_text, files) dir_files = {} files.each do |file| if(File.file?(file)) dir_path = File.dirname(file) dir_hash = dir_files dir_path.split('/').each do |d| if(!dir_hash.has_key?(d)) dir_hash[d] = Hash.new unless(dir_hash.has_key?(d)) if(dir_hash.has_key?(:full_path)) dir_hash[d][:full_path] = "#{dir_hash[:full_path]}/#{d}" else dir_hash[d][:full_path] = d end end dir_hash = dir_hash[d] end dir_hash[:files] = Array.new unless(dir_hash.has_key?(:files)) dir_hash[:files].insert(dir_hash[:files].length, file) end end wxs_text = wxs_text.gsub(/COMPONENT_REFS/) { |s| s = component_refs_xml(dir_files) } wxs_text = wxs_text.gsub(/FILES/) { |s| s = files_xml(dir_files) } return wxs_text end end