wixgem 0.66.0 → 0.84.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/README.md +25 -10
- data/example/example.msi +0 -0
- data/example/example.msm +0 -0
- data/lib/admin.rb +1 -1
- data/lib/associate_extension.rb +46 -0
- data/lib/custom_action.rb +74 -0
- data/lib/temp_directory.rb +18 -0
- data/lib/wixgem.rb +150 -62
- metadata +21 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2f903e98ba851435dde4f9a8d002455b1f85341d
|
4
|
+
data.tar.gz: 0579fd5fb3f257d9bf7d172cebd9f2463dc55f99
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 84d696956ef7cb66ee5e711f7ab24b45aa212ccbbdab504a7ef196bc7714b4c4981844b6c350fb7b18e43af74ff38af5c9f30bfaa4f6106839e6059fe417cfde
|
7
|
+
data.tar.gz: 313a096755a6b651314c8e91fbef7dcec01ec7ca616decd5184b5c7bb432733cb4292cb670c60abc1f496a9fcf487c088b49b69804f1502b50ac77f046bc011a
|
data/README.md
CHANGED
@@ -13,8 +13,6 @@ The [WiX Toolset](http://wixtoolset.org) must be installed.
|
|
13
13
|
```ruby
|
14
14
|
require 'wixgem'
|
15
15
|
|
16
|
-
WIX_TOOLSET_ROOT='path to root of Wix toolset'
|
17
|
-
Wixgem::Wix.install_path = WIX_TOOLSET_ROOT
|
18
16
|
Wixgen::Wix.make_installation('Product.msi', ['rakefile.rb']])
|
19
17
|
|
20
18
|
Wixgen::Wix.make_installation('Product.msi', {product_name: 'productname',
|
@@ -31,8 +29,7 @@ Wixgen::Wix.make_installation('Product.msi', {modify_file_paths: {/\Atest_files\
|
|
31
29
|
require 'wixgem'
|
32
30
|
|
33
31
|
WIX_TOOLSET_ROOT='path to root of Wix toolset'
|
34
|
-
|
35
|
-
Wixgen::Wix.make_mergemodule('Product.msi', ['rakefile.rb']])
|
32
|
+
Wixgen::Wix.make_mergemodule('Product.msm', ['rakefile.rb']])
|
36
33
|
|
37
34
|
```
|
38
35
|
An example rakefile.rb is included in the example directory of the gem.
|
@@ -42,7 +39,7 @@ An example rakefile.rb is included in the example directory of the gem.
|
|
42
39
|
Wixgem will generate an installation or merge module from an array of files. The Wixgem also supports a
|
43
40
|
small set of optional arguments allowing the developer to customize the generated installation file.
|
44
41
|
|
45
|
-
#### Optional input hash
|
42
|
+
#### Optional input hash keys
|
46
43
|
* **product_name**: String specifing the product name of the installation.
|
47
44
|
* **manufacturer**: String specifing the manufacturer of the installation.
|
48
45
|
* **version**: String specifing the version of the installation. i.e. '1.1.0.0'
|
@@ -53,14 +50,32 @@ small set of optional arguments allowing the developer to customize the generate
|
|
53
50
|
* **modify_file_paths**: A hash of regex objects to replacement string pairs. The regular expressions are applied to
|
54
51
|
the file paths allowing the developer to modify the relative location of the files in the installation.
|
55
52
|
* **has_vb6_files**: Required if installation contains any ocx's or dll's compiled with Visual Basic 6.
|
56
|
-
* **remove_existing_products**: A boolean value. If the value is true the installation will remove
|
57
|
-
|
53
|
+
* **remove_existing_products**: A boolean value. If the value is true the installation will remove the previous
|
54
|
+
installation of the product before installing the product.
|
58
55
|
* **all_users**: String value perUser or perMachine. The default is perUser.
|
59
|
-
* **suppress_registry_harvesting** Suppress registry harvesting. Can fix the Runtime Error E6034.
|
56
|
+
* **suppress_registry_harvesting** Suppress's heat's registry harvesting. Can fix the Runtime Error E6034.
|
60
57
|
* **suppress_COM_elements** Suppress COM elements.
|
61
58
|
* **installer_version** Represents the minimum version of the Windows installer required to install
|
62
|
-
this package. The default version is 4.
|
63
|
-
3.0, 3.5, 4.0, 4.5.
|
59
|
+
this package. The default version is 4.5. Other valid versions are 2.0,
|
60
|
+
3.0, 3.5, 4.0, 4.5.
|
61
|
+
* **requires_netframework** Tests to see if the require netframework version is installed on the machine. The
|
62
|
+
associated value specifies the netframework version. The net framework strings can
|
63
|
+
be found at http://wixtoolset.org/documentation/manual/v3/customactions/wixnetfxextension.html
|
64
|
+
* **binary_table** Key is associated with an array of hashes specifying a file and a binary key to place into the
|
65
|
+
binary table.
|
66
|
+
* **custom_actions** Key is associated with an array of hashes specifying the arguments for custom actions.
|
67
|
+
* ** shortcuts ** Key is associated with a hash specifying arguments to create shortcuts. Currently,
|
68
|
+
the only supported shortcut is a desktop shortcut.
|
69
|
+
* ** extensions ** Key is associated with a hash to register executables with extensions.
|
70
|
+
* ** com_self_register ** Is a key associated with an array of files com dll's/exe's to mark for self
|
71
|
+
registration
|
72
|
+
* ** ignore_files ** Is a key associated with an array of files to ignore when generating the installation. This
|
73
|
+
key is useful for having files copied to the installation folder to generating the installation,
|
74
|
+
but not adding the files to the installation. An example of usage is I had a COM dll causing
|
75
|
+
heat some problems, so I needed to add the dependency dll's to the install directory so heat could
|
76
|
+
harvest the com registry entries, but heat was choking on adding the support dll to the
|
77
|
+
installation. Thus, I was able to create a merge module for the COM dll and another merge module for
|
78
|
+
the supporting dlls.
|
64
79
|
* **debug**: Boolean value. If debug is true the Product's wxs file and a log file are copied
|
65
80
|
to the same directory as the output msi file. If you are familiar with WiX this can helpful
|
66
81
|
if there is a problem.
|
data/example/example.msi
ADDED
Binary file
|
data/example/example.msm
ADDED
Binary file
|
data/lib/admin.rb
CHANGED
@@ -0,0 +1,46 @@
|
|
1
|
+
class AssociateExtension
|
2
|
+
def initialize(xml_doc)
|
3
|
+
@xml_doc = xml_doc
|
4
|
+
end
|
5
|
+
|
6
|
+
def associate(file, extension)
|
7
|
+
file = file.gsub(/\//,'\\')
|
8
|
+
file_elements = REXML::XPath.match(@xml_doc, "//File[@Source='.\\#{file}']")
|
9
|
+
raise "Unable to find file '#{file}' to associate with extension '#{extension}'" if(file_elements.nil? || file_elements.size != 1)
|
10
|
+
|
11
|
+
file_parent = file_elements[0].parent
|
12
|
+
|
13
|
+
app=File.basename(file)
|
14
|
+
# App Paths to support Start,Run -> "myapp"
|
15
|
+
#<RegistryValue Root="HKLM" Key="SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\MyApp.exe" Value="[!MyApp.exe]" Type="string" />
|
16
|
+
file_parent.add_element 'RegistryValue', { 'Root' => 'HKLM', 'Key' => "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\#{app}",
|
17
|
+
'Value' => "[INSTALLDIR]#{file}", 'Type' => 'string' }
|
18
|
+
#<RegistryValue Root="HKLM" Key="SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\MyApp.exe" Name="Path" Value="[APPLICATIONFOLDER]" Type="string" />
|
19
|
+
file_parent.add_element 'RegistryValue', { 'Root' => 'HKLM', 'Key' => "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\#{app}",
|
20
|
+
'Name' => 'Path', 'Value' => '[INSTALLDIR]', 'Type' => 'string' }
|
21
|
+
|
22
|
+
# Extend to the "open with" list + Win7 jump menu pinning
|
23
|
+
#<RegistryValue Root="HKLM" Key="SOFTWARE\Classes\Applications\MyApp.exe\SupportedTypes" Name=".xyz" Value="" Type="string" />
|
24
|
+
file_parent.add_element 'RegistryValue', { 'Root' => 'HKLM', 'Key' => "SOFTWARE\\Classes\\Applications\\#{app}\\SupportedTypes",
|
25
|
+
'Name' => extension, 'Value' => '', 'Type' => 'string' }
|
26
|
+
#<RegistryValue Root="HKLM" Key="SOFTWARE\Classes\Applications\MyApp.exe\shell\open" Name="FriendlyAppName" Value="!(loc.ApplicationName)" Type="string" />
|
27
|
+
file_parent.add_element 'RegistryValue', { 'Root' => 'HKLM', 'Key' => "SOFTWARE\\Classes\\Applications\\#{app}\\shell\\open\\command",
|
28
|
+
'Value' => "[INSTALLDIR]#{file} \"%1\"", 'Type' => 'string' }
|
29
|
+
|
30
|
+
# MyApp.Document ProgID
|
31
|
+
#<RegistryValue Root="HKLM" Key="SOFTWARE\Classes\MyApp.Document" Name="FriendlyTypeName" Value="!(loc.DescXYZ)" Type="string" />
|
32
|
+
file_parent.add_element 'RegistryValue', { 'Root' => 'HKLM', 'Key' => "SOFTWARE\\Classes\\#{File.basename(app, '.exe')}.Document",
|
33
|
+
'Name' => 'Aim Project File', 'Value' => "[INSTALLDIR]#{app} \"%1\"", 'Type' => 'string' }
|
34
|
+
|
35
|
+
#<ProgId Id="MyApp.Document" Description="!(loc.DescXYZ)" Icon="filetype.ico" Advertise="yes">
|
36
|
+
# <Extension Id="xyz">
|
37
|
+
# <Verb Id="open" Command="!(loc.ExplorerMenuOpenXYZ)" Argument=""%1"" />
|
38
|
+
# <MIME Advertise="yes" ContentType="application/xyz" Default="yes" />
|
39
|
+
# </Extension>
|
40
|
+
#</ProgId>
|
41
|
+
prog_id = file_parent.add_element 'ProgId', { 'Id' => "#{File.basename(app, '.exe')}.Document", 'Description' => "Aim project file",
|
42
|
+
'Advertise' => 'yes'}
|
43
|
+
ext = prog_id.add_element 'Extension', { 'Id' => extension.gsub(/\./, '') }
|
44
|
+
ext.add_element 'Verb', { 'Id' => 'open', 'Command' => "[INSTALLDIR]#{app}", 'Argument' => "\"%1\"" }
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
require 'SecureRandom'
|
3
|
+
|
4
|
+
module Wixgem
|
5
|
+
|
6
|
+
class CustomAction
|
7
|
+
def initialize(xml_doc, input)
|
8
|
+
@xml_doc = xml_doc
|
9
|
+
@input = input
|
10
|
+
end
|
11
|
+
def add(custom_action)
|
12
|
+
unless(custom_action.key?(:file) || custom_action.key?(:binary_key))
|
13
|
+
raise 'Currently, only supported custom actions work with installed executable or binary key'
|
14
|
+
end
|
15
|
+
|
16
|
+
file_key=nil
|
17
|
+
if(custom_action.key?(:file))
|
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))
|
21
|
+
|
22
|
+
file_key = file_elements[0].attributes['Id']
|
23
|
+
end
|
24
|
+
|
25
|
+
id = "ca_#{SecureRandom.uuid.gsub(/-/,'')}"
|
26
|
+
id = custom_action[:id] if(custom_action.key?(:id))
|
27
|
+
|
28
|
+
cmd_line = ''
|
29
|
+
cmd_line = custom_action[:exe_command] if(custom_action.key?(:exe_command))
|
30
|
+
|
31
|
+
impersonate = 'yes'
|
32
|
+
impersonate = custom_action[:impersonate] if(custom_action.key?(:impersonate))
|
33
|
+
|
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))
|
37
|
+
|
38
|
+
execute='deferred'
|
39
|
+
execute = custom_action[:execute] if(custom_action.key?(:execute))
|
40
|
+
|
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, 'ExeCommand' => cmd_line, '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
|
+
install_execute_sequence = fragment.add_element 'InstallExecuteSequence'
|
55
|
+
|
56
|
+
custom_action[:before] = 'InstallFinalize' if(!custom_action.key?(:after) && !custom_action.key?(:before))
|
57
|
+
if(custom_action.key?(:after))
|
58
|
+
action = install_execute_sequence.add_element 'Custom', { 'Action' => id, 'After' => custom_action[:after] }
|
59
|
+
action.text = condition
|
60
|
+
else
|
61
|
+
action = install_execute_sequence.add_element 'Custom', { 'Action' => id, 'Before' => custom_action[:before] }
|
62
|
+
action.text = condition
|
63
|
+
end
|
64
|
+
|
65
|
+
control=nil
|
66
|
+
elements = REXML::XPath.match(@xml_doc, "/Wix/Product")
|
67
|
+
elements = REXML::XPath.match(@xml_doc, "/Wix/Module") if(elements.nil? || elements.size == 0)
|
68
|
+
|
69
|
+
elements[0].add_element 'CustomActionRef', { 'Id' => id }
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
#module Wixgem
|
4
|
+
|
5
|
+
def temp_directory
|
6
|
+
tmp_file = "#{ENV['TEMP'].gsub(/\\/,'/')}/#{SecureRandom.hex}"
|
7
|
+
FileUtils.mkpath(tmp_file)
|
8
|
+
begin
|
9
|
+
yield tmp_file
|
10
|
+
rescue Exception => e
|
11
|
+
raise e
|
12
|
+
ensure
|
13
|
+
sleep(0.1)
|
14
|
+
FileUtils.rm_rf(tmp_file)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
#end
|
data/lib/wixgem.rb
CHANGED
@@ -1,14 +1,24 @@
|
|
1
1
|
require 'fileutils'
|
2
|
-
require 'tmpdir.rb'
|
3
2
|
require 'rexml/document'
|
4
3
|
require 'CMD'
|
5
4
|
require 'SecureRandom'
|
6
|
-
|
7
|
-
require_relative
|
5
|
+
|
6
|
+
require_relative 'file.rb'
|
7
|
+
require_relative 'shortcut.rb'
|
8
|
+
require_relative 'custom_action.rb'
|
9
|
+
require_relative 'temp_directory.rb'
|
10
|
+
require_relative 'associate_extension.rb'
|
11
|
+
|
12
|
+
# Editor for wix Files WixEdit: http://http://wixedit.sourceforge.net/
|
13
|
+
# Full list of Wix editors : http://robmensching.com/blog/posts/2007/11/20/wix-editors/
|
14
|
+
# I guess SharpDevelop is good
|
15
|
+
|
16
|
+
# Good web page for including the dialog https://www.packtpub.com/books/content/windows-installer-xml-wix-adding-user-interface
|
8
17
|
|
9
18
|
module Wixgem
|
10
19
|
|
11
20
|
class Wix
|
21
|
+
|
12
22
|
@@install_path = ''
|
13
23
|
@@install_path = ENV['WIX'] unless(ENV['WIX'].nil?)
|
14
24
|
|
@@ -50,53 +60,77 @@ class Wix
|
|
50
60
|
@logger = nil
|
51
61
|
end
|
52
62
|
|
63
|
+
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' }
|
68
|
+
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
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.manage_netframework(xml_doc, input)
|
79
|
+
wix = REXML::XPath.match(xml_doc, "/Wix")[0]
|
80
|
+
add_netfx_namespace = false
|
81
|
+
if(input.key?(:requires_netframework))
|
82
|
+
add_netfx_namespace=true
|
83
|
+
fragment = wix.add_element 'Fragment'
|
84
|
+
fragment.add_element 'PropertyRef', { 'Id' => input[:requires_netframework] }
|
85
|
+
condition = fragment.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]}]]>"
|
87
|
+
end
|
88
|
+
|
89
|
+
wix.attributes['xmlns:netfx'] = 'https://schemas.microsoft.com/wix/NetFxExtension' if(add_netfx_namespace)
|
90
|
+
return xml_doc
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.manage_ui(xml_doc, input)
|
94
|
+
product_elements = REXML::XPath.match(xml_doc, "/Wix/Product")
|
95
|
+
|
96
|
+
return if(product_elements.nil? || product_elements.size != 1)
|
97
|
+
return unless(input.key?(:ui))
|
98
|
+
|
99
|
+
product = product_elements[0]
|
100
|
+
ui = product.add_element 'UIRef', { 'Id' => input[:ui] }
|
101
|
+
|
102
|
+
return xml_doc
|
103
|
+
end
|
104
|
+
|
53
105
|
def self.manage_upgrade(xml_doc, input)
|
54
|
-
|
55
|
-
return xml_doc if(
|
106
|
+
products = REXML::XPath.match(xml_doc, '//Wix/Product')
|
107
|
+
return xml_doc if(products.length == 0)
|
56
108
|
|
57
|
-
if(input
|
109
|
+
if(input[:remove_existing_products])
|
58
110
|
raise 'Hash must have a version key if the hash has a :remove_existing_products key' unless(input.has_key?(:version))
|
59
111
|
raise 'Hash must have an upgrade_code key if the hash has a :remove_existing_products key' unless(input.has_key?(:upgrade_code))
|
60
112
|
|
61
|
-
upgrade =
|
62
|
-
upgrade.add_element 'UpgradeVersion', { 'Minimum' => input[:version], 'OnlyDetect'=>'yes', 'Property'=>'NEWERVERSIONDETECTED' }
|
63
|
-
upgrade.add_element 'UpgradeVersion', { 'Minimum' => '0.0.0', 'IncludeMinimum'=>'yes','Maximum'=>input[:version],'IncludeMaximum'=>'no','Property'=>'OLDERVERSIONBEINGUPGRADED' }
|
64
|
-
|
65
|
-
install_and_execute = REXML::XPath.match(xml_doc, '//Wix/Product/InstallExecuteSequence')
|
66
|
-
install_and_execute[0].add_element 'RemoveExistingProducts', { 'After'=>'InstallValidate' }
|
113
|
+
upgrade = products[0].add_element 'MajorUpgrade', { 'AllowDowngrades' => 'yes' }
|
67
114
|
end
|
68
115
|
|
69
116
|
return xml_doc
|
70
117
|
end
|
71
118
|
|
72
119
|
def self.manage_custom_actions(xml_doc, input)
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
manufacturer = input[:manufacturer] if(input.has_key?(:manufacturer))
|
78
|
-
|
79
|
-
install_path = '[ProgramFilesFolder][ProductName]'
|
80
|
-
install_path = "[ProgramFilesFolder][Manufacturer]\\[ProductName]" unless(manufacturer == 'Default Manufacturer')
|
81
|
-
|
82
|
-
product = REXML::XPath.match(xml_doc, '//Wix/Product')
|
83
|
-
return xml_doc if(product.length == 0)
|
84
|
-
|
85
|
-
product[0].add_element 'SetProperty', { 'Id' => 'ARPINSTALLLOCATION', 'Value' => "#{install_path}", 'After' => 'CostFinalize', 'Sequence' => 'both' }
|
86
|
-
product[0].add_element 'CustomAction', { 'Id' => 'SetTARGETDIR', 'Property' => 'TARGETDIR', 'Value' => "#{install_path}", 'Execute' => 'firstSequence', 'Return' => 'check'}
|
120
|
+
custom_actions = CustomAction.new(xml_doc, input)
|
121
|
+
return xml_doc if(input[:custom_actions].nil?)
|
122
|
+
|
123
|
+
input[:custom_actions].each { |ca| custom_actions.add(ca) } if(input.key?(:custom_actions))
|
87
124
|
|
88
|
-
|
89
|
-
|
125
|
+
return xml_doc
|
126
|
+
end
|
127
|
+
|
128
|
+
def self.manage_associate_extensions(xml_doc, input)
|
129
|
+
return xml_doc unless(input.key?(:extensions))
|
90
130
|
|
91
|
-
|
92
|
-
|
131
|
+
ext = AssociateExtension.new(xml_doc)
|
132
|
+
input[:extensions].each { |exe, file_ext| ext.associate(exe, file_ext) }
|
93
133
|
|
94
|
-
admin_execute_sequence = product[0].add_element 'AdminExecuteSequence'
|
95
|
-
custom_action = admin_execute_sequence.add_element 'Custom', { 'Action' => 'SetTARGETDIR', 'Before'=>'CostInitialize' }
|
96
|
-
|
97
|
-
admin_ui_sequence = product[0].add_element 'AdminUISequence'
|
98
|
-
custom_action = admin_ui_sequence.add_element 'Custom', { 'Action' => 'SetTARGETDIR', 'Before'=>'CostInitialize' }
|
99
|
-
|
100
134
|
return xml_doc
|
101
135
|
end
|
102
136
|
|
@@ -112,7 +146,7 @@ class Wix
|
|
112
146
|
}
|
113
147
|
return xml_doc if(merge_modules.length == 0)
|
114
148
|
|
115
|
-
directory_root = REXML::XPath.match(xml_doc,
|
149
|
+
directory_root = REXML::XPath.match(xml_doc, "//Directory[@Id='INSTALLDIR']")
|
116
150
|
if(directory_root.length == 0)
|
117
151
|
module_root = REXML::XPath.match(xml_doc, '//Wix/Module')
|
118
152
|
raise 'Merge modules can not be added to a merge module' unless(module_root.nil?)
|
@@ -161,6 +195,30 @@ class Wix
|
|
161
195
|
return xml_doc
|
162
196
|
end
|
163
197
|
|
198
|
+
def self.manage_self_register(xml_doc, input)
|
199
|
+
return xml_doc unless(input.has_key?(:com_self_register))
|
200
|
+
input[:com_self_register].each do |file|
|
201
|
+
file_elements = REXML::XPath.match(xml_doc, "//File[@Source='.\\#{file.gsub(/\//,'\\')}']")
|
202
|
+
raise "Unable to find file '#{file}' for self registering" unless (file_elements.length == 1)
|
203
|
+
file_elements[0].attributes['SelfRegCost'] = '0'
|
204
|
+
end
|
205
|
+
|
206
|
+
return xml_doc
|
207
|
+
end
|
208
|
+
|
209
|
+
def self.manage_binary_table(xml_doc, input)
|
210
|
+
return xml_doc unless(input.has_key?(:binary_table))
|
211
|
+
wix_element = REXML::XPath.match(xml_doc, "/Wix")[0]
|
212
|
+
|
213
|
+
fragment = wix_element.add_element 'Fragment'
|
214
|
+
input[:binary_table].each { |entry|
|
215
|
+
#puts "File: #{entry[:file]}"
|
216
|
+
binary = fragment.add_element 'Binary', { 'Id' => entry[:id], 'SourceFile' => entry[:file] }
|
217
|
+
}
|
218
|
+
|
219
|
+
return xml_doc
|
220
|
+
end
|
221
|
+
|
164
222
|
def self.modify_file_path(input, file)
|
165
223
|
return file unless(input.kind_of?(Hash) && input.has_key?(:modify_file_paths))
|
166
224
|
|
@@ -208,9 +266,17 @@ class Wix
|
|
208
266
|
max_path = files.max { |a, b| a.length <=> b.length }
|
209
267
|
columen_size = max_path.length + 10
|
210
268
|
end
|
211
|
-
|
269
|
+
|
270
|
+
ingore_files = self.ignore_files(input)
|
271
|
+
if(input.has_key?(:ignore_files))
|
272
|
+
@logger << "------------------------------------ ignoring files -----------------------------------" unless(@logger.nil?)
|
273
|
+
input[:ignore_files].each { |file| @logger << file }
|
274
|
+
end
|
275
|
+
|
212
276
|
@logger << "------------------------------------ Installation Paths -----------------------------------" unless(@logger.nil?)
|
213
277
|
@logger << "%-#{columen_size}s %s\n" % ['File path', 'Installation Path'] unless(@logger.nil?)
|
278
|
+
files.reject! { |f| ingore_files.include?(f) }
|
279
|
+
|
214
280
|
files.each do |file|
|
215
281
|
if(File.file?(file))
|
216
282
|
install_path = file
|
@@ -219,13 +285,7 @@ class Wix
|
|
219
285
|
end
|
220
286
|
@logger << "%-#{columen_size}s %s\n" % [file, install_path] unless(@logger.nil?)
|
221
287
|
end
|
222
|
-
end
|
223
|
-
|
224
|
-
if(input.has_key?(:ignore_files))
|
225
|
-
@logger << "------------------------------------ ignoring files -----------------------------------" unless(@logger.nil?)
|
226
|
-
input[:ignore_files].each { |file| @logger << file }
|
227
|
-
end
|
228
|
-
|
288
|
+
end
|
229
289
|
@logger << "-------------------------------------------------------------------------------------------" unless(@logger.nil?)
|
230
290
|
end
|
231
291
|
|
@@ -244,6 +304,11 @@ class Wix
|
|
244
304
|
end
|
245
305
|
end
|
246
306
|
|
307
|
+
def self.modify_binary_files(input)
|
308
|
+
return unless(input.key?(:binary_table))
|
309
|
+
input[:binary_table].each { |entry| entry[:file] = File.absolute_path(entry[:file]) }
|
310
|
+
end
|
311
|
+
|
247
312
|
def self.log_wix_output(cmd)
|
248
313
|
return unless(@debug && !@logger.nil?)
|
249
314
|
|
@@ -265,6 +330,11 @@ class Wix
|
|
265
330
|
cmd = cmd.gsub(/-srd/, '-svb6 -srd') if(input.has_key?(:has_vb6_files) && input[:has_vb6_files])
|
266
331
|
cmd = cmd.gsub(/-srd/, '-sreg -srd') if(input.has_key?(:suppress_registry_harvesting) && input[:suppress_registry_harvesting])
|
267
332
|
cmd = cmd.gsub(/-srd/, '-scom -srd') if(input.has_key?(:suppress_COM_elements) && input[:suppress_COM_elements])
|
333
|
+
if(input[:msi?])
|
334
|
+
cmd = cmd.gsub(/-srd/, '-dr INSTALLDIR -srd')
|
335
|
+
else
|
336
|
+
cmd = cmd.gsub(/-srd/, '-dr MergeRedirectFolder -srd')
|
337
|
+
end
|
268
338
|
return cmd
|
269
339
|
end
|
270
340
|
|
@@ -310,9 +380,10 @@ class Wix
|
|
310
380
|
file_elements = REXML::XPath.match(xml_doc, '//Wix/Fragment/DirectoryRef/Component/File')
|
311
381
|
file_elements[0].attributes['Source'] = "SourceDir\\#{file.gsub(/\//,'\\')}" if(file_elements.length == 1)
|
312
382
|
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
|
383
|
+
|
313
384
|
File.open(filename, 'w') { |f| f.puts(xml_doc.to_s) }
|
314
385
|
end
|
315
|
-
directory_fragments['.'] = '
|
386
|
+
directory_fragments['.'] = 'INSTALLDIR'
|
316
387
|
|
317
388
|
xml_doc = REXML::Document.new(File.read(wxs_file))
|
318
389
|
|
@@ -362,6 +433,7 @@ class Wix
|
|
362
433
|
end
|
363
434
|
|
364
435
|
product_name = File.basename(wxs_file, '.wxs')
|
436
|
+
input[:product_name] = product_name unless(input.has_key?(:product_name))
|
365
437
|
product_name = input[:product_name] if(input.has_key?(:product_name))
|
366
438
|
|
367
439
|
manufacturer = 'Not Set'
|
@@ -375,6 +447,9 @@ class Wix
|
|
375
447
|
|
376
448
|
upgrade_code = ''
|
377
449
|
upgrade_code = input[:upgrade_code] if(input.has_key?(:upgrade_code))
|
450
|
+
|
451
|
+
install_path = '[ProgramFilesFolder][ProductName]'
|
452
|
+
install_path = "[ProgramFilesFolder][Manufacturer]\\[ProductName]" unless(manufacturer == 'Not Set')
|
378
453
|
|
379
454
|
wxs_text = File.read(wxs_file)
|
380
455
|
|
@@ -388,36 +463,50 @@ class Wix
|
|
388
463
|
wxs_text = wxs_text.gsub(/Product Id=\"[^\"]+\"/) { |s| s = "Product Id=\"#{product_code}\"" } unless(product_code.empty?)
|
389
464
|
wxs_text = wxs_text.gsub(/UpgradeCode=\"[^\"]+\"/) { |s| s = "UpgradeCode=\"#{upgrade_code}\"" } unless(upgrade_code.empty?)
|
390
465
|
|
466
|
+
File.open(wxs_file, 'w') { |f| f.write(wxs_text) }
|
467
|
+
|
391
468
|
xml_doc = REXML::Document.new(wxs_text)
|
469
|
+
products = REXML::XPath.match(xml_doc, "/Wix/Product")
|
470
|
+
products.each do |product|
|
471
|
+
product.add_element 'SetProperty', { 'Id' => 'ARPINSTALLLOCATION', 'Value' => "#{install_path}", 'After' => 'CostFinalize', 'Sequence' => 'both' }
|
472
|
+
end
|
473
|
+
|
392
474
|
packages = REXML::XPath.match(xml_doc, '//Wix/Product/Package')
|
393
475
|
packages.each do |package|
|
394
476
|
package.add_attribute('InstallScope', 'perMachine') if(input.has_key?(:all_users))
|
477
|
+
package.add_attribute('InstallScope', input[:install_scope]) if(input.has_key?(:install_scope))
|
395
478
|
package.attributes['InstallerVersion'] = 450
|
396
479
|
package.attributes['InstallerVersion'] = (input[:installer_version]*100).to_i if(input.has_key?(:installer_version))
|
480
|
+
package.attributes['InstallPrivileges']= input[:install_priviledges] if(input.has_key?(:install_priviledges))
|
397
481
|
end
|
398
482
|
|
483
|
+
xml_doc = manage_installdir(xml_doc, input)
|
484
|
+
xml_doc = manage_netframework(xml_doc, input)
|
485
|
+
#xml_doc = manage_ui(xml_doc, input)
|
399
486
|
xml_doc = manage_custom_actions(xml_doc, input)
|
400
487
|
xml_doc = manage_upgrade(xml_doc,input)
|
401
488
|
xml_doc = manage_msm_files(xml_doc)
|
402
489
|
xml_doc = manage_read_only_files(xml_doc,input)
|
403
490
|
xml_doc = manage_shortcuts(xml_doc, input)
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
491
|
+
xml_doc = manage_self_register(xml_doc, input)
|
492
|
+
xml_doc = manage_binary_table(xml_doc, input)
|
493
|
+
xml_doc = manage_associate_extensions(xml_doc, input)
|
494
|
+
|
495
|
+
formatter = REXML::Formatters::Pretty.new(2)
|
496
|
+
formatter.compact = true
|
497
|
+
File.open(wxs_file, 'w') { |f| formatter.write(xml_doc, f) }
|
411
498
|
end
|
412
499
|
|
413
|
-
def self.create_output(wxs_file, output)
|
500
|
+
def self.create_output(wxs_file, input, output)
|
414
501
|
wixobj_file = "#{File.basename(wxs_file,'.wxs')}.wixobj"
|
415
502
|
|
416
503
|
candle_cmd = CMD.new("\"#{install_path}/bin/candle.exe\" -out \"#{wixobj_file}\" \"#{wxs_file}\"", { quiet: true })
|
417
504
|
candle_cmd.execute
|
418
505
|
log_wix_output(candle_cmd)
|
419
506
|
|
420
|
-
|
507
|
+
cmd_args = "-nologo -out \"#{output}\" \"#{wixobj_file}\""
|
508
|
+
cmd_args = "-ext WixUIExtension -cultures:en-us #{cmd_args}" if(input.key?(:ui))
|
509
|
+
light_cmd = CMD.new("\"#{install_path}/bin/light.exe\" #{cmd_args}", { quiet: true })
|
421
510
|
light_cmd.execute
|
422
511
|
log_wix_output(light_cmd)
|
423
512
|
end
|
@@ -434,7 +523,6 @@ class Wix
|
|
434
523
|
verify_input_keys(input)
|
435
524
|
|
436
525
|
@debug = input[:debug] if(!@debug && input.has_key?(:debug))
|
437
|
-
|
438
526
|
start_logger if(@debug)
|
439
527
|
|
440
528
|
FileUtils.mkpath(File.dirname(output)) unless(Dir.exists?(File.dirname(output)))
|
@@ -445,21 +533,21 @@ class Wix
|
|
445
533
|
|
446
534
|
output_absolute_path = File.absolute_path(output)
|
447
535
|
input[:original_pwd] = Dir.pwd
|
536
|
+
input[:msi?] = output.include?('.msi')
|
537
|
+
|
538
|
+
modify_binary_files(input)
|
448
539
|
|
449
|
-
|
450
|
-
#FileUtils.rm_rf(dir) if(Dir.exists?(dir))
|
451
|
-
#FileUtils.mkdir(dir)
|
452
|
-
Dir.mktmpdir do |dir|
|
540
|
+
temp_directory do |dir|
|
453
541
|
wxs_file = "#{basename}.wxs"
|
454
542
|
begin
|
455
543
|
copy_install_files(dir, input)
|
456
544
|
|
457
545
|
Dir.chdir(dir) do |current_dir|
|
458
546
|
create_wxs_file(wxs_file, input, ext)
|
459
|
-
create_output(wxs_file, output_absolute_path)
|
547
|
+
create_output(wxs_file, input, output_absolute_path)
|
460
548
|
end
|
461
549
|
rescue Exception => e
|
462
|
-
raise
|
550
|
+
raise e
|
463
551
|
ensure
|
464
552
|
FileUtils.cp("#{dir}/#{wxs_file}", "#{output_absolute_path}.wxs") if(File.exists?("#{dir}/#{wxs_file}") && @debug)
|
465
553
|
File.open("#{output_absolute_path}.log", 'w') { |f| f.puts(@logger) } if(@debug &!@logger.nil?)
|
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.84.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-12-
|
11
|
+
date: 2015-12-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -94,6 +94,20 @@ dependencies:
|
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: ocra
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
97
111
|
description: Simple Ruby interface to facilitate creating and compiling windows installation
|
98
112
|
files with the Wix Toolset.
|
99
113
|
email: KCCKSMarshall@gmail.com
|
@@ -103,12 +117,17 @@ extra_rdoc_files: []
|
|
103
117
|
files:
|
104
118
|
- LICENSE
|
105
119
|
- README.md
|
120
|
+
- example/example.msi
|
121
|
+
- example/example.msm
|
106
122
|
- example/install_files/directory/file2.txt
|
107
123
|
- example/install_files/file1.txt
|
108
124
|
- example/rakefile.rb
|
109
125
|
- lib/admin.rb
|
126
|
+
- lib/associate_extension.rb
|
127
|
+
- lib/custom_action.rb
|
110
128
|
- lib/file.rb
|
111
129
|
- lib/shortcut.rb
|
130
|
+
- lib/temp_directory.rb
|
112
131
|
- lib/wixgem.rb
|
113
132
|
homepage: http://rubygems.org/gems/wixgem
|
114
133
|
licenses:
|