Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Multivm hostname #1280

Closed
wants to merge 54 commits into from
@kbrock

Hi,

When in a multi vm environment, all vms have the same name in virtualbox. This makes it tricky to know which machine is which.

This patch uses the vm's host_name if it is available.

A) This is based upon the 1.0 branch, since that is what I use. Please point me to the 1.1 (master) vs 1.0 (stable) branching strategy FAQ and I can rebase.

B) If you have an example of an action tested / and how much you want to mock out, please let me know. (I saw some good legacy tests that used the environment)

C) Also, I noticed that Environment#root_path is documented to return a String, but the existing code assumes a Pathname is coming out.This threw a wrench into my testing, so please advise and I can fix this as well.

Thanks for the great tool,
Keenan

jhf and others added some commits
@jhf jhf Detect and disable DNS settings that break on Ubuntu 12.04. 99a5749
@mitchellh Update version 3242b4b
@mitchellh v1.0.3 fb09c4f
@mitchellh Fixes a bug where interfaces are assigned in a wrong order when using…
… ruby1.8, causing vm boot to stop as documented in issue #898
bd41440
@oker1 oker1 preserve attributes on packaging when using ruby 1.9.2 9c038c7
@mitchellh Merge pull request #951 from oker1/preserve
Preserve attritubes on included files
191dc01
@mitchellh Revert "preserve attributes on packaging when using ruby 1.9.2"
This reverts commit 9c038c7.

I didn't mean to backport this.
29d24f7
@pmorton pmorton Update drivers to support reading MAC Addresses ddabacb
@mitchellh Merge pull request #966 from pmorton/read_mac_addresses
Add the ability to map mac addresses to interfaces
0e5f076
@mitchellh Revert "Update drivers to support reading MAC Addresses"
This reverts commit ddabacb.
536dfc1
@mitchellh ssh-config help text uses --host instead of -h 4f62226
@mitchellh Use 127.0.0.1 instead of localhost for port use checking. [GH-1057]
Many systems actually don't have "localhost" setup as loopback in their
/etc/hosts file, so this would fail. This makes it pass.
9a4ca51
@mitchellh Disable read timeout on Net::HTTP 0b219fb
@mitchellh Retry SSH on EHOSTUNREACH errors 8a41237
@mitchellh Add missing translation for "saving" state [GH-1110] 4eba2e8
Julian Hille Added driver for VirtualBox 4.2 to 1.0.x stable this is so far not ve…
…ry deep tested. but vagrant up and base commands to work.
f268f62
@mitchellh Merge pull request #1120 from julianhille/1-0-stable
Added driver for VirtualBox 4.2 to 1.0.x stable this is so far not very...
04fef0a
@mitchellh Update CHANGELOG fd20760
@mitchellh v1.0.4 efc7508
@mitchellh Update CHANGELOG 5ab18a4
@marklap marklap Update load_plugins to be more Windows friendly. Uses File::PATH_SEPA…
…RATOR instead of hard-coded colon (':').
8c2e7b7
@mitchellh Merge pull request #1128 from sbfaulkner/1-0-stable
backport Windows fix onto 1-0-stable
cf00531
@smerrill smerrill Add Fedora 17+ NFS support. 7a4c808
@smerrill smerrill Also change Fedora 16 NFS handling. f7dfce5
@pbrisbin pbrisbin Fix arch host class
1. Detect os by /etc/os-release
2. Bring nfs_cleanup from parent class
3. Use systemd if available
3f68c83
@pbrisbin pbrisbin Remove #nfs? override
My system is now showing nfsd in /proc/filesystems. It must've been
some transient hiccup local to me.
fac08b5
@mitchellh Work around 4.2.0 bug on Windows
VirtualBox 4.2.0 on Windows has a critical bug where "showvminfo
--machinereadable" only outputs 5 lines of output no matter what.
Vagrant relies heavily on this output to read things such as network
interfaces, shared folders, etc. Therefore, prior to this commit,
Vagrant was broken on Windows. Note that this is 100% a VIRTUALBOX BUG.
But enough users will use VirtualBox 4.2.0 on Windows that Vagrant must
work around it.

We work around it by introducing "jank mode" for the 4.2 driver on
Windows. On 4.2.0 only on Windows, Vagrant will use the human-readable
version of "showvminfo" and use some pretty crazy regular expressions to
parse out the information it needs. This approach is far less tested but
it at least gets things working again on Windows with 4.2.0. I'm hoping
in the future that Oracle will quickly fix this issue for a 4.2.1, but
I'm not certain yet.

Even if Oracle fixes the issue, this workaround will be in Vagrant
forever to accomodate legacy 4.2.0 users on Windows.
6323a8e
@mitchellh Up version for development 7fb503a
@mitchellh Need an array for drop_while jank mode f12f556
@mitchellh Update CHAGELOG with older pull request dcac900
@mitchellh Merge pull request #1140 from smerrill/add-fedora-17-host-1-0-stable
Fedora 16+ NFS support.
f8370ab
@mitchellh Update CHANGELOG for GH-1140 ebc00a7
@mitchellh Style changes on GH-1140 2d710f5
@mitchellh Merge pull request #1142 from pbrisbin/arch-fix-2
Fix arch host class to work with systemd changes
1fb9077
@mitchellh Update CHANGELOG for GH-1142 03c3e22
@mitchellh Use protected over private, style preference a4cb5a2
@mitchellh v1.0.5 be0bc66
@LucasArruda

Thanks for your efficiency!

petere and others added some commits
@petere petere Check exit codes of puppet provisioners
Previously, failures in applying the puppet manifests would be
ignored, because puppet apply/agent don't have any useful exit codes
by default.  (Errors are printed, but vagrant continues.)

Use the option --detailed-exitcodes of puppet apply/agent to check for
success.
a0404db
@obscurerichard obscurerichard Fix Windows shell provisioning
Resolves [GH-1036] [GH-1164] [GH-1181]
780dc31
@mitchellh Merge pull request #1182 from obscurerichard/fix-windows-shell-provis…
…ioning-vs-1-0-stable

Fix Windows shell provisioning
b33474c
@mitchellh Update CHANGELOG and whitespace 3a4c2a0
@mitchellh Update version b62e3b0
@mitchellh Merge pull request #1180 from maestrodev/v1.0.5-exitcodes
Check exit codes of puppet provisioners
2cb9f97
@mitchellh Update CHANGELOG fdae725
@mitchellh Fix DNS resolution bug for 12.10 [GH-1176] fd707b0
@mitchellh Allow hostname to be a substring of the guest name on Ubuntu [GH-1163] 69c5ad5
@mitchellh Become Puppet 3.x compatible [GH-1169] 95d313c
@mitchellh Work around bug in OS X 10.8 and VirtualBox wrt VBoxManage
OS X 10.8 introduced a bug where on setuid/setgid executables, it will
print a warning to stdout if any DYLD_ enviornmental variables are set
(most common being DYLD_LIBRARY_PATH).

VirtualBox, specifically VBoxManage, sometimes shells out to external
programs to do some work, reading stdout for the result. The warnings
injected by OS X cause VirtualBox to read bad values, breaking Vagrant.

These work around both of these issues. Great.
e367a8c
@mitchellh Update gemspec to not require git for new vagrant installers 562c893
@mitchellh Clean LD_LIBRARY_PATH prior to calling VBoxManage as well 97062d3
@mitchellh Remove dependency of VirtualBox for running tests e5f58f6
@mitchellh v1.0.6 476b19a
@mitchellh Update CHANGELOG 54f7d83
@spider-network

This version is currently not pushed to rubygems.org

@spider-network It is now! Sorry about that.

@kbrock

oops - wrong branch

@kbrock kbrock closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on May 2, 2012
  1. @jhf

    Detect and disable DNS settings that break on Ubuntu 12.04.

    jhf authored committed
  2. Update version

    authored
  3. v1.0.3

    authored
Commits on May 5, 2012
  1. Fixes a bug where interfaces are assigned in a wrong order when using…

    authored
    … ruby1.8, causing vm boot to stop as documented in issue #898
Commits on May 26, 2012
  1. @oker1
  2. Merge pull request #951 from oker1/preserve

    authored
    Preserve attritubes on included files
  3. Revert "preserve attributes on packaging when using ruby 1.9.2"

    authored
    This reverts commit 9c038c7.
    
    I didn't mean to backport this.
Commits on Jun 8, 2012
  1. @pmorton
Commits on Jun 12, 2012
  1. Merge pull request #966 from pmorton/read_mac_addresses

    authored
    Add the ability to map mac addresses to interfaces
Commits on Jul 30, 2012
Commits on Aug 9, 2012
  1. Use 127.0.0.1 instead of localhost for port use checking. [GH-1057]

    authored
    Many systems actually don't have "localhost" setup as loopback in their
    /etc/hosts file, so this would fail. This makes it pass.
Commits on Aug 16, 2012
Commits on Aug 29, 2012
Commits on Sep 10, 2012
Commits on Sep 13, 2012
  1. Added driver for VirtualBox 4.2 to 1.0.x stable this is so far not ve…

    Julian Hille authored
    …ry deep tested. but vagrant up and base commands to work.
Commits on Sep 14, 2012
  1. Merge pull request #1120 from julianhille/1-0-stable

    authored
    Added driver for VirtualBox 4.2 to 1.0.x stable this is so far not very...
  2. Update CHANGELOG

    authored
  3. v1.0.4

    authored
  4. Update CHANGELOG

    authored
Commits on Sep 15, 2012
  1. @marklap

    Update load_plugins to be more Windows friendly. Uses File::PATH_SEPA…

    marklap authored S. Brent Faulkner committed
    …RATOR instead of hard-coded colon (':').
  2. Merge pull request #1128 from sbfaulkner/1-0-stable

    authored
    backport Windows fix onto 1-0-stable
Commits on Sep 18, 2012
  1. @smerrill

    Add Fedora 17+ NFS support.

    smerrill authored
  2. @smerrill
  3. @pbrisbin

    Fix arch host class

    pbrisbin authored
    1. Detect os by /etc/os-release
    2. Bring nfs_cleanup from parent class
    3. Use systemd if available
Commits on Sep 19, 2012
  1. @pbrisbin

    Remove #nfs? override

    pbrisbin authored
    My system is now showing nfsd in /proc/filesystems. It must've been
    some transient hiccup local to me.
  2. Work around 4.2.0 bug on Windows

    authored
    VirtualBox 4.2.0 on Windows has a critical bug where "showvminfo
    --machinereadable" only outputs 5 lines of output no matter what.
    Vagrant relies heavily on this output to read things such as network
    interfaces, shared folders, etc. Therefore, prior to this commit,
    Vagrant was broken on Windows. Note that this is 100% a VIRTUALBOX BUG.
    But enough users will use VirtualBox 4.2.0 on Windows that Vagrant must
    work around it.
    
    We work around it by introducing "jank mode" for the 4.2 driver on
    Windows. On 4.2.0 only on Windows, Vagrant will use the human-readable
    version of "showvminfo" and use some pretty crazy regular expressions to
    parse out the information it needs. This approach is far less tested but
    it at least gets things working again on Windows with 4.2.0. I'm hoping
    in the future that Oracle will quickly fix this issue for a 4.2.1, but
    I'm not certain yet.
    
    Even if Oracle fixes the issue, this workaround will be in Vagrant
    forever to accomodate legacy 4.2.0 users on Windows.
  3. Up version for development

    authored
  4. Merge pull request #1140 from smerrill/add-fedora-17-host-1-0-stable

    authored
    Fedora 16+ NFS support.
  5. Update CHANGELOG for GH-1140

    authored
  6. Style changes on GH-1140

    authored
  7. Merge pull request #1142 from pbrisbin/arch-fix-2

    authored
    Fix arch host class to work with systemd changes
  8. Update CHANGELOG for GH-1142

    authored
  9. v1.0.5

    authored
Commits on Oct 11, 2012
  1. @petere @carlossg

    Check exit codes of puppet provisioners

    petere authored carlossg committed
    Previously, failures in applying the puppet manifests would be
    ignored, because puppet apply/agent don't have any useful exit codes
    by default.  (Errors are printed, but vagrant continues.)
    
    Use the option --detailed-exitcodes of puppet apply/agent to check for
    success.
Commits on Oct 12, 2012
  1. @obscurerichard
Commits on Oct 13, 2012
  1. Merge pull request #1182 from obscurerichard/fix-windows-shell-provis…

    authored
    …ioning-vs-1-0-stable
    
    Fix Windows shell provisioning
  2. Update version

    authored
  3. Merge pull request #1180 from maestrodev/v1.0.5-exitcodes

    authored
    Check exit codes of puppet provisioners
  4. Update CHANGELOG

    authored
Commits on Nov 20, 2012
  1. Work around bug in OS X 10.8 and VirtualBox wrt VBoxManage

    authored
    OS X 10.8 introduced a bug where on setuid/setgid executables, it will
    print a warning to stdout if any DYLD_ enviornmental variables are set
    (most common being DYLD_LIBRARY_PATH).
    
    VirtualBox, specifically VBoxManage, sometimes shells out to external
    programs to do some work, reading stdout for the result. The warnings
    injected by OS X cause VirtualBox to read bad values, breaking Vagrant.
    
    These work around both of these issues. Great.
Commits on Dec 3, 2012
Commits on Dec 16, 2012
Commits on Dec 21, 2012
  1. v1.0.6

    authored
  2. Update CHANGELOG

    authored
Commits on Dec 29, 2012
  1. @kbrock
This page is out of date. Refresh to see the latest.
View
39 CHANGELOG.md
@@ -1,3 +1,42 @@
+## 1.0.6 (December 21, 2012)
+
+ - Shell provisioner outputs proper line endings on Windows [GH-1164]
+ - SSH upload opens file to stream which fixes strange upload issues.
+ - Check for proper exit codes for Puppet, since multiple exit codes
+ can mean success. [GH-1180]
+ - Fix issue where DNS doesn't resolve properly for 12.10. [GH-1176]
+ - Allow hostname to be a substring of the box name for Ubuntu [GH-1163]
+ - Use `puppet agent` instead of `puppetd` to be Puppet 3.x
+ compatible. [GH-1169]
+ - Work around bug in VirtualBox exposed by bug in OS X 10.8 where
+ VirtualBox executables couldn't handle garbage being injected into
+ stdout by OS X.
+
+## 1.0.5 (September 18, 2012)
+
+ - Work around a critical bug in VirtualBox 4.2.0 on Windows that
+ causes Vagrant to not work. [GH-1130]
+ - Plugin loading works better on Windows by using the proper
+ file path separator.
+ - NFS works on Fedora 16+. [GH-1140]
+ - NFS works with newer versions of Arch hosts that use systemd. [GH-1142]
+
+## 1.0.4 (September 13, 2012)
+
+ - VirtualBox 4.2 driver. [GH-1120]
+ - Correct `ssh-config` help to use `--host`, not `-h`.
+ - Use "127.0.0.1" instead of "localhost" for port checking to fix problem
+ where "localhost" is not properly setup. [GH-1057]
+ - Disable read timeout on Net::HTTP to avoid `rbuf_fill` error. [GH-1072]
+ - Retry SSH on `EHOSTUNREACH` errors.
+ - Add missing translation for "saving" state. [GH-1110]
+
+## 1.0.3 (May 1, 2012)
+
+ - Don't enable NAT DNS proxy on machines where resolv.conf already points
+ to localhost. This allows Vagrant to work once again with Ubuntu
+ 12.04. [GH-909]
+
## 1.0.2 (March 25, 2012)
- Provisioners will still mount folders and such if `--no-provision` is
View
2  lib/vagrant/action/vm/check_port_collisions.rb
@@ -33,7 +33,7 @@ def call(env)
hostport = options[:hostport].to_i
hostport = current[options[:name]] if current.has_key?(options[:name])
- if existing.include?(hostport) || is_port_open?("localhost", hostport)
+ if existing.include?(hostport) || is_port_open?("127.0.0.1", hostport)
# We have a collision! Handle it
send("handle_#{handler}".to_sym, options, existing)
end
View
2  lib/vagrant/action/vm/default_name.rb
@@ -11,7 +11,7 @@ def initialize(app, env)
def call(env)
@logger.info("Setting the default name of the VM")
- name = env[:root_path].basename.to_s + "_#{Time.now.to_i}"
+ name = (env[:vm].config.vm.host_name || env[:root_path].basename).to_s + "_#{Time.now.to_i}"
env[:vm].driver.set_name(name)
@app.call(env)
View
2  lib/vagrant/action/vm/network.rb
@@ -135,7 +135,7 @@ def assign_interface_numbers(networks, adapters)
# Make a first pass to assign interface numbers by adapter location
vm_adapters = @env[:vm].driver.read_network_interfaces
- vm_adapters.each do |number, adapter|
+ vm_adapters.sort.each do |number, adapter|
if adapter[:type] != :none
# Not used, so assign the interface number and increment
adapter_to_interface[number] = current
View
35 lib/vagrant/action/vm/sane_defaults.rb
@@ -28,13 +28,34 @@ def call(env)
]
attempt_and_log(command, "Enabling the Host I/O cache on the SATA controller...")
- # Enable the DNS proxy while in NAT mode. This shields the guest
- # VM from external DNS changs on the host machine.
- command = [
- "modifyvm", env[:vm].uuid,
- "--natdnsproxy1", "on"
- ]
- attempt_and_log(command, "Enable the NAT DNS proxy on adapter 1...")
+ enable_dns_proxy = true
+ begin
+ contents = File.read("/etc/resolv.conf")
+
+ if contents =~ /^nameserver 127\.0\.(0|1)\.1$/
+ # The use of both natdnsproxy and natdnshostresolver break on
+ # Ubuntu 12.04 that uses resolvconf with localhost. When used
+ # VirtualBox will give the client dns server 10.0.2.3, while
+ # not binding to that address itself. Therefore disable this
+ # feature if host uses the resolvconf server 127.0.0.1
+ @logger.info("Disabling DNS proxy since resolv.conf contains 127.0.0.1")
+ enable_dns_proxy = false
+ end
+ rescue Errno::ENOENT; end
+
+ # Enable/disable the NAT DNS proxy as necessary
+ if enable_dns_proxy
+ command = [
+ "modifyvm", env[:vm].uuid,
+ "--natdnsproxy1", "on"
+ ]
+ attempt_and_log(command, "Enable the NAT DNS proxy on adapter 1...")
+ else
+ command = [ "modifyvm", env[:vm].uuid, "--natdnsproxy1", "off" ]
+ attempt_and_log(command, "Disable the NAT DNS proxy on adapter 1...")
+ command = [ "modifyvm", env[:vm].uuid, "--natdnshostresolver1", "off" ]
+ attempt_and_log(command, "Disable the NAT DNS resolver on adapter 1...")
+ end
@app.call(env)
end
View
4 lib/vagrant/command/ssh_config.rb
@@ -11,11 +11,11 @@ def execute
options = {}
opts = OptionParser.new do |opts|
- opts.banner = "Usage: vagrant ssh-config [vm-name] [-h name]"
+ opts.banner = "Usage: vagrant ssh-config [vm-name] [--host name]"
opts.separator ""
- opts.on("--host COMMAND", "Name the host for the config..") do |h|
+ opts.on("--host NAME", "Name the host for the config..") do |h|
options[:host] = h
end
end
View
20 lib/vagrant/communication/ssh.rb
@@ -77,15 +77,16 @@ def upload(from, to)
# Do an SCP-based upload...
connect do |connection|
+ # Open file read only to fix issue #1036
scp = Net::SCP.new(connection)
- scp.upload!(from, to)
+ scp.upload!(File.open(from, "r"), to)
end
rescue Net::SCP::Error => e
# If we get the exit code of 127, then this means SCP is unavailable.
raise Errors::SCPUnavailable if e.message =~ /\(127\)/
- # Otherwise, just raise the error up
- raise
+ # Otherwise, just raise the error up
+ raise
end
protected
@@ -131,8 +132,17 @@ def connect
# Connect to SSH, giving it a few tries
connection = nil
begin
+ # These are the exceptions that we retry because they represent
+ # errors that are generally fixed from a retry and don't
+ # necessarily represent immediate failure cases.
+ exceptions = [
+ Errno::ECONNREFUSED,
+ Errno::EHOSTUNREACH,
+ Net::SSH::Disconnect,
+ Timeout::Error
+ ]
+
@logger.info("Connecting to SSH: #{ssh_info[:host]}:#{ssh_info[:port]}")
- exceptions = [Errno::ECONNREFUSED, Net::SSH::Disconnect]
connection = retryable(:tries => @vm.config.ssh.max_tries, :on => exceptions) do
Net::SSH.start(ssh_info[:host], ssh_info[:username], opts)
end
@@ -159,7 +169,7 @@ def connect
# Yield the connection that is ready to be used and
# return the value of the block
return yield connection if block_given?
- end
+ end
# Executes the command on an SSH connection within a login shell.
def shell_execute(connection, command, sudo=false)
View
1  lib/vagrant/downloaders/http.rb
@@ -19,6 +19,7 @@ def download!(source_url, destination_file)
proxy_uri = resolve_proxy(uri)
http = Net::HTTP.new(uri.host, uri.port, proxy_uri.host, proxy_uri.port, proxy_uri.user, proxy_uri.password)
+ http.read_timeout = nil # Disable the read timeout, just let it try to download
if uri.scheme == "https"
http.use_ssl = true
View
1  lib/vagrant/driver.rb
@@ -3,5 +3,6 @@ module Driver
autoload :VirtualBox, 'vagrant/driver/virtualbox'
autoload :VirtualBox_4_0, 'vagrant/driver/virtualbox_4_0'
autoload :VirtualBox_4_1, 'vagrant/driver/virtualbox_4_1'
+ autoload :VirtualBox_4_2, 'vagrant/driver/virtualbox_4_2'
end
end
View
3  lib/vagrant/driver/virtualbox.rb
@@ -44,7 +44,8 @@ def initialize(uuid=nil)
@logger.debug("Finding driver for VirtualBox version: #{@version}")
driver_map = {
"4.0" => VirtualBox_4_0,
- "4.1" => VirtualBox_4_1
+ "4.1" => VirtualBox_4_1,
+ "4.2" => VirtualBox_4_2
}
driver_klass = nil
View
606 lib/vagrant/driver/virtualbox_4_2.rb
@@ -0,0 +1,606 @@
+require 'log4r'
+
+require 'vagrant/driver/virtualbox_base'
+require 'vagrant/util/platform'
+
+module Vagrant
+ module Driver
+ # Driver for VirtualBox 4.2.x
+ class VirtualBox_4_2 < VirtualBoxBase
+ def initialize(uuid)
+ super()
+
+ @logger = Log4r::Logger.new("vagrant::driver::virtualbox_4_2")
+ @uuid = uuid
+
+ # "Jank mode." VirtualBox 4.2.0 has a horrendous bug where
+ # showvminfo with `--machinereadable` doesn't return proper output.
+ # In this case, Vagrant works around it by using equally horrendous
+ # regular expressions for the non-machine-readable output of
+ # showvminfo. This, ladies and gentlemen, is jank mode.
+ @jank_mode = false
+ if Util::Platform.windows?
+ if execute("--version").start_with?("4.2.0r")
+ @logger.info("Windows with v4.2.0. Jank mode engage.")
+ @jank_mode = true
+ end
+ end
+ end
+
+ def clear_forwarded_ports
+ args = []
+ read_forwarded_ports(@uuid).each do |nic, name, _, _|
+ args.concat(["--natpf#{nic}", "delete", name])
+ end
+
+ execute("modifyvm", @uuid, *args) if !args.empty?
+ end
+
+ def clear_shared_folders
+ return jank_clear_shared_folders if @jank_mode
+
+ info = execute("showvminfo", @uuid, "--machinereadable", :retryable => true)
+ info.split("\n").each do |line|
+ if line =~ /^SharedFolderNameMachineMapping\d+="(.+?)"$/
+ execute("sharedfolder", "remove", @uuid, "--name", $1.to_s)
+ end
+ end
+ end
+
+ def create_dhcp_server(network, options)
+ execute("dhcpserver", "add", "--ifname", network,
+ "--ip", options[:dhcp_ip],
+ "--netmask", options[:netmask],
+ "--lowerip", options[:dhcp_lower],
+ "--upperip", options[:dhcp_upper],
+ "--enable")
+ end
+
+ def create_host_only_network(options)
+ # Create the interface
+ execute("hostonlyif", "create") =~ /^Interface '(.+?)' was successfully created$/
+ name = $1.to_s
+
+ # Configure it
+ execute("hostonlyif", "ipconfig", name,
+ "--ip", options[:adapter_ip],
+ "--netmask", options[:netmask])
+
+ # Return the details
+ return {
+ :name => name,
+ :ip => options[:adapter_ip],
+ :netmask => options[:netmask],
+ :dhcp => nil
+ }
+ end
+
+ def delete
+ execute("unregistervm", @uuid, "--delete")
+ end
+
+ def delete_unused_host_only_networks
+ networks = []
+ execute("list", "hostonlyifs").split("\n").each do |line|
+ networks << $1.to_s if line =~ /^Name:\s+(.+?)$/
+ end
+
+ execute("list", "vms").split("\n").each do |line|
+ if line =~ /^".+?"\s+\{(.+?)\}$/
+ if @jank_mode
+ adapters = jank_read_hostonly_adapters($1.to_s)
+ adapters.each do |adapter|
+ networks.delete(adapter)
+ end
+ else
+ info = execute("showvminfo", $1.to_s, "--machinereadable", :retryable => true)
+ info.split("\n").each do |info_line|
+ if info_line =~ /^hostonlyadapter\d+="(.+?)"$/
+ networks.delete($1.to_s)
+ end
+ end
+ end
+ end
+ end
+
+ networks.each do |name|
+ # First try to remove any DHCP servers attached. We use `raw` because
+ # it is okay if this fails. It usually means that a DHCP server was
+ # never attached.
+ raw("dhcpserver", "remove", "--ifname", name)
+
+ # Delete the actual host only network interface.
+ execute("hostonlyif", "remove", name)
+ end
+ end
+
+ def discard_saved_state
+ execute("discardstate", @uuid)
+ end
+
+ def enable_adapters(adapters)
+ args = []
+ adapters.each do |adapter|
+ args.concat(["--nic#{adapter[:adapter]}", adapter[:type].to_s])
+
+ if adapter[:bridge]
+ args.concat(["--bridgeadapter#{adapter[:adapter]}",
+ adapter[:bridge]])
+ end
+
+ if adapter[:hostonly]
+ args.concat(["--hostonlyadapter#{adapter[:adapter]}",
+ adapter[:hostonly]])
+ end
+
+ if adapter[:mac_address]
+ args.concat(["--macaddress#{adapter[:adapter]}",
+ adapter[:mac_address]])
+ end
+
+ if adapter[:nic_type]
+ args.concat(["--nictype#{adapter[:adapter]}", adapter[:nic_type].to_s])
+ end
+ end
+
+ execute("modifyvm", @uuid, *args)
+ end
+
+ def execute_command(command)
+ raw(*command)
+ end
+
+ def export(path)
+ # TODO: Progress
+ execute("export", @uuid, "--output", path.to_s)
+ end
+
+ def forward_ports(ports)
+ args = []
+ ports.each do |options|
+ pf_builder = [options[:name],
+ options[:protocol] || "tcp",
+ "",
+ options[:hostport],
+ "",
+ options[:guestport]]
+
+ args.concat(["--natpf#{options[:adapter] || 1}",
+ pf_builder.join(",")])
+ end
+
+ execute("modifyvm", @uuid, *args) if !args.empty?
+ end
+
+ def halt
+ execute("controlvm", @uuid, "poweroff")
+ end
+
+ def import(ovf)
+ output = ""
+ total = ""
+ last = 0
+ execute("import", ovf) do |type, data|
+ if type == :stdout
+ # Keep track of the stdout so that we can get the VM name
+ output << data
+ elsif type == :stderr
+ # Append the data so we can see the full view
+ total << data
+
+ # Break up the lines. We can't get the progress until we see an "OK"
+ lines = total.split("\n")
+ if lines.include?("OK.")
+ # The progress of the import will be in the last line. Do a greedy
+ # regular expression to find what we're looking for.
+ if lines.last =~ /.+(\d{2})%/
+ current = $1.to_i
+ if current > last
+ last = current
+ yield current if block_given?
+ end
+ end
+ end
+ end
+ end
+
+ # Find the name of the VM name
+ if output !~ /Suggested VM name "(.+?)"/
+ @logger.error("Couldn't find VM name in the output.")
+ return nil
+ end
+
+ name = $1.to_s
+
+ output = execute("list", "vms")
+ if output =~ /^"#{Regexp.escape(name)}" \{(.+?)\}$/
+ return $1.to_s
+ end
+
+ nil
+ end
+
+ def read_forwarded_ports(uuid=nil, active_only=false)
+ uuid ||= @uuid
+ @logger.debug("read_forward_ports: uuid=#{uuid} active_only=#{active_only}")
+
+ return jank_read_forwarded_ports(uuid, active_only) if @jank_mode
+
+ results = []
+ current_nic = nil
+ info = execute("showvminfo", uuid, "--machinereadable", :retryable => true)
+ info.split("\n").each do |line|
+ # This is how we find the nic that a FP is attached to,
+ # since this comes first.
+ current_nic = $1.to_i if line =~ /^nic(\d+)=".+?"$/
+
+ # If we care about active VMs only, then we check the state
+ # to verify the VM is running.
+ if active_only && line =~ /^VMState="(.+?)"$/ && $1.to_s != "running"
+ return []
+ end
+
+ # Parse out the forwarded port information
+ if line =~ /^Forwarding.+?="(.+?),.+?,.*?,(.+?),.*?,(.+?)"$/
+ result = [current_nic, $1.to_s, $2.to_i, $3.to_i]
+ @logger.debug(" - #{result.inspect}")
+ results << result
+ end
+ end
+
+ results
+ end
+
+ def read_bridged_interfaces
+ execute("list", "bridgedifs").split("\n\n").collect do |block|
+ info = {}
+
+ block.split("\n").each do |line|
+ if line =~ /^Name:\s+(.+?)$/
+ info[:name] = $1.to_s
+ elsif line =~ /^IPAddress:\s+(.+?)$/
+ info[:ip] = $1.to_s
+ elsif line =~ /^NetworkMask:\s+(.+?)$/
+ info[:netmask] = $1.to_s
+ elsif line =~ /^Status:\s+(.+?)$/
+ info[:status] = $1.to_s
+ end
+ end
+
+ # Return the info to build up the results
+ info
+ end
+ end
+
+ def read_guest_additions_version
+ output = execute("guestproperty", "get", @uuid, "/VirtualBox/GuestAdd/Version",
+ :retryable => true)
+ if output =~ /^Value: (.+?)$/
+ # Split the version by _ since some distro versions modify it
+ # to look like this: 4.1.2_ubuntu, and the distro part isn't
+ # too important.
+ value = $1.to_s
+ return value.split("_").first
+ end
+
+ return nil
+ end
+
+ def read_host_only_interfaces
+ dhcp = {}
+ execute("list", "dhcpservers", :retryable => true).split("\n\n").each do |block|
+ info = {}
+
+ block.split("\n").each do |line|
+ if line =~ /^NetworkName:\s+HostInterfaceNetworking-(.+?)$/
+ info[:network] = $1.to_s
+ elsif line =~ /^IP:\s+(.+?)$/
+ info[:ip] = $1.to_s
+ elsif line =~ /^lowerIPAddress:\s+(.+?)$/
+ info[:lower] = $1.to_s
+ elsif line =~ /^upperIPAddress:\s+(.+?)$/
+ info[:upper] = $1.to_s
+ end
+ end
+
+ # Set the DHCP info
+ dhcp[info[:network]] = info
+ end
+
+ execute("list", "hostonlyifs", :retryable => true).split("\n\n").collect do |block|
+ info = {}
+
+ block.split("\n").each do |line|
+ if line =~ /^Name:\s+(.+?)$/
+ info[:name] = $1.to_s
+ elsif line =~ /^IPAddress:\s+(.+?)$/
+ info[:ip] = $1.to_s
+ elsif line =~ /^NetworkMask:\s+(.+?)$/
+ info[:netmask] = $1.to_s
+ elsif line =~ /^Status:\s+(.+?)$/
+ info[:status] = $1.to_s
+ end
+ end
+
+ # Set the DHCP info if it exists
+ info[:dhcp] = dhcp[info[:name]] if dhcp[info[:name]]
+
+ info
+ end
+ end
+
+ def read_mac_address
+ return jank_read_mac_address if @jank_mode
+
+ info = execute("showvminfo", @uuid, "--machinereadable", :retryable => true)
+ info.split("\n").each do |line|
+ return $1.to_s if line =~ /^macaddress1="(.+?)"$/
+ end
+
+ nil
+ end
+
+ def read_machine_folder
+ execute("list", "systemproperties", :retryable => true).split("\n").each do |line|
+ if line =~ /^Default machine folder:\s+(.+?)$/i
+ return $1.to_s
+ end
+ end
+
+ nil
+ end
+
+ def read_network_interfaces
+ return jank_read_network_interfaces if @jank_mode
+
+ nics = {}
+ info = execute("showvminfo", @uuid, "--machinereadable", :retryable => true)
+ info.split("\n").each do |line|
+ if line =~ /^nic(\d+)="(.+?)"$/
+ adapter = $1.to_i
+ type = $2.to_sym
+
+ nics[adapter] ||= {}
+ nics[adapter][:type] = type
+ elsif line =~ /^hostonlyadapter(\d+)="(.+?)"$/
+ adapter = $1.to_i
+ network = $2.to_s
+
+ nics[adapter] ||= {}
+ nics[adapter][:hostonly] = network
+ elsif line =~ /^bridgeadapter(\d+)="(.+?)"$/
+ adapter = $1.to_i
+ network = $2.to_s
+
+ nics[adapter] ||= {}
+ nics[adapter][:bridge] = network
+ end
+ end
+
+ nics
+ end
+
+ def read_state
+ return jank_read_state if @jank_mode
+
+ output = execute("showvminfo", @uuid, "--machinereadable", :retryable => true)
+ if output =~ /^name="<inaccessible>"$/
+ return :inaccessible
+ elsif output =~ /^VMState="(.+?)"$/
+ return $1.to_sym
+ end
+
+ nil
+ end
+
+ def read_used_ports
+ ports = []
+ execute("list", "vms", :retryable => true).split("\n").each do |line|
+ if line =~ /^".+?" \{(.+?)\}$/
+ uuid = $1.to_s
+
+ # Ignore our own used ports
+ next if uuid == @uuid
+
+ read_forwarded_ports(uuid, true).each do |_, _, hostport, _|
+ ports << hostport
+ end
+ end
+ end
+
+ ports
+ end
+
+ def read_vms
+ results = []
+ execute("list", "vms", :retryable => true).split("\n").each do |line|
+ if line =~ /^".+?" \{(.+?)\}$/
+ results << $1.to_s
+ end
+ end
+
+ results
+ end
+
+ def set_mac_address(mac)
+ execute("modifyvm", @uuid, "--macaddress1", mac)
+ end
+
+ def set_name(name)
+ execute("modifyvm", @uuid, "--name", name)
+ end
+
+ def share_folders(folders)
+ folders.each do |folder|
+ args = ["--name",
+ folder[:name],
+ "--hostpath",
+ folder[:hostpath]]
+ args << "--transient" if folder.has_key?(:transient) && folder[:transient]
+ execute("sharedfolder", "add", @uuid, *args)
+ end
+ end
+
+ def ssh_port(expected_port)
+ @logger.debug("Searching for SSH port: #{expected_port.inspect}")
+
+ # Look for the forwarded port only by comparing the guest port
+ read_forwarded_ports.each do |_, _, hostport, guestport|
+ return hostport if guestport == expected_port
+ end
+
+ nil
+ end
+
+ def start(mode)
+ command = ["startvm", @uuid, "--type", mode.to_s]
+ r = raw(*command)
+
+ if r.exit_code == 0 || r.stdout =~ /VM ".+?" has been successfully started/
+ # Some systems return an exit code 1 for some reason. For that
+ # we depend on the output.
+ return true
+ end
+
+ # If we reached this point then it didn't work out.
+ raise Errors::VBoxManageError, :command => command.inspect
+ end
+
+ def suspend
+ execute("controlvm", @uuid, "savestate")
+ end
+
+ def verify!
+ # This command sometimes fails if kernel drivers aren't properly loaded
+ # so we just run the command and verify that it succeeded.
+ execute("list", "hostonlyifs")
+ end
+
+ def verify_image(path)
+ r = raw("import", path.to_s, "--dry-run")
+ return r.exit_code == 0
+ end
+
+ def vm_exists?(uuid)
+ raw("showvminfo", uuid).exit_code == 0
+ end
+
+ protected
+
+ # JANK MODE METHODS:
+ #
+ # All the methods below are created to work around a horrendous
+ # bug in VirtualBox 4.2.0 on Windows where "showvminfo --machinereadable"
+ # doesn't output enough data. So, instead, on Windows we use the plain
+ # "showvminfo" and parse the human readable output.
+
+ def jank_clear_shared_folders
+ info = execute("showvminfo", @uuid, :retryable => true)
+
+ # Get the shared folders part
+ info = info.split("\n")
+ info = info.drop_while { |line| line !~ /^Shared folders:/i }
+ info = info.take_while { |line| line != "" && line !~ /^Name:/i }
+
+ # Find all the shared folders and delete them all
+ info.each do |line|
+ if line =~ /^Name: '(.+?)'/
+ execute("sharedfolder", "remove", @uuid, "--name", $1.to_s)
+ end
+ end
+ end
+
+ def jank_read_forwarded_ports(uuid, active_only)
+ results = []
+
+ info = execute("showvminfo", uuid, :retryable => true)
+ info.split("\n").each do |line|
+ # If we care about active VMs only, then we check the state
+ # to verify the VM is running.
+ if active_only && line =~ /^State:\s+(.+?) \(.+?\)$/ && $1.to_s != "running"
+ return []
+ end
+
+ # Parse out the forwarded port information
+ if line =~ /^NIC (\d) Rule\(\d\):\s+name = (.+?), protocol = .+?, host ip = .*?, host port = (.+?), guest ip = .*?, guest port = (.+?)$/
+ result = [$1.to_i, $2.to_s, $3.to_i, $4.to_i]
+ @logger.debug(" - #{result.inspect}")
+ results << result
+ end
+ end
+
+ results
+ end
+
+ def jank_read_hostonly_adapters(uuid)
+ adapters = []
+
+ nics = jank_read_network_interfaces(uuid)
+ nics.each do |adapter, data|
+ if data[:type] == :hostonly
+ adapters << data[:hostonly]
+ end
+ end
+
+ adapters
+ end
+
+ def jank_read_mac_address
+ info = execute("showvminfo", @uuid, :retryable => true)
+ info.split("\n").each do |line|
+ return $1.to_s if line =~ /^NIC 1:\s+MAC: (.+?),/
+ end
+
+ nil
+ end
+
+ def jank_read_network_interfaces(uuid=nil)
+ uuid ||= @uuid
+ nics = {}
+ info = execute("showvminfo", uuid, :retryable => true)
+ info.split("\n").each do |line|
+ if line =~ /^NIC (\d):\s+MAC: .+?, Attachment: (.+?), Cable/
+ adapter = $1.to_i
+ long_type = $2.to_s
+
+ type = nil
+ data = nil
+ if long_type == "NAT"
+ type = :nat
+ elsif long_type =~ /^Host-only Interface '(.+?)'$/i
+ type = :hostonly
+ data = $1.to_s
+ elsif long_type =~ /^Bridged Interface '(.+?)'$/i
+ type = :bridge
+ data = $1.to_s
+ end
+
+ nics[adapter] ||= {}
+ nics[adapter][:type] = type
+ nics[adapter][:hostonly] = data if type == :hostonly
+ nics[adapter][:bridge] = data if type == :bridge
+ end
+ end
+
+ nics
+ end
+
+ def jank_read_state
+ output = execute("showvminfo", @uuid, :retryable => true)
+ if output =~ /^Name:\s+<inaccessible>$/
+ return :inaccessible
+ elsif output =~ /^State:\s+(.+?) \(.+?\)$/
+ # Silly edge cases for a jank mode. This probably doesn't
+ # cover every case, but if we can get Vagrant MOSTLY working
+ # with this buggy version of VirtualBox on Windows, I'll be
+ # quite happy.
+ state = $1.to_s.downcase.gsub(" ", "")
+ state = "poweroff" if state == "poweredoff"
+ return state.to_sym
+ end
+
+ nil
+ end
+ end
+ end
+end
View
17 lib/vagrant/driver/virtualbox_base.rb
@@ -300,9 +300,26 @@ def raw(*command, &block)
@logger.info("Interrupted.")
end
+ # The following is a workaround for a combined VirtualBox and
+ # Mac OS X 10.8 bug:
+ #
+ # Remove the DYLD_LIBRARY_PATH environmental variable on Mac. This
+ # is to fix a bug in Mac OS X 10.8 where a warning is printed to the
+ # console if this is set when executing certain programs, which
+ # can cause some VBoxManage commands to break because they work
+ # by just reading stdout and don't expect the OS to just inject
+ # garbage into it.
+ old_dyld_lib_path = ENV.delete("DYLD_LIBRARY_PATH")
+ old_ld_lib_path = ENV.delete("LD_LIBRARY_PATH")
+
Util::Busy.busy(int_callback) do
Subprocess.execute(@vboxmanage_path, *command, &block)
end
+ ensure
+ # Reset the library path if it was set before. See above comments
+ # for more information on why this was unset in the first place.
+ ENV["DYLD_LIBRARY_PATH"] = old_dyld_lib_path if old_dyld_lib_path
+ ENV["LD_LIBRARY_PATH"] = old_ld_lib_path if old_ld_lib_path
end
end
end
View
2  lib/vagrant/environment.rb
@@ -507,7 +507,7 @@ def find_vagrantfile(search_path)
def load_plugins
# Add our private gem path to the gem path and reset the paths
# that Rubygems knows about.
- ENV["GEM_PATH"] = "#{@gems_path}:#{ENV["GEM_PATH"]}"
+ ENV["GEM_PATH"] = "#{@gems_path}#{::File::PATH_SEPARATOR}#{ENV["GEM_PATH"]}"
::Gem.clear_paths
# Load the plugins
View
2  lib/vagrant/guest/ubuntu.rb
@@ -12,7 +12,7 @@ def mount_shared_folder(name, guestpath, options)
end
def change_host_name(name)
- if !vm.channel.test("sudo hostname | grep '#{name}'")
+ if !vm.channel.test("sudo hostname | grep '^#{name}$'")
vm.channel.sudo("sed -i 's/.*$/#{name}/' /etc/hostname")
vm.channel.sudo("sed -i 's@^\\(127[.]0[.]1[.]1[[:space:]]\\+\\)@\\1#{name} #{name.split('.')[0]} @' /etc/hosts")
vm.channel.sudo("service hostname start")
View
31 lib/vagrant/hosts/arch.rb
@@ -2,7 +2,7 @@ module Vagrant
module Hosts
class Arch < Linux
def self.match?
- File.exist?("/etc/rc.conf") && File.exist?("/etc/pacman.conf")
+ File.exist?("/etc/os-release") && File.read("/etc/os-release") =~ /arch linux/i
end
# Normal, mid-range precedence.
@@ -19,17 +19,36 @@ def nfs_export(id, ip, folders)
@ui.info I18n.t("vagrant.hosts.arch.nfs_export.prepare")
sleep 0.5
+ nfs_cleanup(id)
+
output.split("\n").each do |line|
# This should only ask for administrative permission once, even
# though its executed in multiple subshells.
system(%Q[sudo su root -c "echo '#{line}' >> /etc/exports"])
end
- # We run restart here instead of "update" just in case nfsd
- # is not starting
- system("sudo /etc/rc.d/rpcbind restart")
- system("sudo /etc/rc.d/nfs-common restart")
- system("sudo /etc/rc.d/nfs-server restart")
+ if systemd?
+ # Call start to be nice. This will be a no-op if things are
+ # already running. Then use exportfs to pick up the changes we
+ # just made.
+ system("sudo systemctl start nfsd.service rpc-idmapd.service rpc-mountd.service rpcbind.service")
+ system("sudo exportfs -r")
+ else
+ # The restarting of services when we might not need to can be
+ # considered evil, but this will be obviated by systemd soon
+ # enough anyway.
+ system("sudo /etc/rc.d/rpcbind restart")
+ system("sudo /etc/rc.d/nfs-common restart")
+ system("sudo /etc/rc.d/nfs-server restart")
+ end
+ end
+
+ protected
+
+ # This tests to see if systemd is used on the system. This is used
+ # in newer versions of Arch, and requires a change in behavior.
+ def systemd?
+ Kernel.system("which systemctl &>/dev/null")
end
end
end
View
17 lib/vagrant/hosts/fedora.rb
@@ -24,6 +24,23 @@ def initialize(*args)
super
@nfs_server_binary = "/etc/init.d/nfs"
+
+ # On Fedora 16+, systemd replaced init.d, so we have to use the
+ # proper NFS binary. This checks to see if we need to do that.
+ release_file = Pathname.new("/etc/redhat-release")
+ begin
+ release_file.open("r") do |f|
+ version_number = /Fedora release ([0-9]+)/.match(f.gets)[1].to_i
+ if version_number >= 16
+ # "service nfs-server" will redirect properly to systemctl
+ # when "service nfs-server restart" is called.
+ @nfs_server_binary = "/usr/sbin/service nfs-server"
+ end
+ end
+ rescue Errno::ENOENT
+ # File doesn't exist, not a big deal, assume we're on a
+ # lower version.
+ end
end
end
end
View
2  lib/vagrant/provisioners/puppet.rb
@@ -151,7 +151,7 @@ def run_puppet_client
facter = "#{facts.join(" ")} "
end
- command = "cd #{manifests_guest_path} && #{facter}puppet apply #{options}"
+ command = "cd #{manifests_guest_path} && #{facter}puppet apply #{options} --detailed-exitcodes || [ $? -eq 2 ]"
env[:ui].info I18n.t("vagrant.provisioners.puppet.running_puppet",
:manifest => @manifest_file)
View
8 lib/vagrant/provisioners/puppet_server.rb
@@ -21,8 +21,8 @@ def self.config_class
end
def provision!
- verify_binary("puppetd")
- run_puppetd_client
+ verify_binary("puppet")
+ run_puppet_agent
end
def verify_binary(binary)
@@ -32,7 +32,7 @@ def verify_binary(binary)
:binary => binary)
end
- def run_puppetd_client
+ def run_puppet_agent
options = config.options
options = [options] if !options.is_a?(Array)
@@ -66,7 +66,7 @@ def run_puppetd_client
facter = "#{facts.join(" ")} "
end
- command = "#{facter}puppetd #{options} --server #{config.puppet_server}"
+ command = "#{facter}puppet agent #{options} --server #{config.puppet_server} --detailed-exitcodes || [ $? -eq 2 ]"
env[:ui].info I18n.t("vagrant.provisioners.puppet_server.running_puppetd")
env[:vm].channel.sudo(command) do |type, data|
View
6 lib/vagrant/provisioners/shell.rb
@@ -59,6 +59,12 @@ def with_script_file
# Otherwise we have an inline script, we need to Tempfile it,
# and handle it specially...
file = Tempfile.new('vagrant-shell')
+
+ # Unless you set binmode, on a Windows host the shell script will
+ # have CRLF line endings instead of LF line endings, causing havoc
+ # when the guest executes it
+ file.binmode
+
begin
file.write(config.inline)
file.fsync
View
2  lib/vagrant/version.rb
@@ -2,5 +2,5 @@ module Vagrant
# This will always be up to date with the current version of Vagrant,
# since it is used to generate the gemspec and is also the source of
# the version for `vagrant -v`
- VERSION = "1.0.2"
+ VERSION = "1.0.6"
end
View
4 templates/locales/en.yml
@@ -299,6 +299,10 @@ en:
shut it down forcefully, or you can run `vagrant suspend` to simply
suspend the virtual machine. In either case, to restart it again,
simply run `vagrant up`.
+ saving: |-
+ The VM is currently saving its state. In a few moments this state
+ should transition to "saved." Please run `vagrant status` again
+ in a few seconds.
saved: |-
To resume this VM, simply run `vagrant up`.
stuck: |-
View
8 test/unit/vagrant/environment_test.rb
@@ -97,6 +97,14 @@
end
describe "primary VM" do
+ before do
+ # This is really nasty but we do this to remove the dependency on
+ # having VirtualBox installed to run tests.
+ Vagrant::Driver::VirtualBox.stub(:new) do |uuid|
+ double("vm-#{uuid}")
+ end
+ end
+
it "should be the only VM if not a multi-VM environment" do
instance.primary_vm.should == instance.vms.values.first
end
View
35 vagrant.gemspec
@@ -32,8 +32,39 @@ Gem::Specification.new do |s|
s.add_development_dependency "rspec-expectations", "~> 2.8.0"
s.add_development_dependency "rspec-mocks", "~> 2.8.0"
- s.files = `git ls-files`.split("\n")
- s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
+ # The following block of code determines the files that should be included
+ # in the gem. It does this by reading all the files in the directory where
+ # this gemspec is, and parsing out the ignored files from the gitignore.
+ # Note that the entire gitignore(5) syntax is not supported, specifically
+ # the "!" syntax, but it should mostly work correctly.
+ root_path = File.dirname(__FILE__)
+ all_files = Dir.chdir(root_path) { Dir.glob("**/{*,.*}") }
+ all_files.reject! { |file| [".", ".."].include?(File.basename(file)) }
+ gitignore_path = File.join(root_path, ".gitignore")
+ gitignore = File.readlines(gitignore_path)
+ gitignore.map! { |line| line.chomp.strip }
+ gitignore.reject! { |line| line.empty? || line =~ /^(#|!)/ }
+
+ unignored_files = all_files.reject do |file|
+ # Ignore any directories, the gemspec only cares about files
+ next true if File.directory?(file)
+
+ # Ignore any paths that match anything in the gitignore. We do
+ # two tests here:
+ #
+ # - First, test to see if the entire path matches the gitignore.
+ # - Second, match if the basename does, this makes it so that things
+ # like '.DS_Store' will match sub-directories too (same behavior
+ # as git).
+ #
+ gitignore.any? do |ignore|
+ File.fnmatch(ignore, file, File::FNM_PATHNAME) ||
+ File.fnmatch(ignore, File.basename(file), File::FNM_PATHNAME)
+ end
+ end
+
+ s.files = unignored_files
+ s.executables = unignored_files.map { |f| f[/^bin\/(.*)/, 1] }.compact
s.require_path = 'lib'
end
Something went wrong with that request. Please try again.