wixgem 0.93.0 → 0.99.0

Sign up to get free protection for your applications and to get access to all the features.
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