wixgem 0.47.0 → 0.48.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
  SHA1:
3
- metadata.gz: 678485dbc753adc3b92f0e69a927797626abd3f0
4
- data.tar.gz: 435a5a32bd415d89ee0616a844dd3de646bb8bdc
3
+ metadata.gz: 6cc49605457da97d26245c8d8d141bae95d2ea6f
4
+ data.tar.gz: a486cfdb2dfe6f9e7434328ad11c0d587db481b9
5
5
  SHA512:
6
- metadata.gz: a924e211519f31188cc3763e1f1f0ba0dc063aba8b4697863a9fe58f38e6c0ce5c1f98d2c247c56e62e61b3fe6968d99213795eef6c193d00b8207728697b297
7
- data.tar.gz: 96071d10cabcf0a4f536ecaca035de5dd184fd9185492eb0e03f7e56d4067b9e6f241b178fb938421f367ae47a1459ae767f3484397e93f590cac3e5779e3060
6
+ metadata.gz: f64e9cb3bb1d1092914d3f701889df6cafed615b5aa12d9fed383e23ea0f7881f3574d7ee0c5f159f54614d54b3689d443287751ffcc62bf7bfea0b82e2e062a
7
+ data.tar.gz: 243e5b1b0526550ba457c63b3228ed236bbde014dd33b0396cd979b57f167be81b090a13ee5df7187f82b20815d4f32058b66bbb411c345c57c8ed27dc0b957f
@@ -69,7 +69,6 @@ class WindowsInstaller
69
69
  raise "Failed to find product code for product: #{product_name}"
70
70
  end
71
71
 
72
- private
73
72
  def self.product_info(installer, code)
74
73
  raise 'Windows installer cannot be nil' if(installer.nil?)
75
74
  hash = Hash.new
@@ -96,13 +95,13 @@ class WindowsInstaller
96
95
  return hash
97
96
  end
98
97
 
99
- public
100
98
  def self.dump_info(product_name)
101
99
  installer = WIN32OLE.new('WindowsInstaller.Installer')
102
100
  properties = product_info(installer, product_code_from_product_name(product_name, installer))
103
101
  properties.each { |id, value| puts "#{id}: #{value}" }
104
102
  end
105
103
 
104
+ private
106
105
  def self.msi_records(msi_file)
107
106
  records = {}
108
107
 
@@ -164,7 +163,7 @@ class WindowsInstaller
164
163
  end
165
164
 
166
165
  def self.execute(cmd)
167
- command = Wixgem::Command.new(cmd)
166
+ command = Wixgem::Command.new(cmd, { quiet: true } )
168
167
  #command[:debug] = true
169
168
  command.execute
170
169
  end
data/lib/command.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  require 'open3'
2
- require 'hash'
3
2
 
4
3
  module Wixgem
5
4
 
data/lib/wixgem.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  require 'fileutils'
2
- require 'SecureRandom'
3
2
  require 'tmpdir.rb'
4
3
  require 'rexml/document'
5
4
  require "#{File.dirname(__FILE__)}/command.rb"
5
+ require 'SecureRandom'
6
6
 
7
7
  module Wixgem
8
8
 
@@ -29,12 +29,12 @@ class Wix
29
29
 
30
30
  def self.make_mergemodule(output_file, input)
31
31
  gem_dir = File.dirname(__FILE__)
32
- apply_wix_template(output_file, input)
32
+ create_package(output_file, input)
33
33
  end
34
34
 
35
35
  def self.make_installation(output_file, input)
36
36
  gem_dir = File.dirname(__FILE__)
37
- apply_wix_template(output_file, input)
37
+ create_package(output_file, input)
38
38
  end
39
39
 
40
40
  private
@@ -127,8 +127,33 @@ class Wix
127
127
  return xml_doc
128
128
  end
129
129
 
130
+ def self.modify_file_path(input, file)
131
+ return file unless(input.kind_of?(Hash) && input.has_key?(:modify_file_paths))
132
+
133
+ modify_paths = input[:modify_file_paths]
134
+ modify_paths.each { |regex, replacement_string| file = file.gsub(regex, replacement_string) }
135
+
136
+ return file
137
+ end
138
+
139
+ def self.files(input)
140
+ files = input
141
+ files = input[:files] if(input.kind_of?(Hash))
142
+
143
+ files.each { |file| files.delete(file) if(File.directory?(file)) }
144
+
145
+ return files
146
+ end
147
+
148
+ def self.ignore_files(input)
149
+ files = []
150
+ files = input[:ignore_files] if(input.kind_of?(Hash) && input.has_key?(:ignore_files))
151
+
152
+ return files
153
+ end
154
+
130
155
  def self.copy_install_files(directory, input)
131
- files = input[:files]
156
+ files = files(input)
132
157
  raise 'No files were given to wixgem' if(files.length == 0)
133
158
 
134
159
  missing_files = []
@@ -179,24 +204,119 @@ class Wix
179
204
  end
180
205
  end
181
206
 
182
- def self.create_wxs_file(wxs_file, input, ext)
183
- template_option = "-template product"
184
- template_option = "-template module" unless(ext == ".msi")
185
-
186
- cmd = "\"#{install_path}/bin/heat.exe\" dir . #{template_option} -cg InstallionFiles -gg -nologo -srd -o \"#{wxs_file}\""
187
- cmd = cmd.gsub(/-srd/, '-svb6 -srd') if(input.has_key?(:has_vb6_files) && input[:has_vb6_files])
207
+ def self.log_wix_output(cmd)
208
+ return unless(@debug && !@logger.nil?)
209
+
210
+ @logger << "----------------------------------------------------------------------------"
211
+ @logger << cmd
212
+
213
+ if(!cmd[:output].empty?)
214
+ @logger << "--------------------------- std output -----------------------------------"
215
+ @logger << cmd[:output]
216
+ end
217
+
218
+ if(!cmd[:error].empty?)
219
+ @logger << "--------------------------- std error ------------------------------------"
220
+ @logger << cmd[:error]
221
+ end
222
+ end
223
+
224
+ def self.modify_heat_commandline(input, cmd)
225
+ cmd = cmd.gsub(/-srd/, '-svb6 -srd') if(input.has_key?(:has_vb6_files) && input[:has_vb6_files])
188
226
  cmd = cmd.gsub(/-srd/, '-sreg -srd') if(input.has_key?(:suppress_registry_harvesting) && input[:suppress_registry_harvesting])
189
227
  cmd = cmd.gsub(/-srd/, '-scom -srd') if(input.has_key?(:suppress_COM_elements) && input[:suppress_COM_elements])
190
-
191
- heat_cmd = Command.new(cmd, { quiet: true })
192
- @logger << "command: #{heat_cmd[:command]}" if(@debug && !@logger.nil?)
228
+ return cmd
229
+ end
193
230
 
231
+ def self.execute_heat(input, cmd_line_options)
232
+ heat_cmd = Command.new("\"#{install_path}/bin/heat.exe\" #{modify_heat_commandline(input, cmd_line_options)}", { quiet: true })
194
233
  heat_cmd.execute
195
- if(@debug && !heat_cmd[:output].empty?)
196
- @logger << "--------------------------- Heat output -----------------------------------" unless(@logger.nil?)
197
- @logger << heat_cmd[:output] unless(@logger.nil?)
234
+ log_wix_output(heat_cmd)
235
+ end
236
+
237
+ def self.execute_heat_file(wxs_file, input, template_option)
238
+ install_files = files(input)
239
+ modified_paths = []
240
+ install_files.each { |file| modified_paths << modify_file_path(input, file) }
241
+ install_files = modified_paths
242
+
243
+ install_ignore_files = ignore_files(input)
244
+ modified_paths = []
245
+ install_ignore_files.each { |file| modified_paths << modify_file_path(input, file) }
246
+ install_ignore_files = modified_paths
247
+
248
+ install_files.reject! { |f| install_ignore_files.include?(f) }
249
+
250
+ directory_fragments = {}
251
+ wxs_files = {}
252
+ install_files.each do |file|
253
+ windows_path = file.gsub(/\//, '\\')
254
+
255
+ filename = wxs_file
256
+ if(install_files.index(file) == 0)
257
+ execute_heat(input, "file \"#{windows_path}\" #{template_option} -cg InstallionFiles -gg -nologo -srd -o \"#{filename}\"")
258
+ else
259
+ filename = File.basename(wxs_file).gsub('.wxs', "-#{wxs_files.length}.wxs")
260
+ execute_heat(input, "file \"#{windows_path}\" -template fragment -gg -nologo -srd -o \"#{filename}\"")
261
+ wxs_files[file] = filename
262
+ end
263
+
264
+ directory_fragments[File.dirname(file)] = "dir#{SecureRandom.uuid.gsub(/-/,'')}"
265
+ xml_doc = REXML::Document.new(File.read(filename))
266
+ file_elements = REXML::XPath.match(xml_doc, '//Wix/Fragment/DirectoryRef/Component/File')
267
+ file_elements[0].attributes['Source'] = "SourceDir\\#{file.gsub(/\//,'\\')}" if(file_elements.length == 1)
268
+ 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
269
+ File.open(filename, 'w') { |f| f.puts(xml_doc.to_s) }
270
+ end
271
+ directory_fragments['.'] = 'TARGETDIR'
272
+
273
+ xml_doc = REXML::Document.new(File.read(wxs_file))
274
+
275
+ wix_elements = REXML::XPath.match(xml_doc, '//Wix')
276
+ raise "Invalid wxs file: #{wxs_file}" unless(wix_elements.length == 1)
277
+
278
+ directory_fragments.each do |key, id|
279
+ if(key != '.')
280
+ fragment_element = wix_elements[0].add_element 'Fragment'
281
+ directory_ref_element = fragment_element.add_element 'DirectoryRef', { 'Id' => directory_fragments[File.dirname(key)] }
282
+ directory_ref_element.add_element 'Directory', { 'Id' => id, 'Name' => File.basename(key) }
283
+ end
284
+ end
285
+
286
+ component_group_element = REXML::XPath.match(xml_doc, '//Wix/Fragment/ComponentGroup')
287
+ raise "Failed to create installation package for file: #{wxs_file}" unless(component_group_element.length == 1)
288
+
289
+ wxs_files.each do |file, filename|
290
+ xml_fragment_doc = REXML::Document.new(File.read(filename))
291
+ component_elements = REXML::XPath.match(xml_fragment_doc, '//Wix/Fragment/DirectoryRef/Component')
292
+
293
+ component_elements.each do |component_element|
294
+ 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
295
+ component_element = component_group_element[0].add_element component_element, { 'Directory' => directory_fragments[File.dirname(file)] }
296
+ end
198
297
  end
199
-
298
+
299
+ formatter = REXML::Formatters::Pretty.new(2)
300
+ formatter.compact = true # This is the magic line that does what you need!
301
+ xml_text=''
302
+ formatter.write(xml_doc, xml_text)
303
+ File.open(wxs_file, 'w') { |f| f.puts xml_text }
304
+ end
305
+
306
+ def self.execute_heat_dir(wxs_file, input, template_option)
307
+ execute_heat(input,"dir . #{template_option} -cg InstallionFiles -gg -nologo -srd -o \"#{wxs_file}\"")
308
+ end
309
+
310
+ def self.create_wxs_file(wxs_file, input, ext)
311
+ template_option = "-template product"
312
+ template_option = "-template module" unless(ext == ".msi")
313
+
314
+ if(input.has_key?(:ignore_files))
315
+ execute_heat_file(wxs_file, input, template_option)
316
+ else
317
+ execute_heat_dir(wxs_file, input, template_option)
318
+ end
319
+
200
320
  product_name = File.basename(wxs_file, '.wxs')
201
321
  product_name = input[:product_name] if(input.has_key?(:product_name))
202
322
 
@@ -248,25 +368,15 @@ class Wix
248
368
  wixobj_file = "#{File.basename(wxs_file,'.wxs')}.wixobj"
249
369
 
250
370
  candle_cmd = Command.new("\"#{install_path}/bin/candle.exe\" -out \"#{wixobj_file}\" \"#{wxs_file}\"", { quiet: true })
251
- @logger << "command: #{candle_cmd[:command]}" if(@debug && !@logger.nil?)
252
-
253
371
  candle_cmd.execute
254
- if(@debug && !candle_cmd[:output].empty?)
255
- @logger << "--------------------------- Candle output -----------------------------------" unless(@logger.nil?)
256
- @logger << candle_cmd[:output] unless(@logger.nil?)
257
- end
372
+ log_wix_output(candle_cmd)
258
373
 
259
374
  light_cmd = Command.new("\"#{install_path}/bin/light.exe\" -nologo -out \"#{output}\" \"#{wixobj_file}\"", { quiet: true })
260
- @logger << "command: #{light_cmd[:command]}" if(@debug && !@logger.nil?)
261
-
262
375
  light_cmd.execute
263
- if(@debug && !light_cmd[:output].empty?)
264
- @logger << "--------------------------- Light output -----------------------------------" unless(@logger.nil?)
265
- @logger << light_cmd[:output] unless(@logger.nil?)
266
- end
376
+ log_wix_output(light_cmd)
267
377
  end
268
378
 
269
- def self.apply_wix_template(output, input)
379
+ def self.create_package(output, input)
270
380
  raise 'WIX path is not set!' if(install_path.nil?)
271
381
  input = { files: input } unless(input.kind_of?(Hash))
272
382
  @debug = input[:debug] if(!@debug && input.has_key?(:debug))
@@ -281,6 +391,9 @@ class Wix
281
391
 
282
392
  output_absolute_path = File.absolute_path(output)
283
393
 
394
+ #dir = './tmp_dir'
395
+ #FileUtils.rm_rf(dir) if(Dir.exists?(dir))
396
+ #FileUtils.mkdir(dir)
284
397
  Dir.mktmpdir do |dir|
285
398
  copy_install_files(dir, input)
286
399
 
metadata CHANGED
@@ -1,69 +1,69 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wixgem
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.47.0
4
+ version: 0.48.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-31 00:00:00.000000000 Z
11
+ date: 2015-02-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ~>
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ~>
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ~>
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ~>
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ~>
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ~>
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: dev
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ~>
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ~>
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  description: Simple Ruby interface to facilitate creating and compiling windows installation
@@ -81,7 +81,6 @@ files:
81
81
  - example/install_files/file1.txt
82
82
  - example/rakefile.rb
83
83
  - lib/WindowsInstaller.rb
84
- - lib/WindowsInstaller_hold.rb
85
84
  - lib/command.rb
86
85
  - lib/wixgem.rb
87
86
  homepage: http://rubygems.org/gems/wixgem
@@ -94,17 +93,17 @@ require_paths:
94
93
  - lib
95
94
  required_ruby_version: !ruby/object:Gem::Requirement
96
95
  requirements:
97
- - - ">="
96
+ - - '>='
98
97
  - !ruby/object:Gem::Version
99
98
  version: 1.9.1
100
99
  required_rubygems_version: !ruby/object:Gem::Requirement
101
100
  requirements:
102
- - - ">="
101
+ - - '>='
103
102
  - !ruby/object:Gem::Version
104
103
  version: '0'
105
104
  requirements: []
106
105
  rubyforge_project:
107
- rubygems_version: 2.2.2
106
+ rubygems_version: 2.2.0
108
107
  signing_key:
109
108
  specification_version: 4
110
109
  summary: Simple Ruby interface to facilitate working with Wix Toolset
@@ -1,156 +0,0 @@
1
- require 'win32ole'
2
- require 'dev_tasks'
3
-
4
- module Wixgem
5
-
6
- class WindowsInstaller
7
- def self.install(msi_file)
8
- msi_file = msi_file.gsub(/\//, '\\')
9
- raise "#{msi_file} is already installed" if(WindowsInstaller.installed?(msi_file))
10
- execute("msiexec.exe /i #{msi_file}")
11
- end
12
-
13
- def self.uninstall(msi_file)
14
- raise "#{msi_file} does not exist!" unless(File.exists?(msi_file))
15
-
16
- info = msi_properties(installer, msi_file)
17
- uninstall_product_code(info['ProductCode'])
18
- end
19
-
20
- def self.uninstall_product_name(product_name)
21
- raise "#{product_name} is not installed" unless(product_name_installed?(product_name))
22
- uninstall_product_code(product_code_from_product_name(product_name))
23
- end
24
-
25
- def self.uninstall_product_code(product_code)
26
- raise "#{product_code} is not installed" unless(product_code_installed?(product_code))
27
- execute("msiexec.exe /quiet /x #{product_code}")
28
- end
29
-
30
- def self.msi_installed?(msi_file)
31
- info = msi_properties(msi_file)
32
- return product_code_installed?(info['ProductCode'])
33
- end
34
-
35
- def self.product_name_installed?(product_name)
36
- installer = WIN32OLE.new('WindowsInstaller.Installer')
37
- installer.Products.each { |prod_code|
38
- name = installer.ProductInfo(prod_code, "ProductName")
39
- return true if (product_name == name)
40
- }
41
- return false
42
- end
43
-
44
- def self.product_code_installed?(product_code)
45
- installer = WIN32OLE.new('WindowsInstaller.Installer')
46
- installer.Products.each { |installed_product_code| return true if (product_code == installed_product_code) }
47
- return false
48
- end
49
-
50
- def self.product_name_installed_version(product_name)
51
- installer = WIN32OLE.new('WindowsInstaller.Installer')
52
- info = product_info(installer, product_code_from_product_name(product_name, installer))
53
- return info['VersionString']
54
- end
55
-
56
- private
57
- def self.product_code_from_msi(msi_file, installer = nil)
58
- msi_info = msi_properties(msi_file)
59
- return msi_info['ProductCode']
60
- end
61
-
62
- def self.product_code_from_product_name(product_name, installer = nil)
63
- installer = WIN32OLE.new('WindowsInstaller.Installer') if(installer.nil?)
64
- installer.Products.each { |prod_code|
65
- name = installer.ProductInfo(prod_code, "ProductName")
66
- return prod_code if (product_name == name)
67
- }
68
- raise "Failed to find product code for product: #{product_name}"
69
- end
70
-
71
- def self.product_code_properties(product_code, installer = nil)
72
- installer = WIN32OLE.new('WindowsInstaller.Installer') if(installer.nil?)
73
- hash = Hash.new
74
- # known product keywords found on internet. Would be nice to generate.
75
- %w[Language PackageCode Transforms AssignmentType PackageName InstalledProductName VersionString RegCompany
76
- RegOwner ProductID ProductIcon InstallLocation InstallSource InstallDate Publisher LocalPackage HelpLink
77
- HelpTelephone URLInfoAbout URLUpdateInfo InstanceType].sort.each do |prop|
78
- value = installer.ProductInfo(product_code, prop)
79
- hash[prop] = value unless(value.nil? || value == '')
80
- end
81
- return hash
82
- end
83
-
84
- def self.print_properties(product_name)
85
- installer = WIN32OLE.new('WindowsInstaller.Installer')
86
- properties = product_info(installer, product_code(product_name, installer))
87
- properties.each { |id, value| puts "#{id}: #{value}" }
88
- end
89
-
90
- def self.msi_records(msi_file)
91
- records = {}
92
-
93
- installer = WIN32OLE.new('WindowsInstaller.Installer')
94
- sql_query = "SELECT * FROM `Property`"
95
-
96
- db = installer.OpenDatabase(msi_file, 0)
97
-
98
- view = db.OpenView(sql_query)
99
- view.Execute(nil)
100
-
101
- record = view.Fetch()
102
- return '' if(record == nil)
103
-
104
- while(!record.nil?)
105
- records[record.StringData(1)] = record.StringData(2)
106
- record = view.Fetch()
107
- end
108
- db.ole_free
109
- db = nil
110
- installer.ole_free
111
- installer = nil
112
-
113
- return records
114
- end
115
-
116
- def self.print_msi_records(msi_file)
117
- records = msi_records(msi_file)
118
-
119
- puts "#{msi_file} Properties:"
120
- records.each do |key,value|
121
- puts "#{key}: #{value}"
122
- end
123
- end
124
-
125
- def self.print_product_name(product_name)
126
- installer = WIN32OLE.new('WindowsInstaller.Installer')
127
- # only one session per process!
128
- session = installer.OpenProduct(product_code_from_product_name?(product_name, installer))
129
- db = session.Database
130
-
131
- sql_query = "SELECT * FROM `Property`"
132
- view = db.OpenView(sql_query)
133
- view.Execute(nil)
134
-
135
- record = view.Fetch()
136
- return '' if(record == nil)
137
-
138
- puts "Session Properties:"
139
- while(!record.nil?)
140
- puts "#{record.StringData(1)}: #{record.StringData(2)}"
141
- record = view.Fetch()
142
- end
143
- db.ole_free
144
- db = nil
145
- installer.ole_free
146
- installer = nil
147
- puts ''
148
- end
149
-
150
- def self.execute(cmd)
151
- command = Wixgem::Command.new(cmd)
152
- command.execute
153
- end
154
- end
155
-
156
- end