wixgem 0.93.0 → 0.99.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ddea153e8cc07cae015c0042909635ccd7038d9841effe63e50f96dab50e913a
4
- data.tar.gz: bf0053b8b8eed64985cceb49c276a665c2c89ab73407bc296e04ff6c42d43235
3
+ metadata.gz: ad604c669315ebac1c9b8b70a76ee956e65b8b3aeec95e92ad952f3b8e185bb7
4
+ data.tar.gz: 111ab3b46b72aee343a638918dbfce3e6498e5309fe6ceeaa46551f2e1560c5c
5
5
  SHA512:
6
- metadata.gz: 47f45661aaac13b772197ad8106fdf4117e0d610deda357b4f3803c31eb55aafa266f1d8bef8501e7e43ad325e0cb43ee74fe65b6f9f0d3d2bec59d22ee28aa9
7
- data.tar.gz: f0a71b27bd0e182c492c5d3c92febae5b04803cb7862623b4719b1f8fc049f06689f970d06d5ba8948488703e0446ba64dfa4ac50fadd930548249d098676e49
6
+ metadata.gz: 0b74e4e894a2087ed6f89f8d0ee0b9b5dc03a95f124c7ac9535f40e9847ff7b3cb19cb22deb31329c4e3c68978aa63c94f114f5349cdd9a1e7e2531e0a289a28
7
+ data.tar.gz: 9da8e9369d947d367d2a704a6aac16ab7f37a96bf790927ef80c77805cff74ff48acf56c682b3b9807f11f142bb9949148ad57d3cddcd3a51ae3da55c8837742
Binary file
data/example/example.msm CHANGED
Binary file
data/lib/custom_action.rb CHANGED
@@ -9,78 +9,73 @@ class CustomAction
9
9
  @input = input
10
10
  end
11
11
  def add(custom_action)
12
- unless(custom_action.key?(:file) || custom_action.key?(:binary_key) || custom_action.key?(:property))
13
- raise 'Currently, only supported custom actions work with installed executable, binary key, or property'
14
- end
12
+ unless(custom_action.key?(:file) || custom_action.key?(:binary_key) || custom_action.key?(:property) || custom_action.key?(:directory))
13
+ raise 'Currently, only supported custom actions work with installed executable, binary key, property, or directory'
14
+ end
15
15
 
16
- file_key=nil
17
- if(custom_action.key?(:file))
16
+ file_key=nil
17
+ if(custom_action.key?(:file))
18
18
  install_path = ".\\#{custom_action[:file].gsub(/\//,'\\')}"
19
- file_elements = REXML::XPath.match(@xml_doc, "//File[@Source='#{install_path}']")
20
- raise "Unable to locate installation file '#{custom_action[:file]} for custom action'" if(file_elements.nil? || (file_elements.size == 0))
19
+ file_elements = REXML::XPath.match(@xml_doc, "//File[@Source='#{install_path}']")
20
+ raise "Unable to locate installation file '#{custom_action[:file]} for custom action'" if(file_elements.nil? || (file_elements.size == 0))
21
21
 
22
- file_key = file_elements[0].attributes['Id']
23
- end
22
+ file_key = file_elements[0].attributes['Id']
23
+ end
24
24
 
25
- id = "ca_#{SecureRandom.uuid.gsub(/-/,'')}"
26
- id = custom_action[:id] if(custom_action.key?(:id))
25
+ id = "ca_#{SecureRandom.uuid.gsub(/-/,'')}"
26
+ id = custom_action[:id] if(custom_action.key?(:id))
27
+
28
+ impersonate = 'yes'
29
+ impersonate = custom_action[:impersonate] if(custom_action.key?(:impersonate))
27
30
 
28
- cmd_line = ''
29
- cmd_line = custom_action[:exe_command] if(custom_action.key?(:exe_command))
31
+ condition='NOT Installed AND NOT REMOVE'
32
+ condition='1' if(custom_action.key?(:binary_key))
33
+ condition = custom_action[:condition] if(custom_action.key?(:condition))
30
34
 
31
- impersonate = 'yes'
32
- impersonate = custom_action[:impersonate] if(custom_action.key?(:impersonate))
35
+ execute='deferred'
36
+ execute = custom_action[:execute] if(custom_action.key?(:execute))
33
37
 
34
- condition='NOT Installed AND NOT REMOVE'
35
- condition='1' if(custom_action.key?(:binary_key))
36
- condition = custom_action[:condition] if(custom_action.key?(:condition))
38
+ ret='check'
39
+ ret = custom_action[:return] if(custom_action.key?(:return))
37
40
 
38
- execute='deferred'
39
- execute = custom_action[:execute] if(custom_action.key?(:execute))
41
+ wix_element = REXML::XPath.match(@xml_doc, "/Wix")[0]
42
+ fragment = wix_element.add_element 'Fragment'
40
43
 
41
- ret='check'
42
- ret = custom_action[:return] if(custom_action.key?(:return))
43
-
44
- wix_element = REXML::XPath.match(@xml_doc, "/Wix")[0]
45
- fragment = wix_element.add_element 'Fragment'
46
-
47
- action = fragment.add_element 'CustomAction', { 'Id' => id, 'Impersonate' => impersonate, 'Return' => ret, 'HideTarget' => 'no', 'Execute' => execute }
48
- if(custom_action.key?(:binary_key))
49
- action.attributes['BinaryKey'] = custom_action[:binary_key]
50
- else
51
- action.attributes['FileKey'] = file_key
52
- end
53
-
54
- action.attributes['ExeCommand'] = cmd_line if(custom_action.key?(:exe_command))
44
+ action = fragment.add_element 'CustomAction', { 'Id' => id, 'Impersonate' => impersonate, 'Return' => ret, 'HideTarget' => 'no', 'Execute' => execute }
45
+ if(custom_action.key?(:binary_key))
46
+ action.attributes['BinaryKey'] = custom_action[:binary_key]
47
+ else
48
+ action.attributes['FileKey'] = file_key
49
+ end
55
50
 
56
- action.attributes['DllEntry'] = custom_action[:dll_entry] if(custom_action.key?(:dll_entry))
51
+ action.attributes['Directory'] = custom_action[:directory] if(custom_action.key?(:directory))
52
+ action.attributes['ExeCommand'] = custom_action[:exe_command] if(custom_action.key?(:exe_command))
53
+ action.attributes['DllEntry'] = custom_action[:dll_entry] if(custom_action.key?(:dll_entry))
57
54
 
58
- if(custom_action.key?(:property))
59
- raise "Custom action property '#{custom_action[:property]} must have a value!" unless(custom_action.key?(:value))
60
- action.attributes.delete('ExeCommand')
61
- action.attributes.delete('Return')
62
- action.attributes['Property'] = custom_action[:property]
63
- action.attributes['Value'] = custom_action[:value]
64
- end
55
+ if(custom_action.key?(:property))
56
+ raise "Custom action property '#{custom_action[:property]} must have a value!" unless(custom_action.key?(:value))
57
+ action.attributes.delete('ExeCommand')
58
+ action.attributes.delete('Return')
59
+ action.attributes['Property'] = custom_action[:property]
60
+ action.attributes['Value'] = custom_action[:value]
61
+ end
65
62
 
66
63
  install_execute_sequence = fragment.add_element 'InstallExecuteSequence'
67
64
 
68
- custom_action[:before] = 'InstallFinalize' if(!custom_action.key?(:after) && !custom_action.key?(:before))
69
- if(custom_action.key?(:after))
70
- action = install_execute_sequence.add_element 'Custom', { 'Action' => id, 'After' => custom_action[:after] }
65
+ custom_action[:before] = 'InstallFinalize' if(!custom_action.key?(:after) && !custom_action.key?(:before))
66
+ if(custom_action.key?(:after))
67
+ action = install_execute_sequence.add_element 'Custom', { 'Action' => id, 'After' => custom_action[:after] }
71
68
  action.text = condition
72
- else
73
- action = install_execute_sequence.add_element 'Custom', { 'Action' => id, 'Before' => custom_action[:before] }
69
+ else
70
+ action = install_execute_sequence.add_element 'Custom', { 'Action' => id, 'Before' => custom_action[:before] }
74
71
  action.text = condition
75
- end
72
+ end
76
73
 
77
- control=nil
78
- elements = REXML::XPath.match(@xml_doc, "/Wix/Product")
79
- elements = REXML::XPath.match(@xml_doc, "/Wix/Module") if(elements.nil? || elements.size == 0)
74
+ control=nil
75
+ elements = REXML::XPath.match(@xml_doc, "/Wix/Product")
76
+ elements = REXML::XPath.match(@xml_doc, "/Wix/Module") if(elements.nil? || elements.size == 0)
80
77
 
81
- elements[0].add_element 'CustomActionRef', { 'Id' => id }
82
-
78
+ elements[0].add_element 'CustomActionRef', { 'Id' => id }
83
79
  end
84
80
  end
85
-
86
81
  end
data/lib/file.rb CHANGED
@@ -4,10 +4,10 @@ class File
4
4
  def self.read_only?(path)
5
5
  raise "'#{path}' does not exist" unless(File.exists?(path))
6
6
 
7
- fso = WIN32OLE.new('Scripting.FileSystemObject')
7
+ fso = WIN32OLE.new('Scripting.FileSystemObject')
8
8
  raise 'Failed to create Scripting.FileSystemObject' if(fso.nil?)
9
- fo = fso.GetFile(path)
9
+ fo = fso.GetFile(path)
10
10
 
11
- return ((fo.Attributes & 1) != 0) ? true : false
11
+ return ((fo.Attributes & 1) != 0) ? true : false
12
12
  end
13
13
  end
data/lib/service.rb ADDED
@@ -0,0 +1,86 @@
1
+ require 'rexml/document'
2
+ require 'SecureRandom'
3
+
4
+ #module Wixgem
5
+
6
+ class Service
7
+ def initialize(hash)
8
+ @hash = hash
9
+ end
10
+
11
+ def create(xml_doc)
12
+ raise "Service hash is required to have a :service_exe key" unless(@hash.has_key?(:service_exe))
13
+ raise "Service hash is required to have a :service key" unless(@hash.has_key?(:service))
14
+ raise "Service hash is required to have a :name key" unless(@hash[:service].has_key?(:name))
15
+
16
+ service_exe = @hash[:service_exe]
17
+ raise "Service #{file} does not exist" unless(File.exists?(service_exe))
18
+
19
+ file_elements = REXML::XPath.match(xml_doc, "//File[@Source='.\\#{service_exe.gsub(/\//,'\\')}']")
20
+ raise "Service #{@file} does not match a 'File' element with a 'Source' attribute in the wix generated wix file" if(file_elements.length == 0)
21
+
22
+ service_exe_element = file_elements[0]
23
+ service_exe_element.attributes['KeyPath']='yes'
24
+
25
+ create_service_element(service_exe_element)
26
+
27
+ return xml_doc
28
+ end
29
+
30
+ private
31
+ def create_service_element(service_exe_element)
32
+ parent_element = service_exe_element.parent
33
+
34
+ service = @hash[:service]
35
+ service_control = {}
36
+ service_control = @hash[:service_control] if(@hash.has_key?(:service))
37
+
38
+ service_element = parent_element.add_element('ServiceInstall')
39
+
40
+ service_element.attributes['Id'] = "Service_#{SecureRandom.uuid.gsub(/-/,'')}"
41
+ service_element.attributes['Name'] = service[:name]
42
+ service_element.attributes['ErrorControl'] = 'normal'
43
+ service_element.attributes['Start'] = 'demand'
44
+ service_element.attributes['Type'] = 'ownProcess'
45
+
46
+ service_control_element = parent_element.add_element 'ServiceControl'
47
+ service_control_element.attributes['Id'] = "ServiceControl_#{SecureRandom.uuid.gsub(/-/,'')}"
48
+ service_control_element.attributes['Name'] = service[:name]
49
+
50
+ service.each { |attribute, value| service_element.attributes[symbol_to_id(attribute)] = value }
51
+ service_control.each { |attribute, value| service_control_element.attributes[symbol_to_id(attribute)] = value }
52
+
53
+ return service_element
54
+ end
55
+ def symbol_to_id(symbol)
56
+ service_map = {
57
+ account: 'Account',
58
+ arguments: 'Arguments',
59
+ description: 'Description',
60
+ display_name: 'DisplayName',
61
+ erase_description: 'EraseDescription',
62
+ error_control: 'ErrorControl',
63
+ id: 'Id',
64
+ interactive: 'Interactive',
65
+ load_order_group:'LoadOrderGroup',
66
+ name: 'Name',
67
+ password: 'Password',
68
+ start: 'Start',
69
+ type: 'Type',
70
+ vital: 'Vital'
71
+ }
72
+
73
+ return service_map[symbol] if(service_map.has_key?(symbol))
74
+
75
+ service_control_map = {
76
+ id: 'Id',
77
+ name: 'Name',
78
+ remove: 'Remove',
79
+ start: 'Start',
80
+ stop: 'Stop',
81
+ wait: 'Wait'
82
+ }
83
+ return service_control_map[symbol]
84
+ end
85
+ end
86
+
data/lib/wixgem.rb CHANGED
@@ -8,6 +8,7 @@ require_relative 'shortcut.rb'
8
8
  require_relative 'custom_action.rb'
9
9
  require_relative 'temp_directory.rb'
10
10
  require_relative 'associate_extension.rb'
11
+ require_relative 'service.rb'
11
12
 
12
13
  # Editor for wix Files WixEdit: http://http://wixedit.sourceforge.net/
13
14
  # Full list of Wix editors : http://robmensching.com/blog/posts/2007/11/20/wix-editors/
@@ -61,29 +62,29 @@ class Wix
61
62
  end
62
63
 
63
64
  def self.manage_installdir(xml_doc, input)
64
- product_target_elements = REXML::XPath.match(xml_doc, "/Wix/Product/Directory[@Id='TARGETDIR']")
65
- if(!product_target_elements.nil? && product_target_elements.size == 1)
66
- targetdir = product_target_elements[0]
67
- installdir = targetdir.add_element 'Directory', { 'Id' => 'ProgramFilesFolder' }
65
+ product_target_elements = REXML::XPath.match(xml_doc, "/Wix/Product/Directory[@Id='TARGETDIR']")
66
+ if(!product_target_elements.nil? && product_target_elements.size == 1)
67
+ targetdir = product_target_elements[0]
68
+ installdir = targetdir.add_element 'Directory', { 'Id' => 'ProgramFilesFolder' }
68
69
  installdir = installdir.add_element 'Directory', { 'Id' => "Dir_#{input[:manufacturer]}", 'Name' => input[:manufacturer] } if(input.has_key?(:manufacturer))
69
- installdir = installdir.add_element 'Directory', { 'Id' => 'INSTALLDIR', 'Name' => input[:product_name] }
70
- else
71
- module_target_elements = REXML::XPath.match(xml_doc, "/Wix/Module/Directory[@Id='TARGETDIR']")
72
- targetdir = module_target_elements[0]
73
- targetdir.add_element 'Directory', { 'Id' => 'MergeRedirectFolder', 'FileSource' => '.' }
74
- end
75
- return xml_doc
70
+ installdir = installdir.add_element 'Directory', { 'Id' => 'INSTALLDIR', 'Name' => input[:product_name] }
71
+ else
72
+ module_target_elements = REXML::XPath.match(xml_doc, "/Wix/Module/Directory[@Id='TARGETDIR']")
73
+ targetdir = module_target_elements[0]
74
+ targetdir.add_element 'Directory', { 'Id' => 'MergeRedirectFolder', 'FileSource' => '.' }
75
+ end
76
+ return xml_doc
76
77
  end
77
78
 
78
79
  def self.manage_netframework(xml_doc, input)
79
80
  if(input.key?(:requires_netframework))
80
- wix = REXML::XPath.match(xml_doc, "/Wix")[0]
81
- wix.attributes['xmlns:netfx'] = 'https://schemas.microsoft.com/wix/NetFxExtension'
81
+ wix = REXML::XPath.match(xml_doc, "/Wix")[0]
82
+ wix.attributes['xmlns:netfx'] = 'https://schemas.microsoft.com/wix/NetFxExtension'
82
83
 
83
- product = REXML::XPath.match(xml_doc, "/Wix/Product")[0]
84
- product.add_element 'PropertyRef', { 'Id' => input[:requires_netframework] }
85
- condition = product.add_element 'Condition', { 'Message' => "This application requires .NET Framework #{input[:requires_netframework]}. Please install the .NET Framework then run this installer again." }
86
- condition.text = "<![CDATA[Installed OR #{input[:requires_netframework]}]]>"
84
+ product = REXML::XPath.match(xml_doc, "/Wix/Product")[0]
85
+ product.add_element 'PropertyRef', { 'Id' => input[:requires_netframework] }
86
+ condition = product.add_element 'Condition', { 'Message' => "This application requires .NET Framework #{input[:requires_netframework]}. Please install the .NET Framework then run this installer again." }
87
+ condition.text = "<![CDATA[Installed OR #{input[:requires_netframework]}]]>"
87
88
  end
88
89
 
89
90
  return xml_doc
@@ -91,16 +92,16 @@ class Wix
91
92
 
92
93
  def self.manage_win10_crt(xml_doc, input)
93
94
  if(input.key?(:requires_win10_crt))
94
- product = REXML::XPath.match(xml_doc, "/Wix/Product")[0]
95
+ product = REXML::XPath.match(xml_doc, "/Wix/Product")[0]
95
96
 
96
- property = product.add_element 'Property', { 'Id' => 'WIN10_CRT_PRESENT' }
97
- search = property.add_element 'DirectorySearch', { 'Id' => 'SystemFolderDriverVersion', 'Path' => '[SystemFolder]' }
98
- search.add_element 'FileSearch', { 'Name' => 'ucrtbase.dll' }
97
+ property = product.add_element 'Property', { 'Id' => 'WIN10_CRT_PRESENT' }
98
+ search = property.add_element 'DirectorySearch', { 'Id' => 'SystemFolderDriverVersion', 'Path' => '[SystemFolder]' }
99
+ search.add_element 'FileSearch', { 'Name' => 'ucrtbase.dll' }
99
100
 
100
- msg = 'Requires Universal CRT see Windows Update KB2999226. Windows update should have installed the Universal CRT. Download and install from https://www.microsoft.com/en-us/download/details.aspx?id=48145'
101
- condition = product.add_element 'Condition', { 'Message' => msg }
102
- condition.text = "<![CDATA[Installed OR WIN10_CRT_PRESENT]]>"
103
- end
101
+ msg = 'Requires Universal CRT see Windows Update KB2999226. Windows update should have installed the Universal CRT. Download and install from https://www.microsoft.com/en-us/download/details.aspx?id=48145'
102
+ condition = product.add_element 'Condition', { 'Message' => msg }
103
+ condition.text = "<![CDATA[Installed OR WIN10_CRT_PRESENT]]>"
104
+ end
104
105
 
105
106
  return xml_doc
106
107
  end
@@ -108,95 +109,95 @@ class Wix
108
109
  def self.manage_ui(xml_doc, input)
109
110
  product_elements = REXML::XPath.match(xml_doc, "/Wix/Product")
110
111
 
111
- return if(product_elements.nil? || product_elements.size != 1)
112
- return unless(input.key?(:ui))
112
+ return if(product_elements.nil? || product_elements.size != 1)
113
+ return unless(input.key?(:ui))
113
114
 
114
- product = product_elements[0]
115
- ui = product.add_element 'UIRef', { 'Id' => input[:ui] }
115
+ product = product_elements[0]
116
+ ui = product.add_element 'UIRef', { 'Id' => input[:ui] }
116
117
 
117
118
  return xml_doc
118
119
  end
119
120
 
120
121
  def self.manage_upgrade(xml_doc, input)
121
- products = REXML::XPath.match(xml_doc, '//Wix/Product')
122
- return xml_doc if(products.length == 0)
122
+ products = REXML::XPath.match(xml_doc, '//Wix/Product')
123
+ return xml_doc if(products.length == 0)
123
124
 
124
- if(input[:remove_existing_products])
125
- raise 'Hash must have a version key if the hash has a :remove_existing_products key' unless(input.has_key?(:version))
126
- raise 'Hash must have an upgrade_code key if the hash has a :remove_existing_products key' unless(input.has_key?(:upgrade_code))
125
+ if(input[:remove_existing_products])
126
+ raise 'Hash must have a version key if the hash has a :remove_existing_products key' unless(input.has_key?(:version))
127
+ raise 'Hash must have an upgrade_code key if the hash has a :remove_existing_products key' unless(input.has_key?(:upgrade_code))
127
128
 
128
- upgrade = products[0].add_element 'MajorUpgrade', { 'AllowDowngrades' => 'yes' }
129
- end
129
+ upgrade = products[0].add_element 'MajorUpgrade', { 'AllowDowngrades' => 'yes' }
130
+ end
130
131
 
131
- return xml_doc
132
+ return xml_doc
132
133
  end
133
134
 
134
135
  def self.manage_custom_actions(xml_doc, input)
135
136
  custom_actions = CustomAction.new(xml_doc, input)
136
- return xml_doc if(input[:custom_actions].nil?)
137
+ return xml_doc if(input[:custom_actions].nil?)
137
138
 
138
- input[:custom_actions].each { |ca| custom_actions.add(ca) } if(input.key?(:custom_actions))
139
+ input[:custom_actions].each { |ca| custom_actions.add(ca) } if(input.key?(:custom_actions))
139
140
 
140
- return xml_doc
141
+ return xml_doc
141
142
  end
142
143
 
143
144
  def self.manage_associate_extensions(xml_doc, input)
144
145
  return xml_doc unless(input.key?(:extensions))
145
146
 
146
- ext = AssociateExtension.new(xml_doc)
147
- input[:extensions].each { |exe, file_ext| ext.associate(exe, file_ext) }
147
+ ext = AssociateExtension.new(xml_doc)
148
+ input[:extensions].each { |exe, file_ext| ext.associate(exe, file_ext) }
148
149
 
149
- return xml_doc
150
+ return xml_doc
150
151
  end
151
152
 
152
153
  def self.manage_msm_files(xml_doc)
153
- merge_modules = {}
154
- component_group = REXML::XPath.match(xml_doc, '//Wix/Fragment/ComponentGroup')
155
- component_group.each { |component_group|
156
- component_group.each_element('Component') { |component|
157
- component.each_element('File') { |file|
158
- merge_modules[component] = file if(File.extname(file.attributes['Source']) == '.msm')
159
- }
154
+ merge_modules = {}
155
+ component_group = REXML::XPath.match(xml_doc, '//Wix/Fragment/ComponentGroup')
156
+ component_group.each { |component_group|
157
+ component_group.each_element('Component') { |component|
158
+ component.each_element('File') { |file|
159
+ merge_modules[component] = file if(File.extname(file.attributes['Source']) == '.msm')
160
+ }
161
+ }
160
162
  }
161
- }
162
- return xml_doc if(merge_modules.length == 0)
163
-
164
- directory_root = REXML::XPath.match(xml_doc, "//Directory[@Id='INSTALLDIR']")
165
- if(directory_root.length == 0)
166
- module_root = REXML::XPath.match(xml_doc, '//Wix/Module')
167
- raise 'Merge modules can not be added to a merge module' unless(module_root.nil?)
168
- raise 'Wix element //Wix/Product/Directory does not exist'
169
- end
163
+ return xml_doc if(merge_modules.length == 0)
164
+
165
+ directory_root = REXML::XPath.match(xml_doc, "//Directory[@Id='INSTALLDIR']")
166
+ if(directory_root.length == 0)
167
+ module_root = REXML::XPath.match(xml_doc, '//Wix/Module')
168
+ raise 'Merge modules can not be added to a merge module' unless(module_root.nil?)
169
+ raise 'Wix element //Wix/Product/Directory does not exist'
170
+ end
170
171
 
171
- default_feature = REXML::XPath.match(xml_doc, '//Wix/Product/Feature')
172
+ default_feature = REXML::XPath.match(xml_doc, '//Wix/Product/Feature')
172
173
 
173
- merge_modules.each { |component,file|
174
- id = component.attributes['Id'].gsub('cmp','merge')
175
- directory_root[0].add_element 'Merge', { 'Id' => id, 'SourceFile' => file.attributes['Source'], 'Language' => '1033', 'DiskId' => '1'}
176
- default_feature[0].add_element 'MergeRef', { 'Id' => id }
174
+ merge_modules.each { |component,file|
175
+ id = component.attributes['Id'].gsub('cmp','merge')
176
+ directory_root[0].add_element 'Merge', { 'Id' => id, 'SourceFile' => file.attributes['Source'], 'Language' => '1033', 'DiskId' => '1'}
177
+ default_feature[0].add_element 'MergeRef', { 'Id' => id }
177
178
 
178
- component_group[0].delete_element(component)
179
+ component_group[0].delete_element(component)
179
180
  }
180
181
 
181
- return xml_doc
182
+ return xml_doc
182
183
  end
183
184
 
184
185
  def self.manage_read_only_files(xml_doc,input)
185
- install_files = files(input)
186
-
187
- install_files.each do |file|
188
- absolute_path = file
189
- absolute_path = "#{input[:original_pwd]}/#{file}" unless(File.exists?(file))
190
-
191
- if(File.read_only?(absolute_path))
192
- install_path = ".\\#{self.modify_file_path(input, file).gsub(/\//,'\\')}"
193
- install_path = install_path.gsub(/\.\\\\/,'.\\')
194
- file_elements = REXML::XPath.match(xml_doc, "//File[@Source='#{install_path}']")
195
- file_elements[0].attributes['ReadOnly'] = 'yes' if(file_elements.length == 1)
186
+ install_files = files(input)
187
+
188
+ install_files.each do |file|
189
+ absolute_path = file
190
+ absolute_path = "#{input[:original_pwd]}/#{file}" unless(File.exists?(file))
191
+
192
+ if(File.read_only?(absolute_path))
193
+ install_path = ".\\#{self.modify_file_path(input, file).gsub(/\//,'\\')}"
194
+ install_path = install_path.gsub(/\.\\\\/,'.\\')
195
+ file_elements = REXML::XPath.match(xml_doc, "//File[@Source='#{install_path}']")
196
+ file_elements[0].attributes['ReadOnly'] = 'yes' if(file_elements.length == 1)
197
+ end
196
198
  end
197
- end
198
199
 
199
- return xml_doc
200
+ return xml_doc
200
201
  end
201
202
 
202
203
  def self.manage_shortcuts(xml_doc,input)
@@ -207,31 +208,42 @@ class Wix
207
208
  xml_doc = shortcut.create(xml_doc)
208
209
  end
209
210
 
211
+ return xml_doc
212
+ end
213
+
214
+ def self.manage_services(xml_doc,input)
215
+ return xml_doc unless(input.has_key?(:services))
216
+
217
+ input[:services].each do |service_hash|
218
+ service = Service.new(service_hash)
219
+ xml_doc = service.create(xml_doc)
220
+ end
221
+
210
222
  return xml_doc
211
223
  end
212
224
 
213
225
  def self.manage_self_register(xml_doc, input)
214
226
  return xml_doc unless(input.has_key?(:com_self_register))
215
227
  input[:com_self_register].each do |file|
216
- file_elements = REXML::XPath.match(xml_doc, "//File[@Source='.\\#{file.gsub(/\//,'\\')}']")
217
- raise "Unable to find file '#{file}' for self registering" unless (file_elements.length == 1)
218
- file_elements[0].attributes['SelfRegCost'] = '0'
219
- end
228
+ file_elements = REXML::XPath.match(xml_doc, "//File[@Source='.\\#{file.gsub(/\//,'\\')}']")
229
+ raise "Unable to find file '#{file}' for self registering" unless (file_elements.length == 1)
230
+ file_elements[0].attributes['SelfRegCost'] = '0'
231
+ end
220
232
 
221
- return xml_doc
233
+ return xml_doc
222
234
  end
223
235
 
224
236
  def self.manage_binary_table(xml_doc, input)
225
- return xml_doc unless(input.has_key?(:binary_table))
226
- wix_element = REXML::XPath.match(xml_doc, "/Wix")[0]
237
+ return xml_doc unless(input.has_key?(:binary_table))
238
+ wix_element = REXML::XPath.match(xml_doc, "/Wix")[0]
227
239
 
228
- fragment = wix_element.add_element 'Fragment'
229
- input[:binary_table].each { |entry|
230
- #puts "File: #{entry[:file]}"
231
- binary = fragment.add_element 'Binary', { 'Id' => entry[:id], 'SourceFile' => entry[:file] }
232
- }
240
+ fragment = wix_element.add_element 'Fragment'
241
+ input[:binary_table].each { |entry|
242
+ #puts "File: #{entry[:file]}"
243
+ binary = fragment.add_element 'Binary', { 'Id' => entry[:id], 'SourceFile' => entry[:file] }
244
+ }
233
245
 
234
- return xml_doc
246
+ return xml_doc
235
247
  end
236
248
 
237
249
  def self.modify_file_path(input, file)
@@ -246,7 +258,8 @@ class Wix
246
258
  def self.files(input)
247
259
  files = input
248
260
  files = input[:files] if(input.kind_of?(Hash))
249
- return files
261
+
262
+ return files
250
263
  end
251
264
 
252
265
  def self.ignore_files(input)
@@ -257,328 +270,327 @@ class Wix
257
270
  end
258
271
 
259
272
  def self.copy_install_files(directory, input)
260
- files = files(input)
273
+ files = files(input)
261
274
 
262
- missing_files = []
263
- files.each do |file|
264
- if(File.file?(file))
275
+ missing_files = []
276
+ files.each do |file|
277
+ if(File.file?(file))
265
278
  install_path = file
266
279
  if(input.has_key?(:modify_file_paths))
267
280
  input[:modify_file_paths].each { |regex, replacement_string| install_path = install_path.gsub(regex, replacement_string) }
268
281
  end
269
- raise "Invalid relative installation path: #{install_path}" if(install_path.include?(':'))
282
+ raise "Invalid relative installation path: #{install_path}" if(install_path.include?(':'))
270
283
 
271
284
  install_path = "#{directory}/#{install_path}"
272
- FileUtils.mkpath(File.dirname(install_path)) unless(Dir.exists?(File.dirname(install_path)))
273
- FileUtils.cp(file, install_path, { preserve: true })
274
- elsif(!File.exists?(file))
275
- missing_files.insert(missing_files.length, file)
285
+ FileUtils.mkpath(File.dirname(install_path)) unless(Dir.exists?(File.dirname(install_path)))
286
+ FileUtils.cp(file, install_path, { preserve: true })
287
+ elsif(!File.exists?(file))
288
+ missing_files.insert(missing_files.length, file)
289
+ end
276
290
  end
277
- end
278
291
 
279
292
  if(@debug)
280
- if(files.length > 0)
281
- max_path = files.max { |a, b| a.length <=> b.length }
282
- columen_size = max_path.length + 10
283
- end
293
+ if(files.length > 0)
294
+ max_path = files.max { |a, b| a.length <=> b.length }
295
+ columen_size = max_path.length + 10
296
+ end
284
297
 
285
- ingore_files = self.ignore_files(input)
286
- if(input.has_key?(:ignore_files))
287
- @logger << "------------------------------------ ignoring files -----------------------------------" unless(@logger.nil?)
288
- input[:ignore_files].each { |file| @logger << file }
289
- end
290
-
291
- @logger << "------------------------------------ Installation Paths -----------------------------------" unless(@logger.nil?)
292
- @logger << "%-#{columen_size}s %s\n" % ['File path', 'Installation Path'] unless(@logger.nil?)
293
- files.reject! { |f| ingore_files.include?(f) }
294
-
295
- files.each do |file|
296
- if(File.file?(file))
298
+ ingore_files = self.ignore_files(input)
299
+ if(input.has_key?(:ignore_files))
300
+ @logger << "------------------------------------ ignoring files -----------------------------------" unless(@logger.nil?)
301
+ input[:ignore_files].each { |file| @logger << file }
302
+ end
303
+
304
+ @logger << "------------------------------------ Installation Paths -----------------------------------" unless(@logger.nil?)
305
+ @logger << "%-#{columen_size}s %s\n" % ['File path', 'Installation Path'] unless(@logger.nil?)
306
+ files.reject! { |f| ingore_files.include?(f) }
307
+
308
+ files.each do |file|
309
+ if(File.file?(file))
297
310
  install_path = file
298
311
  if(input.has_key?(:modify_file_paths))
299
312
  input[:modify_file_paths].each { |regex, replacement_string| install_path = install_path.gsub(regex, replacement_string) }
300
313
  end
301
- @logger << "%-#{columen_size}s %s\n" % [file, install_path] unless(@logger.nil?)
314
+ @logger << "%-#{columen_size}s %s\n" % [file, install_path] unless(@logger.nil?)
302
315
  end
303
316
  end
304
- @logger << "-------------------------------------------------------------------------------------------" unless(@logger.nil?)
305
- end
306
-
307
- raise 'No files were given to wixgem' if(files.length == 0)
317
+ @logger << "-------------------------------------------------------------------------------------------" unless(@logger.nil?)
318
+ end
308
319
 
309
- if(missing_files.length > 0)
310
- missing_files_str = ''
311
- missing_files.each { |f|
312
- if(missing_files_str.empty?)
313
- missing_files_str = f
314
- else
315
- missing_files_str = "#{missing_files_str}, #{f}"
316
- end
317
- }
318
- raise "Wixgem missing files: #{missing_files_str}"
319
- end
320
+ raise 'No files were given to wixgem' if(files.length == 0)
321
+
322
+ if(missing_files.length > 0)
323
+ missing_files_str = ''
324
+ missing_files.each { |f|
325
+ if(missing_files_str.empty?)
326
+ missing_files_str = f
327
+ else
328
+ missing_files_str = "#{missing_files_str}, #{f}"
329
+ end
330
+ }
331
+ raise "Wixgem missing files: #{missing_files_str}"
332
+ end
320
333
  end
321
334
 
322
335
  def self.modify_binary_files(input)
323
336
  return unless(input.key?(:binary_table))
324
- input[:binary_table].each { |entry| entry[:file] = File.absolute_path(entry[:file]) }
337
+ input[:binary_table].each { |entry| entry[:file] = File.absolute_path(entry[:file]) }
325
338
  end
326
339
 
327
340
  def self.log_wix_output(cmd)
328
- return unless(@debug && !@logger.nil?)
341
+ return unless(@debug && !@logger.nil?)
329
342
 
330
- @logger << "----------------------------------------------------------------------------"
331
- @logger << cmd
343
+ @logger << "----------------------------------------------------------------------------"
344
+ @logger << cmd
332
345
 
333
- if(!cmd[:output].empty?)
334
- @logger << "--------------------------- std output -----------------------------------"
335
- @logger << cmd[:output]
336
- end
346
+ if(!cmd[:output].empty?)
347
+ @logger << "--------------------------- std output -----------------------------------"
348
+ @logger << cmd[:output]
349
+ end
337
350
 
338
- if(!cmd[:error].empty?)
339
- @logger << "--------------------------- std error ------------------------------------"
340
- @logger << cmd[:error]
341
- end
351
+ if(!cmd[:error].empty?)
352
+ @logger << "--------------------------- std error ------------------------------------"
353
+ @logger << cmd[:error]
354
+ end
342
355
  end
343
356
 
344
357
  def self.modify_heat_commandline(input, cmd)
345
358
  cmd = cmd.gsub(/-srd/, '-svb6 -srd') if(input.has_key?(:has_vb6_files) && input[:has_vb6_files])
346
- cmd = cmd.gsub(/-srd/, '-sreg -srd') if(input.has_key?(:suppress_registry_harvesting) && input[:suppress_registry_harvesting])
347
- cmd = cmd.gsub(/-srd/, '-scom -srd') if(input.has_key?(:suppress_COM_elements) && input[:suppress_COM_elements])
348
- if(input[:msi?])
349
- cmd = cmd.gsub(/-srd/, '-dr INSTALLDIR -srd')
350
- else
351
- cmd = cmd.gsub(/-srd/, '-dr MergeRedirectFolder -srd')
352
- end
353
- return cmd
359
+ cmd = cmd.gsub(/-srd/, '-sreg -srd') if(input.has_key?(:suppress_registry_harvesting) && input[:suppress_registry_harvesting])
360
+ cmd = cmd.gsub(/-srd/, '-scom -srd') if(input.has_key?(:suppress_COM_elements) && input[:suppress_COM_elements])
361
+ if(input[:msi?])
362
+ cmd = cmd.gsub(/-srd/, '-dr INSTALLDIR -srd')
363
+ else
364
+ cmd = cmd.gsub(/-srd/, '-dr MergeRedirectFolder -srd')
365
+ end
366
+ return cmd
354
367
  end
355
368
 
356
369
  def self.execute_heat(input, cmd_line_options)
357
- heat_cmd = Execute.new("\"#{install_path.gsub(/\\/,'/')}/bin/heat.exe\" #{modify_heat_commandline(input, cmd_line_options)}", { quiet: true })
358
- heat_cmd.execute
359
- log_wix_output(heat_cmd)
370
+ heat_cmd = Execute.new("\"#{install_path.gsub(/\\/,'/')}/bin/heat.exe\" #{modify_heat_commandline(input, cmd_line_options)}", { quiet: true })
371
+ heat_cmd.execute
372
+ log_wix_output(heat_cmd)
360
373
  end
361
374
 
362
375
  def self.execute_heat_file(wxs_file, input, template_option)
363
- install_files = files(input)
364
- modified_paths = []
376
+ install_files = files(input)
377
+ modified_paths = []
365
378
  install_files.each { |file| modified_paths << modify_file_path(input, file) }
366
- install_files = modified_paths
379
+ install_files = modified_paths
367
380
 
368
- install_ignore_files = ignore_files(input)
369
- modified_paths = []
381
+ install_ignore_files = ignore_files(input)
382
+ modified_paths = []
370
383
  install_ignore_files.each { |file| modified_paths << modify_file_path(input, file) }
371
- install_ignore_files = modified_paths
384
+ install_ignore_files = modified_paths
372
385
 
373
- install_files.reject! { |f| install_ignore_files.include?(f) }
374
-
375
- package_type = 'installation'
376
- package_type = 'merge module' if(template_option.include?('module'))
377
- raise "At least one file is required to build a #{package_type}" if(install_files.length == 0)
386
+ install_files.reject! { |f| install_ignore_files.include?(f) }
387
+ package_type = 'installation'
388
+ package_type = 'merge module' if(template_option.include?('module'))
389
+ raise "At least one file is required to build a #{package_type}" if(install_files.length == 0)
378
390
 
379
- directory_fragments = {}
380
- wxs_files = {}
381
- install_files.each do |file|
382
- windows_path = file.gsub(/\//, '\\')
391
+ directory_fragments = {}
392
+ wxs_files = {}
393
+ install_files.each do |file|
394
+ windows_path = file.gsub(/\//, '\\')
383
395
 
384
- filename = wxs_file
385
- if(install_files.index(file) == 0)
396
+ filename = wxs_file
397
+ if(install_files.index(file) == 0)
386
398
  execute_heat(input, "file \"#{windows_path}\" -v #{template_option} -cg InstallionFiles -gg -nologo -srd -o \"#{filename}\"")
387
- else
388
- filename = File.basename(wxs_file).gsub('.wxs', "-#{wxs_files.length}.wxs")
389
- execute_heat(input, "file \"#{windows_path}\" -v -template fragment -gg -nologo -srd -o \"#{filename}\"")
390
- wxs_files[file] = filename
391
- end
392
-
393
- directory_fragments[File.dirname(file)] = "dir#{SecureRandom.uuid.gsub(/-/,'')}"
394
- xml_doc = REXML::Document.new(File.read(filename))
395
- file_elements = REXML::XPath.match(xml_doc, '//Wix/Fragment/DirectoryRef/Component/File')
396
- file_elements[0].attributes['Source'] = "SourceDir\\#{file.gsub(/\//,'\\')}" if(file_elements.length == 1)
397
- file_elements[0].attributes['Id'] = "fil#{SecureRandom.uuid.gsub(/-/,'')}" if(file_elements.length == 1) # Assigning new Id, because the id is somehow generated from the filename. So it is possible for heat to generate duplicate id's
398
-
399
- File.open(filename, 'w') { |f| f.puts(xml_doc.to_s) }
400
- end
401
- directory_fragments['.'] = 'INSTALLDIR'
399
+ else
400
+ filename = File.basename(wxs_file).gsub('.wxs', "-#{wxs_files.length}.wxs")
401
+ execute_heat(input, "file \"#{windows_path}\" -v -template fragment -gg -nologo -srd -o \"#{filename}\"")
402
+ wxs_files[file] = filename
403
+ end
404
+
405
+ directory_fragments[File.dirname(file)] = "dir#{SecureRandom.uuid.gsub(/-/,'')}"
406
+ xml_doc = REXML::Document.new(File.read(filename))
407
+ file_elements = REXML::XPath.match(xml_doc, '//Wix/Fragment/DirectoryRef/Component/File')
408
+ file_elements[0].attributes['Source'] = "SourceDir\\#{file.gsub(/\//,'\\')}" if(file_elements.length == 1)
409
+ file_elements[0].attributes['Id'] = "fil#{SecureRandom.uuid.gsub(/-/,'')}" if(file_elements.length == 1) # Assigning new Id, because the id is somehow generated from the filename. So it is possible for heat to generate duplicate id's
410
+
411
+ File.open(filename, 'w') { |f| f.puts(xml_doc.to_s) }
412
+ end
413
+ directory_fragments['.'] = 'INSTALLDIR'
402
414
 
403
- xml_doc = REXML::Document.new(File.read(wxs_file))
415
+ xml_doc = REXML::Document.new(File.read(wxs_file))
404
416
 
405
- wix_elements = REXML::XPath.match(xml_doc, '//Wix')
406
- raise "Invalid wxs file: #{wxs_file}" unless(wix_elements.length == 1)
417
+ wix_elements = REXML::XPath.match(xml_doc, '//Wix')
418
+ raise "Invalid wxs file: #{wxs_file}" unless(wix_elements.length == 1)
407
419
 
408
- directory_fragments.each do |key, id|
409
- if(key != '.')
410
- fragment_element = wix_elements[0].add_element 'Fragment'
411
- directory_ref_element = fragment_element.add_element 'DirectoryRef', { 'Id' => directory_fragments[File.dirname(key)] }
412
- directory_ref_element.add_element 'Directory', { 'Id' => id, 'Name' => File.basename(key) }
413
- end
414
- end
420
+ directory_fragments.each do |key, id|
421
+ if(key != '.')
422
+ fragment_element = wix_elements[0].add_element 'Fragment'
423
+ directory_ref_element = fragment_element.add_element 'DirectoryRef', { 'Id' => directory_fragments[File.dirname(key)] }
424
+ directory_ref_element.add_element 'Directory', { 'Id' => id, 'Name' => File.basename(key) }
425
+ end
426
+ end
415
427
 
416
- component_group_element = REXML::XPath.match(xml_doc, '//Wix/Fragment/ComponentGroup')
417
- raise "Failed to create installation package for file: #{wxs_file}" unless(component_group_element.length == 1)
428
+ component_group_element = REXML::XPath.match(xml_doc, '//Wix/Fragment/ComponentGroup')
429
+ raise "Failed to create installation package for file: #{wxs_file}" unless(component_group_element.length == 1)
418
430
 
419
- wxs_files.each do |file, filename|
420
- xml_fragment_doc = REXML::Document.new(File.read(filename))
421
- component_elements = REXML::XPath.match(xml_fragment_doc, '//Wix/Fragment/DirectoryRef/Component')
431
+ wxs_files.each do |file, filename|
432
+ xml_fragment_doc = REXML::Document.new(File.read(filename))
433
+ component_elements = REXML::XPath.match(xml_fragment_doc, '//Wix/Fragment/DirectoryRef/Component')
422
434
 
423
- component_elements.each do |component_element|
424
- component_element.attributes['Id'] = "cmp#{SecureRandom.uuid.gsub(/-/,'')}" # Assigning new Id, because the id is somehow generated from the filename. So it is possible for heat to generate duplicate id's
425
- component_element = component_group_element[0].add_element component_element, { 'Directory' => directory_fragments[File.dirname(file)] }
435
+ component_elements.each do |component_element|
436
+ component_element.attributes['Id'] = "cmp#{SecureRandom.uuid.gsub(/-/,'')}" # Assigning new Id, because the id is somehow generated from the filename. So it is possible for heat to generate duplicate id's
437
+ component_element = component_group_element[0].add_element component_element, { 'Directory' => directory_fragments[File.dirname(file)] }
426
438
  end
427
- end
439
+ end
428
440
 
429
- formatter = REXML::Formatters::Pretty.new(2)
430
- formatter.compact = true # This is the magic line that does what you need!
431
- xml_text=''
432
- formatter.write(xml_doc, xml_text)
433
- File.open(wxs_file, 'w') { |f| f.puts xml_text }
441
+ formatter = REXML::Formatters::Pretty.new(2)
442
+ formatter.compact = true # This is the magic line that does what you need!
443
+ xml_text=''
444
+ formatter.write(xml_doc, xml_text)
445
+ File.open(wxs_file, 'w') { |f| f.puts xml_text }
434
446
  end
435
447
 
436
448
  def self.execute_heat_dir(wxs_file, input, template_option)
437
- execute_heat(input,"dir . #{template_option} -cg InstallionFiles -gg -nologo -srd -o \"#{wxs_file}\"")
449
+ execute_heat(input,"dir . #{template_option} -cg InstallionFiles -gg -nologo -srd -o \"#{wxs_file}\"")
438
450
  end
439
451
 
440
452
  def self.create_wxs_file(wxs_file, input, ext)
441
453
  template_option = "-template product"
442
- template_option = "-template module" unless(ext == ".msi")
454
+ template_option = "-template module" unless(ext == ".msi")
443
455
 
444
- if(input.has_key?(:ignore_files))
445
- execute_heat_file(wxs_file, input, template_option)
446
- else
447
- execute_heat_dir(wxs_file, input, template_option)
448
- end
456
+ if(input.has_key?(:ignore_files))
457
+ execute_heat_file(wxs_file, input, template_option)
458
+ else
459
+ execute_heat_dir(wxs_file, input, template_option)
460
+ end
449
461
 
450
- product_name = File.basename(wxs_file, '.wxs')
451
- input[:product_name] = product_name unless(input.has_key?(:product_name))
462
+ product_name = File.basename(wxs_file, '.wxs')
463
+ input[:product_name] = product_name unless(input.has_key?(:product_name))
452
464
  product_name = input[:product_name] if(input.has_key?(:product_name))
453
465
 
454
466
  manufacturer = 'Not Set'
455
467
  manufacturer = input[:manufacturer] if(input.has_key?(:manufacturer))
456
468
 
457
- product_version = ''
469
+ product_version = ''
458
470
  product_version = input[:version] if(input.has_key?(:version))
459
471
 
460
- product_code = ''
461
- product_code = input[:product_code] if(input.has_key?(:product_code))
472
+ product_code = ''
473
+ product_code = input[:product_code] if(input.has_key?(:product_code))
462
474
 
463
- upgrade_code = ''
464
- upgrade_code = input[:upgrade_code] if(input.has_key?(:upgrade_code))
475
+ upgrade_code = ''
476
+ upgrade_code = input[:upgrade_code] if(input.has_key?(:upgrade_code))
465
477
 
466
- install_path = '[ProgramFilesFolder][ProductName]'
467
- install_path = "[ProgramFilesFolder][Manufacturer]\\[ProductName]" unless(manufacturer == 'Not Set')
478
+ install_path = '[ProgramFilesFolder][ProductName]'
479
+ install_path = "[ProgramFilesFolder][Manufacturer]\\[ProductName]" unless(manufacturer == 'Not Set')
468
480
 
469
- wxs_text = File.read(wxs_file)
481
+ wxs_text = File.read(wxs_file)
470
482
 
471
- wxs_text = wxs_text.gsub(/SourceDir\\/) { |s| s = '.\\' }
472
- wxs_text = wxs_text.gsub(/PUT-PRODUCT-NAME-HERE/) { |s| s = product_name }
473
- wxs_text = wxs_text.gsub(/PUT-MODULE-NAME-HERE/) { |s| s = product_name }
474
- wxs_text = wxs_text.gsub(/PUT-COMPANY-NAME-HERE/) { |s| s = manufacturer }
475
- wxs_text = wxs_text.gsub(/PUT-FEATURE-TITLE-HERE/) { |s| s = 'Files to Install' }
483
+ wxs_text = wxs_text.gsub(/SourceDir\\/) { |s| s = '.\\' }
484
+ wxs_text = wxs_text.gsub(/PUT-PRODUCT-NAME-HERE/) { |s| s = product_name }
485
+ wxs_text = wxs_text.gsub(/PUT-MODULE-NAME-HERE/) { |s| s = product_name }
486
+ wxs_text = wxs_text.gsub(/PUT-COMPANY-NAME-HERE/) { |s| s = manufacturer }
487
+ wxs_text = wxs_text.gsub(/PUT-FEATURE-TITLE-HERE/) { |s| s = 'Files to Install' }
476
488
 
477
- wxs_text = wxs_text.gsub(/Version=\"1.0.0.0\"/) { |s| s = "Version=\"#{product_version}\"" } unless(product_version.empty?)
478
- wxs_text = wxs_text.gsub(/Product Id=\"[^\"]+\"/) { |s| s = "Product Id=\"#{product_code}\"" } unless(product_code.empty?)
479
- wxs_text = wxs_text.gsub(/UpgradeCode=\"[^\"]+\"/) { |s| s = "UpgradeCode=\"#{upgrade_code}\"" } unless(upgrade_code.empty?)
489
+ wxs_text = wxs_text.gsub(/Version=\"1.0.0.0\"/) { |s| s = "Version=\"#{product_version}\"" } unless(product_version.empty?)
490
+ wxs_text = wxs_text.gsub(/Product Id=\"[^\"]+\"/) { |s| s = "Product Id=\"#{product_code}\"" } unless(product_code.empty?)
491
+ wxs_text = wxs_text.gsub(/UpgradeCode=\"[^\"]+\"/) { |s| s = "UpgradeCode=\"#{upgrade_code}\"" } unless(upgrade_code.empty?)
480
492
 
481
- File.open(wxs_file, 'w') { |f| f.write(wxs_text) }
493
+ File.open(wxs_file, 'w') { |f| f.write(wxs_text) }
482
494
 
483
- xml_doc = REXML::Document.new(wxs_text)
484
- products = REXML::XPath.match(xml_doc, "/Wix/Product")
485
- products.each do |product|
486
- product.add_element 'SetProperty', { 'Id' => 'ARPINSTALLLOCATION', 'Value' => "#{install_path}", 'After' => 'CostFinalize', 'Sequence' => 'both' }
487
- end
495
+ xml_doc = REXML::Document.new(wxs_text)
496
+ products = REXML::XPath.match(xml_doc, "/Wix/Product")
497
+ products.each do |product|
498
+ product.add_element 'SetProperty', { 'Id' => 'ARPINSTALLLOCATION', 'Value' => "#{install_path}", 'After' => 'CostFinalize', 'Sequence' => 'both' }
499
+ end
488
500
 
489
- packages = REXML::XPath.match(xml_doc, '//Wix/Product/Package')
490
- packages.each do |package|
491
- package.add_attribute('InstallScope', 'perMachine') if(input.has_key?(:all_users))
492
- package.add_attribute('InstallScope', input[:install_scope]) if(input.has_key?(:install_scope))
493
- package.attributes['InstallerVersion'] = 450
494
- package.attributes['InstallerVersion'] = (input[:installer_version]*100).to_i if(input.has_key?(:installer_version))
501
+ packages = REXML::XPath.match(xml_doc, '//Wix/Product/Package')
502
+ packages.each do |package|
503
+ package.add_attribute('InstallScope', 'perMachine') if(input.has_key?(:all_users))
504
+ package.add_attribute('InstallScope', input[:install_scope]) if(input.has_key?(:install_scope))
505
+ package.attributes['InstallerVersion'] = 450
506
+ package.attributes['InstallerVersion'] = (input[:installer_version]*100).to_i if(input.has_key?(:installer_version))
495
507
  package.attributes['InstallPrivileges']= input[:install_priviledges] if(input.has_key?(:install_priviledges))
496
- end
497
-
498
- xml_doc = manage_installdir(xml_doc, input)
499
- xml_doc = manage_netframework(xml_doc, input)
500
- xml_doc = manage_win10_crt(xml_doc, input)
501
- #xml_doc = manage_ui(xml_doc, input)
502
- xml_doc = manage_custom_actions(xml_doc, input)
503
- xml_doc = manage_upgrade(xml_doc,input)
504
- xml_doc = manage_msm_files(xml_doc)
505
- xml_doc = manage_read_only_files(xml_doc,input)
506
- xml_doc = manage_shortcuts(xml_doc, input)
507
- xml_doc = manage_self_register(xml_doc, input)
508
- xml_doc = manage_binary_table(xml_doc, input)
509
- xml_doc = manage_associate_extensions(xml_doc, input)
508
+ end
509
+
510
+ xml_doc = manage_installdir(xml_doc, input)
511
+ xml_doc = manage_netframework(xml_doc, input)
512
+ xml_doc = manage_win10_crt(xml_doc, input)
513
+ #xml_doc = manage_ui(xml_doc, input)
514
+ xml_doc = manage_custom_actions(xml_doc, input)
515
+ xml_doc = manage_upgrade(xml_doc,input)
516
+ xml_doc = manage_msm_files(xml_doc)
517
+ xml_doc = manage_read_only_files(xml_doc,input)
518
+ xml_doc = manage_shortcuts(xml_doc, input)
519
+ xml_doc = manage_self_register(xml_doc, input)
520
+ xml_doc = manage_binary_table(xml_doc, input)
521
+ xml_doc = manage_associate_extensions(xml_doc, input)
522
+ xml_doc = manage_services(xml_doc, input)
510
523
 
511
524
  formatter = REXML::Formatters::Pretty.new(2)
512
525
  formatter.compact = true
513
- File.open(wxs_file, 'w') { |f| formatter.write(xml_doc, f) }
514
- str = File.read(wxs_file)
515
- str = str.gsub(/&lt;/,'<')
516
- str = str.gsub(/&gt;/,'>')
526
+ File.open(wxs_file, 'w') { |f| formatter.write(xml_doc, f) }
527
+ str = File.read(wxs_file)
528
+ str = str.gsub(/&lt;/,'<')
529
+ str = str.gsub(/&gt;/,'>')
517
530
  File.open(wxs_file, 'w') { |f| f.puts(str) }
518
531
  end
519
532
 
520
533
  def self.create_output(wxs_file, input, output)
521
534
  wixobj_file = "#{File.basename(wxs_file,'.wxs')}.wixobj"
522
535
 
523
- candle_cmd = Execute.new("\"#{install_path.gsub(/\\/,'/')}/bin/candle.exe\" -out \"#{wixobj_file}\" \"#{wxs_file}\"", { quiet: true })
524
- candle_cmd.execute
525
- log_wix_output(candle_cmd)
536
+ candle_cmd = Execute.new("\"#{install_path.gsub(/\\/,'/')}/bin/candle.exe\" -out \"#{wixobj_file}\" \"#{wxs_file}\"", { quiet: true })
537
+ candle_cmd.execute
538
+ log_wix_output(candle_cmd)
526
539
 
527
- cmd_args = "-nologo -out \"#{output}\" \"#{wixobj_file}\""
540
+ cmd_args = "-nologo -out \"#{output}\" \"#{wixobj_file}\""
528
541
  cmd_args = "-ext WixNetfxExtension -ext WixUIExtension -ext WixUtilExtension -cultures:en-us #{cmd_args}"
529
- light_cmd = Execute.new("\"#{install_path.gsub(/\\/,'/')}/bin/light.exe\" #{cmd_args}", { quiet: true })
530
- light_cmd.execute
531
- log_wix_output(light_cmd)
542
+ light_cmd = Execute.new("\"#{install_path.gsub(/\\/,'/')}/bin/light.exe\" #{cmd_args}", { quiet: true })
543
+ light_cmd.execute
544
+ log_wix_output(light_cmd)
532
545
  end
533
546
 
534
547
  def self.verify_input_keys(input)
535
- input[:files].reject! { |f| File.directory?(f) }
548
+ input[:files].reject! { |f| File.directory?(f) }
536
549
 
537
550
  [:files,:ignore_files].each { |key| raise "Hash key #{key} cannot be nil" if(input.has_key?(key) && input[key].nil?)}
538
551
  end
539
552
 
540
553
  def self.create_package(output, input)
541
- raise 'WIX path is not set! Install Wixtoolset or assign with Wixgem::Wix.install_path = <path to wix toolset' if(self.install_path.nil?)
542
- input = { files: input } unless(input.kind_of?(Hash))
543
- verify_input_keys(input)
554
+ raise 'WIX path is not set! Install Wixtoolset or assign with Wixgem::Wix.install_path = <path to wix toolset' if(self.install_path.nil?)
555
+ input = { files: input } unless(input.kind_of?(Hash))
556
+ verify_input_keys(input)
544
557
 
545
- @debug = input[:debug] if(!@debug && input.has_key?(:debug))
546
- start_logger if(@debug)
558
+ @debug = input[:debug] if(!@debug && input.has_key?(:debug))
559
+ start_logger if(@debug)
547
560
 
548
- FileUtils.mkpath(File.dirname(output)) unless(Dir.exists?(File.dirname(output)))
561
+ FileUtils.mkpath(File.dirname(output)) unless(Dir.exists?(File.dirname(output)))
549
562
 
550
- ext = File.extname(output)
563
+ ext = File.extname(output)
551
564
  basename = File.basename(output, ext)
552
- FileUtils.rm(output) if(File.exists?(output))
565
+ FileUtils.rm(output) if(File.exists?(output))
553
566
 
554
- output_absolute_path = File.absolute_path(output)
555
- input[:original_pwd] = Dir.pwd
556
- input[:msi?] = output.include?('.msi')
567
+ output_absolute_path = File.absolute_path(output)
568
+ input[:original_pwd] = Dir.pwd
569
+ input[:msi?] = output.include?('.msi')
557
570
 
558
- modify_binary_files(input)
571
+ modify_binary_files(input)
559
572
 
560
- temp_directory do |dir|
561
- wxs_file = "#{basename}.wxs"
562
- begin
563
- copy_install_files(dir, input)
573
+ temp_directory do |dir|
574
+ wxs_file = "#{basename}.wxs"
575
+ begin
576
+ copy_install_files(dir, input)
564
577
 
565
- Dir.chdir(dir) do |current_dir|
566
- create_wxs_file(wxs_file, input, ext)
567
- create_output(wxs_file, input, output_absolute_path)
568
- end
569
- rescue Exception => e
570
- raise e
571
- ensure
572
- FileUtils.cp("#{dir}/#{wxs_file}", "#{output_absolute_path}.wxs") if(File.exists?("#{dir}/#{wxs_file}") && @debug)
573
- File.open("#{output_absolute_path}.log", 'w') { |f| f.puts(@logger) } if(@debug &!@logger.nil?)
574
- end
575
- end
578
+ Dir.chdir(dir) do |current_dir|
579
+ create_wxs_file(wxs_file, input, ext)
580
+ create_output(wxs_file, input, output_absolute_path)
581
+ end
582
+ rescue Exception => e
583
+ raise e
584
+ ensure
585
+ FileUtils.cp("#{dir}/#{wxs_file}", "#{output_absolute_path}.wxs") if(File.exists?("#{dir}/#{wxs_file}") && @debug)
586
+ File.open("#{output_absolute_path}.log", 'w') { |f| f.puts(@logger) } if(@debug &!@logger.nil?)
587
+ end
588
+ end
576
589
 
577
- pdb_file = output_absolute_path.gsub(ext,'.wixpdb')
578
- FileUtils.rm(pdb_file) if(File.exists?(pdb_file))
590
+ pdb_file = output_absolute_path.gsub(ext,'.wixpdb')
591
+ FileUtils.rm(pdb_file) if(File.exists?(pdb_file))
579
592
 
580
- end_logger if(@debug)
593
+ end_logger if(@debug)
594
+ end
581
595
  end
582
- end
583
-
584
596
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wixgem
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.93.0
4
+ version: 0.99.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Marshall
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-01-24 00:00:00.000000000 Z
11
+ date: 2019-05-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: execute
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: win32-service
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: WindowsInstaller
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -117,6 +131,7 @@ extra_rdoc_files: []
117
131
  files:
118
132
  - LICENSE
119
133
  - README.md
134
+ - example/example.msi
120
135
  - example/example.msm
121
136
  - example/install_files/directory/file2.txt
122
137
  - example/install_files/file1.txt
@@ -125,6 +140,7 @@ files:
125
140
  - lib/associate_extension.rb
126
141
  - lib/custom_action.rb
127
142
  - lib/file.rb
143
+ - lib/service.rb
128
144
  - lib/shortcut.rb
129
145
  - lib/temp_directory.rb
130
146
  - lib/wixgem.rb
@@ -147,7 +163,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
147
163
  - !ruby/object:Gem::Version
148
164
  version: '0'
149
165
  requirements: []
150
- rubygems_version: 3.0.1
166
+ rubygems_version: 3.0.3
151
167
  signing_key:
152
168
  specification_version: 4
153
169
  summary: Simple Ruby interface to facilitate working with Wix Toolset