wixgem 0.39.0 → 0.43.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +5 -1
- data/{spec → lib}/WindowsInstaller.rb +45 -38
- data/lib/WindowsInstaller_hold.rb +156 -0
- data/lib/wixgem.rb +18 -22
- metadata +5 -31
- data/spec/COM_spec.rb +0 -56
- data/spec/command_spec.rb +0 -18
- data/spec/installation_spec.rb +0 -59
- data/spec/mergemodule_spec.rb +0 -76
- data/spec/multiple_product_installation_spec.rb +0 -67
- data/spec/test_files_exist.rb +0 -35
- data/spec/test_install.rb +0 -66
- data/spec/wixpath.rb +0 -3
- data/test_files/32145.txt +0 -1
- data/test_files/8.0/File With Space.txt +0 -1
- data/test_files/9.0/File With Space.txt +0 -1
- data/test_files/9.0/test_files/a_file.txt +0 -1
- data/test_files/File-With-Hyphen.txt +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 53d5561b7f79f736e50eecf763a51183da7c0997
|
4
|
+
data.tar.gz: 8d79cd0de6f4a946b455e655f23ba5e7a7026e71
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a1db621649fc003d17e08cdc79d981019cc91a3b6821abc51a0f88acd939fed00edb7f8dc5f316a6dca21a42f92c93c2e71c21e311ffa013e75f9e3db57e5802
|
7
|
+
data.tar.gz: 0cc002163c565419c6c0f5b28b87e2809b29848bcace63ffb84ba77d9e637f230ec03505ee4de6576273677a4122102410a9cf21136ff95d2c764a4b553f4fd3
|
data/README.md
CHANGED
@@ -14,6 +14,7 @@ The [WiX Toolset](http://wixtoolset.org) must be installed.
|
|
14
14
|
require 'wixgem'
|
15
15
|
|
16
16
|
WIX_TOOLSET_ROOT='path to root of Wix toolset'
|
17
|
+
Wixgem::Wix.install_path = WIX_TOOLSET_ROOT
|
17
18
|
Wixgen::Wix.make_installation('Product.msi', ['rakefile.rb']])
|
18
19
|
|
19
20
|
Wixgen::Wix.make_installation('Product.msi', {product_name: 'productname',
|
@@ -30,6 +31,7 @@ Wixgen::Wix.make_installation('Product.msi', {modify_file_paths: {/\Atest_files\
|
|
30
31
|
require 'wixgem'
|
31
32
|
|
32
33
|
WIX_TOOLSET_ROOT='path to root of Wix toolset'
|
34
|
+
Wixgem::Wix.install_path = WIX_TOOLSET_ROOT
|
33
35
|
Wixgen::Wix.make_mergemodule('Product.msi', ['rakefile.rb']])
|
34
36
|
|
35
37
|
```
|
@@ -56,7 +58,9 @@ small set of optional arguments allowing the developer to customize the generate
|
|
56
58
|
* **all_users**: String value perUser or perMachine. The default is perUser.
|
57
59
|
* **debug**: Boolean value. If debug is true the Product's wxs file and a log file are copied
|
58
60
|
to the same directory as the output msi file. This can help trouble shoot the
|
59
|
-
installation.
|
61
|
+
installation.
|
62
|
+
* **suppress_registry_harvesting** Suppress registry harvesting. Can fix the Runtime Error E6034.
|
63
|
+
* **suppress_COM_elements** Suppress COM elements.
|
60
64
|
|
61
65
|
## License
|
62
66
|
Copyright 2013-2014 Kevin Marshall
|
@@ -1,46 +1,52 @@
|
|
1
1
|
require 'win32ole'
|
2
|
-
require '
|
2
|
+
require File.dirname(__FILE__) + '/command.rb'
|
3
3
|
|
4
|
+
module Wixgem
|
4
5
|
class WindowsInstaller
|
5
|
-
def self.
|
6
|
-
|
6
|
+
def self.install(msi_file)
|
7
|
+
raise "#{msi_file} does not exist!" unless(File.exists?(msi_file))
|
8
|
+
msi_file = msi_file.gsub(/\//, '\\')
|
9
|
+
raise "#{msi_file} is already installed" if(WindowsInstaller.msi_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))
|
7
15
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
value = records['ProductCode']
|
12
|
-
end
|
16
|
+
info = msi_records(msi_file)
|
17
|
+
uninstall_product_code(info['ProductCode'])
|
18
|
+
end
|
13
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_records(msi_file)
|
32
|
+
result = product_code_installed?(info['ProductCode'])
|
33
|
+
return result
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.product_name_installed?(product_name)
|
37
|
+
installer = WIN32OLE.new('WindowsInstaller.Installer')
|
14
38
|
installer.Products.each { |prod_code|
|
15
39
|
name = installer.ProductInfo(prod_code, "ProductName")
|
16
|
-
return true if (
|
17
|
-
return true if (value == prod_code)
|
40
|
+
return true if (product_name == name)
|
18
41
|
}
|
19
42
|
return false
|
20
43
|
end
|
21
44
|
|
22
|
-
def self.
|
23
|
-
msi = msi.gsub(/\//, '\\')
|
24
|
-
raise "#{msi} is already installed" if(WindowsInstaller.installed?(msi))
|
25
|
-
execute("msiexec.exe /i #{msi}")
|
26
|
-
end
|
27
|
-
|
28
|
-
def self.uninstall(msi_product_code_or_product_name)
|
29
|
-
value = msi_product_code_or_product_name
|
30
|
-
if(File.exists?(value))
|
31
|
-
value = value.gsub(/\//, '\\')
|
32
|
-
execute("msiexec.exe /quiet /x #{value}")
|
33
|
-
return
|
34
|
-
end
|
35
|
-
|
45
|
+
def self.product_code_installed?(product_code)
|
36
46
|
installer = WIN32OLE.new('WindowsInstaller.Installer')
|
37
|
-
installer.Products.each { |
|
38
|
-
|
39
|
-
|
40
|
-
}
|
41
|
-
|
42
|
-
execute("msiexec.exe /quiet /x #{value}")
|
43
|
-
end
|
47
|
+
installer.Products.each { |installed_product_code| return true if (product_code == installed_product_code) }
|
48
|
+
return false
|
49
|
+
end
|
44
50
|
|
45
51
|
def self.product_code_installed?(product_code)
|
46
52
|
installer = WIN32OLE.new('WindowsInstaller.Installer')
|
@@ -48,13 +54,13 @@ class WindowsInstaller
|
|
48
54
|
return false
|
49
55
|
end
|
50
56
|
|
51
|
-
def self.
|
57
|
+
def self.version_from_product_name(product_name)
|
52
58
|
installer = WIN32OLE.new('WindowsInstaller.Installer')
|
53
|
-
info = product_info(installer,
|
59
|
+
info = product_info(installer, product_code_from_product_name(product_name, installer))
|
54
60
|
return info['VersionString']
|
55
61
|
end
|
56
62
|
|
57
|
-
def self.
|
63
|
+
def self.product_code_from_product_name(product_name, installer = nil)
|
58
64
|
installer = WIN32OLE.new('WindowsInstaller.Installer') if(installer.nil?)
|
59
65
|
installer.Products.each { |prod_code|
|
60
66
|
name = installer.ProductInfo(prod_code, "ProductName")
|
@@ -93,17 +99,17 @@ class WindowsInstaller
|
|
93
99
|
public
|
94
100
|
def self.dump_info(product_name)
|
95
101
|
installer = WIN32OLE.new('WindowsInstaller.Installer')
|
96
|
-
properties = product_info(installer,
|
102
|
+
properties = product_info(installer, product_code_from_product_name(product_name, installer))
|
97
103
|
properties.each { |id, value| puts "#{id}: #{value}" }
|
98
104
|
end
|
99
105
|
|
100
|
-
def self.msi_records(
|
106
|
+
def self.msi_records(msi_file)
|
101
107
|
records = {}
|
102
108
|
|
103
109
|
installer = WIN32OLE.new('WindowsInstaller.Installer')
|
104
110
|
sql_query = "SELECT * FROM `Property`"
|
105
111
|
|
106
|
-
db = installer.OpenDatabase(
|
112
|
+
db = installer.OpenDatabase(msi_file, 0)
|
107
113
|
|
108
114
|
view = db.OpenView(sql_query)
|
109
115
|
view.Execute(nil)
|
@@ -159,7 +165,8 @@ class WindowsInstaller
|
|
159
165
|
|
160
166
|
def self.execute(cmd)
|
161
167
|
command = Wixgem::Command.new(cmd)
|
168
|
+
#command[:debug] = true
|
162
169
|
command.execute
|
163
170
|
end
|
164
171
|
end
|
165
|
-
|
172
|
+
end
|
@@ -0,0 +1,156 @@
|
|
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
|
data/lib/wixgem.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
require 'fileutils'
|
2
2
|
require 'SecureRandom'
|
3
|
-
require 'logging'
|
4
|
-
require 'tempfile'
|
5
3
|
require 'tmpdir.rb'
|
6
4
|
require 'rexml/document'
|
7
5
|
require "#{File.dirname(__FILE__)}/command.rb"
|
@@ -41,15 +39,11 @@ class Wix
|
|
41
39
|
|
42
40
|
private
|
43
41
|
def self.start_logger
|
44
|
-
@logger =
|
45
|
-
@log_file = Tempfile.new('wixgem')
|
46
|
-
@logger.add_appenders(Logging.appenders.file(@log_file.path))
|
47
|
-
@logger.level = :debug
|
42
|
+
@logger = []
|
48
43
|
end
|
49
44
|
|
50
45
|
def self.end_logger
|
51
46
|
@logger = nil
|
52
|
-
@log_file = nil
|
53
47
|
end
|
54
48
|
|
55
49
|
def self.manage_upgrade(xml_doc, input)
|
@@ -150,18 +144,18 @@ class Wix
|
|
150
144
|
max_path = files.max { |a, b| a.length <=> b.length }
|
151
145
|
columen_size = max_path.length + 10
|
152
146
|
|
153
|
-
@logger
|
154
|
-
@logger
|
147
|
+
@logger << "------------------------------------ Installation Paths -----------------------------------" unless(@logger.nil?)
|
148
|
+
@logger << "%-#{columen_size}s %s\n" % ['File path', 'Installation Path'] unless(@logger.nil?)
|
155
149
|
files.each do |file|
|
156
150
|
if(File.file?(file))
|
157
151
|
install_path = file
|
158
152
|
if(input.has_key?(:modify_file_paths))
|
159
153
|
input[:modify_file_paths].each { |regex, replacement_string| install_path = install_path.gsub(regex, replacement_string) }
|
160
154
|
end
|
161
|
-
@logger
|
155
|
+
@logger << "%-#{columen_size}s %s\n" % [file, install_path] unless(@logger.nil?)
|
162
156
|
end
|
163
157
|
end
|
164
|
-
@logger
|
158
|
+
@logger << "-------------------------------------------------------------------------------------------" unless(@logger.nil?)
|
165
159
|
end
|
166
160
|
|
167
161
|
if(missing_files.length > 0)
|
@@ -182,15 +176,17 @@ class Wix
|
|
182
176
|
template_option = "-template module" unless(ext == ".msi")
|
183
177
|
|
184
178
|
cmd = "\"#{install_path}/bin/heat.exe\" dir . #{template_option} -cg InstallionFiles -gg -nologo -srd -o \"#{wxs_file}\""
|
185
|
-
cmd = cmd.gsub(/-srd/, '-svb6 -srd') if(input.has_key?(:has_vb6_files))
|
179
|
+
cmd = cmd.gsub(/-srd/, '-svb6 -srd') if(input.has_key?(:has_vb6_files) && input[:has_vb6_files])
|
180
|
+
cmd = cmd.gsub(/-srd/, '-sreg -srd') if(input.has_key?(:suppress_registry_harvesting) && input[:suppress_registry_harvesting])
|
181
|
+
cmd = cmd.gsub(/-srd/, '-scom -srd') if(input.has_key?(:suppress_COM_elements) && input[:suppress_COM_elements])
|
186
182
|
|
187
183
|
heat_cmd = Command.new(cmd)
|
188
|
-
@logger
|
184
|
+
@logger << "command: #{heat_cmd[:command]}" if(@debug && !@logger.nil?)
|
189
185
|
|
190
186
|
heat_cmd.execute
|
191
187
|
if(@debug && !heat_cmd[:output].empty?)
|
192
|
-
@logger
|
193
|
-
@logger
|
188
|
+
@logger << "--------------------------- Heat output -----------------------------------" unless(@logger.nil?)
|
189
|
+
@logger << heat_cmd[:output] unless(@logger.nil?)
|
194
190
|
end
|
195
191
|
|
196
192
|
product_name = File.basename(wxs_file, '.wxs')
|
@@ -240,21 +236,21 @@ class Wix
|
|
240
236
|
wixobj_file = "#{File.basename(wxs_file,'.wxs')}.wixobj"
|
241
237
|
|
242
238
|
candle_cmd = Command.new("\"#{install_path}/bin/candle.exe\" -out \"#{wixobj_file}\" \"#{wxs_file}\"")
|
243
|
-
@logger
|
239
|
+
@logger << "command: #{candle_cmd[:command]}" if(@debug && !@logger.nil?)
|
244
240
|
|
245
241
|
candle_cmd.execute
|
246
242
|
if(@debug && !candle_cmd[:output].empty?)
|
247
|
-
@logger
|
248
|
-
@logger
|
243
|
+
@logger << "--------------------------- Candle output -----------------------------------" unless(@logger.nil?)
|
244
|
+
@logger << candle_cmd[:output] unless(@logger.nil?)
|
249
245
|
end
|
250
246
|
|
251
247
|
light_cmd = Command.new("\"#{install_path}/bin/light.exe\" -nologo -out \"#{output}\" \"#{wixobj_file}\"")
|
252
|
-
@logger
|
248
|
+
@logger << "command: #{light_cmd[:command]}" if(@debug && !@logger.nil?)
|
253
249
|
|
254
250
|
light_cmd.execute
|
255
251
|
if(@debug && !light_cmd[:output].empty?)
|
256
|
-
@logger
|
257
|
-
@logger
|
252
|
+
@logger << "--------------------------- Light output -----------------------------------" unless(@logger.nil?)
|
253
|
+
@logger << light_cmd[:output] unless(@logger.nil?)
|
258
254
|
end
|
259
255
|
end
|
260
256
|
|
@@ -285,7 +281,7 @@ class Wix
|
|
285
281
|
raise "Wixgem exception: #{e}"
|
286
282
|
ensure
|
287
283
|
FileUtils.cp(wxs_file, "#{output_absolute_path}.wxs") if(File.exists?(wxs_file) && @debug)
|
288
|
-
|
284
|
+
File.open("#{output_absolute_path}.log", 'w') { |f| f.puts(@logger) } if(@debug &!@logger.nil?)
|
289
285
|
end
|
290
286
|
end
|
291
287
|
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.43.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-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -59,21 +59,7 @@ dependencies:
|
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
|
-
type: :
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "~>"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: logging
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - "~>"
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
76
|
-
type: :runtime
|
62
|
+
type: :development
|
77
63
|
prerelease: false
|
78
64
|
version_requirements: !ruby/object:Gem::Requirement
|
79
65
|
requirements:
|
@@ -94,22 +80,10 @@ files:
|
|
94
80
|
- example/install_files/directory/file2.txt
|
95
81
|
- example/install_files/file1.txt
|
96
82
|
- example/rakefile.rb
|
83
|
+
- lib/WindowsInstaller.rb
|
84
|
+
- lib/WindowsInstaller_hold.rb
|
97
85
|
- lib/command.rb
|
98
86
|
- lib/wixgem.rb
|
99
|
-
- spec/COM_spec.rb
|
100
|
-
- spec/WindowsInstaller.rb
|
101
|
-
- spec/command_spec.rb
|
102
|
-
- spec/installation_spec.rb
|
103
|
-
- spec/mergemodule_spec.rb
|
104
|
-
- spec/multiple_product_installation_spec.rb
|
105
|
-
- spec/test_files_exist.rb
|
106
|
-
- spec/test_install.rb
|
107
|
-
- spec/wixpath.rb
|
108
|
-
- test_files/32145.txt
|
109
|
-
- test_files/8.0/File With Space.txt
|
110
|
-
- test_files/9.0/File With Space.txt
|
111
|
-
- test_files/9.0/test_files/a_file.txt
|
112
|
-
- test_files/File-With-Hyphen.txt
|
113
87
|
homepage: http://rubygems.org/gems/wixgem
|
114
88
|
licenses:
|
115
89
|
- Apache 2.0
|
data/spec/COM_spec.rb
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
require 'rspec'
|
2
|
-
require './lib/wixgem.rb'
|
3
|
-
require './spec/wixpath.rb'
|
4
|
-
require './spec/WindowsInstaller.rb'
|
5
|
-
require './spec/test_files_exist.rb'
|
6
|
-
require 'win32ole'
|
7
|
-
require './admin.rb'
|
8
|
-
|
9
|
-
if(admin?)
|
10
|
-
describe 'Wixgem' do
|
11
|
-
describe 'Installation of a COM object' do
|
12
|
-
it 'should not be able to instance a COM object' do
|
13
|
-
expect { WIN32OLE.new('COMObject.ComClassExample') }.to raise_error
|
14
|
-
end
|
15
|
-
|
16
|
-
installation_file = 'test\\wixgem_com_test.msi'
|
17
|
-
File.delete(installation_file) if(File.exists?(installation_file))
|
18
|
-
WindowsInstaller.uninstall(installation_file) if(WindowsInstaller.installed?(installation_file))
|
19
|
-
|
20
|
-
installation_hash = { debug: true, all_users: 'perMachine', files: ['COMObject/bin/Release/COMObject.dll']}
|
21
|
-
it "should create an installation file using: #{installation_file}" do
|
22
|
-
Wixgem::Wix.make_installation(installation_file, installation_hash)
|
23
|
-
expect(File.exists?(installation_file)).to be(true)
|
24
|
-
end
|
25
|
-
|
26
|
-
# it 'should install' do
|
27
|
-
# WindowsInstaller.install(installation_file)
|
28
|
-
# expect(WindowsInstaller.installed?(installation_file)).to be(true)
|
29
|
-
# end
|
30
|
-
|
31
|
-
# it 'should have installed the COMObject.dll' do
|
32
|
-
# test_files_exist(installation_file, installation_hash)
|
33
|
-
# end
|
34
|
-
|
35
|
-
# it 'should be able to instance a COM object with a GUID' do
|
36
|
-
# object = WIN32OLE.new('{863AEADA-EE73-4f4a-ABC0-3FB384CB41AA}')
|
37
|
-
# expect(object.nil?).to eq(false)
|
38
|
-
# expect(object.GetText).to eq('Hello World')
|
39
|
-
# end
|
40
|
-
|
41
|
-
# it 'should be able to instance a COM object with a Program Id' do
|
42
|
-
# object = WIN32OLE.new('COMObject.ComClassExample')
|
43
|
-
# expect(object.nil?).to eq(false)
|
44
|
-
# expect(object.GetText).to eq('Hello World')
|
45
|
-
# end
|
46
|
-
|
47
|
-
it 'should uninstall' do
|
48
|
-
WindowsInstaller.uninstall(installation_file) if(WindowsInstaller.installed?(installation_file))
|
49
|
-
expect(WindowsInstaller.installed?(installation_file)).to be(false)
|
50
|
-
end
|
51
|
-
|
52
|
-
it 'should cleanup the generaged msi file' do
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
data/spec/command_spec.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
require 'rspec'
|
2
|
-
require './lib/command.rb'
|
3
|
-
|
4
|
-
describe 'Command' do
|
5
|
-
it 'should be able to execute: dir' do
|
6
|
-
cmd = Wixgem::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 = Wixgem::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
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
require 'rspec'
|
2
|
-
require './lib/wixgem.rb'
|
3
|
-
require './spec/wixpath.rb'
|
4
|
-
require './spec/test_install.rb'
|
5
|
-
require './spec/test_files_exist.rb'
|
6
|
-
|
7
|
-
describe 'Wixgem' do
|
8
|
-
#Wixgem::Wix.debug = true
|
9
|
-
describe 'Installation' do
|
10
|
-
test_arguments = {
|
11
|
-
test0: ['wixgem_install_test1.msi', ['rakefile.rb']],
|
12
|
-
test1: ['test/wixgem_install_test1.msi', ['rakefile.rb']],
|
13
|
-
test2: ['test/wixgem_install_test2.msi', {manufacturer: 'musco', files: ['Gemfile']}],
|
14
|
-
test3: ['test/wixgem_install_test3.msi', ['rakefile.rb', 'Gemfile']],
|
15
|
-
test4: ['test/wixgem_install_test4.msi', {version: '1.1.2.3', files: ['Gemfile']}],
|
16
|
-
test5: ['test/wixgem_install_test5.msi', {product_code: '{4528ae5a-c7fa-40a6-a70e-ac8135f1114c}', files: ['Gemfile']}],
|
17
|
-
test6: ['test/wixgem_install_test6.msi', {upgrade_code: '{1d5df00a-c18d-4897-95e6-8c936dd19647}', files: ['Gemfile']}],
|
18
|
-
test7: ['test/wixgem_install_test7.msi', {product_name: 'test_productname', files: ['Gemfile']}],
|
19
|
-
test8: ['test/wixgem_install_test8.msi', {modify_file_paths: {/\Atest_files\// => ''}, files: Dir.glob("test_files/**/*")}]
|
20
|
-
}
|
21
|
-
|
22
|
-
test_arguments.each { |key, value|
|
23
|
-
File.delete(value[0]) if(File.exists?(value[0]))
|
24
|
-
|
25
|
-
it "should create an installation file using: #{value[0]}" do
|
26
|
-
Wixgem::Wix.make_installation(value[0], value[1])
|
27
|
-
expect(File.exists?(value[0])).to be(true)
|
28
|
-
end
|
29
|
-
|
30
|
-
it "should install and uninstall: #{value[0]}" do
|
31
|
-
execute = "test_files_exist('#{value[0]}', #{value[1]})"
|
32
|
-
execute = value[2] if(value.length == 3)
|
33
|
-
test_install(key, value[0], value[1], execute)
|
34
|
-
end
|
35
|
-
}
|
36
|
-
end
|
37
|
-
|
38
|
-
describe 'Packaging excptions' do
|
39
|
-
exception_test_arguments = {
|
40
|
-
test1: ['test/wixgem_install_test1.msi', nil],
|
41
|
-
test2: ['test/wixgem_install_test1.msi', []],
|
42
|
-
test3: ['test/wixgem_install_test1.msi', ['does_not_exist.txt']]
|
43
|
-
}
|
44
|
-
|
45
|
-
exception_test_arguments.each { |key, value|
|
46
|
-
it "#{key} should raise an exception" do
|
47
|
-
expect { Wixgem::Wix.make_installation(value[0], value[1]) }.to raise_error
|
48
|
-
end
|
49
|
-
}
|
50
|
-
end
|
51
|
-
|
52
|
-
describe 'including vb6 files' do
|
53
|
-
it "the wix's heat command should contain the -svb6 flag" do
|
54
|
-
Wixgem::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
|
-
expect(wix_cmd_text.include?('-svb6')).to eq(true)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
data/spec/mergemodule_spec.rb
DELETED
@@ -1,76 +0,0 @@
|
|
1
|
-
require 'rspec'
|
2
|
-
require './lib/wixgem.rb'
|
3
|
-
require './spec/wixpath.rb'
|
4
|
-
require './spec/test_install.rb'
|
5
|
-
require './spec/WindowsInstaller.rb'
|
6
|
-
require './admin.rb'
|
7
|
-
|
8
|
-
describe 'Wixgem' do
|
9
|
-
describe 'Merge Module' do
|
10
|
-
test_arguments = {
|
11
|
-
test1: ['test/wixgem_merge_test1.msm', ['rakefile.rb']],
|
12
|
-
test2: ['test/wixgem_merge_test2.msm', {files: ['Gemfile']}],
|
13
|
-
test3: ['test/wixgem_merge_test3.msm', ['rakefile.rb', 'Gemfile']],
|
14
|
-
test4: ['test/wixgem_merge_test4.msm', Dir.glob("test_files/**/*")],
|
15
|
-
test5: ['test/wixgem_merge_test5.msm', {debug: true, files: Dir.glob("test_files/**/*")}]
|
16
|
-
}
|
17
|
-
|
18
|
-
test_arguments.each { |key, value|
|
19
|
-
File.delete(value[0]) if(File.exists?(value[0]))
|
20
|
-
|
21
|
-
it "should create merge module: #{value[0]}" do
|
22
|
-
Wixgem::Wix.make_mergemodule(value[0], value[1])
|
23
|
-
raise "#{key}: #{value[0]} does not exist" unless(File.exists?(value[0]))
|
24
|
-
end
|
25
|
-
|
26
|
-
install_file = value[0].gsub(/msm/) { |s| s = 'msi' }
|
27
|
-
it "should be able to create an installation file using: #{value[0]}" do
|
28
|
-
Wixgem::Wix.make_installation(install_file, ["#{value[0]}"])
|
29
|
-
|
30
|
-
expect(File.exists?(install_file)).to be(true)
|
31
|
-
end
|
32
|
-
|
33
|
-
it "should install and uninstall: #{install_file}" do
|
34
|
-
test_install(key, install_file, value[1])
|
35
|
-
end
|
36
|
-
|
37
|
-
it "should produce the debug files" do
|
38
|
-
if(key == :test5)
|
39
|
-
expect(File.exists?("#{value[0]}.wxs")).to be(true)
|
40
|
-
expect(File.exists?("#{value[0]}.log")).to be(true)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
}
|
44
|
-
end
|
45
|
-
|
46
|
-
if(admin?)
|
47
|
-
describe 'Multiple merge Module' do
|
48
|
-
msi_file='test\\wixgem_multiple_merge_test1.msi'
|
49
|
-
merge1='test\\wixgem_multiple_merge_test1.msm'
|
50
|
-
merge2='test\\wixgem_multiple_merge_test2.msm'
|
51
|
-
it "should be able to create two merge modules" do
|
52
|
-
Wixgem::Wix.make_mergemodule(merge1, ['rakefile.rb'])
|
53
|
-
expect(File.exists?(merge1)).to be(true)
|
54
|
-
Wixgem::Wix.make_mergemodule(merge2, ['Gemfile'])
|
55
|
-
expect(File.exists?(merge2)).to be(true)
|
56
|
-
end
|
57
|
-
|
58
|
-
it "should be able to create an installation file using: #{msi_file}" do
|
59
|
-
Wixgem::Wix.make_installation(msi_file, [merge1, merge2])
|
60
|
-
expect(File.exists?(msi_file)).to be(true)
|
61
|
-
end
|
62
|
-
|
63
|
-
it "should install contents of merge module" do
|
64
|
-
begin
|
65
|
-
WindowsInstaller.install(msi_file)
|
66
|
-
|
67
|
-
install_dir = "C:/Program Files (x86)/#{File.basename(msi_file, '.msi')}"
|
68
|
-
expect(File.exists?("#{install_dir}/rakefile.rb")).to be(true)
|
69
|
-
expect(File.exists?("#{install_dir}/Gemfile")).to be(true)
|
70
|
-
ensure
|
71
|
-
WindowsInstaller.uninstall(msi_file)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
@@ -1,67 +0,0 @@
|
|
1
|
-
require 'rspec'
|
2
|
-
require './lib/wixgem.rb'
|
3
|
-
require './spec/wixpath.rb'
|
4
|
-
require './spec/WindowsInstaller.rb'
|
5
|
-
require './admin.rb'
|
6
|
-
|
7
|
-
if(admin?)
|
8
|
-
describe 'Wixgem' do
|
9
|
-
describe 'Side by side installations' do
|
10
|
-
product1='wixgem_multiple 1.0'
|
11
|
-
product2='wixgem_multiple 1.1'
|
12
|
-
|
13
|
-
Wixgem::Wix.make_installation("test/wixgem_multiple.1.0.0.msi", {version: '1.0.0.0', product_name: product1, upgrade_code: '{face46ab-74ce-44eb-a2b7-81a8cfad5bab}', files: ['Gemfile']})
|
14
|
-
Wixgem::Wix.make_installation("test/wixgem_multiple.1.1.0.msi", {version: '1.1.0.0', product_name: product2, upgrade_code: '{face46ab-74ce-44eb-a2b7-81a8cfad5bab}', files: ['rakefile.rb']})
|
15
|
-
|
16
|
-
it "should install version 1.0.0" do
|
17
|
-
WindowsInstaller.install('test\\wixgem_multiple.1.0.0.msi')
|
18
|
-
expect(WindowsInstaller.installed?(product1)).to be(true)
|
19
|
-
expect(WindowsInstaller.version(product1)).to eq('1.0.0.0')
|
20
|
-
end
|
21
|
-
|
22
|
-
it "should install version 1.1.0" do
|
23
|
-
WindowsInstaller.install('test\\wixgem_multiple.1.1.0.msi')
|
24
|
-
expect(WindowsInstaller.installed?(product2)).to be(true)
|
25
|
-
expect(WindowsInstaller.version(product2)).to eq('1.1.0.0')
|
26
|
-
end
|
27
|
-
|
28
|
-
it "version 1.0.0 should still be installed" do
|
29
|
-
expect(WindowsInstaller.installed?(product1)).to be(true)
|
30
|
-
end
|
31
|
-
|
32
|
-
it "product codes for version 1.0.0 and 1.0.0 should be different" do
|
33
|
-
expect(WindowsInstaller.product_code(product1)).not_to eq(WindowsInstaller.product_code(product2))
|
34
|
-
end
|
35
|
-
|
36
|
-
it "Should be able to uninstall both products" do
|
37
|
-
WindowsInstaller.uninstall(product1)
|
38
|
-
WindowsInstaller.uninstall(product2)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
describe 'remove previous version' do
|
43
|
-
product1='wixgem_install 1.0'
|
44
|
-
product2='wixgem_install 1.1'
|
45
|
-
Wixgem::Wix.make_installation("test/wixgem_install.1.0.0.msi", {version: '1.0.0.0', product_name: product1, upgrade_code: '{face46ab-74ce-44eb-a2b7-81a8cfad5bab}', files: ['Gemfile']})
|
46
|
-
Wixgem::Wix.make_installation("test/wixgem_install.1.1.0.msi", {version: '1.1.0.0', product_name: product2, remove_existing_products: true, upgrade_code: '{face46ab-74ce-44eb-a2b7-81a8cfad5bab}', files: ['rakefile.rb']})
|
47
|
-
|
48
|
-
it "should install version 1.0.0" do
|
49
|
-
WindowsInstaller.install('test\\wixgem_install.1.0.0.msi')
|
50
|
-
expect(WindowsInstaller.installed?(product1)).to be(true)
|
51
|
-
end
|
52
|
-
|
53
|
-
it "should install version 1.1.0" do
|
54
|
-
WindowsInstaller.install('test\\wixgem_install.1.1.0.msi')
|
55
|
-
expect(WindowsInstaller.installed?(product2)).to be(true)
|
56
|
-
end
|
57
|
-
|
58
|
-
it "the version 1.0.0 should have been uninstalled" do
|
59
|
-
expect(WindowsInstaller.installed?(product1)).to be(false)
|
60
|
-
end
|
61
|
-
|
62
|
-
it "should be able to uninstall #{product2}" do
|
63
|
-
WindowsInstaller.uninstall(product2)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
data/spec/test_files_exist.rb
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
def files(data)
|
2
|
-
files = data
|
3
|
-
if(data.kind_of?(Hash))
|
4
|
-
files = data[:files]
|
5
|
-
|
6
|
-
if(data.has_key?(:modify_file_paths))
|
7
|
-
modify_paths = data[:modify_file_paths]
|
8
|
-
files.each_index do |index|
|
9
|
-
file_path = files[index]
|
10
|
-
modify_paths.each { |regex, replacement_string| file_path = file_path.gsub(regex, replacement_string) }
|
11
|
-
files[index] = file_path
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
return files
|
16
|
-
end
|
17
|
-
|
18
|
-
def test_files_exist(msi_file, data)
|
19
|
-
files = files(data)
|
20
|
-
|
21
|
-
product_name = File.basename(msi_file, File.extname(msi_file))
|
22
|
-
product_name = data[:product_name] if(data.kind_of?(Hash) && data.has_key?(:product_name))
|
23
|
-
|
24
|
-
manufacturer = ''
|
25
|
-
manufacturer = data[:manufacturer] if(data.kind_of?(Hash) && data.has_key?(:manufacturer))
|
26
|
-
|
27
|
-
relative_install_dir = product_name
|
28
|
-
raise "#{name}: relative_install_dir should be set to the product name" if(relative_install_dir.length == 0)
|
29
|
-
relative_install_dir = "#{manufacturer}/#{relative_install_dir}" if(manufacturer.length > 0)
|
30
|
-
|
31
|
-
files.each { |file|
|
32
|
-
full_path = "C:/Program Files (x86)/#{relative_install_dir}/#{file}"
|
33
|
-
raise "#{full_path} not installed." unless(File.exists?(full_path))
|
34
|
-
}
|
35
|
-
end
|
data/spec/test_install.rb
DELETED
@@ -1,66 +0,0 @@
|
|
1
|
-
require './spec/WindowsInstaller.rb'
|
2
|
-
|
3
|
-
require './admin.rb'
|
4
|
-
require './lib/command.rb'
|
5
|
-
|
6
|
-
def get_product_name(msi_file, arg2)
|
7
|
-
product_name = File.basename(msi_file, File.extname(msi_file))
|
8
|
-
product_name = arg2[:product_name] if(arg2.has_key?(:product_name))
|
9
|
-
|
10
|
-
return product_name
|
11
|
-
end
|
12
|
-
|
13
|
-
def test_msi(msi_file, arg2)
|
14
|
-
product_name = get_product_name(msi_file, arg2)
|
15
|
-
|
16
|
-
msi_info = WindowsInstaller.msi_records(msi_file)
|
17
|
-
#puts msi_info.to_s
|
18
|
-
|
19
|
-
if(arg2.has_key?(:product_name))
|
20
|
-
raise "ProductName is #{msi_info['ProductName']} expected #{product_name}" unless(product_name == msi_info['ProductName'])
|
21
|
-
end
|
22
|
-
|
23
|
-
if(arg2.has_key?(:product_code))
|
24
|
-
expected = arg2[:product_code].upcase
|
25
|
-
raise "ProductCode is #{msi_info['ProductCode']} expected #{expected}" unless(expected == msi_info['ProductCode'])
|
26
|
-
end
|
27
|
-
|
28
|
-
if(arg2.has_key?(:upgrade_code))
|
29
|
-
expected = arg2[:upgrade_code].upcase
|
30
|
-
raise "UpgradeCode is #{msi_info['UpgradeCode']} expected #{expected}" unless(expected == msi_info['UpgradeCode'])
|
31
|
-
end
|
32
|
-
|
33
|
-
expected_product_version = '1.0.0.0'
|
34
|
-
expected_product_version = arg2[:version] if(arg2.has_key?(:version))
|
35
|
-
raise "Invalid product version #{msi_info['ProductVersion']}" if(msi_info['ProductVersion'] != expected_product_version)
|
36
|
-
|
37
|
-
expected_manufacturer = 'Not Set'
|
38
|
-
expected_manufacturer = arg2[:manufacturer] if(arg2.has_key?(:manufacturer))
|
39
|
-
raise "Invalid Manufacturer #{msi_info['Manufacturer']}" if(msi_info['Manufacturer'] != expected_manufacturer)
|
40
|
-
end
|
41
|
-
|
42
|
-
def test_install(name, msi_file, arg2, callback=nil)
|
43
|
-
arg2 = { files: arg2} unless(arg2.kind_of?(Hash))
|
44
|
-
msi_file = msi_file.gsub(/\//) { |s| s = '\\' }
|
45
|
-
test_msi(msi_file, arg2)
|
46
|
-
|
47
|
-
msi_info = WindowsInstaller.msi_records(msi_file)
|
48
|
-
product_name = msi_info['ProductName']
|
49
|
-
|
50
|
-
if(admin?)
|
51
|
-
while(WindowsInstaller.installed?(product_name))
|
52
|
-
WindowsInstaller.uninstall(product_name)
|
53
|
-
end
|
54
|
-
raise "#{name}: Uninstall #{product_name} before running tests" if(WindowsInstaller.installed?(product_name))
|
55
|
-
|
56
|
-
begin
|
57
|
-
WindowsInstaller.install(msi_file)
|
58
|
-
raise "#{name}: Product name #{product_name} is not installed" unless(WindowsInstaller.installed?(product_name))
|
59
|
-
|
60
|
-
eval callback unless(callback == nil)
|
61
|
-
ensure
|
62
|
-
WindowsInstaller.uninstall(msi_file) if(WindowsInstaller.installed?(product_name))
|
63
|
-
raise "Failed to uninstall product #{product_name}" if(WindowsInstaller.installed?(product_name))
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
data/spec/wixpath.rb
DELETED
data/test_files/32145.txt
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
Number File
|
@@ -1 +0,0 @@
|
|
1
|
-
Test File
|
@@ -1 +0,0 @@
|
|
1
|
-
Hello World
|
@@ -1 +0,0 @@
|
|
1
|
-
Test file
|
@@ -1 +0,0 @@
|
|
1
|
-
Test it
|