Use bundler to load plugins
This commit is contained in:
parent
7c8fc34a25
commit
f2c6175d16
321
lib/vagrant.rb
321
lib/vagrant.rb
|
@ -1,314 +1,17 @@
|
||||||
require 'log4r'
|
# This file is load before RubyGems are loaded, and allow us to actually
|
||||||
require 'rubygems'
|
# resolve plugin dependencies and load the proper versions of everything.
|
||||||
|
|
||||||
# Enable logging if it is requested. We do this before
|
if defined?(Vagrant)
|
||||||
# anything else so that we can setup the output before
|
raise "vagrant is somehow already loaded. bug."
|
||||||
# any logging occurs.
|
|
||||||
if ENV["VAGRANT_LOG"] && ENV["VAGRANT_LOG"] != ""
|
|
||||||
# Require Log4r and define the levels we'll be using
|
|
||||||
require 'log4r/config'
|
|
||||||
Log4r.define_levels(*Log4r::Log4rConfig::LogLevels)
|
|
||||||
|
|
||||||
level = nil
|
|
||||||
begin
|
|
||||||
level = Log4r.const_get(ENV["VAGRANT_LOG"].upcase)
|
|
||||||
rescue NameError
|
|
||||||
# This means that the logging constant wasn't found,
|
|
||||||
# which is fine. We just keep `level` as `nil`. But
|
|
||||||
# we tell the user.
|
|
||||||
level = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
# Some constants, such as "true" resolve to booleans, so the
|
|
||||||
# above error checking doesn't catch it. This will check to make
|
|
||||||
# sure that the log level is an integer, as Log4r requires.
|
|
||||||
level = nil if !level.is_a?(Integer)
|
|
||||||
|
|
||||||
if !level
|
|
||||||
# We directly write to stderr here because the VagrantError system
|
|
||||||
# is not setup yet.
|
|
||||||
$stderr.puts "Invalid VAGRANT_LOG level is set: #{ENV["VAGRANT_LOG"]}"
|
|
||||||
$stderr.puts ""
|
|
||||||
$stderr.puts "Please use one of the standard log levels: debug, info, warn, or error"
|
|
||||||
exit 1
|
|
||||||
end
|
|
||||||
|
|
||||||
# Set the logging level on all "vagrant" namespaced
|
|
||||||
# logs as long as we have a valid level.
|
|
||||||
if level
|
|
||||||
logger = Log4r::Logger.new("vagrant")
|
|
||||||
logger.outputters = Log4r::Outputter.stderr
|
|
||||||
logger.level = level
|
|
||||||
logger = nil
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
require 'json'
|
ENV["VAGRANT_INSTALLER_EMBEDDED_DIR"] = "/Applications/Vagrant/embedded"
|
||||||
require 'pathname'
|
|
||||||
require 'stringio'
|
|
||||||
|
|
||||||
require 'childprocess'
|
# Initialize Bundler before we load _any_ RubyGems.
|
||||||
require 'i18n'
|
require_relative "vagrant/bundler"
|
||||||
|
require_relative "vagrant/plugin_manager"
|
||||||
|
Vagrant::Bundler.instance.init!(Vagrant::PluginManager.plugins)
|
||||||
|
|
||||||
# OpenSSL must be loaded here since when it is loaded via `autoload`
|
# Initialize Vagrant first, then load the remaining dependencies
|
||||||
# there are issues with ciphers not being properly loaded.
|
require "vagrant/init"
|
||||||
require 'openssl'
|
Bundler.require(:default)
|
||||||
|
|
||||||
# Always make the version available
|
|
||||||
require 'vagrant/version'
|
|
||||||
global_logger = Log4r::Logger.new("vagrant::global")
|
|
||||||
global_logger.info("Vagrant version: #{Vagrant::VERSION}")
|
|
||||||
global_logger.info("Ruby version: #{RUBY_VERSION}")
|
|
||||||
global_logger.info("RubyGems version: #{Gem::VERSION}")
|
|
||||||
ENV.each do |k, v|
|
|
||||||
global_logger.info("#{k}=#{v.inspect}") if k =~ /^VAGRANT_/
|
|
||||||
end
|
|
||||||
|
|
||||||
# We need these components always so instead of an autoload we
|
|
||||||
# just require them explicitly here.
|
|
||||||
require "vagrant/registry"
|
|
||||||
|
|
||||||
module Vagrant
|
|
||||||
autoload :Action, 'vagrant/action'
|
|
||||||
autoload :BatchAction, 'vagrant/batch_action'
|
|
||||||
autoload :Box, 'vagrant/box'
|
|
||||||
autoload :BoxCollection, 'vagrant/box_collection'
|
|
||||||
autoload :CLI, 'vagrant/cli'
|
|
||||||
autoload :Command, 'vagrant/command'
|
|
||||||
autoload :Config, 'vagrant/config'
|
|
||||||
autoload :Driver, 'vagrant/driver'
|
|
||||||
autoload :Environment, 'vagrant/environment'
|
|
||||||
autoload :Errors, 'vagrant/errors'
|
|
||||||
autoload :Guest, 'vagrant/guest'
|
|
||||||
autoload :Hosts, 'vagrant/hosts'
|
|
||||||
autoload :Machine, 'vagrant/machine'
|
|
||||||
autoload :MachineState, 'vagrant/machine_state'
|
|
||||||
autoload :Plugin, 'vagrant/plugin'
|
|
||||||
autoload :UI, 'vagrant/ui'
|
|
||||||
autoload :Util, 'vagrant/util'
|
|
||||||
|
|
||||||
# These are the various plugin versions and their components in
|
|
||||||
# a lazy loaded Hash-like structure.
|
|
||||||
PLUGIN_COMPONENTS = Registry.new.tap do |c|
|
|
||||||
c.register(:"1") { Plugin::V1::Plugin }
|
|
||||||
c.register([:"1", :command]) { Plugin::V1::Command }
|
|
||||||
c.register([:"1", :communicator]) { Plugin::V1::Communicator }
|
|
||||||
c.register([:"1", :config]) { Plugin::V1::Config }
|
|
||||||
c.register([:"1", :guest]) { Plugin::V1::Guest }
|
|
||||||
c.register([:"1", :host]) { Plugin::V1::Host }
|
|
||||||
c.register([:"1", :provider]) { Plugin::V1::Provider }
|
|
||||||
c.register([:"1", :provisioner]) { Plugin::V1::Provisioner }
|
|
||||||
|
|
||||||
c.register(:"2") { Plugin::V2::Plugin }
|
|
||||||
c.register([:"2", :command]) { Plugin::V2::Command }
|
|
||||||
c.register([:"2", :communicator]) { Plugin::V2::Communicator }
|
|
||||||
c.register([:"2", :config]) { Plugin::V2::Config }
|
|
||||||
c.register([:"2", :guest]) { Plugin::V2::Guest }
|
|
||||||
c.register([:"2", :host]) { Plugin::V2::Host }
|
|
||||||
c.register([:"2", :provider]) { Plugin::V2::Provider }
|
|
||||||
c.register([:"2", :provisioner]) { Plugin::V2::Provisioner }
|
|
||||||
c.register([:"2", :synced_folder]) { Plugin::V2::SyncedFolder }
|
|
||||||
end
|
|
||||||
|
|
||||||
# This returns a true/false showing whether we're running from the
|
|
||||||
# environment setup by the Vagrant installers.
|
|
||||||
#
|
|
||||||
# @return [Boolean]
|
|
||||||
def self.in_installer?
|
|
||||||
!!ENV["VAGRANT_INSTALLER_ENV"]
|
|
||||||
end
|
|
||||||
|
|
||||||
# The source root is the path to the root directory of
|
|
||||||
# the Vagrant gem.
|
|
||||||
def self.source_root
|
|
||||||
@source_root ||= Pathname.new(File.expand_path('../../', __FILE__))
|
|
||||||
end
|
|
||||||
|
|
||||||
# Configure a Vagrant environment. The version specifies the version
|
|
||||||
# of the configuration that is expected by the block. The block, based
|
|
||||||
# on that version, configures the environment.
|
|
||||||
#
|
|
||||||
# Note that the block isn't run immediately. Instead, the configuration
|
|
||||||
# block is stored until later, and is run when an environment is loaded.
|
|
||||||
#
|
|
||||||
# @param [String] version Version of the configuration
|
|
||||||
def self.configure(version, &block)
|
|
||||||
Config.run(version, &block)
|
|
||||||
end
|
|
||||||
|
|
||||||
# This checks if a plugin with the given name is installed. This can
|
|
||||||
# be used from the Vagrantfile to easily branch based on plugin
|
|
||||||
# availability.
|
|
||||||
def self.has_plugin?(name)
|
|
||||||
manager = plugin("2").manager
|
|
||||||
|
|
||||||
manager.required.any? { |gem_name| gem_name == name } ||
|
|
||||||
manager.registered.any? { |plugin| plugin.name == name }
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns a superclass to use when creating a plugin for Vagrant.
|
|
||||||
# Given a specific version, this returns a proper superclass to use
|
|
||||||
# to register plugins for that version.
|
|
||||||
#
|
|
||||||
# Optionally, if you give a specific component, then it will return
|
|
||||||
# the proper superclass for that component as well.
|
|
||||||
#
|
|
||||||
# Plugins and plugin components should subclass the classes returned by
|
|
||||||
# this method. This method lets Vagrant core control these superclasses
|
|
||||||
# and change them over time without affecting plugins. For example, if
|
|
||||||
# the V1 superclass happens to be "Vagrant::V1," future versions of
|
|
||||||
# Vagrant may move it to "Vagrant::Plugins::V1" and plugins will not be
|
|
||||||
# affected.
|
|
||||||
#
|
|
||||||
# @param [String] version
|
|
||||||
# @param [String] component
|
|
||||||
# @return [Class]
|
|
||||||
def self.plugin(version, component=nil)
|
|
||||||
# Build up the key and return a result
|
|
||||||
key = version.to_s.to_sym
|
|
||||||
key = [key, component.to_s.to_sym] if component
|
|
||||||
result = PLUGIN_COMPONENTS.get(key)
|
|
||||||
|
|
||||||
# If we found our component then we return that
|
|
||||||
return result if result
|
|
||||||
|
|
||||||
# If we didn't find a result, then raise an exception, depending
|
|
||||||
# on if we got a component or not.
|
|
||||||
raise ArgumentError, "Plugin superclass not found for version/component: " +
|
|
||||||
"#{version} #{component}"
|
|
||||||
end
|
|
||||||
|
|
||||||
# This should be used instead of Ruby's built-in `require` in order to
|
|
||||||
# load a Vagrant plugin. This will load the given plugin by first doing
|
|
||||||
# a normal `require`, giving a nice error message if things go wrong,
|
|
||||||
# and second by verifying that a Vagrant plugin was actually defined in
|
|
||||||
# the process.
|
|
||||||
#
|
|
||||||
# @param [String] name Name of the plugin to load.
|
|
||||||
def self.require_plugin(name)
|
|
||||||
logger = Log4r::Logger.new("vagrant::root")
|
|
||||||
|
|
||||||
if ENV["VAGRANT_NO_PLUGINS"]
|
|
||||||
logger.warn("VAGRANT_NO_PLUGINS is set, not loading 3rd party plugin: #{name}")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
# Redirect stdout/stderr so that we can output it in our own way.
|
|
||||||
previous_stderr = $stderr
|
|
||||||
previous_stdout = $stdout
|
|
||||||
$stderr = StringIO.new
|
|
||||||
$stdout = StringIO.new
|
|
||||||
|
|
||||||
# Attempt the normal require
|
|
||||||
begin
|
|
||||||
require name
|
|
||||||
plugin("2").manager.plugin_required(name)
|
|
||||||
rescue Exception => e
|
|
||||||
# Since this is a rare case, we create a one-time logger here
|
|
||||||
# in order to output the error
|
|
||||||
logger.error("Failed to load plugin: #{name}")
|
|
||||||
logger.error(" -- Error: #{e.inspect}")
|
|
||||||
logger.error(" -- Backtrace:")
|
|
||||||
logger.error(e.backtrace.join("\n"))
|
|
||||||
|
|
||||||
# If it is a LoadError we first try to see if it failed loading
|
|
||||||
# the top-level entrypoint. If so, then we report a different error.
|
|
||||||
if e.is_a?(LoadError)
|
|
||||||
# Parse the message in order to get what failed to load, and
|
|
||||||
# add some extra protection around if the message is different.
|
|
||||||
parts = e.to_s.split(" -- ", 2)
|
|
||||||
if parts.length == 2 && parts[1] == name
|
|
||||||
raise Errors::PluginLoadError, :plugin => name
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Get the string data out from the stdout/stderr captures
|
|
||||||
stderr = $stderr.string
|
|
||||||
stdout = $stdout.string
|
|
||||||
if !stderr.empty? || !stdout.empty?
|
|
||||||
raise Errors::PluginLoadFailedWithOutput,
|
|
||||||
:plugin => name,
|
|
||||||
:stderr => stderr,
|
|
||||||
:stdout => stdout
|
|
||||||
end
|
|
||||||
|
|
||||||
# And raise an error itself
|
|
||||||
raise Errors::PluginLoadFailed,
|
|
||||||
:plugin => name
|
|
||||||
end
|
|
||||||
|
|
||||||
# Log plugin version
|
|
||||||
gem = Gem::Specification.find { |spec| spec.name == name }
|
|
||||||
version = gem ? gem.version : "<unknown>"
|
|
||||||
logger.info("Loaded plugin #{name}, version #{version}")
|
|
||||||
ensure
|
|
||||||
$stderr = previous_stderr if previous_stderr
|
|
||||||
$stdout = previous_stdout if previous_stdout
|
|
||||||
end
|
|
||||||
|
|
||||||
# This allows a Vagrantfile to specify the version of Vagrant that is
|
|
||||||
# required. You can specify a list of requirements which will all be checked
|
|
||||||
# against the running Vagrant version.
|
|
||||||
#
|
|
||||||
# This should be specified at the _top_ of any Vagrantfile.
|
|
||||||
#
|
|
||||||
# Examples are shown below:
|
|
||||||
#
|
|
||||||
# Vagrant.require_version(">= 1.3.5")
|
|
||||||
# Vagrant.require_version(">= 1.3.5", "< 1.4.0")
|
|
||||||
# Vagrant.require_version("~> 1.3.5")
|
|
||||||
#
|
|
||||||
def self.require_version(*requirements)
|
|
||||||
logger = Log4r::Logger.new("vagrant::root")
|
|
||||||
logger.info("Version requirements from Vagrantfile: #{requirements.inspect}")
|
|
||||||
|
|
||||||
req = Gem::Requirement.new(*requirements)
|
|
||||||
if req.satisfied_by?(Gem::Version.new(VERSION))
|
|
||||||
logger.info(" - Version requirements satisfied!")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
raise Errors::VagrantVersionBad,
|
|
||||||
requirements: requirements.join(", "),
|
|
||||||
version: VERSION
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Default I18n to load the en locale
|
|
||||||
I18n.load_path << File.expand_path("templates/locales/en.yml", Vagrant.source_root)
|
|
||||||
|
|
||||||
if I18n.config.respond_to?(:enforce_available_locales=)
|
|
||||||
# Make sure only available locales are used. This will be the default in the
|
|
||||||
# future but we need this to silence a deprecation warning from 0.6.9
|
|
||||||
I18n.config.enforce_available_locales = true
|
|
||||||
end
|
|
||||||
|
|
||||||
# A lambda that knows how to load plugins from a single directory.
|
|
||||||
plugin_load_proc = lambda do |directory|
|
|
||||||
# We only care about directories
|
|
||||||
next false if !directory.directory?
|
|
||||||
|
|
||||||
# If there is a plugin file in the top-level directory, then load
|
|
||||||
# that up.
|
|
||||||
plugin_file = directory.join("plugin.rb")
|
|
||||||
if plugin_file.file?
|
|
||||||
global_logger.debug("Loading core plugin: #{plugin_file}")
|
|
||||||
load(plugin_file)
|
|
||||||
next true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Go through the `plugins` directory and attempt to load any plugins. The
|
|
||||||
# plugins are allowed to be in a directory in `plugins` or at most one
|
|
||||||
# directory deep within the plugins directory. So a plugin can be at
|
|
||||||
# `plugins/foo` or also at `plugins/foo/bar`, but no deeper.
|
|
||||||
Vagrant.source_root.join("plugins").children(true).each do |directory|
|
|
||||||
# Ignore non-directories
|
|
||||||
next if !directory.directory?
|
|
||||||
|
|
||||||
# Load from this directory, and exit if we successfully loaded a plugin
|
|
||||||
next if plugin_load_proc.call(directory)
|
|
||||||
|
|
||||||
# Otherwise, attempt to load from sub-directories
|
|
||||||
directory.children(true).each(&plugin_load_proc)
|
|
||||||
end
|
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
require "tempfile"
|
||||||
|
|
||||||
|
require_relative "paths"
|
||||||
|
require_relative "version"
|
||||||
|
|
||||||
|
module Vagrant
|
||||||
|
# This class manages Vagrant's interaction with Bundler. Vagrant uses
|
||||||
|
# Bundler as a way to properly resolve all dependencies of Vagrant and
|
||||||
|
# all Vagrant-installed plugins.
|
||||||
|
class Bundler
|
||||||
|
def self.instance
|
||||||
|
@bundler ||= self.new
|
||||||
|
end
|
||||||
|
|
||||||
|
# Initializes Bundler and the various gem paths so that we can begin
|
||||||
|
# loading gems. This must only be called once.
|
||||||
|
def init!(plugins)
|
||||||
|
raise "Bundler already initialized" if defined?(::Bundler)
|
||||||
|
|
||||||
|
# Setup the Bundler configuration
|
||||||
|
@configfile = Tempfile.new("vagrant-bundler-config")
|
||||||
|
@configfile.close
|
||||||
|
|
||||||
|
# Build up the Gemfile for our Bundler context
|
||||||
|
@gemfile = Tempfile.new("vagrant-gemfile")
|
||||||
|
@gemfile.puts(%Q[gem "vagrant", "= #{Vagrant::VERSION}"])
|
||||||
|
plugins.each do |plugin|
|
||||||
|
@gemfile.puts(%Q[gem "#{plugin}"])
|
||||||
|
end
|
||||||
|
@gemfile.close
|
||||||
|
|
||||||
|
# Set the environmental variables for Bundler
|
||||||
|
ENV["BUNDLE_CONFIG"] = @configfile.path
|
||||||
|
ENV["BUNDLE_GEMFILE"] = @gemfile.path
|
||||||
|
ENV["GEM_PATH"] =
|
||||||
|
"#{Vagrant.user_data_path.join("gems")}#{::File::PATH_SEPARATOR}#{ENV["GEM_PATH"]}"
|
||||||
|
Gem.clear_paths
|
||||||
|
|
||||||
|
# Load Bundler and setup our paths
|
||||||
|
require "bundler"
|
||||||
|
::Bundler.setup
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -128,9 +128,6 @@ module Vagrant
|
||||||
@default_private_key_path = @home_path.join("insecure_private_key")
|
@default_private_key_path = @home_path.join("insecure_private_key")
|
||||||
copy_insecure_private_key
|
copy_insecure_private_key
|
||||||
|
|
||||||
# Load the plugins
|
|
||||||
load_plugins
|
|
||||||
|
|
||||||
# Call the hooks that does not require configurations to be loaded
|
# Call the hooks that does not require configurations to be loaded
|
||||||
# by using a "clean" action runner
|
# by using a "clean" action runner
|
||||||
hook(:environment_plugins_loaded, runner: Action::Runner.new(env: self))
|
hook(:environment_plugins_loaded, runner: Action::Runner.new(env: self))
|
||||||
|
@ -591,7 +588,7 @@ module Vagrant
|
||||||
def setup_home_path
|
def setup_home_path
|
||||||
@home_path = Pathname.new(File.expand_path(@home_path ||
|
@home_path = Pathname.new(File.expand_path(@home_path ||
|
||||||
ENV["VAGRANT_HOME"] ||
|
ENV["VAGRANT_HOME"] ||
|
||||||
default_home_path))
|
Vagrant.user_data_path))
|
||||||
@logger.info("Home path: #{@home_path}")
|
@logger.info("Home path: #{@home_path}")
|
||||||
|
|
||||||
# Setup the list of child directories that need to be created if they
|
# Setup the list of child directories that need to be created if they
|
||||||
|
@ -691,23 +688,6 @@ module Vagrant
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# This returns the default home directory path for Vagrant, which
|
|
||||||
# can differ depending on the system.
|
|
||||||
#
|
|
||||||
# @return [Pathname]
|
|
||||||
def default_home_path
|
|
||||||
path = "~/.vagrant.d"
|
|
||||||
|
|
||||||
# On Windows, we default ot the USERPROFILE directory if it
|
|
||||||
# is available. This is more compatible with Cygwin and sharing
|
|
||||||
# the home directory across shells.
|
|
||||||
if Util::Platform.windows? && ENV["USERPROFILE"]
|
|
||||||
path = "#{ENV["USERPROFILE"]}/.vagrant.d"
|
|
||||||
end
|
|
||||||
|
|
||||||
Pathname.new(path)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Finds the Vagrantfile in the given directory.
|
# Finds the Vagrantfile in the given directory.
|
||||||
#
|
#
|
||||||
# @param [Pathname] path Path to search in.
|
# @param [Pathname] path Path to search in.
|
||||||
|
@ -722,55 +702,6 @@ module Vagrant
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
# Loads the Vagrant plugins by properly setting up RubyGems so that
|
|
||||||
# our private gem repository is on the 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}#{::File::PATH_SEPARATOR}#{ENV["GEM_PATH"]}"
|
|
||||||
::Gem.clear_paths
|
|
||||||
|
|
||||||
# If we're in a Bundler environment, don't load plugins. This only
|
|
||||||
# happens in plugin development environments.
|
|
||||||
if defined?(Bundler)
|
|
||||||
require 'bundler/shared_helpers'
|
|
||||||
if Bundler::SharedHelpers.in_bundle?
|
|
||||||
@logger.warn("In a bundler environment, not loading environment plugins!")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# This keeps track of the old plugins that need to be reinstalled
|
|
||||||
# because they were installed with an old version of Ruby.
|
|
||||||
reinstall = []
|
|
||||||
|
|
||||||
# Load the plugins
|
|
||||||
plugins_json_file = @home_path.join("plugins.json")
|
|
||||||
@logger.debug("Loading plugins from: #{plugins_json_file}")
|
|
||||||
state = VagrantPlugins::CommandPlugin::StateFile.new(plugins_json_file)
|
|
||||||
state.installed_plugins.each do |name, extra|
|
|
||||||
# If the Ruby version changed, then they need to reinstall the plugin
|
|
||||||
if extra["ruby_version"] != RUBY_VERSION
|
|
||||||
reinstall << name
|
|
||||||
next
|
|
||||||
end
|
|
||||||
|
|
||||||
@logger.info("Loading plugin from JSON: #{name}")
|
|
||||||
begin
|
|
||||||
Vagrant.require_plugin(name)
|
|
||||||
rescue Errors::PluginLoadError => e
|
|
||||||
@ui.error(e.message + "\n")
|
|
||||||
rescue Errors::PluginLoadFailed => e
|
|
||||||
@ui.error(e.message + "\n")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if !reinstall.empty?
|
|
||||||
@ui.warn(I18n.t("vagrant.plugin_needs_reinstall",
|
|
||||||
names: reinstall.join(", ")))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# This upgrades a Vagrant 1.0.x "dotfile" to the new V2 format.
|
# This upgrades a Vagrant 1.0.x "dotfile" to the new V2 format.
|
||||||
#
|
#
|
||||||
# This is a destructive process. Once the upgrade is complete, the
|
# This is a destructive process. Once the upgrade is complete, the
|
||||||
|
|
|
@ -0,0 +1,308 @@
|
||||||
|
require 'rubygems'
|
||||||
|
require 'log4r'
|
||||||
|
|
||||||
|
# Enable logging if it is requested. We do this before
|
||||||
|
# anything else so that we can setup the output before
|
||||||
|
# any logging occurs.
|
||||||
|
if ENV["VAGRANT_LOG"] && ENV["VAGRANT_LOG"] != ""
|
||||||
|
# Require Log4r and define the levels we'll be using
|
||||||
|
require 'log4r/config'
|
||||||
|
Log4r.define_levels(*Log4r::Log4rConfig::LogLevels)
|
||||||
|
|
||||||
|
level = nil
|
||||||
|
begin
|
||||||
|
level = Log4r.const_get(ENV["VAGRANT_LOG"].upcase)
|
||||||
|
rescue NameError
|
||||||
|
# This means that the logging constant wasn't found,
|
||||||
|
# which is fine. We just keep `level` as `nil`. But
|
||||||
|
# we tell the user.
|
||||||
|
level = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
# Some constants, such as "true" resolve to booleans, so the
|
||||||
|
# above error checking doesn't catch it. This will check to make
|
||||||
|
# sure that the log level is an integer, as Log4r requires.
|
||||||
|
level = nil if !level.is_a?(Integer)
|
||||||
|
|
||||||
|
if !level
|
||||||
|
# We directly write to stderr here because the VagrantError system
|
||||||
|
# is not setup yet.
|
||||||
|
$stderr.puts "Invalid VAGRANT_LOG level is set: #{ENV["VAGRANT_LOG"]}"
|
||||||
|
$stderr.puts ""
|
||||||
|
$stderr.puts "Please use one of the standard log levels: debug, info, warn, or error"
|
||||||
|
exit 1
|
||||||
|
end
|
||||||
|
|
||||||
|
# Set the logging level on all "vagrant" namespaced
|
||||||
|
# logs as long as we have a valid level.
|
||||||
|
if level
|
||||||
|
logger = Log4r::Logger.new("vagrant")
|
||||||
|
logger.outputters = Log4r::Outputter.stderr
|
||||||
|
logger.level = level
|
||||||
|
logger = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
require 'json'
|
||||||
|
require 'pathname'
|
||||||
|
require 'stringio'
|
||||||
|
|
||||||
|
require 'childprocess'
|
||||||
|
require 'i18n'
|
||||||
|
|
||||||
|
# OpenSSL must be loaded here since when it is loaded via `autoload`
|
||||||
|
# there are issues with ciphers not being properly loaded.
|
||||||
|
require 'openssl'
|
||||||
|
|
||||||
|
# Always make the version available
|
||||||
|
require 'vagrant/version'
|
||||||
|
global_logger = Log4r::Logger.new("vagrant::global")
|
||||||
|
global_logger.info("Vagrant version: #{Vagrant::VERSION}")
|
||||||
|
global_logger.info("Ruby version: #{RUBY_VERSION}")
|
||||||
|
global_logger.info("RubyGems version: #{Gem::VERSION}")
|
||||||
|
ENV.each do |k, v|
|
||||||
|
global_logger.info("#{k}=#{v.inspect}") if k =~ /^VAGRANT_/
|
||||||
|
end
|
||||||
|
|
||||||
|
# We need these components always so instead of an autoload we
|
||||||
|
# just require them explicitly here.
|
||||||
|
require "vagrant/registry"
|
||||||
|
|
||||||
|
module Vagrant
|
||||||
|
autoload :Action, 'vagrant/action'
|
||||||
|
autoload :BatchAction, 'vagrant/batch_action'
|
||||||
|
autoload :Box, 'vagrant/box'
|
||||||
|
autoload :BoxCollection, 'vagrant/box_collection'
|
||||||
|
autoload :CLI, 'vagrant/cli'
|
||||||
|
autoload :Command, 'vagrant/command'
|
||||||
|
autoload :Config, 'vagrant/config'
|
||||||
|
autoload :Driver, 'vagrant/driver'
|
||||||
|
autoload :Environment, 'vagrant/environment'
|
||||||
|
autoload :Errors, 'vagrant/errors'
|
||||||
|
autoload :Guest, 'vagrant/guest'
|
||||||
|
autoload :Hosts, 'vagrant/hosts'
|
||||||
|
autoload :Machine, 'vagrant/machine'
|
||||||
|
autoload :MachineState, 'vagrant/machine_state'
|
||||||
|
autoload :Plugin, 'vagrant/plugin'
|
||||||
|
autoload :UI, 'vagrant/ui'
|
||||||
|
autoload :Util, 'vagrant/util'
|
||||||
|
|
||||||
|
# These are the various plugin versions and their components in
|
||||||
|
# a lazy loaded Hash-like structure.
|
||||||
|
PLUGIN_COMPONENTS = Registry.new.tap do |c|
|
||||||
|
c.register(:"1") { Plugin::V1::Plugin }
|
||||||
|
c.register([:"1", :command]) { Plugin::V1::Command }
|
||||||
|
c.register([:"1", :communicator]) { Plugin::V1::Communicator }
|
||||||
|
c.register([:"1", :config]) { Plugin::V1::Config }
|
||||||
|
c.register([:"1", :guest]) { Plugin::V1::Guest }
|
||||||
|
c.register([:"1", :host]) { Plugin::V1::Host }
|
||||||
|
c.register([:"1", :provider]) { Plugin::V1::Provider }
|
||||||
|
c.register([:"1", :provisioner]) { Plugin::V1::Provisioner }
|
||||||
|
|
||||||
|
c.register(:"2") { Plugin::V2::Plugin }
|
||||||
|
c.register([:"2", :command]) { Plugin::V2::Command }
|
||||||
|
c.register([:"2", :communicator]) { Plugin::V2::Communicator }
|
||||||
|
c.register([:"2", :config]) { Plugin::V2::Config }
|
||||||
|
c.register([:"2", :guest]) { Plugin::V2::Guest }
|
||||||
|
c.register([:"2", :host]) { Plugin::V2::Host }
|
||||||
|
c.register([:"2", :provider]) { Plugin::V2::Provider }
|
||||||
|
c.register([:"2", :provisioner]) { Plugin::V2::Provisioner }
|
||||||
|
c.register([:"2", :synced_folder]) { Plugin::V2::SyncedFolder }
|
||||||
|
end
|
||||||
|
|
||||||
|
# This returns a true/false showing whether we're running from the
|
||||||
|
# environment setup by the Vagrant installers.
|
||||||
|
#
|
||||||
|
# @return [Boolean]
|
||||||
|
def self.in_installer?
|
||||||
|
!!ENV["VAGRANT_INSTALLER_ENV"]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Configure a Vagrant environment. The version specifies the version
|
||||||
|
# of the configuration that is expected by the block. The block, based
|
||||||
|
# on that version, configures the environment.
|
||||||
|
#
|
||||||
|
# Note that the block isn't run immediately. Instead, the configuration
|
||||||
|
# block is stored until later, and is run when an environment is loaded.
|
||||||
|
#
|
||||||
|
# @param [String] version Version of the configuration
|
||||||
|
def self.configure(version, &block)
|
||||||
|
Config.run(version, &block)
|
||||||
|
end
|
||||||
|
|
||||||
|
# This checks if a plugin with the given name is installed. This can
|
||||||
|
# be used from the Vagrantfile to easily branch based on plugin
|
||||||
|
# availability.
|
||||||
|
def self.has_plugin?(name)
|
||||||
|
manager = plugin("2").manager
|
||||||
|
|
||||||
|
manager.required.any? { |gem_name| gem_name == name } ||
|
||||||
|
manager.registered.any? { |plugin| plugin.name == name }
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns a superclass to use when creating a plugin for Vagrant.
|
||||||
|
# Given a specific version, this returns a proper superclass to use
|
||||||
|
# to register plugins for that version.
|
||||||
|
#
|
||||||
|
# Optionally, if you give a specific component, then it will return
|
||||||
|
# the proper superclass for that component as well.
|
||||||
|
#
|
||||||
|
# Plugins and plugin components should subclass the classes returned by
|
||||||
|
# this method. This method lets Vagrant core control these superclasses
|
||||||
|
# and change them over time without affecting plugins. For example, if
|
||||||
|
# the V1 superclass happens to be "Vagrant::V1," future versions of
|
||||||
|
# Vagrant may move it to "Vagrant::Plugins::V1" and plugins will not be
|
||||||
|
# affected.
|
||||||
|
#
|
||||||
|
# @param [String] version
|
||||||
|
# @param [String] component
|
||||||
|
# @return [Class]
|
||||||
|
def self.plugin(version, component=nil)
|
||||||
|
# Build up the key and return a result
|
||||||
|
key = version.to_s.to_sym
|
||||||
|
key = [key, component.to_s.to_sym] if component
|
||||||
|
result = PLUGIN_COMPONENTS.get(key)
|
||||||
|
|
||||||
|
# If we found our component then we return that
|
||||||
|
return result if result
|
||||||
|
|
||||||
|
# If we didn't find a result, then raise an exception, depending
|
||||||
|
# on if we got a component or not.
|
||||||
|
raise ArgumentError, "Plugin superclass not found for version/component: " +
|
||||||
|
"#{version} #{component}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# This should be used instead of Ruby's built-in `require` in order to
|
||||||
|
# load a Vagrant plugin. This will load the given plugin by first doing
|
||||||
|
# a normal `require`, giving a nice error message if things go wrong,
|
||||||
|
# and second by verifying that a Vagrant plugin was actually defined in
|
||||||
|
# the process.
|
||||||
|
#
|
||||||
|
# @param [String] name Name of the plugin to load.
|
||||||
|
def self.require_plugin(name)
|
||||||
|
logger = Log4r::Logger.new("vagrant::root")
|
||||||
|
|
||||||
|
if ENV["VAGRANT_NO_PLUGINS"]
|
||||||
|
logger.warn("VAGRANT_NO_PLUGINS is set, not loading 3rd party plugin: #{name}")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# Redirect stdout/stderr so that we can output it in our own way.
|
||||||
|
previous_stderr = $stderr
|
||||||
|
previous_stdout = $stdout
|
||||||
|
$stderr = StringIO.new
|
||||||
|
$stdout = StringIO.new
|
||||||
|
|
||||||
|
# Attempt the normal require
|
||||||
|
begin
|
||||||
|
require name
|
||||||
|
plugin("2").manager.plugin_required(name)
|
||||||
|
rescue Exception => e
|
||||||
|
# Since this is a rare case, we create a one-time logger here
|
||||||
|
# in order to output the error
|
||||||
|
logger.error("Failed to load plugin: #{name}")
|
||||||
|
logger.error(" -- Error: #{e.inspect}")
|
||||||
|
logger.error(" -- Backtrace:")
|
||||||
|
logger.error(e.backtrace.join("\n"))
|
||||||
|
|
||||||
|
# If it is a LoadError we first try to see if it failed loading
|
||||||
|
# the top-level entrypoint. If so, then we report a different error.
|
||||||
|
if e.is_a?(LoadError)
|
||||||
|
# Parse the message in order to get what failed to load, and
|
||||||
|
# add some extra protection around if the message is different.
|
||||||
|
parts = e.to_s.split(" -- ", 2)
|
||||||
|
if parts.length == 2 && parts[1] == name
|
||||||
|
raise Errors::PluginLoadError, :plugin => name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Get the string data out from the stdout/stderr captures
|
||||||
|
stderr = $stderr.string
|
||||||
|
stdout = $stdout.string
|
||||||
|
if !stderr.empty? || !stdout.empty?
|
||||||
|
raise Errors::PluginLoadFailedWithOutput,
|
||||||
|
:plugin => name,
|
||||||
|
:stderr => stderr,
|
||||||
|
:stdout => stdout
|
||||||
|
end
|
||||||
|
|
||||||
|
# And raise an error itself
|
||||||
|
raise Errors::PluginLoadFailed,
|
||||||
|
:plugin => name
|
||||||
|
end
|
||||||
|
|
||||||
|
# Log plugin version
|
||||||
|
gem = Gem::Specification.find { |spec| spec.name == name }
|
||||||
|
version = gem ? gem.version : "<unknown>"
|
||||||
|
logger.info("Loaded plugin #{name}, version #{version}")
|
||||||
|
ensure
|
||||||
|
$stderr = previous_stderr if previous_stderr
|
||||||
|
$stdout = previous_stdout if previous_stdout
|
||||||
|
end
|
||||||
|
|
||||||
|
# This allows a Vagrantfile to specify the version of Vagrant that is
|
||||||
|
# required. You can specify a list of requirements which will all be checked
|
||||||
|
# against the running Vagrant version.
|
||||||
|
#
|
||||||
|
# This should be specified at the _top_ of any Vagrantfile.
|
||||||
|
#
|
||||||
|
# Examples are shown below:
|
||||||
|
#
|
||||||
|
# Vagrant.require_version(">= 1.3.5")
|
||||||
|
# Vagrant.require_version(">= 1.3.5", "< 1.4.0")
|
||||||
|
# Vagrant.require_version("~> 1.3.5")
|
||||||
|
#
|
||||||
|
def self.require_version(*requirements)
|
||||||
|
logger = Log4r::Logger.new("vagrant::root")
|
||||||
|
logger.info("Version requirements from Vagrantfile: #{requirements.inspect}")
|
||||||
|
|
||||||
|
req = Gem::Requirement.new(*requirements)
|
||||||
|
if req.satisfied_by?(Gem::Version.new(VERSION))
|
||||||
|
logger.info(" - Version requirements satisfied!")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
raise Errors::VagrantVersionBad,
|
||||||
|
requirements: requirements.join(", "),
|
||||||
|
version: VERSION
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Default I18n to load the en locale
|
||||||
|
I18n.load_path << File.expand_path("templates/locales/en.yml", Vagrant.source_root)
|
||||||
|
|
||||||
|
if I18n.config.respond_to?(:enforce_available_locales=)
|
||||||
|
# Make sure only available locales are used. This will be the default in the
|
||||||
|
# future but we need this to silence a deprecation warning from 0.6.9
|
||||||
|
I18n.config.enforce_available_locales = true
|
||||||
|
end
|
||||||
|
|
||||||
|
# A lambda that knows how to load plugins from a single directory.
|
||||||
|
plugin_load_proc = lambda do |directory|
|
||||||
|
# We only care about directories
|
||||||
|
next false if !directory.directory?
|
||||||
|
|
||||||
|
# If there is a plugin file in the top-level directory, then load
|
||||||
|
# that up.
|
||||||
|
plugin_file = directory.join("plugin.rb")
|
||||||
|
if plugin_file.file?
|
||||||
|
global_logger.debug("Loading core plugin: #{plugin_file}")
|
||||||
|
load(plugin_file)
|
||||||
|
next true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Go through the `plugins` directory and attempt to load any plugins. The
|
||||||
|
# plugins are allowed to be in a directory in `plugins` or at most one
|
||||||
|
# directory deep within the plugins directory. So a plugin can be at
|
||||||
|
# `plugins/foo` or also at `plugins/foo/bar`, but no deeper.
|
||||||
|
Vagrant.source_root.join("plugins").children(true).each do |directory|
|
||||||
|
# Ignore non-directories
|
||||||
|
next if !directory.directory?
|
||||||
|
|
||||||
|
# Load from this directory, and exit if we successfully loaded a plugin
|
||||||
|
next if plugin_load_proc.call(directory)
|
||||||
|
|
||||||
|
# Otherwise, attempt to load from sub-directories
|
||||||
|
directory.children(true).each(&plugin_load_proc)
|
||||||
|
end
|
|
@ -0,0 +1,26 @@
|
||||||
|
require "pathname"
|
||||||
|
|
||||||
|
module Vagrant
|
||||||
|
# The source root is the path to the root directory of
|
||||||
|
# the Vagrant gem.
|
||||||
|
def self.source_root
|
||||||
|
@source_root ||= Pathname.new(File.expand_path('../../../', __FILE__))
|
||||||
|
end
|
||||||
|
|
||||||
|
# This returns the path to the ~/.vagrant.d folder where Vagrant's
|
||||||
|
# per-user state is stored.
|
||||||
|
#
|
||||||
|
# @return [Pathname]
|
||||||
|
def self.user_data_path
|
||||||
|
path = "~/.vagrant.d"
|
||||||
|
|
||||||
|
# On Windows, we default ot the USERPROFILE directory if it
|
||||||
|
# is available. This is more compatible with Cygwin and sharing
|
||||||
|
# the home directory across shells.
|
||||||
|
if ENV["USERPROFILE"]
|
||||||
|
path = "#{ENV["USERPROFILE"]}/.vagrant.d"
|
||||||
|
end
|
||||||
|
|
||||||
|
return Pathname.new(path).expand_path
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,16 @@
|
||||||
|
require "json"
|
||||||
|
|
||||||
|
require_relative "paths"
|
||||||
|
|
||||||
|
module Vagrant
|
||||||
|
class PluginManager
|
||||||
|
def self.global_plugins_file
|
||||||
|
Vagrant.user_data_path.join("plugins.json")
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.plugins
|
||||||
|
plugins = JSON.parse(global_plugins_file.read)
|
||||||
|
plugins["installed"].keys
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -14,6 +14,7 @@ Gem::Specification.new do |s|
|
||||||
s.required_rubygems_version = ">= 1.3.6"
|
s.required_rubygems_version = ">= 1.3.6"
|
||||||
s.rubyforge_project = "vagrant"
|
s.rubyforge_project = "vagrant"
|
||||||
|
|
||||||
|
s.add_dependency "bundler", "~> 1.5.1"
|
||||||
s.add_dependency "childprocess", "~> 0.3.7"
|
s.add_dependency "childprocess", "~> 0.3.7"
|
||||||
s.add_dependency "erubis", "~> 2.7.0"
|
s.add_dependency "erubis", "~> 2.7.0"
|
||||||
s.add_dependency "i18n", "~> 0.6.0"
|
s.add_dependency "i18n", "~> 0.6.0"
|
||||||
|
@ -25,8 +26,6 @@ Gem::Specification.new do |s|
|
||||||
s.add_development_dependency "contest", ">= 0.1.2"
|
s.add_development_dependency "contest", ">= 0.1.2"
|
||||||
s.add_development_dependency "minitest", "~> 2.5.1"
|
s.add_development_dependency "minitest", "~> 2.5.1"
|
||||||
s.add_development_dependency "mocha"
|
s.add_development_dependency "mocha"
|
||||||
# This has problems on Windows, we need to find a better way:
|
|
||||||
# s.add_development_dependency "sys-proctable", "~> 0.9.0"
|
|
||||||
s.add_development_dependency "rspec", "~> 2.14.0"
|
s.add_development_dependency "rspec", "~> 2.14.0"
|
||||||
|
|
||||||
# The following block of code determines the files that should be included
|
# The following block of code determines the files that should be included
|
||||||
|
|
Loading…
Reference in New Issue