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