Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Depend on Vagrant 0.8.2, remove VirtualBox hacks since 0.9.1 incorps …

…changes
  • Loading branch information...
commit b5ddc8e7f1b09dba12d6d079fd5cb9a914a685a9 1 parent d67effa
Mitchell Hashimoto mitchellh authored
Showing with 159 additions and 162 deletions.
  1. +4 −4 Gemfile.lock
  2. +154 −157 lib/veewee/session.rb
  3. +1 −1  veewee.gemspec
8 Gemfile.lock
View
@@ -9,7 +9,7 @@ PATH
progressbar
rspec (~> 2.5.0)
thor (~> 0.14.6)
- vagrant (~> 0.8.0)
+ vagrant (~> 0.8.2)
GEM
remote: http://rubygems.org/
@@ -49,7 +49,7 @@ GEM
rspec-mocks (2.5.0)
term-ansicolor (1.0.6)
thor (0.14.6)
- vagrant (0.8.1)
+ vagrant (0.8.2)
archive-tar-minitar (= 0.5.2)
erubis (~> 2.7.0)
i18n (~> 0.5.0)
@@ -57,8 +57,8 @@ GEM
net-scp (~> 1.0.4)
net-ssh (~> 2.1.4)
thor (~> 0.14.6)
- virtualbox (~> 0.9.0)
- virtualbox (0.9.0)
+ virtualbox (~> 0.9.1)
+ virtualbox (0.9.1)
ffi (~> 1.0.9)
PLATFORMS
311 lib/veewee/session.rb
View
@@ -7,13 +7,10 @@
require 'highline/import'
require 'tempfile'
require 'virtualbox'
-require 'virtualbox/abstract_model'
-require 'virtualbox/ext/byte_normalizer'
-
module Veewee
class Session
-
+
attr_accessor :veewee_dir
attr_accessor :definition_dir
attr_accessor :template_dir
@@ -30,10 +27,10 @@ def self.setenv(env)
@iso_dir=env[:iso_dir]
@tmp_dir=env[:tmp_dir]
end
-
+
def self.declare(options)
defaults={
- :cpu_count => '1', :memory_size=> '256',
+ :cpu_count => '1', :memory_size=> '256',
:disk_size => '10240', :disk_format => 'VDI', :hostiocache => 'off' ,
:os_type_id => 'Ubuntu',
:iso_file => "ubuntu-10.10-server-i386.iso", :iso_src => "", :iso_md5 => "", :iso_download_timeout => 1000,
@@ -44,16 +41,16 @@ def self.declare(options)
:sudo_cmd => "echo '%p'|sudo -S sh '%f'",
:shutdown_cmd => "shutdown -h now",
:postinstall_files => [ "postinstall.sh"],:postinstall_timeout => 10000}
-
+
@definition=defaults.merge(options)
-
+
end
-
+
def self.define(boxname,template_name,options = {})
#Check if template_name exists
-
+
options = { "force" => false, "format" => "vagrant" }.merge(options)
-
+
if File.directory?(File.join(@template_dir,template_name))
else
puts "This template can not be found, use vagrant basebox templates to list all templates"
@@ -62,7 +59,7 @@ def self.define(boxname,template_name,options = {})
if !File.exists?(@definition_dir)
FileUtils.mkdir(@definition_dir)
end
-
+
if File.directory?(File.join(@definition_dir,boxname))
if !options["force"]
puts "The definition for #{boxname} already exists. Use --force to overwrite"
@@ -75,18 +72,18 @@ def self.define(boxname,template_name,options = {})
puts "The basebox '#{boxname}' has been successfully created from the template ''#{template_name}'"
puts "You can now edit the definition files stored in definitions/#{boxname}"
puts "or build the box with:"
- if (options["format"]=='vagrant')
+ if (options["format"]=='vagrant')
puts "vagrant basebox build '#{boxname}'"
end
if (options["format"]=='veewee')
puts "veewee build '#{boxname}'"
end
-
+
end
-
+
def self.definition_exists?(boxname)
if File.directory?(File.join(@definition_dir,boxname))
if File.exists?(File.join(@definition_dir,boxname,'definition.rb'))
@@ -97,7 +94,7 @@ def self.definition_exists?(boxname)
else
return false
end
-
+
end
def self.undefine(boxname)
@@ -120,7 +117,7 @@ def self.list_templates( options = { :format => 'vagrant'})
definition=Dir.glob("#{sub}/definition.rb")
if definition.length!=0
name=sub.sub(/#{@template_dir}\//,'')
- if (options[:format]=='vagrant')
+ if (options[:format]=='vagrant')
puts "vagrant basebox define '<boxname>' '#{name}'"
end
if (options[:format]=='veewee')
@@ -149,7 +146,7 @@ def self.clean
def self.verify_iso(filename,autodownload = false)
if File.exists?(File.join(@iso_dir,filename))
- puts
+ puts
puts "Verifying the isofile #{filename} is ok."
else
@@ -157,7 +154,7 @@ def self.verify_iso(filename,autodownload = false)
path1=Pathname.new(full_path)
path2=Pathname.new(Dir.pwd)
rel_path=path1.relative_path_from(path2).to_s
-
+
puts
puts "We did not find an isofile in <currentdir>/iso. \n\nThe definition provided the following download information:"
unless "#{@definition[:iso_src]}"==""
@@ -166,7 +163,7 @@ def self.verify_iso(filename,autodownload = false)
puts "- Md5 Checksum: #{@definition[:iso_md5]}"
puts "#{@definition[:iso_download_instructions]}"
puts
-
+
if @definition[:iso_src] == ""
puts "Please follow the instructions above:"
puts "- to get the ISO"
@@ -175,60 +172,60 @@ def self.verify_iso(filename,autodownload = false)
puts
exit
else
-
+
question=ask("Download? (Yes/No)") {|q| q.default="No"}
if question.downcase == "yes"
if !File.exists?(@iso_dir)
puts "Creating an iso directory"
FileUtils.mkdir(@iso_dir)
end
-
+
download_progress(@definition[:iso_src],full_path)
else
puts "You have choosen for manual download: "
puts "curl -C - -L '#{@definition[:iso_src]}' -o '#{rel_path}'"
puts "md5 '#{rel_path}' "
- puts
+ puts
exit
end
-
+
end
end
-
+
end
def self.export_box(boxname)
#Now we have to load the definition (reads definition.rb)
load_definition(boxname)
-
+
Veewee::Export.vagrant(boxname,@box_dir,@definition)
#vagrant removes the mapping
#we need to restore it in order to be able to login again
add_ssh_nat_mapping(boxname)
-
+
end
-
+
def self.remove_box(boxname)
puts "Not yet implemented"
end
def self.build(boxname,options)
-
+
options = { "force" => false, "format" => "vagrant", "nogui" => false }.merge(options)
-
+
#Now we have to load the definition (reads definition.rb)
load_definition(boxname)
#Command to execute locally
@vboxcmd=determine_vboxcmd
-
+
ssh_options={ :user => @definition[:ssh_user], :port => @definition[:ssh_host_port], :password => @definition[:ssh_password],
- :timeout => @definition[:ssh_timeout]}
-
+ :timeout => @definition[:ssh_timeout]}
+
#Suppress those annoying virtualbox messages
- suppress_messages
-
-
+ suppress_messages
+
+
vm=VirtualBox::VM.find(boxname)
if (!vm.nil? && (vm.saved?))
@@ -236,7 +233,7 @@ def self.build(boxname,options)
vm.discard_state
vm.reload
end
-
+
if (!vm.nil? && !(vm.powered_off?))
puts "Shutting down vm #{boxname}"
#We force it here, maybe vm.shutdown is cleaner
@@ -250,32 +247,32 @@ def self.build(boxname,options)
end
sleep 3
end
-
-
+
+
verify_iso(@definition[:iso_file])
-
+
if (options["force"]==false)
- else
+ else
puts "Forcing build by destroying #{boxname} machine"
destroy_vm(boxname)
end
-
+
if Veewee::Utils.is_port_open?("localhost", @definition[:ssh_host_port])
puts "Hmm, the port #{@definition[:ssh_host_port]} is open. And we shut down?"
exit
end
-
+
checksums=calculate_checksums(@definition,boxname)
-
+
transaction(boxname,"0-initial-#{checksums[0]}",checksums) do
-
+
#Create the Virtualmachine and set all the memory and other stuff
create_vm(boxname)
-
+
#Create a disk with the same name as the boxname
create_disk(boxname)
-
-
+
+
#These command actually call the commandline of Virtualbox, I hope to use the virtualbox-ruby library in the future
add_ide_controller(boxname)
add_sata_controller(boxname)
@@ -290,13 +287,13 @@ def self.build(boxname,options)
else
start_vm(boxname,"gui")
end
-
+
#waiting for it to boot
puts "Waiting for the machine to boot"
sleep @definition[:boot_wait].to_i
-
+
Veewee::Scancode.send_sequence("#{@vboxcmd}","#{boxname}",@definition[:boot_cmd_sequence],@definition[:kickstart_port])
-
+
kickstartfile=@definition[:kickstart_file]
if kickstartfile.nil? || kickstartfile.length == 0
puts "Skipping webserver as no kickstartfile was specified"
@@ -307,7 +304,7 @@ def self.build(boxname,options)
Veewee::Web.wait_for_request(kickstartfile,{:port => @definition[:kickstart_port],
:host => @definition[:kickstart_ip], :timeout => @definition[:kickstart_timeout],
:web_dir => File.join(@definition_dir,boxname)})
- end
+ end
if kickstartfile.is_a? Array
kickstartfiles=kickstartfile
kickstartfiles.each do |kickfile|
@@ -317,10 +314,10 @@ def self.build(boxname,options)
end
end
end
-
-
+
+
Veewee::Ssh.when_ssh_login_works("localhost",ssh_options) do
- #Transfer version of Virtualbox to $HOME/.vbox_version
+ #Transfer version of Virtualbox to $HOME/.vbox_version
versionfile=Tempfile.open("vbox.version")
versionfile.puts "#{VirtualBox::Global.global.lib.virtualbox.version.split('_')[0]}"
versionfile.rewind
@@ -335,16 +332,16 @@ def self.build(boxname,options)
versionfile.delete
end
end #initial Transaction
-
-
+
+
counter=1
@definition[:postinstall_files].each do |postinstall_file|
-
-
- filename=File.join(@definition_dir,boxname,postinstall_file)
-
+
+
+ filename=File.join(@definition_dir,boxname,postinstall_file)
+
transaction(boxname,"#{counter}-#{postinstall_file}-#{checksums[counter]}",checksums) do
-
+
Veewee::Ssh.when_ssh_login_works("localhost",ssh_options) do
begin
Veewee::Ssh.transfer_file("localhost",filename,File.basename(filename),ssh_options)
@@ -359,30 +356,30 @@ def self.build(boxname,options)
puts "***#{newcommand}"
Veewee::Ssh.execute("localhost","#{newcommand}",ssh_options)
end
-
+
end
counter+=1
-
- end
-
+
+ end
+
puts "#{boxname} was built successfully. "
puts ""
puts "Now you can: "
puts "- verify your box by running : vagrant basebox validate #{boxname}"
puts "- export your vm to a .box file by running : vagrant basebox export #{boxname}"
-
+
end
-
+
def self.determine_vboxcmd
return "VBoxManage"
end
-
+
def self.start_vm(boxname,mode)
vm=VirtualBox::VM.find(boxname)
vm.start(mode)
end
-
+
def self.load_definition(boxname)
if definition_exists?(boxname)
@@ -392,14 +389,14 @@ def self.load_definition(boxname)
rescue LoadError
puts "Error loading definition of #{boxname}"
exit
- end
+ end
else
puts "Error: definition for basebox '#{boxname}' does not exist."
list_definitions
exit
end
end
-
+
def self.add_ssh_nat_mapping(boxname)
vm=VirtualBox::VM.find(boxname)
#Map SSH Ports
@@ -410,24 +407,24 @@ def self.add_ssh_nat_mapping(boxname)
port.hostport = @definition[:ssh_host_port].to_i
vm.network_adapters[0].nat_driver.forwarded_ports << port
port.save
- vm.save
+ vm.save
end
-
+
def self.destroy_vm(boxname)
-
+
load_definition(boxname)
- @vboxcmd=determine_vboxcmd
+ @vboxcmd=determine_vboxcmd
#:destroy_medium => :delete, will delete machine + all media attachments
#vm.destroy(:destroy_medium => :delete)
##vm.destroy(:destroy_image => true)
-
+
#VBoxManage unregistervm "test-machine" --delete
#because the destroy does remove the .vbox file on 4.0.x
#PDB
#vm.destroy()
-
-
-
+
+
+
vm=VirtualBox::VM.find(boxname)
if (!vm.nil? && !(vm.powered_off?))
@@ -441,50 +438,50 @@ def self.destroy_vm(boxname)
exit
end
sleep 3
- end
+ end
+
-
- command="#{@vboxcmd} unregistervm '#{boxname}' --delete"
+ command="#{@vboxcmd} unregistervm '#{boxname}' --delete"
puts command
puts "Deleting vm #{boxname}"
-
+
#Exec and system stop the execution here
Veewee::Shell.execute("#{command}")
sleep 1
-
+
#if the disk was not attached when the machine was destroyed we also need to delete the disk
location=boxname+"."+@definition[:disk_format].downcase
- found=false
+ found=false
VirtualBox::HardDrive.all.each do |d|
if d.location.match(/#{location}/)
-
- if File.exists?(d.location)
+
+ if File.exists?(d.location)
command="#{@vboxcmd} closemedium disk '#{d.location}' --delete"
else
- command="#{@vboxcmd} closemedium disk '#{d.location}'"
+ command="#{@vboxcmd} closemedium disk '#{d.location}'"
end
-
+
#command="#{@vboxcmd} closemedium disk '#{d.location}' --delete"
puts "Deleting disk #{d.location}"
puts "#{command}"
- Veewee::Shell.execute("#{command}")
-
- if File.exists?(d.location)
+ Veewee::Shell.execute("#{command}")
+
+ if File.exists?(d.location)
puts "We tried to delete the disk file via virtualbox '#{d.location} but failed"
puts "Removing it manually"
FileUtils.rm(d.location)
exit
- end
+ end
#v.3
#d.destroy(true)
break
end
- end
+ end
end
-
+
def self.create_vm(boxname,force=false)
-
+
#Verifying the os.id with the :os_type_id specified
matchfound=false
VirtualBox::Global.global.lib.virtualbox.guest_os_types.collect { |os|
@@ -504,9 +501,9 @@ def self.create_vm(boxname,force=false)
puts "shutting down box"
#We force it here, maybe vm.shutdown is cleaner
vm.stop
- end
+ end
- if !vm.nil?
+ if !vm.nil?
puts "Box already exists"
#vm.stop
#vm.destroy
@@ -521,7 +518,7 @@ def self.create_vm(boxname,force=false)
# Modify the vm to enable or disable hw virtualization extensions
vm_flags=%w{pagefusion acpi ioapic pae hpet hwvirtex hwvirtexcl nestedpaging largepages vtxvpid synthxcpu rtcuseutc}
-
+
vm_flags.each do |vm_flag|
unless @definition[vm_flag.to_sym].nil?
puts "Setting VM Flag #{vm_flag} to #{@definition[vm_flag.to_sym]}"
@@ -532,7 +529,7 @@ def self.create_vm(boxname,force=false)
# Todo Check for java
# Todo check output of commands
-
+
# Check for floppy
unless @definition[:floppy_files].nil?
require 'tmpdir'
@@ -546,20 +543,20 @@ def self.create_vm(boxname,force=false)
command="java -jar #{javacode_dir}/dir2floppy.jar '#{temp_dir}' '#{floppy_file}'"
puts "#{command}"
Veewee::Shell.execute("#{command}")
-
+
# Create floppy controller
command="#{@vboxcmd} storagectl '#{boxname}' --name 'Floppy Controller' --add floppy"
puts "#{command}"
Veewee::Shell.execute("#{command}")
-
+
# Attach floppy to machine (the vfd extension is crucial to detect msdos type floppy)
command="#{@vboxcmd} storageattach '#{boxname}' --storagectl 'Floppy Controller' --port 0 --device 0 --type fdd --medium '#{floppy_file}'"
puts "#{command}"
- Veewee::Shell.execute("#{command}")
-
+ Veewee::Shell.execute("#{command}")
+
end
-
-
+
+
#Exec and system stop the execution here
Veewee::Shell.execute("#{command}")
@@ -575,43 +572,43 @@ def self.create_vm(boxname,force=false)
puts "but now it's gone"
exit
end
-
- #Set all params we know
+
+ #Set all params we know
vm.memory_size=@definition[:memory_size].to_i
vm.os_type_id=@definition[:os_type_id]
vm.cpu_count=@definition[:cpu_count].to_i
vm.name=boxname
puts "Creating vm #{vm.name} : #{vm.memory_size}M - #{vm.cpu_count} CPU - #{vm.os_type_id}"
- #setting bootorder
+ #setting bootorder
vm.boot_order[0]=:hard_disk
vm.boot_order[1]=:dvd
vm.boot_order[2]=:null
vm.boot_order[3]=:null
vm.validate
vm.save
-
+
end
-
+
def self.create_disk(boxname)
#Now check the disks
#Maybe one day we can use the name, now we have to check location
#disk=VirtualBox::HardDrive.find(boxname)
location=boxname+"."+@definition[:disk_format].downcase
-
- found=false
+
+ found=false
VirtualBox::HardDrive.all.each do |d|
if !d.location.match(/#{location}/).nil?
found=true
break
end
- end
+ end
@vboxcmd=determine_vboxcmd
-
+
if !found
puts "Creating new harddrive of size #{@definition[:disk_size].to_i} "
-
+
#newdisk=VirtualBox::HardDrive.new
#newdisk.format=@definition[:disk_format]
#newdisk.logical_size=@definition[:disk_size].to_i
@@ -620,38 +617,38 @@ def self.create_disk(boxname)
##PDB: again problems with the virtualbox GEM
##VirtualBox::Global.global.max_vdi_size=1000000
#newdisk.save
-
+
command="#{@vboxcmd} list systemproperties|grep '^Default machine'|cut -d ':' -f 2|sed -e 's/^[ ]*//'"
results=IO.popen("#{command}")
place=results.gets.chop
results.close
-
+
command ="#{@vboxcmd} createhd --filename '#{place}/#{boxname}/#{boxname}.#{@definition[:disk_format].downcase}' --size '#{@definition[:disk_size].to_i}' --format #{@definition[:disk_format].downcase} > /dev/null"
puts "#{command}"
Veewee::Shell.execute("#{command}")
-
+
end
-
+
end
-
+
def self.add_ide_controller(boxname)
#unless => "${vboxcmd} showvminfo '${vname}' | grep 'IDE Controller' "
command ="#{@vboxcmd} storagectl '#{boxname}' --name 'IDE Controller' --add ide"
Veewee::Shell.execute("#{command}")
end
-
+
def self.add_sata_controller(boxname)
#unless => "${vboxcmd} showvminfo '${vname}' | grep 'SATA Controller' ";
command ="#{@vboxcmd} storagectl '#{boxname}' --name 'SATA Controller' --add sata --hostiocache #{@definition[:hostiocache]}"
Veewee::Shell.execute("#{command}")
end
-
-
+
+
def self.attach_disk(boxname)
location=boxname+"."+@definition[:disk_format].downcase
-
+
@vboxcmd=determine_vboxcmd
-
+
command="#{@vboxcmd} list systemproperties|grep '^Default machine'|cut -d ':' -f 2|sed -e 's/^[ ]*//'"
results=IO.popen("#{command}")
place=results.gets.chop
@@ -659,13 +656,13 @@ def self.attach_disk(boxname)
location="#{place}/#{boxname}/"+location
puts "Attaching disk: #{location}"
-
+
#command => "${vboxcmd} storageattach '${vname}' --storagectl 'SATA Controller' --port 0 --device 0 --type hdd --medium '${vname}.vdi'",
command ="#{@vboxcmd} storageattach '#{boxname}' --storagectl 'SATA Controller' --port 0 --device 0 --type hdd --medium '#{location}'"
Veewee::Shell.execute("#{command}")
end
-
+
def self.mount_isofile(boxname,isofile)
full_iso_file=File.join(@iso_dir,isofile)
puts "Mounting cdrom: #{full_iso_file}"
@@ -673,9 +670,9 @@ def self.mount_isofile(boxname,isofile)
command ="#{@vboxcmd} storageattach '#{boxname}' --storagectl 'IDE Controller' --type dvddrive --port 1 --device 0 --medium '#{full_iso_file}'"
Veewee::Shell.execute("#{command}")
end
-
-
-
+
+
+
def self.suppress_messages
#Setting this annoying messages to register
VirtualBox::ExtraData.global["GUI/RegistrationData"]="triesLeft=0"
@@ -684,7 +681,7 @@ def self.suppress_messages
VirtualBox::ExtraData.global["GUI/UpdateCheckCount"]="60"
update_date=Time.now+86400
VirtualBox::ExtraData.global["GUI/UpdateDate"]="1 d, #{update_date.year}-#{update_date.month}-#{update_date.day}, stable"
-
+
VirtualBox::ExtraData.global.save
end
@@ -698,7 +695,7 @@ def self.local_ip
ensure
Socket.do_not_reverse_lookup = orig
end
-
+
def self.validate_box(boxname,options)
require 'cucumber'
@@ -725,16 +722,16 @@ def self.validate_box(boxname,options)
end
end
-
+
def self.list_ostypes
puts
puts "Available os types:"
VirtualBox::Global.global.lib.virtualbox.guest_os_types.collect { |os|
puts "#{os.id}: #{os.description}"
- }
+ }
end
-
-
+
+
def self.calculate_checksums(definition,boxname)
#TODO: get rid of definitiondir and so one
@@ -752,7 +749,7 @@ def self.calculate_checksums(definition,boxname)
unless postinstall_files.nil?
for filename in postinstall_files
begin
- full_filename=File.join(@definition_dir,boxname,filename)
+ full_filename=File.join(@definition_dir,boxname,filename)
checksums << Digest::MD5.hexdigest(File.read(full_filename))
rescue
@@ -782,14 +779,14 @@ def self.download_progress(url,localfile)
dst.write(src.read)
}
}
-
+
end
-
+
def self.transaction(boxname,step_name,checksums,&block)
current_step_nr=step_name.split("-")[0].to_i
- vm=VirtualBox::VM.find(boxname)
+ vm=VirtualBox::VM.find(boxname)
snapnames=Array.new
#If vm exists , look for snapshots
@@ -801,9 +798,9 @@ def self.transaction(boxname,step_name,checksums,&block)
while (snapshot!=nil)
#puts "#{counter}:#{snapshot.name}"
snapnames[counter]=snapshot.name
- counter=counter+1
+ counter=counter+1
snapshot=snapshot.children[0]
- end
+ end
end
#find the last snapshot matching the state
@@ -815,7 +812,7 @@ def self.transaction(boxname,step_name,checksums,&block)
# puts "we found a bad state"
last_good_state=c-1
break
- end
+ end
end
#puts "Last good state: #{last_good_state}"
@@ -854,13 +851,13 @@ def self.transaction(boxname,step_name,checksums,&block)
#puts "last good state #{last_good_state}"
-
+
if (current_step_nr > last_good_state)
if (last_good_state==-1)
#no initial snapshot is found, clean machine!
- vm=VirtualBox::VM.find(boxname)
-
+ vm=VirtualBox::VM.find(boxname)
+
if !vm.nil?
if vm.running?
puts "Stopping machine"
@@ -869,7 +866,7 @@ def self.transaction(boxname,step_name,checksums,&block)
sleep 1
end
end
-
+
#detaching cdroms (used to work in 3.x)
# vm.medium_attachments.each do |m|
# if m.type==:dvd
@@ -877,21 +874,21 @@ def self.transaction(boxname,step_name,checksums,&block)
# m.detach
# end
# end
-
+
vm.reload
puts "We found no good state so we are destroying the previous machine+disks"
destroy_vm(boxname)
end
-
+
end
#puts "(re-)executing step #{step_name}"
-
-
+
+
yield
-
+
#Need to look it up again because if it was an initial load
- vm=VirtualBox::VM.find(boxname)
+ vm=VirtualBox::VM.find(boxname)
puts "Step [#{current_step_nr}] was successfully - saving state"
vm.save_state
sleep 2 #waiting for it to be ok
@@ -900,11 +897,11 @@ def self.transaction(boxname,step_name,checksums,&block)
vm.take_snapshot(step_name,"snapshot taken by veewee")
sleep 2 #waiting for it to be started again
vm.start
- end
+ end
#pp snapnames
end
-
+
end #End Class
end #End Module
2  veewee.gemspec
View
@@ -14,7 +14,7 @@ Gem::Specification.new do |s|
s.required_rubygems_version = ">= 1.3.6"
s.rubyforge_project = "veewee"
- s.add_dependency "vagrant", "~> 0.8.0"
+ s.add_dependency "vagrant", "~> 0.8.2"
s.add_dependency "net-ssh", "~> 2.1.0"
s.add_dependency "popen4", "~> 0.1.2"
s.add_dependency "thor", "~> 0.14.6"
Please sign in to comment.
Something went wrong with that request. Please try again.