diff --git a/lib/vagrant/cli.rb b/lib/vagrant/cli.rb index cca8c0184..920828407 100644 --- a/lib/vagrant/cli.rb +++ b/lib/vagrant/cli.rb @@ -4,12 +4,14 @@ require 'optparse' module Vagrant # Manages the command line interface to Vagrant. class CLI < Vagrant.plugin("2", :command) + def initialize(argv, env) super @logger = Log4r::Logger.new("vagrant::cli") @main_args, @sub_command, @sub_args = split_main_and_subcommand(argv) + Util::CheckpointClient.instance.setup(env).check @logger.info("CLI: #{@main_args.inspect} #{@sub_command.inspect} #{@sub_args.inspect}") end @@ -36,6 +38,8 @@ module Vagrant command_class = command_plugin[0].call @logger.debug("Invoking command class: #{command_class} #{@sub_args.inspect}") + Util::CheckpointClient.instance.display + # Initialize and execute the command class, returning the exit status. result = 0 begin diff --git a/lib/vagrant/util.rb b/lib/vagrant/util.rb index cef24e8ad..32babe50d 100644 --- a/lib/vagrant/util.rb +++ b/lib/vagrant/util.rb @@ -1,6 +1,7 @@ module Vagrant module Util autoload :Busy, 'vagrant/util/busy' + autoload :CheckpointClient, 'vagrant/util/checkpoint_client' autoload :CommandDeprecation, 'vagrant/util/command_deprecation' autoload :Counter, 'vagrant/util/counter' autoload :CredentialScrubber, 'vagrant/util/credential_scrubber' diff --git a/lib/vagrant/util/checkpoint_client.rb b/lib/vagrant/util/checkpoint_client.rb new file mode 100644 index 000000000..7df5bf170 --- /dev/null +++ b/lib/vagrant/util/checkpoint_client.rb @@ -0,0 +1,174 @@ +require "log4r" +require "singleton" + +module Vagrant + module Util + class CheckpointClient + + include Singleton + + # Maximum number of seconds to wait for check to complete + CHECKPOINT_TIMEOUT = 10 + + # @return [Log4r::Logger] + attr_reader :logger + + # @return [Boolean] + attr_reader :enabled + + # @return [Hash] + attr_reader :files + + # @return [Vagrant::Environment] + attr_reader :env + + def initialize + @logger = Log4r::Logger.new("vagrant::checkpoint_client") + @enabled = false + end + + # Setup will attempt to load the checkpoint library and define + # required paths + # + # @param [Vagrant::Environment] env + # @return [self] + def setup(env) + begin + require "checkpoint" + @enabled = true + rescue LoadError + @logger.warn("checkpoint library not found. disabling.") + end + @files = { + signature: env.data_dir.join("checkpoint_signature"), + cache: env.data_dir.join("checkpoint_cache") + } + @checkpoint_thread = nil + @env = env + self + end + + # Start checkpoint check + # + # @return [self] + def check + start_check + self + end + + # Check has completed + def complete? + !@checkpoint_thread.nil? && !@checkpoint_thread.alive? + end + + # Result of check + # + # @return [Hash, nil] + def result + if !enabled || @checkpoint_thread.nil? + nil + elsif !defined?(@result) + @checkpoint_thread.join(CHECKPOINT_TIMEOUT) + @result = @checkpoint_thread[:result] + else + @result + end + end + + # Run check + # + # @return [self] + def start_check + if enabled && @checkpoint_thread.nil? + logger.debug("starting plugin check") + @checkpoint_thread = Thread.new do + begin + Thread.current[:result] = Checkpoint.check( + product: "vagrant", + version: VERSION, + signature_file: files[:signature], + cache_file: files[:cache] + ) + if !Thread.current[:result].is_a?(Hash) + Thread.current[:result] = nil + end + logger.debug("plugin check complete") + rescue => e + logger.debug("plugin check failure - #{e}") + end + end + end + self + end + + # Display any alerts or version update information + # + # @return [boolean] true if displayed, false if not + def display + if !defined?(@displayed) + if !complete? + @logger.debug("waiting for checkpoint to complete...") + end + # Don't display if information is cached + if result && !result["cached"] + version_check + alerts_check + else + @logger.debug("no information received from checkpoint") + end + @displayed = true + else + false + end + end + + def alerts_check + if result["alerts"] && !result["alerts"].empty? + result["alerts"].group_by{|a| a["level"]}.each_pair do |_, alerts| + alerts.each do |alert| + date = nil + begin + date = Time.at(alert["date"]) + rescue + date = Time.now + end + output = I18n.t("vagrant.alert", + message: alert["message"], + date: date, + url: alert["url"] + ) + case alert["level"] + when "info" + alert_ui = Vagrant::UI::Prefixed.new(env.ui, "vagrant") + alert_ui.info(output) + when "warn" + alert_ui = Vagrant::UI::Prefixed.new(env.ui, "vagrant-warning") + alert_ui.warn(output) + when "critical" + alert_ui = Vagrant::UI::Prefixed.new(env.ui, "vagrant-alert") + alert_ui.error(output) + end + end + env.ui.info("") + end + else + @logger.debug("no alert notifications to display") + end + end + + def version_check + latest_version = Gem::Version.new(result["current_version"]) + installed_version = Gem::Version.new(VERSION) + ui = Vagrant::UI::Prefixed.new(env.ui, "vagrant") + if latest_version > installed_version + @logger.info("new version of Vagrant available - #{latest_version}") + ui.info(I18n.t("vagrant.version_upgrade_available", latest_version: latest_version)) + env.ui.info("") + else + @logger.debug("vagrant is currently up to date") + end + end + + end + end +end diff --git a/plugins/commands/version/command.rb b/plugins/commands/version/command.rb index c3c47acfa..95c818b48 100644 --- a/plugins/commands/version/command.rb +++ b/plugins/commands/version/command.rb @@ -22,7 +22,7 @@ module VagrantPlugins @env.ui.machine("version-installed", Vagrant::VERSION) # Load the latest information - cp = @env.checkpoint + cp = Vagrant::Util::CheckpointClient.instance.result if !cp @env.ui.output("\n"+I18n.t( "vagrant.version_no_checkpoint")) diff --git a/templates/locales/en.yml b/templates/locales/en.yml index d8a6986c0..90eced48f 100644 --- a/templates/locales/en.yml +++ b/templates/locales/en.yml @@ -1,5 +1,10 @@ en: vagrant: + alert: |- + [%{date}]: + %{message} + + - %{url} boot_completed: |- Machine booted and ready! boot_waiting: |- @@ -283,6 +288,10 @@ en: version_no_checkpoint: |- Vagrant was unable to check for the latest version of Vagrant. Please check manually at https://www.vagrantup.com + version_upgrade_available: |- + A new version of Vagrant is available: %{latest_version}! + To upgrade visit: https://www.vagrantup.com/downloads.html + version_upgrade_howto: |- To upgrade to the latest version, visit the downloads page and download and install the latest version of Vagrant from the URL diff --git a/vagrant.gemspec b/vagrant.gemspec index 13a08c513..d26b32adf 100644 --- a/vagrant.gemspec +++ b/vagrant.gemspec @@ -20,7 +20,7 @@ Gem::Specification.new do |s| s.add_dependency "erubis", "~> 2.7.0" s.add_dependency "i18n", ">= 0.6.0", "<= 0.8.0" s.add_dependency "listen", "~> 3.1.5" - s.add_dependency "hashicorp-checkpoint", "~> 0.1.1" + s.add_dependency "hashicorp-checkpoint", "~> 0.1.5" s.add_dependency "log4r", "~> 1.1.9", "< 1.1.11" s.add_dependency "net-ssh", "~> 4.2.0" s.add_dependency "net-sftp", "~> 2.1"