wixgem 0.32.0 → 0.33.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 +4 -4
- data/lib/command.rb +24 -0
- data/lib/wixgem.rb +78 -70
- data/spec/COM_spec.rb +28 -14
- data/spec/WindowsInstaller.rb +139 -0
- data/spec/command_spec.rb +18 -0
- data/spec/installation_spec.rb +2 -2
- data/spec/mergemodule_spec.rb +4 -5
- data/spec/multiple_product_installation_spec.rb +0 -3
- data/spec/test_install.rb +14 -12
- metadata +19 -5
- data/lib/templates/Install.wxs +0 -26
- data/lib/templates/mergemodule.wxs +0 -15
- data/spec/execute.rb +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0ad9f8a4070ee4bddfa138baf13adfa2b6bc74d2
|
4
|
+
data.tar.gz: fd44d0d360a288cc10d5f07e88e77c2017c0591c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bb6c4dddc389dee7cdba6d8596a4eb8939c657ce4f11675115cd3f3101543602255032e6c1cb4933b834f2088a58ca0984db62bb41f4a2b199f4dab95c1601a0
|
7
|
+
data.tar.gz: 2c5c97aeb97acb74ed7b37f8121a34c83485bb5fbd662ab35736d6b2fb80283dd41c27cef717ff9e307ac78b3cd680d7451ad66d7dafd5ee455618f7903b94a3
|
data/lib/command.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'open3'
|
2
|
+
require 'hash'
|
3
|
+
|
4
|
+
class Command < Hash
|
5
|
+
def initialize(cmd)
|
6
|
+
self[:command]=cmd
|
7
|
+
self[:output] = ''
|
8
|
+
self[:error] = ''
|
9
|
+
self[:exit_code] = ''
|
10
|
+
self[:ignore_exit_code] = false
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute
|
14
|
+
begin
|
15
|
+
self[:output],self[:error], self[:exit_code] = Open3.capture3(self[:command])
|
16
|
+
self[:exit_code]=self[:exit_code].to_i
|
17
|
+
rescue Exception => e
|
18
|
+
self[:error] = "Exception: " + e.to_s
|
19
|
+
self[:exit_code]=1
|
20
|
+
end
|
21
|
+
|
22
|
+
raise self[:error] unless((self[:exit_code] == 0) || self[:ignore_exit_code])
|
23
|
+
end
|
24
|
+
end
|
data/lib/wixgem.rb
CHANGED
@@ -1,12 +1,17 @@
|
|
1
1
|
require 'fileutils'
|
2
2
|
require 'SecureRandom'
|
3
|
+
require 'logging'
|
4
|
+
require 'tempfile'
|
3
5
|
require 'tmpdir.rb'
|
4
6
|
require 'rexml/document'
|
7
|
+
require "#{File.dirname(__FILE__)}/command.rb"
|
5
8
|
|
6
9
|
class Wix
|
7
10
|
def self.initialize
|
8
11
|
@install_path = ''
|
9
12
|
@debug = false
|
13
|
+
@logger = nil
|
14
|
+
@log_file = nil
|
10
15
|
end
|
11
16
|
def self.install_path=(path)
|
12
17
|
@install_path = path
|
@@ -33,17 +38,23 @@ class Wix
|
|
33
38
|
end
|
34
39
|
|
35
40
|
private
|
41
|
+
def self.start_logger
|
42
|
+
@logger = ::Logging.logger['Wixgem_logger']
|
43
|
+
@log_file = Tempfile.new('wixgem')
|
44
|
+
@logger.add_appenders(Logging.appenders.file(@log_file.path))
|
45
|
+
@logger.level = :debug
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.end_logger
|
49
|
+
@logger = nil
|
50
|
+
@log_file = nil
|
51
|
+
end
|
52
|
+
|
36
53
|
def self.manage_upgrade(xml_doc, input)
|
37
54
|
product = REXML::XPath.match(xml_doc, '//Wix/Product')
|
38
55
|
return xml_doc if(product.length == 0)
|
39
56
|
|
40
|
-
|
41
|
-
manufacturer = input[:manufacturer] if(input.kind_of?(Hash) && input.has_key?(:manufacturer))
|
42
|
-
|
43
|
-
if(input.kind_of?(Hash) &&
|
44
|
-
input.has_key?(:remove_existing_products) &&
|
45
|
-
input[:remove_existing_products])
|
46
|
-
|
57
|
+
if(input.has_key?(:remove_existing_products) && input[:remove_existing_products])
|
47
58
|
raise 'Hash must have a version key if the hash has a :remove_existing_products key' unless(input.has_key?(:version))
|
48
59
|
raise 'Hash must have an upgrade_code key if the hash has a :remove_existing_products key' unless(input.has_key?(:upgrade_code))
|
49
60
|
|
@@ -58,27 +69,9 @@ class Wix
|
|
58
69
|
return xml_doc
|
59
70
|
end
|
60
71
|
|
61
|
-
def self.manage_com_files(xml_doc)
|
62
|
-
component_groups = REXML::XPath.match(xml_doc, '//Wix/Fragment/ComponentGroup')
|
63
|
-
return xml_doc if(component_groups.nil?)
|
64
|
-
|
65
|
-
com_dlls = {}
|
66
|
-
component_groups.each do |component_group|
|
67
|
-
component_group.each_element do |component|
|
68
|
-
classes = component.get_elements('Class')
|
69
|
-
if((classes.length == 1) && (classes[0].attributes["Context"] == 'InprocServer32'))
|
70
|
-
files = component.get_elements('File')
|
71
|
-
files[0].add_attribute('Assembly','.net')
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
return xml_doc
|
77
|
-
end
|
78
|
-
|
79
72
|
def self.manage_custom_actions(xml_doc, input)
|
80
73
|
manufacturer = 'Not Set'
|
81
|
-
manufacturer = input[:manufacturer] if(input.
|
74
|
+
manufacturer = input[:manufacturer] if(input.has_key?(:manufacturer))
|
82
75
|
|
83
76
|
install_path = '[ProgramFilesFolder][ProductName]'
|
84
77
|
install_path = "[ProgramFilesFolder][Manufacturer]\\[ProductName]" unless(manufacturer == 'Not Set')
|
@@ -122,16 +115,14 @@ class Wix
|
|
122
115
|
end
|
123
116
|
|
124
117
|
def self.copy_install_files(directory, input)
|
125
|
-
|
126
|
-
files = input[:files] if(input.kind_of?(Hash))
|
127
|
-
|
118
|
+
files = input[:files]
|
128
119
|
raise 'No files were given to wixgem' if(files.length == 0)
|
129
120
|
|
130
121
|
missing_files = []
|
131
122
|
files.each do |file|
|
132
123
|
if(File.file?(file))
|
133
124
|
install_path = file
|
134
|
-
if(input.
|
125
|
+
if(input.has_key?(:modify_file_paths))
|
135
126
|
input[:modify_file_paths].each { |regex, replacement_string| install_path = install_path.gsub(regex, replacement_string) }
|
136
127
|
end
|
137
128
|
|
@@ -146,20 +137,21 @@ class Wix
|
|
146
137
|
if(@debug)
|
147
138
|
max_path = files.max { |a, b| a.length <=> b.length }
|
148
139
|
columen_size = max_path.length + 10
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
f.printf("%-#{columen_size}s %s\n" % [file, install_path])
|
140
|
+
|
141
|
+
@logger.debug "------------------------------------ Installation Paths -----------------------------------"
|
142
|
+
@logger.debug "%-#{columen_size}s %s\n" % ['File path', 'Installation Path']
|
143
|
+
files.each do |file|
|
144
|
+
if(File.file?(file))
|
145
|
+
install_path = file
|
146
|
+
if(input.has_key?(:modify_file_paths))
|
147
|
+
input[:modify_file_paths].each { |regex, replacement_string| install_path = install_path.gsub(regex, replacement_string) }
|
158
148
|
end
|
159
|
-
|
160
|
-
|
149
|
+
@logger.debug "%-#{columen_size}s %s\n" % [file, install_path]
|
150
|
+
end
|
151
|
+
end
|
152
|
+
@logger.debug "-------------------------------------------------------------------------------------------"
|
161
153
|
end
|
162
|
-
|
154
|
+
|
163
155
|
if(missing_files.length > 0)
|
164
156
|
missing_files_str = ''
|
165
157
|
missing_files.each { |f|
|
@@ -177,28 +169,32 @@ class Wix
|
|
177
169
|
template_option = "-template product"
|
178
170
|
template_option = "-template module" unless(ext == ".msi")
|
179
171
|
|
180
|
-
|
181
|
-
|
172
|
+
cmd = "\"#{install_path}/bin/heat.exe\" dir . #{template_option} -cg InstallionFiles -gg -nologo -srd -o \"#{wxs_file}\""
|
173
|
+
cmd = cmd.gsub(/-srd/, '-svb6 -srd') if(input.has_key?(:has_vb6_files))
|
182
174
|
|
183
|
-
|
175
|
+
heat_cmd = Command.new(cmd)
|
176
|
+
@logger.debug "command: #{heat_cmd[:command]}" if(@debug)
|
184
177
|
|
185
|
-
|
186
|
-
|
187
|
-
|
178
|
+
heat_cmd.execute
|
179
|
+
if(@debug)
|
180
|
+
@logger.debug "--------------------------- Heat output -----------------------------------"
|
181
|
+
@logger.debug heat_cmd[:output]
|
182
|
+
end
|
183
|
+
|
188
184
|
product_name = File.basename(wxs_file, '.wxs')
|
189
|
-
product_name = input[:product_name] if(input.
|
185
|
+
product_name = input[:product_name] if(input.has_key?(:product_name))
|
190
186
|
|
191
187
|
manufacturer = 'Not Set'
|
192
|
-
manufacturer = input[:manufacturer] if(input.
|
188
|
+
manufacturer = input[:manufacturer] if(input.has_key?(:manufacturer))
|
193
189
|
|
194
190
|
product_version = ''
|
195
|
-
product_version = input[:version] if(input.
|
191
|
+
product_version = input[:version] if(input.has_key?(:version))
|
196
192
|
|
197
193
|
product_code = ''
|
198
|
-
product_code = input[:product_code] if(input.
|
194
|
+
product_code = input[:product_code] if(input.has_key?(:product_code))
|
199
195
|
|
200
196
|
upgrade_code = ''
|
201
|
-
upgrade_code = input[:upgrade_code] if(input.
|
197
|
+
upgrade_code = input[:upgrade_code] if(input.has_key?(:upgrade_code))
|
202
198
|
|
203
199
|
wxs_text = File.read(wxs_file)
|
204
200
|
|
@@ -213,9 +209,11 @@ class Wix
|
|
213
209
|
wxs_text = wxs_text.gsub(/UpgradeCode=\"[^\"]+\"/) { |s| s = "UpgradeCode=\"#{upgrade_code}\"" } unless(upgrade_code.empty?)
|
214
210
|
|
215
211
|
xml_doc = REXML::Document.new(wxs_text)
|
212
|
+
packages = REXML::XPath.match(xml_doc, '//Wix/Product/Package')
|
213
|
+
packages.each { |package| package.add_attribute('InstallScope', 'perMachine') } if(input.has_key?(:all_users))
|
214
|
+
|
216
215
|
xml_doc = manage_custom_actions(xml_doc, input)
|
217
216
|
xml_doc = manage_upgrade(xml_doc,input)
|
218
|
-
xml_doc = manage_com_files(xml_doc)
|
219
217
|
xml_doc = manage_msm_files(xml_doc)
|
220
218
|
|
221
219
|
File.open(wxs_file, 'w') { |f| f.puts(xml_doc.to_s) }
|
@@ -229,21 +227,32 @@ class Wix
|
|
229
227
|
def self.create_output(wxs_file, output)
|
230
228
|
wixobj_file = "#{File.basename(wxs_file,'.wxs')}.wixobj"
|
231
229
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
230
|
+
candle_cmd = Command.new("\"#{install_path}\\bin\\candle.exe\" -out \"#{wixobj_file}\" \"#{wxs_file}\"")
|
231
|
+
@logger.debug "command: #{candle_cmd[:command]}" if(@debug)
|
232
|
+
|
233
|
+
candle_cmd.execute
|
234
|
+
if(@debug)
|
235
|
+
@logger.debug "--------------------------- Candle output -----------------------------------"
|
236
|
+
@logger.debug candle_cmd[:output]
|
237
|
+
end
|
238
|
+
|
239
|
+
light_cmd = Command.new("\"#{install_path}\\bin\\light.exe\" -nologo -out \"#{output}\" \"#{wixobj_file}\"")
|
240
|
+
@logger.debug "command: #{light_cmd[:command]}" if(@debug)
|
236
241
|
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
242
|
+
light_cmd.execute
|
243
|
+
if(@debug)
|
244
|
+
@logger.debug "--------------------------- Light output -----------------------------------"
|
245
|
+
@logger.debug light_cmd[:output]
|
246
|
+
end
|
241
247
|
end
|
242
248
|
|
243
249
|
def self.apply_wix_template(output, input, template)
|
244
250
|
raise 'WIX path is not set!' if(install_path.nil?)
|
251
|
+
input = { files: input } unless(input.kind_of?(Hash))
|
252
|
+
@debug = input[:debug] if(!@debug && input.has_key?(:debug))
|
245
253
|
|
246
|
-
|
254
|
+
start_logger if(@debug)
|
255
|
+
|
247
256
|
FileUtils.mkpath(File.dirname(output)) unless(Dir.exists?(File.dirname(output)))
|
248
257
|
|
249
258
|
ext = File.extname(output)
|
@@ -260,18 +269,17 @@ class Wix
|
|
260
269
|
begin
|
261
270
|
create_wxs_file(wxs_file, input, ext)
|
262
271
|
create_output(wxs_file, output_absolute_path)
|
272
|
+
rescue Exception => e
|
273
|
+
raise "Wixgem exception: #{e}"
|
263
274
|
ensure
|
264
|
-
if(@debug)
|
265
|
-
|
266
|
-
wix_cmds_file = "#{File.basename(wxs_file,'.wxs')}.wix_cmds.txt"
|
267
|
-
FileUtils.cp(wix_cmds_file, "#{output_absolute_path}.wix_cmds.txt") if(File.exists?(wix_cmds_file))
|
268
|
-
end
|
275
|
+
FileUtils.cp(wxs_file, "#{output_absolute_path}.wxs") if(File.exists?(wxs_file) && @debug)
|
276
|
+
FileUtils.cp(@log_file.path, "#{output_absolute_path}.log") if(@debug)
|
269
277
|
end
|
270
278
|
end
|
271
|
-
|
272
|
-
FileUtils.mv('installation_files.txt', "#{output_absolute_path}_paths.txt") if(File.exists?('installation_files.txt'))
|
273
279
|
end
|
274
280
|
pdb_file = output_absolute_path.gsub(ext,'.wixpdb')
|
275
281
|
FileUtils.rm(pdb_file) if(File.exists?(pdb_file))
|
282
|
+
|
283
|
+
end_logger if(@debug)
|
276
284
|
end
|
277
285
|
end
|
data/spec/COM_spec.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
require 'rspec'
|
2
2
|
require './lib/wixgem.rb'
|
3
3
|
require './spec/wixpath.rb'
|
4
|
-
require './WindowsInstaller.rb'
|
4
|
+
require './spec/WindowsInstaller.rb'
|
5
|
+
require './spec/test_files_exist.rb'
|
5
6
|
require 'win32ole'
|
7
|
+
require './admin.rb'
|
6
8
|
|
9
|
+
if(admin?)
|
7
10
|
describe 'Wixgem' do
|
8
11
|
describe 'Installation of a COM object' do
|
9
12
|
it 'should not be able to instance a COM object' do
|
@@ -15,28 +18,39 @@ describe 'Wixgem' do
|
|
15
18
|
WindowsInstaller.uninstall(installation_file)
|
16
19
|
end
|
17
20
|
|
21
|
+
installation_hash = { debug: true, modify_file_paths: {/^.+Release\// => ''}, all_users: 'perMachine', files: ['COMObject/bin/Release/COMObject.dll']}
|
18
22
|
it "should create an installation file using: #{installation_file}" do
|
19
|
-
Wix.make_installation(installation_file,
|
23
|
+
Wix.make_installation(installation_file, installation_hash)
|
20
24
|
expect(File.exists?(installation_file)).to be(true)
|
21
25
|
end
|
22
26
|
|
23
|
-
|
27
|
+
it 'should install' do
|
28
|
+
WindowsInstaller.install(installation_file)
|
29
|
+
expect(WindowsInstaller.installed?(installation_file)).to be(true)
|
30
|
+
end
|
24
31
|
|
32
|
+
it 'should have installed the COMObject.dll' do
|
33
|
+
test_files_exist(installation_file, installation_hash)
|
34
|
+
end
|
35
|
+
|
25
36
|
it 'should be able to instance a COM object with a GUID' do
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
37
|
+
object = WIN32OLE.new('{863AEADA-EE73-4f4a-ABC0-3FB384CB41AA}')
|
38
|
+
expect(object.nil?).to eq(false)
|
39
|
+
puts "Text: #{object.GetText}"
|
40
|
+
expect(object.GetText).to eq('Hello World')
|
30
41
|
end
|
31
42
|
|
32
|
-
it 'should be able to instance a COM object with a Program Id' do
|
33
|
-
|
34
|
-
|
35
|
-
#
|
36
|
-
|
37
|
-
#expect(object.GetText).to eq('Hello World')
|
43
|
+
it 'should be able to instance a COM object with a Program Id' do
|
44
|
+
object = WIN32OLE.new('COMObject.ComClassExample')
|
45
|
+
expect(object.nil?).to eq(false)
|
46
|
+
puts "Text: #{object.GetText}"
|
47
|
+
expect(object.GetText).to eq('Hello World')
|
38
48
|
end
|
39
49
|
|
40
|
-
|
50
|
+
it 'should uninstall' do
|
51
|
+
WindowsInstaller.uninstall(installation_file) if(WindowsInstaller.installed?(installation_file))
|
52
|
+
expect(WindowsInstaller.installed?(installation_file)).to be(false)
|
53
|
+
end
|
41
54
|
end
|
42
55
|
end
|
56
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'win32ole'
|
2
|
+
require 'dev_tasks'
|
3
|
+
|
4
|
+
class WindowsInstaller
|
5
|
+
def self.installed?(product_name)
|
6
|
+
installer = WIN32OLE.new('WindowsInstaller.Installer')
|
7
|
+
installer.Products.each { |prod_code|
|
8
|
+
name = installer.ProductInfo(prod_code, "ProductName")
|
9
|
+
return true if (product_name == name)
|
10
|
+
}
|
11
|
+
return false
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.install(msi)
|
15
|
+
raise "#{msi} is already installed" if(WindowsInstaller.installed?(msi))
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.uninstall(msi)
|
19
|
+
execute("msiexec.exe /quiet /x #{msi}") if(File.exists?(msi))
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.product_code_installed?(product_code)
|
23
|
+
installer = WIN32OLE.new('WindowsInstaller.Installer')
|
24
|
+
installer.Products.each { |prod_code| return true if (product_code == prod_code) }
|
25
|
+
return false
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.version?(product_name)
|
29
|
+
installer = WIN32OLE.new('WindowsInstaller.Installer')
|
30
|
+
info = product_info(installer, product_code?(product_name, installer))
|
31
|
+
return info['VersionString']
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.product_code?(product_name, installer = nil)
|
35
|
+
installer = WIN32OLE.new('WindowsInstaller.Installer') if(installer.nil?)
|
36
|
+
installer.Products.each { |prod_code|
|
37
|
+
name = installer.ProductInfo(prod_code, "ProductName")
|
38
|
+
return prod_code if (product_name == name)
|
39
|
+
}
|
40
|
+
raise "Failed to find product code for product: #{product_name}"
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
def self.product_info(installer, code)
|
45
|
+
raise 'Windows installer cannot be nil' if(installer.nil?)
|
46
|
+
hash = Hash.new
|
47
|
+
# known product keywords found on internet. Would be nice to generate.
|
48
|
+
%w[Language PackageCode Transforms AssignmentType PackageName InstalledProductName VersionString RegCompany
|
49
|
+
RegOwner ProductID ProductIcon InstallLocation InstallSource InstallDate Publisher LocalPackage HelpLink
|
50
|
+
HelpTelephone URLInfoAbout URLUpdateInfo InstanceType].sort.each do |prop|
|
51
|
+
value = installer.ProductInfo(code, prop)
|
52
|
+
hash[prop] = value unless(value.nil? || value == '')
|
53
|
+
end
|
54
|
+
return hash
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.msi_info(installer, msi_file)
|
58
|
+
raise 'Windows installer cannot be nil' if(installer.nil?)
|
59
|
+
hash = Hash.new
|
60
|
+
# known product keywords found on internet. Would be nice to generate.
|
61
|
+
%w[Language PackageCode Transforms AssignmentType PackageName InstalledProductName VersionString RegCompany
|
62
|
+
RegOwner ProductID ProductIcon InstallLocation InstallSource InstallDate Publisher LocalPackage HelpLink
|
63
|
+
HelpTelephone URLInfoAbout URLUpdateInfo InstanceType].sort.each do |prop|
|
64
|
+
value = installer.ProductInfo(code, prop)
|
65
|
+
hash[prop] = value unless(value.nil? || value == '')
|
66
|
+
end
|
67
|
+
return hash
|
68
|
+
end
|
69
|
+
|
70
|
+
public
|
71
|
+
def self.dump_info(product_name)
|
72
|
+
installer = WIN32OLE.new('WindowsInstaller.Installer')
|
73
|
+
properties = product_info(installer, product_code?(product_name, installer))
|
74
|
+
properties.each { |id, value| puts "#{id}: #{value}" }
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.msi_records(msi)
|
78
|
+
records = {}
|
79
|
+
|
80
|
+
installer = WIN32OLE.new('WindowsInstaller.Installer')
|
81
|
+
sql_query = "SELECT * FROM `Property`"
|
82
|
+
|
83
|
+
db = installer.OpenDatabase(msi, 0)
|
84
|
+
|
85
|
+
view = db.OpenView(sql_query)
|
86
|
+
view.Execute(nil)
|
87
|
+
|
88
|
+
record = view.Fetch()
|
89
|
+
return '' if(record == nil)
|
90
|
+
|
91
|
+
while(!record.nil?)
|
92
|
+
records[record.StringData(1)] = record.StringData(2)
|
93
|
+
record = view.Fetch()
|
94
|
+
end
|
95
|
+
db = nil
|
96
|
+
installer = nil
|
97
|
+
|
98
|
+
return records
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.dump_msi_records(msi)
|
102
|
+
records = msi_records(msi)
|
103
|
+
|
104
|
+
puts "#{msi} Properties:"
|
105
|
+
records.each do |key,value|
|
106
|
+
puts "#{key}: #{value}"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.dump_product(product_name)
|
111
|
+
installer = WIN32OLE.new('WindowsInstaller.Installer')
|
112
|
+
# only one session per process!
|
113
|
+
session = installer.OpenProduct(product_code?(product_name, installer))
|
114
|
+
db = session.Database
|
115
|
+
|
116
|
+
sql_query = "SELECT * FROM `Property`"
|
117
|
+
view = db.OpenView(sql_query)
|
118
|
+
view.Execute(nil)
|
119
|
+
|
120
|
+
record = view.Fetch()
|
121
|
+
return '' if(record == nil)
|
122
|
+
|
123
|
+
puts "Session Properties:"
|
124
|
+
while(!record.nil?)
|
125
|
+
puts "#{record.StringData(1)}: #{record.StringData(2)}"
|
126
|
+
record = view.Fetch()
|
127
|
+
end
|
128
|
+
db = nil
|
129
|
+
installer = nil
|
130
|
+
puts ''
|
131
|
+
end
|
132
|
+
|
133
|
+
def execute(cmd)
|
134
|
+
command = Command.new(cmd)
|
135
|
+
command.execute
|
136
|
+
|
137
|
+
raise "Failed: #{cmd} Status: #{command[:exit_code]}\nStdout: #{command[:output]}\nStderr: #{command[:error]}" unless(command[:exit_code] == 0)
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require './lib/command.rb'
|
3
|
+
|
4
|
+
describe 'Command' do
|
5
|
+
it 'should be able to execute: dir' do
|
6
|
+
cmd = Command.new('dir')
|
7
|
+
cmd.execute
|
8
|
+
expect(cmd[:output].empty?).to eq(false)
|
9
|
+
expect(cmd[:output].include?('Directory')).to eq(true)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should fail executing: isnotacommand' do
|
13
|
+
cmd = Command.new('isnotacommand')
|
14
|
+
expect { cmd.execute }.to raise_error
|
15
|
+
expect(cmd[:error].include?('No such file or directory')).to eq(true)
|
16
|
+
expect(cmd[:exit_status]).to_not eq(0)
|
17
|
+
end
|
18
|
+
end
|
data/spec/installation_spec.rb
CHANGED
@@ -51,8 +51,8 @@ describe 'Wixgem' do
|
|
51
51
|
|
52
52
|
describe 'including vb6 files' do
|
53
53
|
it "the wix's heat command should contain the -svb6 flag" do
|
54
|
-
Wix.make_installation('test/wixgem_install_vb6_files.msi', {manufacturer: 'musco', has_vb6_files: true, files: ['rakefile.rb'], debug: true})
|
55
|
-
wix_cmd_text = File.read('test/wixgem_install_vb6_files.msi.
|
54
|
+
Wix.make_installation('test/wixgem_install_vb6_files.msi', {debug: true, manufacturer: 'musco', has_vb6_files: true, files: ['rakefile.rb'], debug: true})
|
55
|
+
wix_cmd_text = File.read('test/wixgem_install_vb6_files.msi.log')
|
56
56
|
expect(wix_cmd_text.include?('-svb6')).to eq(true)
|
57
57
|
end
|
58
58
|
end
|
data/spec/mergemodule_spec.rb
CHANGED
@@ -2,7 +2,7 @@ require 'rspec'
|
|
2
2
|
require './lib/wixgem.rb'
|
3
3
|
require './spec/wixpath.rb'
|
4
4
|
require './spec/test_install.rb'
|
5
|
-
require './spec/
|
5
|
+
require './spec/WindowsInstaller.rb'
|
6
6
|
require './admin.rb'
|
7
7
|
|
8
8
|
Wix.debug=true
|
@@ -37,8 +37,7 @@ describe 'Wixgem' do
|
|
37
37
|
it "should produce the debug files" do
|
38
38
|
if(key == :test5)
|
39
39
|
expect(File.exists?("#{value[0]}.wxs")).to be(true)
|
40
|
-
expect(File.exists?("#{value[0]}.
|
41
|
-
expect(File.exists?("#{value[0]}_paths.txt")).to be(true)
|
40
|
+
expect(File.exists?("#{value[0]}.log")).to be(true)
|
42
41
|
end
|
43
42
|
end
|
44
43
|
}
|
@@ -63,13 +62,13 @@ describe 'Wixgem' do
|
|
63
62
|
|
64
63
|
it "should install contents of merge module" do
|
65
64
|
begin
|
66
|
-
|
65
|
+
WindowsInstaller.install(msi_file)
|
67
66
|
|
68
67
|
install_dir = "C:/Program Files (x86)/#{File.basename(msi_file, '.msi')}"
|
69
68
|
expect(File.exists?("#{install_dir}/rakefile.rb")).to be(true)
|
70
69
|
expect(File.exists?("#{install_dir}/Gemfile")).to be(true)
|
71
70
|
ensure
|
72
|
-
|
71
|
+
WindowsInstaller.uninstall(msi_file)
|
73
72
|
end
|
74
73
|
end
|
75
74
|
end
|
data/spec/test_install.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
-
require './WindowsInstaller.rb'
|
1
|
+
require './spec/WindowsInstaller.rb'
|
2
|
+
|
2
3
|
require './admin.rb'
|
3
|
-
require './
|
4
|
+
require './lib/command.rb'
|
4
5
|
|
5
6
|
def get_product_name(msi_file, arg2)
|
6
7
|
product_name = File.basename(msi_file, File.extname(msi_file))
|
7
|
-
product_name = arg2[:product_name] if(arg2.
|
8
|
+
product_name = arg2[:product_name] if(arg2.has_key?(:product_name))
|
8
9
|
|
9
10
|
return product_name
|
10
11
|
end
|
@@ -15,30 +16,32 @@ def test_msi(msi_file, arg2)
|
|
15
16
|
msi_info = WindowsInstaller.msi_records(msi_file)
|
16
17
|
#puts msi_info.to_s
|
17
18
|
|
18
|
-
if(arg2.
|
19
|
+
if(arg2.has_key?(:product_name))
|
19
20
|
raise "ProductName is #{msi_info['ProductName']} expected #{product_name}" unless(product_name == msi_info['ProductName'])
|
20
21
|
end
|
21
22
|
|
22
|
-
if(arg2.
|
23
|
+
if(arg2.has_key?(:product_code))
|
23
24
|
expected = arg2[:product_code].upcase
|
24
25
|
raise "ProductCode is #{msi_info['ProductCode']} expected #{expected}" unless(expected == msi_info['ProductCode'])
|
25
26
|
end
|
26
27
|
|
27
|
-
if(arg2.
|
28
|
+
if(arg2.has_key?(:upgrade_code))
|
28
29
|
expected = arg2[:upgrade_code].upcase
|
29
30
|
raise "UpgradeCode is #{msi_info['UpgradeCode']} expected #{expected}" unless(expected == msi_info['UpgradeCode'])
|
30
31
|
end
|
31
32
|
|
32
33
|
expected_product_version = '1.0.0.0'
|
33
|
-
expected_product_version = arg2[:version] if(arg2.
|
34
|
+
expected_product_version = arg2[:version] if(arg2.has_key?(:version))
|
34
35
|
raise "Invalid product version #{msi_info['ProductVersion']}" if(msi_info['ProductVersion'] != expected_product_version)
|
35
36
|
|
36
37
|
expected_manufacturer = 'Not Set'
|
37
|
-
expected_manufacturer = arg2[:manufacturer] if(arg2.
|
38
|
+
expected_manufacturer = arg2[:manufacturer] if(arg2.has_key?(:manufacturer))
|
38
39
|
raise "Invalid Manufacturer #{msi_info['Manufacturer']}" if(msi_info['Manufacturer'] != expected_manufacturer)
|
39
40
|
end
|
40
41
|
|
41
42
|
def test_install(name, msi_file, arg2, callback=nil)
|
43
|
+
arg2 = { files: arg2} unless(arg2.kind_of?(Hash))
|
44
|
+
|
42
45
|
msi_file = msi_file.gsub(/\//) { |s| s = '\\' }
|
43
46
|
|
44
47
|
test_msi(msi_file, arg2)
|
@@ -49,19 +52,18 @@ def test_install(name, msi_file, arg2, callback=nil)
|
|
49
52
|
|
50
53
|
if(admin?)
|
51
54
|
while(WindowsInstaller.installed?(product_name))
|
52
|
-
|
55
|
+
WindowsInstaller.uninstall(product_name)
|
53
56
|
end
|
54
57
|
raise "#{name}: Uninstall #{product_name} before running tests" if(WindowsInstaller.installed?(product_name))
|
55
58
|
|
56
59
|
begin
|
57
|
-
|
58
|
-
#WindowsInstaller.dump_info(product_name)
|
60
|
+
WindowsInstaller.install(msi_file)
|
59
61
|
|
60
62
|
raise "#{name}: Product name #{product_name} is not installed" unless(WindowsInstaller.installed?(product_name))
|
61
63
|
|
62
64
|
eval callback unless(callback == nil)
|
63
65
|
ensure
|
64
|
-
|
66
|
+
WindowsInstaller.uninstall(msi_file) if(WindowsInstaller.installed?(product_name))
|
65
67
|
raise "Failed to uninstall product #{product_name}" if(WindowsInstaller.installed?(product_name))
|
66
68
|
end
|
67
69
|
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.
|
4
|
+
version: 0.33.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: 2015-01-
|
11
|
+
date: 2015-01-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -72,6 +72,20 @@ dependencies:
|
|
72
72
|
- - '='
|
73
73
|
- !ruby/object:Gem::Version
|
74
74
|
version: 1.0.28
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: logging
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
75
89
|
description: Simple Ruby interface to facilitate creating and compiling windows installation
|
76
90
|
files with the Wix Toolset.
|
77
91
|
email: KCCKSMarshall@gmail.com
|
@@ -86,11 +100,11 @@ files:
|
|
86
100
|
- example/install_files/directory/file2.txt
|
87
101
|
- example/install_files/file1.txt
|
88
102
|
- example/rakefile.rb
|
89
|
-
- lib/
|
90
|
-
- lib/templates/mergemodule.wxs
|
103
|
+
- lib/command.rb
|
91
104
|
- lib/wixgem.rb
|
92
105
|
- spec/COM_spec.rb
|
93
|
-
- spec/
|
106
|
+
- spec/WindowsInstaller.rb
|
107
|
+
- spec/command_spec.rb
|
94
108
|
- spec/installation_spec.rb
|
95
109
|
- spec/mergemodule_spec.rb
|
96
110
|
- spec/multiple_product_installation_spec.rb
|
data/lib/templates/Install.wxs
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
-
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
3
|
-
<Product Id="PRODUCT_CODE" Name="PRODUCT_NAME" Language="1033" Version="VERSION" Manufacturer="MANUFACTURER" UpgradeCode="UPGRADE_CODE">
|
4
|
-
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
|
5
|
-
|
6
|
-
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
|
7
|
-
<Media Id="1" Cabinet="WixgemTest.cab" EmbedCab="yes" />
|
8
|
-
|
9
|
-
<!-- Step 1: Define the directory structure -->
|
10
|
-
<Directory Id="TARGETDIR" Name="SourceDir">
|
11
|
-
<Directory Id="ProgramFilesFolder">
|
12
|
-
INSTALL_DIR
|
13
|
-
</Directory>
|
14
|
-
</Directory>
|
15
|
-
|
16
|
-
<!-- Step 2: Add files to installer package -->
|
17
|
-
<DirectoryRef Id="INSTALLFOLDER">
|
18
|
-
FILES
|
19
|
-
</DirectoryRef>
|
20
|
-
|
21
|
-
<!-- Step 3: Tell Wix to install the files-->
|
22
|
-
<Feature Id="ProductFeature" Title="PRODUCT_NAME Installation" Level="1">
|
23
|
-
COMPONENT_REFS
|
24
|
-
</Feature>
|
25
|
-
</Product>
|
26
|
-
</Wix>
|
@@ -1,15 +0,0 @@
|
|
1
|
-
<?xml version="1.0" encoding="utf-8"?>
|
2
|
-
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
3
|
-
<Module Id="MODULE_NAME" Language="1033" Version="VERSION">
|
4
|
-
<Package Id="PRODUCT_CODE" InstallerVersion="200" Manufacturer="MANUFACTURER" />
|
5
|
-
COMPONENT_REFS
|
6
|
-
<Directory Id="TARGETDIR" Name="SourceDir">
|
7
|
-
<Directory Id="MergeRedirectFolder" />
|
8
|
-
</Directory>
|
9
|
-
</Module>
|
10
|
-
<Fragment>
|
11
|
-
<DirectoryRef Id="MergeRedirectFolder">
|
12
|
-
FILES
|
13
|
-
</DirectoryRef>
|
14
|
-
</Fragment>
|
15
|
-
</Wix>
|
data/spec/execute.rb
DELETED