veewee 0.3.0.alpha5 → 0.3.0.alpha6

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.
data/README.md CHANGED
@@ -1,24 +1,3 @@
1
- # Note: due to a miss manipulation on my side, the veewee03 branch got merged with master
2
- # Therefore the current state of the masterbranch on github is highly unstable
3
-
4
- To refer to the old master, I've put up the state before the error at
5
- <https://github.com/jedi4ever/veewee-old>
6
-
7
- -------
8
-
9
- Maintaining two branches with complete different structures isn't fun. So..... I want to merge the two.
10
-
11
- Veewee03 will bring many new features:
12
-
13
- - kvm and vmware fusion support -
14
- - veewee as a standalone tool tool if you don't use virtualbox,vagrant
15
- - postinstall scripts can now be toggle with --include and --exclude
16
-
17
- Caveat: it's alpha-functional but not as polished as the previous version. But I'm sure with your help this won't take long.
18
-
19
- My apologies for all the pull-requests to the previous version that will not be merged automatically. I'm focusing more on get this version stable and will incorporate the ideas later (some already are)
20
-
21
- ---
22
1
  **VeeWee:** the tool to easily build vagrant base boxes or kvm,virtualbox and fusion images
23
2
 
24
3
  Vagrant is a great tool to test new things or changes in a virtual machine(Virtualbox) using either chef or puppet.
@@ -52,3 +31,7 @@ People have reported good experiences, why don't you give it a try?
52
31
  IDEAS:
53
32
 
54
33
  - Now you integrate this with your CI build to create a daily basebox
34
+
35
+ [whren - 2012/04/12]
36
+
37
+ See [use of pre_postinstall_file in defition.rb](https://github.com/whren/veewee/wiki/Use-of-pre_postinstall_file-in-definition.rb)
@@ -1,5 +1,6 @@
1
1
  Changelog
2
2
  now has include-postinstall, exclude-postinstall
3
+ now has pre_postinstall_file allowing pre postinstall execution (ie to export http_proxy, https_proxy)
3
4
  ostypes are now synchronized accross kvm
4
5
  require libvirt 0.8+ version
5
6
  user veewee instead of vagrant
@@ -13,7 +14,7 @@ Todo:
13
14
  validate vms - + features selection
14
15
  check libvirt version
15
16
  windows test
16
- validation of checks (also - inclide/exclude)
17
+ validation of checks (also - include/exclude)
17
18
  check execs with exit code
18
19
  multinetwork card
19
20
  dkms for kernel installs
data/doc/TODO CHANGED
@@ -54,7 +54,7 @@ Todo:
54
54
  validate vms - + features selection
55
55
  check libvirt version
56
56
  windows test
57
- validation of checks (also - inclide/exclude)
57
+ validation of checks (also - include/exclude)
58
58
  check execs with exit code
59
59
  multinetwork card
60
60
  dkms for kernel installs
@@ -327,7 +327,9 @@ module Fission
327
327
 
328
328
  unless File.binary?(file)
329
329
  text = (File.read file).gsub from, to
330
- File.open(file, 'w'){ |f| f.print text }
330
+ # Force binary mode to prevent windows from putting CR-LF end line style
331
+ # http://www.ruby-forum.com/topic/60697#58748
332
+ File.open(file, 'wb'){ |f| f.print text }
331
333
  end
332
334
 
333
335
  end
@@ -349,7 +351,9 @@ module Fission
349
351
  content=content+"uuid.action = \"create\"\n"
350
352
 
351
353
  # Now rewrite the vmx file
352
- File.open(new_vmx_file,'w'){ |f| f.print content}
354
+ # Force binary mode to prevent windows from putting CR-LF end line style
355
+ # http://www.ruby-forum.com/topic/60697#58748
356
+ File.open(new_vmx_file,'wb'){ |f| f.print content}
353
357
 
354
358
  end
355
359
 
@@ -24,6 +24,8 @@ module Veewee
24
24
  attr_accessor :sudo_cmd
25
25
  attr_accessor :shutdown_cmd
26
26
 
27
+ attr_accessor :pre_postinstall_file
28
+
27
29
  attr_accessor :postinstall_files, :postinstall_timeout
28
30
 
29
31
  attr_accessor :floppy_files
@@ -58,6 +60,7 @@ module Veewee
58
60
  @floppy_files = nil
59
61
 
60
62
  # Default there are no post install files
63
+ @pre_postinstall_file = nil
61
64
  @postinstall_files=[]; @postinstall_timeout = 10000;
62
65
 
63
66
  @iso_file=""
@@ -38,7 +38,7 @@ module Veewee
38
38
  self.create(options)
39
39
 
40
40
  # Check the GUI mode required
41
- env.logger.info "Provider asks the box to start: GUI enabled? #{!options[:nogui]}"
41
+ env.logger.info "Provider asks the box to start: GUI enabled? #{!options['nogui']}"
42
42
  self.up(options)
43
43
 
44
44
  # Waiting for it to boot
@@ -77,6 +77,7 @@ module Veewee
77
77
  self.transfer_buildinfo(options)
78
78
  self.handle_postinstall(options)
79
79
 
80
+
80
81
  env.ui.success "The box #{name} was built succesfully!"
81
82
  env.ui.info "You can now login to the box with:"
82
83
  env.ui.info ssh_command_string
@@ -157,7 +158,7 @@ module Veewee
157
158
  # It requires a definition to find all the necessary information
158
159
  def handle_kickstart(options)
159
160
 
160
- # Filtering post install files based upon --postinstall-include and --postinstall--exclude
161
+ # Filtering post install files based upon --postinstall-include and --postinstall--exclude
161
162
  definition.postinstall_files=filter_postinstall_files(options)
162
163
  # Handling the kickstart by web
163
164
  kickstartfiles=definition.kickstart_file
@@ -190,13 +191,32 @@ module Veewee
190
191
  # This function handles all the post-install scripts
191
192
  # It requires a box(to login to) and a definition(listing the postinstall files)
192
193
  def handle_postinstall(options)
194
+ is_pre_postinstall_file = !definition.pre_postinstall_file.nil? && !definition.pre_postinstall_file.length != 0
195
+ transfered = false
193
196
  definition.postinstall_files.each do |postinstall_file|
194
197
  # Filenames of postinstall_files are relative to their definition
195
198
  filename=File.join(definition.path,postinstall_file)
196
199
  unless File.basename(postinstall_file)=~/^_/
197
200
  self.scp(filename,File.basename(filename))
198
201
  self.exec("chmod +x \"#{File.basename(filename)}\"")
199
- self.exec(sudo("./"+File.basename(filename)))
202
+ if is_pre_postinstall_file
203
+ # Filename of pre_postinstall_file are relative to their definition
204
+ pre_filename=File.join(definition.path, definition.pre_postinstall_file)
205
+ # Upload the pre postinstall script if not already transfered
206
+ if !transfered
207
+ self.scp(pre_filename,File.basename(pre_filename))
208
+ transfered = true
209
+ self.exec("chmod +x \"#{File.basename(pre_filename)}\"")
210
+ # Inject the call to the real script by executing the first argument (it will be the postinstall script file name to be executed)
211
+ self.exec("execute=\"\\n# We must execute the script passed as the first argument\\n\\$1\" && printf \"%b\\n\" \"$execute\" >> #{File.basename(pre_filename)}")
212
+ end
213
+ command = "./" + File.basename(pre_filename)
214
+ command = sudo(command) + " ./"+File.basename(filename)
215
+ else
216
+ command = "./"+File.basename(filename)
217
+ command = sudo(command)
218
+ end
219
+ self.exec(command)
200
220
  else
201
221
  env.logger.info "Skipping postinstallfile #{postinstall_file}"
202
222
  end
@@ -210,6 +230,9 @@ module Veewee
210
230
  build_info.each do |info|
211
231
  begin
212
232
  infofile=Tempfile.open("#{info[:filename]}")
233
+ # Force binary mode to prevent windows from putting CR-LF end line style
234
+ # http://www.ruby-forum.com/topic/127453#568546
235
+ infofile.binmode
213
236
  infofile.puts "#{info[:content]}"
214
237
  infofile.rewind
215
238
  infofile.close
@@ -40,6 +40,9 @@ module Veewee
40
40
  # We assume large 10K files, so this is tempfile object
41
41
  env.logger.info "#{src.class}"
42
42
  env.ui.info "Moving #{src.path} to #{localfile}"
43
+ # Force the close of the src stream to release handle before moving
44
+ # Not forcing the close may cause an issue on windows (Permission Denied)
45
+ src.close
43
46
  FileUtils.mv(src.path,localfile)
44
47
  #open(localfile,"wb") { |dst|
45
48
  #dst.write(src.read)
@@ -51,7 +54,7 @@ module Veewee
51
54
  def hashsum(filename)
52
55
  checksum=Digest::MD5.new
53
56
  buflen=1024
54
- open(filename, "r") do |io|
57
+ open(filename, "rb") do |io|
55
58
  counter = 0
56
59
  while (!io.eof)
57
60
  readBuf = io.readpartial(buflen)
@@ -19,7 +19,7 @@ module Veewee
19
19
  sleep 2
20
20
  end
21
21
 
22
- command="#{@vboxcmd} unregistervm '#{name}' --delete"
22
+ command="#{@vboxcmd} unregistervm \"#{name}\" --delete"
23
23
  env.ui.info command
24
24
  env.ui.info "Deleting vm #{name}"
25
25
 
@@ -39,9 +39,9 @@ module Veewee
39
39
  if location.match(/#{pattern}/)
40
40
 
41
41
  if File.exists?(location)
42
- command="#{@vboxcmd} closemedium disk '#{location}' --delete"
42
+ command="#{@vboxcmd} closemedium disk \"#{location}\" --delete"
43
43
  else
44
- command="#{@vboxcmd} closemedium disk '#{location}'"
44
+ command="#{@vboxcmd} closemedium disk \"#{location}\""
45
45
  end
46
46
 
47
47
  env.ui.info "Deleting disk #{location}"
@@ -44,7 +44,7 @@ module Veewee
44
44
  end
45
45
 
46
46
  def send_keycode(keycode)
47
- command= "#{@vboxcmd} controlvm '#{name}' keyboardputscancode #{keycode}"
47
+ command= "#{@vboxcmd} controlvm \"#{name}\" keyboardputscancode #{keycode}"
48
48
  env.logger.info "#{command}"
49
49
  sshresult=shell_exec("#{command}",{:mute => true})
50
50
  unless sshresult.stdout.index("E_ACCESSDENIED").nil?
@@ -4,21 +4,21 @@ module Veewee
4
4
  module BoxCommand
5
5
 
6
6
  def add_ide_controller
7
- #unless => "${vboxcmd} showvminfo '${vname}' | grep 'IDE Controller' "
8
- command ="#{@vboxcmd} storagectl '#{name}' --name 'IDE Controller' --add ide"
7
+ #unless => "${vboxcmd} showvminfo \"${vname}\" | grep \"IDE Controller\" "
8
+ command ="#{@vboxcmd} storagectl \"#{name}\" --name \"IDE Controller\" --add ide"
9
9
  shell_exec("#{command}")
10
10
  end
11
11
 
12
12
  def add_sata_controller
13
- #unless => "${vboxcmd} showvminfo '${vname}' | grep 'SATA Controller' ";
14
- command ="#{@vboxcmd} storagectl '#{name}' --name 'SATA Controller' --add sata --hostiocache #{definition.hostiocache} --sataportcount 1"
13
+ #unless => "${vboxcmd} showvminfo \"${vname}\" | grep \"SATA Controller\" ";
14
+ command ="#{@vboxcmd} storagectl \"#{name}\" --name \"SATA Controller\" --add sata --hostiocache #{definition.hostiocache} --sataportcount 1"
15
15
  shell_exec("#{command}")
16
16
  end
17
17
 
18
18
  def attach_serial_console
19
- command ="#{@vboxcmd} modifyvm '#{name}' --uart1 0x3F8 4"
19
+ command ="#{@vboxcmd} modifyvm \"#{name}\" --uart1 0x3F8 4"
20
20
  shell_exec("#{command}")
21
- command ="#{@vboxcmd} modifyvm '#{name}' --uartmode1 file '#{File.join(FileUtils.pwd,name+"-serial-console"+'.log')}'"
21
+ command ="#{@vboxcmd} modifyvm \"#{name}\" --uartmode1 file \"#{File.join(FileUtils.pwd,name+"-serial-console"+".log")}\""
22
22
  shell_exec("#{command}")
23
23
  end
24
24
 
@@ -26,20 +26,23 @@ module Veewee
26
26
 
27
27
  unless definition.nil?
28
28
  #Map SSH Ports
29
- command="#{@vboxcmd} modifyvm '#{name}' --natpf#{self.natinterface} 'guestssh,tcp,,#{definition.ssh_host_port},,#{definition.ssh_guest_port}'"
29
+ command="#{@vboxcmd} modifyvm \"#{name}\" --natpf#{self.natinterface} \"guestssh,tcp,,#{definition.ssh_host_port},,#{definition.ssh_guest_port}\""
30
30
  shell_exec("#{command}")
31
31
  end
32
32
  end
33
33
 
34
34
  def add_shared_folder
35
- command="#{@vboxcmd} sharedfolder add '#{name}' --name 'veewee-validation' --hostpath '#{File.expand_path(env.validation_dir)}' --automount"
35
+ command="#{@vboxcmd} sharedfolder add \"#{name}\" --name \"veewee-validation\" --hostpath \"#{File.expand_path(env.validation_dir)}\" --automount"
36
36
  shell_exec("#{command}")
37
37
  end
38
38
 
39
39
  def get_vbox_home
40
40
  command="#{@vboxcmd} list systemproperties"
41
41
  shell_results=shell_exec("#{command}")
42
- location=shell_results.stdout.split(/\n/).grep(/Default machine/)[0].split(":")[1].strip
42
+ # On windows Default machine path would include a drive letter, then ':'.
43
+ # So here we tell to split no more than 2 elements to keep the full path
44
+ # This should work for all OS as we just need to separate the parameter name with first ':' from the value
45
+ location=shell_results.stdout.split(/\n/).grep(/Default machine/)[0].split(":", 2)[1].strip
43
46
  return location
44
47
  end
45
48
 
@@ -55,7 +58,7 @@ module Veewee
55
58
  ["GUI/UpdateCheckCount","60"]
56
59
  ]
57
60
  extraData.each do |data|
58
- command="#{@vboxcmd} setextradata global '#{data[0]}' '#{data[1]}'"
61
+ command="#{@vboxcmd} setextradata global \"#{data[0]}\" \"#{data[1]}\""
59
62
  shell_results=shell_exec("#{command}")
60
63
  end
61
64
 
@@ -67,7 +70,7 @@ module Veewee
67
70
 
68
71
 
69
72
  place=get_vbox_home
70
- command ="#{@vboxcmd} createhd --filename '#{File.join(place,name,name+"."+definition.disk_format.downcase)}' --size '#{definition.disk_size.to_i}' --format #{definition.disk_format.downcase}"
73
+ command ="#{@vboxcmd} createhd --filename \"#{File.join(place,name,name+"."+definition.disk_format.downcase)}\" --size \"#{definition.disk_size.to_i}\" --format #{definition.disk_format.downcase}"
71
74
  shell_exec("#{command}")
72
75
 
73
76
  end
@@ -80,8 +83,8 @@ module Veewee
80
83
  location="#{File.join(place,name,location)}"
81
84
  env.ui.info "Attaching disk: #{location}"
82
85
 
83
- #command => "${vboxcmd} storageattach '${vname}' --storagectl 'SATA Controller' --port 0 --device 0 --type hdd --medium '${vname}.vdi'",
84
- command ="#{@vboxcmd} storageattach '#{name}' --storagectl 'SATA Controller' --port 0 --device 0 --type hdd --medium '#{location}'"
86
+ #command => "${vboxcmd} storageattach \"${vname}\" --storagectl \"SATA Controller\" --port 0 --device 0 --type hdd --medium \"${vname}.vdi\"",
87
+ command ="#{@vboxcmd} storageattach \"#{name}\" --storagectl \"SATA Controller\" --port 0 --device 0 --type hdd --medium \"#{location}\""
85
88
  shell_exec("#{command}")
86
89
 
87
90
  end
@@ -90,14 +93,14 @@ module Veewee
90
93
  def attach_isofile
91
94
  full_iso_file=File.join(env.config.veewee.iso_dir,definition.iso_file)
92
95
  env.ui.info "Mounting cdrom: #{full_iso_file}"
93
- command ="#{@vboxcmd} storageattach '#{name}' --storagectl 'IDE Controller' --type dvddrive --port 0 --device 0 --medium '#{full_iso_file}'"
96
+ command ="#{@vboxcmd} storageattach \"#{name}\" --storagectl \"IDE Controller\" --type dvddrive --port 0 --device 0 --medium \"#{full_iso_file}\""
94
97
  shell_exec("#{command}")
95
98
  end
96
99
 
97
100
  def attach_guest_additions
98
101
  full_iso_file=File.join(env.config.veewee.iso_dir,"VBoxGuestAdditions_#{self.vbox_version}.iso")
99
102
  env.ui.info "Mounting guest additions: #{full_iso_file}"
100
- command ="#{@vboxcmd} storageattach '#{name}' --storagectl 'IDE Controller' --type dvddrive --port 1 --device 0 --medium '#{full_iso_file}'"
103
+ command ="#{@vboxcmd} storageattach \"#{name}\" --storagectl \"IDE Controller\" --type dvddrive --port 1 --device 0 --medium \"#{full_iso_file}\""
101
104
  shell_exec("#{command}")
102
105
  end
103
106
 
@@ -106,7 +109,7 @@ module Veewee
106
109
  # Create floppy controller
107
110
  unless definition.floppy_files.nil?
108
111
 
109
- command="#{@vboxcmd} storagectl '#{name}' --name 'Floppy Controller' --add floppy"
112
+ command="#{@vboxcmd} storagectl \"#{name}\" --name \"Floppy Controller\" --add floppy"
110
113
  shell_exec("#{command}")
111
114
  end
112
115
  end
@@ -117,7 +120,7 @@ module Veewee
117
120
 
118
121
  # Attach floppy to machine (the vfd extension is crucial to detect msdos type floppy)
119
122
  floppy_file=File.join(definition.path,"virtualfloppy.vfd")
120
- command="#{@vboxcmd} storageattach '#{name}' --storagectl 'Floppy Controller' --port 0 --device 0 --type fdd --medium '#{floppy_file}'"
123
+ command="#{@vboxcmd} storageattach \"#{name}\" --storagectl \"Floppy Controller\" --port 0 --device 0 --type fdd --medium \"#{floppy_file}\""
121
124
  shell_exec("#{command}")
122
125
  end
123
126
  end
@@ -129,7 +132,7 @@ module Veewee
129
132
  end
130
133
 
131
134
  def create_vm
132
- command="#{@vboxcmd} createvm --name '#{name}' --ostype '#{vbox_os_type_id(definition.os_type_id)}' --register"
135
+ command="#{@vboxcmd} createvm --name \"#{name}\" --ostype \"#{vbox_os_type_id(definition.os_type_id)}\" --register"
133
136
 
134
137
  #Exec and system stop the execution here
135
138
  shell_exec("#{command}")
@@ -137,15 +140,15 @@ module Veewee
137
140
  env.ui.info "Creating vm #{name} : #{definition.memory_size}M - #{definition.cpu_count} CPU - #{vbox_os_type_id(definition.os_type_id)}"
138
141
 
139
142
  #setting cpu's
140
- command="#{@vboxcmd} modifyvm '#{name}' --cpus #{definition.cpu_count}"
143
+ command="#{@vboxcmd} modifyvm \"#{name}\" --cpus #{definition.cpu_count}"
141
144
  shell_exec("#{command}")
142
145
 
143
146
  #setting memory size
144
- command="#{@vboxcmd} modifyvm '#{name}' --memory #{definition.memory_size}"
147
+ command="#{@vboxcmd} modifyvm \"#{name}\" --memory #{definition.memory_size}"
145
148
  shell_exec("#{command}")
146
149
 
147
150
  #setting bootorder
148
- command="#{@vboxcmd} modifyvm '#{name}' --boot1 disk --boot2 dvd --boot3 none --boot4 none"
151
+ command="#{@vboxcmd} modifyvm \"#{name}\" --boot1 disk --boot2 dvd --boot3 none --boot4 none"
149
152
  shell_exec("#{command}")
150
153
 
151
154
  # Modify the vm to enable or disable hw virtualization extensions
@@ -4,7 +4,7 @@ module Veewee
4
4
  module BoxCommand
5
5
 
6
6
  def forwarding(name)
7
- command="#{@vboxcmd} showvminfo --details --machinereadable '#{self.name}'"
7
+ command="#{@vboxcmd} showvminfo --details --machinereadable \"#{self.name}\""
8
8
  shell_results=shell_exec("#{command}")
9
9
  rules=shell_results.stdout.split(/\n/).grep(/^Forward/)
10
10
  result=nil
@@ -28,7 +28,7 @@ module Veewee
28
28
 
29
29
  def delete_forwarding(name)
30
30
  forward=self.forwarding(name)
31
- command="#{@vboxcmd} controlvm '#{self.name}' natpf#{self.natinterface} delete #{name}"
31
+ command="#{@vboxcmd} controlvm \"#{self.name}\" natpf#{self.natinterface} delete #{name}"
32
32
  shell_results=shell_exec("#{command}")
33
33
  end
34
34
 
@@ -8,7 +8,7 @@ module Veewee
8
8
  if (self.exists? && self.running?)
9
9
  env.ui.info "Shutting down vm #{name}"
10
10
  #We force it here, maybe vm.shutdown is cleaner
11
- command="#{@vboxcmd} controlvm '#{name}' poweroff"
11
+ command="#{@vboxcmd} controlvm \"#{name}\" poweroff"
12
12
  shell_exec("#{command}")
13
13
  end
14
14
  end
@@ -10,7 +10,7 @@ module Veewee
10
10
  exit -1
11
11
  end
12
12
 
13
- gui_enabled=options[:nogui]==true ? false : true
13
+ gui_enabled=options['nogui']==true ? false : true
14
14
 
15
15
  raise Veewee::Error,"Box is already running" if self.running?
16
16
 
@@ -35,9 +35,9 @@ module Veewee
35
35
  # Once assembled we start the machine
36
36
  env.logger.info "Started the VM with GUI Enabled? #{gui_enabled}"
37
37
 
38
- command="#{@vboxcmd} startvm --type gui '#{name}'"
38
+ command="#{@vboxcmd} startvm --type gui \"#{name}\""
39
39
  unless (gui_enabled)
40
- command="#{@vboxcmd} startvm --type headless '#{name}'"
40
+ command="#{@vboxcmd} startvm --type headless \"#{name}\""
41
41
  end
42
42
  shell_results=shell_exec("#{command}",{:mute => true})
43
43
  end
@@ -4,5 +4,5 @@ end
4
4
 
5
5
  # Only set the version constant if it wasn't set before
6
6
  unless defined?(Veewee::VERSION)
7
- ::Veewee::VERSION="0.3.0.alpha5"
7
+ ::Veewee::VERSION="0.3.0.alpha6"
8
8
  end
@@ -32,7 +32,10 @@ Gem::Specification.new do |s|
32
32
  s.add_dependency "fog", "~> 1.1.2"
33
33
  s.add_dependency "childprocess"
34
34
 
35
- s.add_dependency "CFPropertyList", "~> 2.0.17"
35
+ # Modified dependency version, as libxml-ruby dependency has been removed in version 2.1.1
36
+ # See : https://github.com/ckruse/CFPropertyList/issues/14
37
+ # See : https://github.com/jedi4ever/veewee/issues/6
38
+ s.add_dependency "CFPropertyList", ">= 2.1.1"
36
39
  # s.add_dependency "libvirt"
37
40
  s.add_dependency "rspec", "~> 2.5"
38
41
 
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: veewee
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease: 6
5
- version: 0.3.0.alpha5
5
+ version: 0.3.0.alpha6
6
6
  platform: ruby
7
7
  authors:
8
8
  - Patrick Debois
@@ -149,9 +149,9 @@ dependencies:
149
149
  requirement: &id013 !ruby/object:Gem::Requirement
150
150
  none: false
151
151
  requirements:
152
- - - ~>
152
+ - - ">="
153
153
  - !ruby/object:Gem::Version
154
- version: 2.0.17
154
+ version: 2.1.1
155
155
  type: :runtime
156
156
  prerelease: false
157
157
  version_requirements: *id013
@@ -916,7 +916,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
916
916
  requirements:
917
917
  - - ">="
918
918
  - !ruby/object:Gem::Version
919
- hash: -2945739560758709107
919
+ hash: -1280042332517595849
920
920
  segments:
921
921
  - 0
922
922
  version: "0"