vagrant-parallels 2.2.2 → 2.2.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/lib/vagrant-parallels/action/forward_ports.rb +19 -17
- data/lib/vagrant-parallels/action/network.rb +72 -75
- data/lib/vagrant-parallels/action.rb +1 -2
- data/lib/vagrant-parallels/driver/base.rb +80 -98
- data/lib/vagrant-parallels/guest_cap/darwin/install_parallels_tools.rb +4 -1
- data/lib/vagrant-parallels/guest_cap/linux/install_parallels_tools.rb +6 -1
- data/lib/vagrant-parallels/model/forwarded_port.rb +14 -2
- data/lib/vagrant-parallels/util/compile_forwarded_ports.rb +19 -17
- data/lib/vagrant-parallels/version.rb +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ede8c43d4ad31a4ad5cec8ecf94158e93a825ea959bf4a2cbf5da1b1428108ad
|
4
|
+
data.tar.gz: 0e56a44dcbd181577e69ef04525be3278a86fd6c0ccb41139635a19176d3768e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a283f0ebedc0074f277fd902725d6724b1db7a7c822621885f5df8bba6197abe9e3e6a914a5cfc8146c4abd187c04a81c59ff02f364c058ffa3fbe7f7fc634be
|
7
|
+
data.tar.gz: 8af828330dc40be03eefcd34834e2eb1d7490ba7ed7331d01dbec224f148ca9743d961cc2510c889d97112f50bc3f7d0db0047c0c3cb5cc03316ed256ed665a3
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
## 2.2.5 (February 22, 2022)
|
2
|
+
BUG FIXES:
|
3
|
+
- Fixed Parallels Tool installation on M1 hosts with arm64
|
4
|
+
[[GH-416](https://github.com/Parallels/vagrant-parallels/pull/416)]
|
5
|
+
|
6
|
+
## 2.2.4 (August 18, 2021)
|
7
|
+
BUG FIXES:
|
8
|
+
- Fixed running the provisioner on "vagrant up --provision"
|
9
|
+
[[GH-402](https://github.com/Parallels/vagrant-parallels/pull/402)]
|
10
|
+
|
11
|
+
## 2.2.3 (July 14, 2021)
|
12
|
+
BUG FIXES:
|
13
|
+
- Fixed the compatibility with Vagrant 2.2.17
|
14
|
+
[[GH-399](https://github.com/Parallels/vagrant-parallels/pull/399)]
|
15
|
+
|
1
16
|
## 2.2.2 (June 23, 2021)
|
2
17
|
BUG FIXES:
|
3
18
|
- Fixed shared folder mount on the VM reboot
|
@@ -5,7 +5,7 @@ module VagrantPlugins
|
|
5
5
|
include VagrantPlugins::Parallels::Util::CompileForwardedPorts
|
6
6
|
@@lock = Mutex.new
|
7
7
|
|
8
|
-
def initialize(app,
|
8
|
+
def initialize(app, _env)
|
9
9
|
@app = app
|
10
10
|
end
|
11
11
|
|
@@ -22,17 +22,15 @@ module VagrantPlugins
|
|
22
22
|
return @app.call(env) if env[:forwarded_ports].empty?
|
23
23
|
|
24
24
|
# Acquire both of class- and process-level locks so that we don't
|
25
|
-
# forward ports
|
25
|
+
# forward ports simultaneously with someone else.
|
26
26
|
@@lock.synchronize do
|
27
|
-
|
28
|
-
env[:
|
29
|
-
|
30
|
-
forward_ports
|
31
|
-
end
|
32
|
-
rescue Errors::EnvironmentLockedError
|
33
|
-
sleep 1
|
34
|
-
retry
|
27
|
+
env[:machine].env.lock('forward_ports') do
|
28
|
+
env[:ui].output(I18n.t('vagrant.actions.vm.forward_ports.forwarding'))
|
29
|
+
forward_ports
|
35
30
|
end
|
31
|
+
rescue Vagrant::Errors::EnvironmentLockedError
|
32
|
+
sleep 1
|
33
|
+
retry
|
36
34
|
end
|
37
35
|
|
38
36
|
@app.call(env)
|
@@ -46,7 +44,9 @@ module VagrantPlugins
|
|
46
44
|
@env[:forwarded_ports].each do |fp|
|
47
45
|
message_attributes = {
|
48
46
|
guest_port: fp.guest_port,
|
49
|
-
|
47
|
+
guest_ip: fp.guest_ip,
|
48
|
+
host_port: fp.host_port,
|
49
|
+
host_ip: fp.host_ip
|
50
50
|
}
|
51
51
|
|
52
52
|
# Assuming the only reason to establish port forwarding is
|
@@ -54,7 +54,7 @@ module VagrantPlugins
|
|
54
54
|
# bridged networking don't require port-forwarding and establishing
|
55
55
|
# forwarded ports on these attachment types has uncertain behaviour.
|
56
56
|
@env[:ui].detail(I18n.t('vagrant_parallels.actions.vm.forward_ports.forwarding_entry',
|
57
|
-
message_attributes))
|
57
|
+
**message_attributes))
|
58
58
|
|
59
59
|
# In Parallels Desktop the scope port forwarding rules is global,
|
60
60
|
# so we have to keep their names unique.
|
@@ -69,14 +69,16 @@ module VagrantPlugins
|
|
69
69
|
|
70
70
|
# Add the options to the ports array to send to the driver later
|
71
71
|
ports << {
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
72
|
+
guest_port: fp.guest_port,
|
73
|
+
guest_ip: fp.guest_ip,
|
74
|
+
host_port: fp.host_port,
|
75
|
+
host_ip: fp.host_ip,
|
76
|
+
name: unique_id,
|
77
|
+
protocol: fp.protocol
|
76
78
|
}
|
77
79
|
end
|
78
80
|
|
79
|
-
|
81
|
+
unless ports.empty?
|
80
82
|
# We only need to forward ports if there are any to forward
|
81
83
|
@env[:machine].provider.driver.forward_ports(ports)
|
82
84
|
end
|
@@ -16,7 +16,7 @@ module VagrantPlugins
|
|
16
16
|
include Vagrant::Util::ScopedHashOverride
|
17
17
|
@@lock = Mutex.new
|
18
18
|
|
19
|
-
def initialize(app,
|
19
|
+
def initialize(app, _env)
|
20
20
|
@app = app
|
21
21
|
@logger = Log4r::Logger.new('vagrant_parallels::action::network')
|
22
22
|
end
|
@@ -44,20 +44,20 @@ module VagrantPlugins
|
|
44
44
|
|
45
45
|
# Figure out the slot that this adapter will go into
|
46
46
|
slot = options[:adapter]
|
47
|
-
|
48
|
-
if available_slots.empty?
|
49
|
-
raise VagrantPlugins::Parallels::Errors::ParallelsNoRoomForHighLevelNetwork
|
50
|
-
end
|
47
|
+
unless slot
|
48
|
+
raise VagrantPlugins::Parallels::Errors::ParallelsNoRoomForHighLevelNetwork if available_slots.empty?
|
51
49
|
|
52
50
|
slot = available_slots.shift
|
53
51
|
end
|
54
52
|
|
55
53
|
# Configure it
|
56
54
|
data = nil
|
57
|
-
|
55
|
+
#noinspection RubyCaseWithoutElseBlockInspection
|
56
|
+
case type
|
57
|
+
when :private_network
|
58
58
|
# private_network = hostonly
|
59
59
|
data = [:hostonly, options]
|
60
|
-
|
60
|
+
when :public_network
|
61
61
|
# public_network = bridged
|
62
62
|
data = [:bridged, options]
|
63
63
|
end
|
@@ -103,16 +103,15 @@ module VagrantPlugins
|
|
103
103
|
networks << network
|
104
104
|
end
|
105
105
|
|
106
|
-
|
106
|
+
unless adapters.empty?
|
107
107
|
# Enable the adapters
|
108
108
|
@logger.info('Enabling adapters...')
|
109
109
|
env[:ui].output(I18n.t('vagrant.actions.vm.network.preparing'))
|
110
110
|
adapters.each do |adapter|
|
111
|
-
env[:ui].detail(I18n.t(
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
extra: '',
|
111
|
+
env[:ui].detail(I18n.t('vagrant_parallels.parallels.network_adapter',
|
112
|
+
adapter: adapter[:adapter].to_s,
|
113
|
+
type: adapter[:type].to_s,
|
114
|
+
extra: '',
|
116
115
|
))
|
117
116
|
end
|
118
117
|
|
@@ -124,12 +123,12 @@ module VagrantPlugins
|
|
124
123
|
|
125
124
|
# If we have networks to configure, then we configure it now, since
|
126
125
|
# that requires the machine to be up and running.
|
127
|
-
|
126
|
+
unless adapters.empty? && networks.empty?
|
128
127
|
assign_interface_numbers(networks, adapters)
|
129
128
|
|
130
129
|
# Only configure the networks the user requested us to configure
|
131
130
|
networks_to_configure = networks.select { |n| n[:auto_config] }
|
132
|
-
|
131
|
+
unless networks_to_configure.empty?
|
133
132
|
env[:ui].info I18n.t('vagrant.actions.vm.network.configuring')
|
134
133
|
env[:machine].guest.capability(:configure_networks, networks_to_configure)
|
135
134
|
end
|
@@ -138,10 +137,10 @@ module VagrantPlugins
|
|
138
137
|
|
139
138
|
def bridged_config(options)
|
140
139
|
{
|
141
|
-
auto_config:
|
142
|
-
bridge:
|
143
|
-
mac:
|
144
|
-
nic_type:
|
140
|
+
auto_config: true,
|
141
|
+
bridge: nil,
|
142
|
+
mac: nil,
|
143
|
+
nic_type: nil,
|
145
144
|
use_dhcp_assigned_default_route: false
|
146
145
|
}.merge(options || {})
|
147
146
|
end
|
@@ -162,17 +161,17 @@ module VagrantPlugins
|
|
162
161
|
Array(config[:bridge]).each do |bridge|
|
163
162
|
bridge = bridge.downcase if bridge.respond_to?(:downcase)
|
164
163
|
bridgedifs.each do |interface|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
164
|
+
next unless bridge === interface[:name].downcase
|
165
|
+
|
166
|
+
@logger.debug('Specific bridge found as configured in the Vagrantfile. Using it.')
|
167
|
+
chosen_bridge = interface[:name]
|
168
|
+
break
|
170
169
|
end
|
171
170
|
break if chosen_bridge
|
172
171
|
end
|
173
172
|
|
174
173
|
# If one wasn't found, then we notify the user here.
|
175
|
-
|
174
|
+
unless chosen_bridge
|
176
175
|
@env[:ui].info I18n.t(
|
177
176
|
'vagrant.actions.vm.bridged_networking.specific_not_found',
|
178
177
|
bridge: config[:bridge])
|
@@ -183,7 +182,7 @@ module VagrantPlugins
|
|
183
182
|
# specified in the Vagrantfile, or the bridge specified in the Vagrantfile
|
184
183
|
# wasn't found), then we fall back to the normal means of searching for a
|
185
184
|
# bridged network.
|
186
|
-
|
185
|
+
unless chosen_bridge
|
187
186
|
if bridgedifs.length == 1
|
188
187
|
# One bridgable interface? Just use it.
|
189
188
|
chosen_bridge = bridgedifs[0][:name]
|
@@ -197,15 +196,14 @@ module VagrantPlugins
|
|
197
196
|
interface = bridgedifs[index]
|
198
197
|
@env[:ui].info("#{index + 1}) #{interface[:name]}", prefix: false)
|
199
198
|
end
|
200
|
-
@env[:ui].info(I18n.t(
|
201
|
-
'vagrant.actions.vm.bridged_networking.choice_help')+"\n")
|
199
|
+
@env[:ui].info("#{I18n.t('vagrant.actions.vm.bridged_networking.choice_help')}\n")
|
202
200
|
|
203
201
|
# The range of valid choices
|
204
202
|
valid = Range.new(1, bridgedifs.length)
|
205
203
|
|
206
204
|
# The choice that the user has chosen as the bridging interface
|
207
205
|
choice = nil
|
208
|
-
|
206
|
+
until valid.include?(choice)
|
209
207
|
choice = @env[:ui].ask(
|
210
208
|
'Which interface should the network bridge to? Enter a number: ')
|
211
209
|
choice = choice.to_i
|
@@ -219,11 +217,11 @@ module VagrantPlugins
|
|
219
217
|
|
220
218
|
# Given the choice we can now define the adapter we're using
|
221
219
|
{
|
222
|
-
adapter:
|
223
|
-
type:
|
224
|
-
bridge:
|
220
|
+
adapter: config[:adapter],
|
221
|
+
type: :bridged,
|
222
|
+
bridge: chosen_bridge,
|
225
223
|
mac_address: config[:mac],
|
226
|
-
nic_type:
|
224
|
+
nic_type: config[:nic_type]
|
227
225
|
}
|
228
226
|
end
|
229
227
|
|
@@ -231,16 +229,16 @@ module VagrantPlugins
|
|
231
229
|
if config[:ip]
|
232
230
|
options = {
|
233
231
|
auto_config: true,
|
234
|
-
mac:
|
235
|
-
netmask:
|
236
|
-
type:
|
232
|
+
mac: nil,
|
233
|
+
netmask: '255.255.255.0',
|
234
|
+
type: :static
|
237
235
|
}.merge(config)
|
238
236
|
options[:type] = options[:type].to_sym
|
239
237
|
return options
|
240
238
|
end
|
241
239
|
|
242
240
|
{
|
243
|
-
type:
|
241
|
+
type: :dhcp,
|
244
242
|
use_dhcp_assigned_default_route: config[:use_dhcp_assigned_default_route]
|
245
243
|
}
|
246
244
|
end
|
@@ -248,10 +246,10 @@ module VagrantPlugins
|
|
248
246
|
def hostonly_config(options)
|
249
247
|
options = {
|
250
248
|
auto_config: true,
|
251
|
-
mac:
|
252
|
-
name:
|
253
|
-
nic_type:
|
254
|
-
type:
|
249
|
+
mac: nil,
|
250
|
+
name: nil,
|
251
|
+
nic_type: nil,
|
252
|
+
type: :static
|
255
253
|
}.merge(options)
|
256
254
|
|
257
255
|
# Make sure the type is a symbol
|
@@ -290,13 +288,14 @@ module VagrantPlugins
|
|
290
288
|
# network interface.
|
291
289
|
@env[:machine].provider.driver.read_bridged_interfaces.each do |interface|
|
292
290
|
next if interface[:status] == 'Down'
|
291
|
+
|
293
292
|
that_netaddr = IPAddr.new("#{interface[:ip]}/#{interface[:netmask]}")
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
293
|
+
next unless netaddr.include? that_netaddr
|
294
|
+
|
295
|
+
raise VagrantPlugins::Parallels::Errors::NetworkCollision,
|
296
|
+
hostonly_netaddr: netaddr,
|
297
|
+
bridge_netaddr: that_netaddr,
|
298
|
+
bridge_interface: interface[:name]
|
300
299
|
end
|
301
300
|
end
|
302
301
|
|
@@ -319,14 +318,14 @@ module VagrantPlugins
|
|
319
318
|
end
|
320
319
|
|
321
320
|
{
|
322
|
-
adapter_ip:
|
321
|
+
adapter_ip: options[:adapter_ip],
|
323
322
|
auto_config: options[:auto_config],
|
324
|
-
ip:
|
325
|
-
mac:
|
326
|
-
name:
|
327
|
-
netmask:
|
328
|
-
nic_type:
|
329
|
-
type:
|
323
|
+
ip: options[:ip],
|
324
|
+
mac: options[:mac],
|
325
|
+
name: options[:name],
|
326
|
+
netmask: options[:netmask],
|
327
|
+
nic_type: options[:nic_type],
|
328
|
+
type: options[:type]
|
330
329
|
}.merge(dhcp_options)
|
331
330
|
end
|
332
331
|
|
@@ -334,7 +333,7 @@ module VagrantPlugins
|
|
334
333
|
@logger.info("Searching for matching hostonly network: #{config[:ip]}")
|
335
334
|
interface = hostonly_find_matching_network(config)
|
336
335
|
|
337
|
-
|
336
|
+
unless interface
|
338
337
|
@logger.info('Network not found. Creating if we can.')
|
339
338
|
|
340
339
|
# Create a new network
|
@@ -343,25 +342,25 @@ module VagrantPlugins
|
|
343
342
|
end
|
344
343
|
|
345
344
|
{
|
346
|
-
adapter:
|
347
|
-
hostonly:
|
345
|
+
adapter: config[:adapter],
|
346
|
+
hostonly: interface[:name],
|
348
347
|
mac_address: config[:mac],
|
349
|
-
nic_type:
|
350
|
-
type:
|
348
|
+
nic_type: config[:nic_type],
|
349
|
+
type: :hostonly
|
351
350
|
}
|
352
351
|
end
|
353
352
|
|
354
353
|
def hostonly_network_config(config)
|
355
354
|
{
|
356
|
-
type:
|
355
|
+
type: config[:type],
|
357
356
|
adapter_ip: config[:adapter_ip],
|
358
|
-
ip:
|
359
|
-
netmask:
|
357
|
+
ip: config[:ip],
|
358
|
+
netmask: config[:netmask]
|
360
359
|
}
|
361
360
|
end
|
362
361
|
|
363
362
|
|
364
|
-
def shared_config(
|
363
|
+
def shared_config(_options)
|
365
364
|
{
|
366
365
|
auto_config: false
|
367
366
|
}
|
@@ -370,11 +369,11 @@ module VagrantPlugins
|
|
370
369
|
def shared_adapter(config)
|
371
370
|
{
|
372
371
|
adapter: config[:adapter],
|
373
|
-
type:
|
372
|
+
type: :shared
|
374
373
|
}
|
375
374
|
end
|
376
375
|
|
377
|
-
def shared_network_config(
|
376
|
+
def shared_network_config(_config)
|
378
377
|
{}
|
379
378
|
end
|
380
379
|
|
@@ -396,11 +395,11 @@ module VagrantPlugins
|
|
396
395
|
# Make a first pass to assign interface numbers by adapter location
|
397
396
|
vm_adapters = @env[:machine].provider.driver.read_network_interfaces
|
398
397
|
vm_adapters.sort.each do |number, adapter|
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
398
|
+
next unless adapter[:type] != :none
|
399
|
+
|
400
|
+
# Not used, so assign the interface number and increment
|
401
|
+
adapter_to_interface[number] = current
|
402
|
+
current += 1
|
404
403
|
end
|
405
404
|
|
406
405
|
# Make a pass through the adapters to assign the :interface
|
@@ -419,9 +418,7 @@ module VagrantPlugins
|
|
419
418
|
# Get the list of numbers
|
420
419
|
net_nums = []
|
421
420
|
@env[:machine].provider.driver.read_virtual_networks.each do |net|
|
422
|
-
if net['Network ID'] =~ /^vagrant-vnet(\d+)$/
|
423
|
-
net_nums << $1.to_i
|
424
|
-
end
|
421
|
+
net_nums << $1.to_i if net['Network ID'] =~ /^vagrant-vnet(\d+)$/
|
425
422
|
end
|
426
423
|
|
427
424
|
if net_nums.empty?
|
@@ -440,12 +437,12 @@ module VagrantPlugins
|
|
440
437
|
options = {
|
441
438
|
network_id: config[:name] || next_network_id,
|
442
439
|
adapter_ip: config[:adapter_ip],
|
443
|
-
netmask:
|
440
|
+
netmask: config[:netmask],
|
444
441
|
}
|
445
442
|
|
446
443
|
if config[:type] == :dhcp
|
447
444
|
options[:dhcp] = {
|
448
|
-
ip:
|
445
|
+
ip: config[:dhcp_ip],
|
449
446
|
lower: config[:dhcp_lower],
|
450
447
|
upper: config[:dhcp_upper]
|
451
448
|
}
|
@@ -277,8 +277,7 @@ module VagrantPlugins
|
|
277
277
|
b.use Call, IsState, :running do |env1, b1|
|
278
278
|
# If the VM is running, run the necessary provisioners
|
279
279
|
if env1[:result]
|
280
|
-
b1.use
|
281
|
-
action_provision
|
280
|
+
b1.use action_provision
|
282
281
|
next
|
283
282
|
end
|
284
283
|
|
@@ -27,11 +27,11 @@ module VagrantPlugins
|
|
27
27
|
# This flag is used to keep track of interrupted state (SIGINT)
|
28
28
|
@interrupted = false
|
29
29
|
|
30
|
-
@prlctl_path
|
30
|
+
@prlctl_path = util_path('prlctl')
|
31
31
|
@prlsrvctl_path = util_path('prlsrvctl')
|
32
32
|
@prldisktool_path = util_path('prl_disk_tool')
|
33
33
|
|
34
|
-
|
34
|
+
unless @prlctl_path
|
35
35
|
# This means that Parallels Desktop was not found, so we raise this
|
36
36
|
# error here.
|
37
37
|
raise VagrantPlugins::Parallels::Errors::ParallelsNotDetected
|
@@ -60,9 +60,7 @@ module VagrantPlugins
|
|
60
60
|
args.concat(["--nat-#{r[:protocol]}-del", r[:name]])
|
61
61
|
end
|
62
62
|
|
63
|
-
|
64
|
-
execute_prlsrvctl('net', 'set', read_shared_network_id, *args)
|
65
|
-
end
|
63
|
+
execute_prlsrvctl('net', 'set', read_shared_network_id, *args) unless args.empty?
|
66
64
|
end
|
67
65
|
|
68
66
|
# Clears the shared folders that have been set on the virtual machine.
|
@@ -78,7 +76,7 @@ module VagrantPlugins
|
|
78
76
|
# @param [String] src_name Name or UUID of the source VM or template.
|
79
77
|
# @param [<String => String>] options Options to clone virtual machine.
|
80
78
|
# @return [String] UUID of the new VM.
|
81
|
-
def clone_vm(src_name, options={})
|
79
|
+
def clone_vm(src_name, options = {})
|
82
80
|
dst_name = "vagrant_temp_#{(Time.now.to_f * 1000.0).to_i}_#{rand(100000)}"
|
83
81
|
|
84
82
|
args = ['clone', src_name, '--name', dst_name]
|
@@ -146,10 +144,10 @@ module VagrantPlugins
|
|
146
144
|
|
147
145
|
# Return the details
|
148
146
|
{
|
149
|
-
name:
|
150
|
-
ip:
|
147
|
+
name: options[:network_id],
|
148
|
+
ip: options[:adapter_ip],
|
151
149
|
netmask: options[:netmask],
|
152
|
-
dhcp:
|
150
|
+
dhcp: options[:dhcp]
|
153
151
|
}
|
154
152
|
end
|
155
153
|
|
@@ -160,9 +158,7 @@ module VagrantPlugins
|
|
160
158
|
# @return [String] ID of the created snapshot.
|
161
159
|
def create_snapshot(uuid, snapshot_name)
|
162
160
|
stdout = execute_prlctl('snapshot', uuid, '--name', snapshot_name)
|
163
|
-
if stdout =~
|
164
|
-
return Regexp.last_match(1)
|
165
|
-
end
|
161
|
+
return Regexp.last_match(1) if stdout =~ /{([\w-]+)}/
|
166
162
|
|
167
163
|
raise Errors::SnapshotIdNotDetected, stdout: stdout
|
168
164
|
end
|
@@ -222,7 +218,7 @@ module VagrantPlugins
|
|
222
218
|
# ['create-vm', 'add-vm', 'remove-vm', 'clone-vm']
|
223
219
|
def disable_password_restrictions(acts)
|
224
220
|
server_info = json { execute_prlsrvctl('info', '--json') }
|
225
|
-
server_info.fetch('Require password to',[]).each do |act|
|
221
|
+
server_info.fetch('Require password to', []).each do |act|
|
226
222
|
execute_prlsrvctl('set', '--require-pwd', "#{act}:off") if acts.include? act
|
227
223
|
end
|
228
224
|
end
|
@@ -251,34 +247,29 @@ module VagrantPlugins
|
|
251
247
|
|
252
248
|
# Disable all previously existing adapters (except shared 'vnet0')
|
253
249
|
existing_adapters.each do |adapter|
|
254
|
-
if adapter != 'vnet0'
|
255
|
-
execute_prlctl('set', @uuid, '--device-set', adapter, '--disable')
|
256
|
-
end
|
250
|
+
execute_prlctl('set', @uuid, '--device-set', adapter, '--disable') if adapter != 'vnet0'
|
257
251
|
end
|
258
252
|
|
259
253
|
adapters.each do |adapter|
|
260
254
|
args = []
|
261
255
|
if existing_adapters.include? "net#{adapter[:adapter]}"
|
262
|
-
args.concat(['--device-set',"net#{adapter[:adapter]}", '--enable'])
|
256
|
+
args.concat(['--device-set', "net#{adapter[:adapter]}", '--enable'])
|
263
257
|
else
|
264
|
-
args.concat([
|
258
|
+
args.concat(%w[--device-add net])
|
265
259
|
end
|
266
260
|
|
267
|
-
|
261
|
+
case adapter[:type]
|
262
|
+
when :hostonly
|
268
263
|
args.concat(['--type', 'host', '--iface', adapter[:hostonly]])
|
269
|
-
|
264
|
+
when :bridged
|
270
265
|
args.concat(['--type', 'bridged', '--iface', adapter[:bridge]])
|
271
|
-
|
272
|
-
args.concat([
|
266
|
+
when :shared
|
267
|
+
args.concat(%w[--type shared])
|
273
268
|
end
|
274
269
|
|
275
|
-
if adapter[:mac_address]
|
276
|
-
args.concat(['--mac', adapter[:mac_address]])
|
277
|
-
end
|
270
|
+
args.concat(['--mac', adapter[:mac_address]]) if adapter[:mac_address]
|
278
271
|
|
279
|
-
if adapter[:nic_type]
|
280
|
-
args.concat(['--adapter-type', adapter[:nic_type].to_s])
|
281
|
-
end
|
272
|
+
args.concat(['--adapter-type', adapter[:nic_type].to_s]) if adapter[:nic_type]
|
282
273
|
|
283
274
|
execute_prlctl('set', @uuid, *args)
|
284
275
|
end
|
@@ -308,9 +299,9 @@ module VagrantPlugins
|
|
308
299
|
protocol = options[:protocol] || 'tcp'
|
309
300
|
pf_builder = [
|
310
301
|
options[:name],
|
311
|
-
options[:
|
302
|
+
options[:host_port],
|
312
303
|
@uuid,
|
313
|
-
options[:
|
304
|
+
options[:guest_port]
|
314
305
|
]
|
315
306
|
|
316
307
|
args.concat(["--nat-#{protocol}-add", pf_builder.join(',')])
|
@@ -329,7 +320,7 @@ module VagrantPlugins
|
|
329
320
|
snap_config = File.join(settings.fetch('Home'), 'Snapshots.xml')
|
330
321
|
|
331
322
|
# There are no snapshots, exit
|
332
|
-
return {}
|
323
|
+
return {} unless File.exist?(snap_config)
|
333
324
|
|
334
325
|
xml = Nokogiri::XML(File.read(snap_config))
|
335
326
|
snapshots = {}
|
@@ -349,7 +340,7 @@ module VagrantPlugins
|
|
349
340
|
end
|
350
341
|
|
351
342
|
# Halts the virtual machine (pulls the plug).
|
352
|
-
def halt(force=false)
|
343
|
+
def halt(force = false)
|
353
344
|
args = ['stop', @uuid]
|
354
345
|
args << '--kill' if force
|
355
346
|
execute_prlctl(*args)
|
@@ -370,22 +361,18 @@ module VagrantPlugins
|
|
370
361
|
info = {}
|
371
362
|
ifconfig = execute('ifconfig', iface)
|
372
363
|
# Assign default values
|
373
|
-
info[:name]
|
374
|
-
info[:ip]
|
364
|
+
info[:name] = iface
|
365
|
+
info[:ip] = '0.0.0.0'
|
375
366
|
info[:netmask] = '0.0.0.0'
|
376
|
-
info[:status]
|
367
|
+
info[:status] = 'Down'
|
377
368
|
|
378
|
-
if ifconfig =~ /(?<=inet\s)(\S*)/
|
379
|
-
info[:ip] = $1.to_s
|
380
|
-
end
|
369
|
+
info[:ip] = $1.to_s if ifconfig =~ /(?<=inet\s)(\S*)/
|
381
370
|
if ifconfig =~ /(?<=netmask\s)(\S*)/
|
382
371
|
# Netmask will be converted from hex to dec:
|
383
372
|
# '0xffffff00' -> '255.255.255.0'
|
384
|
-
info[:netmask] = $1.hex.to_s(16).scan(/../).each.map{|octet| octet.hex}.join('.')
|
385
|
-
end
|
386
|
-
if ifconfig =~ /\W(UP)\W/ and ifconfig !~ /(?<=status:\s)inactive$/
|
387
|
-
info[:status] = 'Up'
|
373
|
+
info[:netmask] = $1.hex.to_s(16).scan(/../).each.map { |octet| octet.hex }.join('.')
|
388
374
|
end
|
375
|
+
info[:status] = 'Up' if ifconfig =~ /\W(UP)\W/ and ifconfig !~ /(?<=status:\s)inactive$/
|
389
376
|
|
390
377
|
bridged_ifaces << info
|
391
378
|
end
|
@@ -406,7 +393,7 @@ module VagrantPlugins
|
|
406
393
|
# @param [Boolean] global If true, returns all the rules on the host.
|
407
394
|
# Otherwise only rules related to the context VM will be returned.
|
408
395
|
# @return [Array<Symbol => String>]
|
409
|
-
def read_forwarded_ports(global=false)
|
396
|
+
def read_forwarded_ports(global = false)
|
410
397
|
all_rules = read_shared_interface[:nat]
|
411
398
|
|
412
399
|
if global
|
@@ -426,44 +413,44 @@ module VagrantPlugins
|
|
426
413
|
leases = {}
|
427
414
|
begin
|
428
415
|
File.open(leases_file).grep(/#{mac_addr}/) do |line|
|
429
|
-
_, ip, exp, dur,
|
416
|
+
_, ip, exp, dur, = line.split /([\d.]*)="(\d*),(\d*),(\w*),(\w*)".*/
|
430
417
|
leases[ip] = exp.to_i - dur.to_i
|
431
418
|
end
|
432
419
|
rescue Errno::EACCES
|
433
|
-
raise Errors::DhcpLeasesNotAccessible, :
|
420
|
+
raise Errors::DhcpLeasesNotAccessible, leases_file: leases_file.to_s
|
434
421
|
rescue Errno::ENOENT
|
435
422
|
# File does not exist
|
436
423
|
# Perhaps, it is the fist start of Parallels Desktop
|
437
|
-
return
|
424
|
+
return ''
|
438
425
|
end
|
439
426
|
|
440
|
-
return
|
427
|
+
return '' if leases.empty?
|
441
428
|
|
442
429
|
# Get the most resent lease and return an associated IP
|
443
|
-
leases.
|
430
|
+
leases.max_by { |_ip, lease_time| lease_time }.first
|
444
431
|
end
|
445
432
|
|
446
433
|
# Returns path to the Parallels Tools ISO file.
|
447
434
|
#
|
448
435
|
# @param [String] guest_os Guest os type: "linux", "darwin" or "windows"
|
449
436
|
# @return [String] Path to the ISO.
|
450
|
-
def read_guest_tools_iso_path(guest_os)
|
451
|
-
guest_os = guest_os.to_sym
|
452
|
-
iso_name ={
|
437
|
+
def read_guest_tools_iso_path(guest_os, arch=nil)
|
438
|
+
guest_os = (guest_os + (['arm', 'arm64', 'aarch64'].include?(arch.to_s.strip) ? '_arm' : '')).to_sym
|
439
|
+
iso_name = {
|
453
440
|
linux: 'prl-tools-lin.iso',
|
441
|
+
linux_arm: 'prl-tools-lin-arm.iso',
|
454
442
|
darwin: 'prl-tools-mac.iso',
|
443
|
+
darwin_arm: 'prl-tools-mac-arm.iso',
|
455
444
|
windows: 'PTIAgent.exe'
|
456
445
|
}
|
457
|
-
return nil
|
446
|
+
return nil unless iso_name[guest_os]
|
458
447
|
|
459
|
-
bundle_id =
|
448
|
+
bundle_id = 'com.parallels.desktop.console'
|
460
449
|
bundle_path = execute('mdfind', "kMDItemCFBundleIdentifier == #{bundle_id}")
|
461
450
|
iso_path = File.expand_path("./Contents/Resources/Tools/#{iso_name[guest_os]}",
|
462
451
|
bundle_path.split("\n")[0])
|
463
452
|
|
464
|
-
|
465
|
-
raise Errors::ParallelsToolsIsoNotFound, :iso_path => iso_path
|
466
|
-
end
|
453
|
+
raise Errors::ParallelsToolsIsoNotFound, iso_path: iso_path unless File.exist?(iso_path)
|
467
454
|
|
468
455
|
iso_path
|
469
456
|
end
|
@@ -478,7 +465,7 @@ module VagrantPlugins
|
|
478
465
|
# @return [Symbol]
|
479
466
|
def read_guest_tools_state
|
480
467
|
state = read_settings.fetch('GuestTools', {}).fetch('state', nil)
|
481
|
-
state
|
468
|
+
state ||= 'not_installed'
|
482
469
|
state.to_sym
|
483
470
|
end
|
484
471
|
|
@@ -512,18 +499,18 @@ module VagrantPlugins
|
|
512
499
|
end
|
513
500
|
|
514
501
|
iface = {
|
515
|
-
name:
|
502
|
+
name: net_info['Network ID'],
|
516
503
|
status: 'Down'
|
517
504
|
}
|
518
505
|
|
519
506
|
adapter = net_info['Parallels adapter']
|
520
507
|
if adapter
|
521
|
-
iface[:ip]
|
522
|
-
iface[:netmask]
|
523
|
-
iface[:status]
|
508
|
+
iface[:ip] = adapter['IPv4 address']
|
509
|
+
iface[:netmask] = adapter['IPv4 subnet mask']
|
510
|
+
iface[:status] = 'Up'
|
524
511
|
|
525
512
|
if adapter['IPv6 address'] && adapter['IPv6 subnet mask']
|
526
|
-
iface[:ipv6]
|
513
|
+
iface[:ipv6] = adapter['IPv6 address']
|
527
514
|
iface[:ipv6_prefix] = adapter['IPv6 subnet mask']
|
528
515
|
end
|
529
516
|
end
|
@@ -542,9 +529,7 @@ module VagrantPlugins
|
|
542
529
|
name.start_with?('net') && params['type'] == 'shared'
|
543
530
|
end
|
544
531
|
|
545
|
-
if shared_ifaces.empty?
|
546
|
-
raise Errors::SharedInterfaceNotFound
|
547
|
-
end
|
532
|
+
raise Errors::SharedInterfaceNotFound if shared_ifaces.empty?
|
548
533
|
|
549
534
|
shared_ifaces.values.first.fetch('mac', nil)
|
550
535
|
end
|
@@ -570,14 +555,15 @@ module VagrantPlugins
|
|
570
555
|
adapter = name.match(/^net(\d+)$/)[1].to_i
|
571
556
|
nics[adapter] ||= {}
|
572
557
|
|
573
|
-
|
558
|
+
case params['type']
|
559
|
+
when 'shared'
|
574
560
|
nics[adapter][:type] = :shared
|
575
|
-
|
561
|
+
when 'host'
|
576
562
|
nics[adapter][:type] = :hostonly
|
577
|
-
nics[adapter][:hostonly] = params.fetch('iface','')
|
578
|
-
|
563
|
+
nics[adapter][:hostonly] = params.fetch('iface', '')
|
564
|
+
when 'bridged'
|
579
565
|
nics[adapter][:type] = :bridged
|
580
|
-
nics[adapter][:bridge] = params.fetch('iface','')
|
566
|
+
nics[adapter][:bridge] = params.fetch('iface', '')
|
581
567
|
end
|
582
568
|
end
|
583
569
|
nics
|
@@ -586,8 +572,8 @@ module VagrantPlugins
|
|
586
572
|
# Returns virtual machine settings
|
587
573
|
#
|
588
574
|
# @return [<String => String, Hash>]
|
589
|
-
def read_settings(uuid
|
590
|
-
vm = json { execute_prlctl('list', uuid, '--info', '--no-header', '--json')
|
575
|
+
def read_settings(uuid = @uuid)
|
576
|
+
vm = json { execute_prlctl('list', uuid, '--info', '--no-header', '--json') }
|
591
577
|
vm.last
|
592
578
|
end
|
593
579
|
|
@@ -609,20 +595,20 @@ module VagrantPlugins
|
|
609
595
|
end
|
610
596
|
|
611
597
|
iface = {
|
612
|
-
nat:
|
598
|
+
nat: [],
|
613
599
|
status: 'Down'
|
614
600
|
}
|
615
601
|
adapter = net_info['Parallels adapter']
|
616
602
|
|
617
603
|
if adapter
|
618
|
-
iface[:ip]
|
619
|
-
iface[:netmask]
|
620
|
-
iface[:status]
|
604
|
+
iface[:ip] = adapter['IPv4 address']
|
605
|
+
iface[:netmask] = adapter['IPv4 subnet mask']
|
606
|
+
iface[:status] = 'Up'
|
621
607
|
end
|
622
608
|
|
623
609
|
if net_info.key?('DHCPv4 server')
|
624
610
|
iface[:dhcp] = {
|
625
|
-
ip:
|
611
|
+
ip: net_info['DHCPv4 server']['Server address'],
|
626
612
|
lower: net_info['DHCPv4 server']['IP scope start address'],
|
627
613
|
upper: net_info['DHCPv4 server']['IP scope end address']
|
628
614
|
}
|
@@ -631,10 +617,10 @@ module VagrantPlugins
|
|
631
617
|
net_info['NAT server'].each do |group, rules|
|
632
618
|
rules.each do |name, params|
|
633
619
|
iface[:nat] << {
|
634
|
-
name:
|
635
|
-
protocol:
|
636
|
-
guest:
|
637
|
-
hostport:
|
620
|
+
name: name,
|
621
|
+
protocol: group == 'TCP rules' ? 'tcp' : 'udp',
|
622
|
+
guest: params['destination IP/VM id'],
|
623
|
+
hostport: params['source port'],
|
638
624
|
guestport: params['destination port']
|
639
625
|
}
|
640
626
|
end
|
@@ -650,7 +636,7 @@ module VagrantPlugins
|
|
650
636
|
def read_shared_folders
|
651
637
|
shf_info = read_settings.fetch('Host Shared Folders', {})
|
652
638
|
list = {}
|
653
|
-
shf_info.delete_if { |k,
|
639
|
+
shf_info.delete_if { |k, _v| k == 'enabled' }.each do |id, data|
|
654
640
|
list[id] = data.fetch('path')
|
655
641
|
end
|
656
642
|
|
@@ -686,11 +672,9 @@ module VagrantPlugins
|
|
686
672
|
# @param [String] option Name of option (See all: `prlctl list -L`)
|
687
673
|
# @param [String] uuid Virtual machine UUID
|
688
674
|
# @return [String]
|
689
|
-
def read_vm_option(option, uuid
|
690
|
-
out = execute_prlctl('list', uuid,'--no-header', '-o', option).strip
|
691
|
-
if out.empty?
|
692
|
-
raise Errors::ParallelsVMOptionNotFound, vm_option: option
|
693
|
-
end
|
675
|
+
def read_vm_option(option, uuid = @uuid)
|
676
|
+
out = execute_prlctl('list', uuid, '--no-header', '-o', option).strip
|
677
|
+
raise Errors::ParallelsVMOptionNotFound, vm_option: option if out.empty?
|
694
678
|
|
695
679
|
out
|
696
680
|
end
|
@@ -699,7 +683,7 @@ module VagrantPlugins
|
|
699
683
|
#
|
700
684
|
# @return [<String => String>]
|
701
685
|
def read_vms
|
702
|
-
args = %w
|
686
|
+
args = %w[list --all --no-header --json -o name,uuid]
|
703
687
|
vms_arr = json { execute_prlctl(*args) }
|
704
688
|
templates_arr = json { execute_prlctl(*args, '--template') }
|
705
689
|
|
@@ -711,7 +695,7 @@ module VagrantPlugins
|
|
711
695
|
#
|
712
696
|
# @return [Array <String => String>]
|
713
697
|
def read_vms_info
|
714
|
-
args = %w
|
698
|
+
args = %w[list --all --info --no-header --json]
|
715
699
|
vms_arr = json { execute_prlctl(*args) }
|
716
700
|
templates_arr = json { execute_prlctl(*args, '--template') }
|
717
701
|
|
@@ -722,7 +706,7 @@ module VagrantPlugins
|
|
722
706
|
#
|
723
707
|
# @param [String] pvm_file Path to the machine image (*.pvm)
|
724
708
|
# @param [Array<String>] opts List of options for "prlctl register"
|
725
|
-
def register(pvm_file, opts=[])
|
709
|
+
def register(pvm_file, opts = [])
|
726
710
|
execute_prlctl('register', pvm_file, *opts)
|
727
711
|
end
|
728
712
|
|
@@ -823,7 +807,7 @@ module VagrantPlugins
|
|
823
807
|
|
824
808
|
# Sometimes this happens. In this case, retry.
|
825
809
|
# If we don't see this text, the VM really doesn't exist.
|
826
|
-
return false
|
810
|
+
return false unless result.stderr.include?('Login failed:')
|
827
811
|
|
828
812
|
# Sleep a bit though to give Parallels Desktop time to fix itself
|
829
813
|
sleep 2
|
@@ -861,8 +845,8 @@ module VagrantPlugins
|
|
861
845
|
# If there was an error running command, show the error and the
|
862
846
|
# output.
|
863
847
|
raise VagrantPlugins::Parallels::Errors::ExecutionError,
|
864
|
-
|
865
|
-
|
848
|
+
command: command.inspect,
|
849
|
+
stderr: r.stderr
|
866
850
|
end
|
867
851
|
end
|
868
852
|
r.stdout
|
@@ -877,12 +861,10 @@ module VagrantPlugins
|
|
877
861
|
JSON.parse(data)
|
878
862
|
rescue JSON::JSONError
|
879
863
|
# We retried already, raise the issue and be done
|
880
|
-
if raise_error
|
881
|
-
raise VagrantPlugins::Parallels::Errors::JSONParseError, data: data
|
882
|
-
end
|
864
|
+
raise VagrantPlugins::Parallels::Errors::JSONParseError, data: data if raise_error
|
883
865
|
|
884
866
|
# Remove garbage before/after json string[GH-204]
|
885
|
-
data = data[/(
|
867
|
+
data = data[/({.*}|\[.*\])/m]
|
886
868
|
|
887
869
|
# Remove all control characters unsupported by JSON [GH-219]
|
888
870
|
data.tr!("\u0000-\u001f", '')
|
@@ -903,7 +885,7 @@ module VagrantPlugins
|
|
903
885
|
end
|
904
886
|
|
905
887
|
# Append in the options for subprocess
|
906
|
-
command << {notify: [:stdout, :stderr]}
|
888
|
+
command << { notify: [:stdout, :stderr] }
|
907
889
|
|
908
890
|
Vagrant::Util::Busy.busy(int_callback) do
|
909
891
|
Vagrant::Util::Subprocess.execute(*command, &block)
|
@@ -5,8 +5,11 @@ module VagrantPlugins
|
|
5
5
|
|
6
6
|
def self.install_parallels_tools(machine)
|
7
7
|
machine.communicate.tap do |comm|
|
8
|
+
arch = ''
|
9
|
+
comm.execute("uname -p") { |type, data| arch << data if type == :stdout }
|
10
|
+
|
8
11
|
tools_iso_path = File.expand_path(
|
9
|
-
machine.provider.driver.read_guest_tools_iso_path(
|
12
|
+
machine.provider.driver.read_guest_tools_iso_path("darwin", arch),
|
10
13
|
machine.env.root_path
|
11
14
|
)
|
12
15
|
remote_file = '/tmp/prl-tools-mac.iso'
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
|
1
3
|
module VagrantPlugins
|
2
4
|
module Parallels
|
3
5
|
module GuestLinuxCap
|
@@ -8,8 +10,11 @@ module VagrantPlugins
|
|
8
10
|
machine.communicate.sudo('ptiagent-cmd --install')
|
9
11
|
else
|
10
12
|
machine.communicate.tap do |comm|
|
13
|
+
arch = ''
|
14
|
+
comm.execute("uname -p") { |type, data| arch << data if type == :stdout }
|
15
|
+
|
11
16
|
tools_iso_path = File.expand_path(
|
12
|
-
machine.provider.driver.read_guest_tools_iso_path(
|
17
|
+
machine.provider.driver.read_guest_tools_iso_path("linux", arch),
|
13
18
|
machine.env.root_path
|
14
19
|
)
|
15
20
|
remote_file = '/tmp/prl-tools-lin.iso'
|
@@ -29,14 +29,26 @@ module VagrantPlugins
|
|
29
29
|
# @return [Integer]
|
30
30
|
attr_reader :host_port
|
31
31
|
|
32
|
-
|
32
|
+
# The ip of the guest to be used for the port.
|
33
|
+
#
|
34
|
+
# @return [String]
|
35
|
+
attr_reader :guest_ip
|
36
|
+
|
37
|
+
# The ip of the host used to access the port.
|
38
|
+
#
|
39
|
+
# @return [String]
|
40
|
+
attr_reader :host_ip
|
41
|
+
|
42
|
+
def initialize(id, host_port, guest_port, host_ip, guest_ip, **options)
|
33
43
|
@id = id
|
34
44
|
@guest_port = guest_port
|
45
|
+
@guest_ip = guest_ip
|
35
46
|
@host_port = host_port
|
47
|
+
@host_ip = host_ip
|
36
48
|
|
37
49
|
options ||= {}
|
38
50
|
@auto_correct = false
|
39
|
-
@auto_correct = options[:auto_correct] if options.
|
51
|
+
@auto_correct = options[:auto_correct] if options.key?(:auto_correct)
|
40
52
|
@protocol = options[:protocol] || 'tcp'
|
41
53
|
end
|
42
54
|
|
@@ -12,23 +12,25 @@ module VagrantPlugins
|
|
12
12
|
mappings = {}
|
13
13
|
|
14
14
|
config.vm.networks.each do |type, options|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
15
|
+
next unless type == :forwarded_port
|
16
|
+
|
17
|
+
guest_port = options[:guest]
|
18
|
+
guest_ip = options[:guest_ip]
|
19
|
+
host_port = options[:host]
|
20
|
+
host_ip = options[:host_ip]
|
21
|
+
protocol = options[:protocol] || 'tcp'
|
22
|
+
options = scoped_hash_override(options, :parallels)
|
23
|
+
id = options[:id]
|
24
|
+
|
25
|
+
# If the forwarded port was marked as disabled, ignore.
|
26
|
+
next if options[:disabled]
|
27
|
+
|
28
|
+
# Temporary disable automatically pre-configured forwarded ports
|
29
|
+
# for SSH, since it is working not so well [GH-146]
|
30
|
+
next if id == 'ssh'
|
31
|
+
|
32
|
+
mappings[host_port.to_s + protocol.to_s] =
|
33
|
+
Model::ForwardedPort.new(id, host_port, guest_port, host_ip, guest_ip, **options)
|
32
34
|
end
|
33
35
|
|
34
36
|
mappings.values
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vagrant-parallels
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.2.
|
4
|
+
version: 2.2.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mikhail Zholobov
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2022-02-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nokogiri
|
@@ -31,28 +31,28 @@ dependencies:
|
|
31
31
|
requirements:
|
32
32
|
- - "~>"
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version:
|
34
|
+
version: '13.0'
|
35
35
|
type: :development
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
39
|
- - "~>"
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
-
version:
|
41
|
+
version: '13.0'
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: rspec
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
45
45
|
requirements:
|
46
46
|
- - "~>"
|
47
47
|
- !ruby/object:Gem::Version
|
48
|
-
version: 3.
|
48
|
+
version: 3.10.0
|
49
49
|
type: :development
|
50
50
|
prerelease: false
|
51
51
|
version_requirements: !ruby/object:Gem::Requirement
|
52
52
|
requirements:
|
53
53
|
- - "~>"
|
54
54
|
- !ruby/object:Gem::Version
|
55
|
-
version: 3.
|
55
|
+
version: 3.10.0
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
57
|
name: rspec-its
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|