From b8702ac8899f960e75361c4e874ef30da38c815c Mon Sep 17 00:00:00 2001 From: Chris Roberts Date: Fri, 27 Mar 2020 09:58:33 -0700 Subject: [PATCH] Include default options in option parser Adds method to shared helpers for adding procs to be evaluated which can add default modifications to the option parser used by commands. Customized option parser class within Vagrant handles processing defined procs to set options. --- bin/vagrant | 11 +++++++ lib/vagrant.rb | 25 +++++++++++++++ lib/vagrant/plugin/v2/command.rb | 2 +- lib/vagrant/shared_helpers.rb | 28 +++++++++++++++++ test/unit/bin/vagrant_test.rb | 16 ++++++++++ test/unit/vagrant/shared_helpers_test.rb | 40 ++++++++++++++++++------ 6 files changed, 112 insertions(+), 10 deletions(-) diff --git a/bin/vagrant b/bin/vagrant index 272b4ea68..5f6725b50 100755 --- a/bin/vagrant +++ b/bin/vagrant @@ -99,6 +99,17 @@ begin $VERBOSE = nil end + # Add any option flags defined within this file here + # so they are automatically propagated to all commands + Vagrant.add_default_cli_options(proc { |o| + o.on("--[no-]color", "Enable or disable color output") + o.on("--machine-readable", "Enable machine readable output") + o.on("-v", "--version", "Display Vagrant version") + o.on("--debug", "Enable debug output") + o.on("--timestamp", "Enable timestamps on log output") + o.on("--debug-timestamp", "Enable debug output with timestamps") + }) + # Create a logger right away logger = Log4r::Logger.new("vagrant::bin::vagrant") logger.info("`vagrant` invoked: #{ARGV.inspect}") diff --git a/lib/vagrant.rb b/lib/vagrant.rb index 66840226f..98dcac650 100644 --- a/lib/vagrant.rb +++ b/lib/vagrant.rb @@ -9,6 +9,31 @@ class Log4r::BasicFormatter end end + +require "optparse" + +module Vagrant + # This is a customized OptionParser for Vagrant plugins. It + # will automatically add any default CLI options defined + # outside of command implementations to the local option + # parser instances in use + class OptionParser < ::OptionParser + def initialize(*_) + super + Vagrant.default_cli_options.each do |opt_proc| + opt_proc.call(self) + end + end + end +end + +# Inject the option parser into the vagrant plugins +# module so it is automatically used when defining +# command options +module VagrantPlugins + OptionParser = Vagrant::OptionParser +end + require "vagrant/shared_helpers" require "rubygems" require "vagrant/util" diff --git a/lib/vagrant/plugin/v2/command.rb b/lib/vagrant/plugin/v2/command.rb index 5b39ef49f..967dbda0f 100644 --- a/lib/vagrant/plugin/v2/command.rb +++ b/lib/vagrant/plugin/v2/command.rb @@ -51,7 +51,7 @@ module Vagrant argv = @argv.dup # Default opts to a blank optionparser if none is given - opts ||= OptionParser.new + opts ||= Vagrant::OptionParser.new # Add the help option, which must be on every command. opts.on_tail("-h", "--help", "Print this help") do diff --git a/lib/vagrant/shared_helpers.rb b/lib/vagrant/shared_helpers.rb index 5cab18f39..4bcfaadf0 100644 --- a/lib/vagrant/shared_helpers.rb +++ b/lib/vagrant/shared_helpers.rb @@ -186,4 +186,32 @@ module Vagrant end @_global_logger end + + # Add a new block of default CLI options which + # should be automatically added to all commands + # + # @param [Proc] block Proc instance containing OptParser configuration + # @return [nil] + def self.add_default_cli_options(block) + if !block.is_a?(Proc) + raise TypeError, + "Expecting type `Proc` but received `#{block.class}`" + end + if block.arity != 1 && block.arity != -1 + raise ArgumentError, + "Proc must accept OptionParser argument" + end + @_default_cli_options = [] if !@_default_cli_options + @_default_cli_options << block + nil + end + + # Array of default CLI options to automatically + # add to commands. + # + # @return [Array] Default optparse options + def self.default_cli_options + @_default_cli_options = [] if !@_default_cli_options + @_default_cli_options.dup + end end diff --git a/test/unit/bin/vagrant_test.rb b/test/unit/bin/vagrant_test.rb index 08edcb20e..d3f0b19ca 100644 --- a/test/unit/bin/vagrant_test.rb +++ b/test/unit/bin/vagrant_test.rb @@ -93,6 +93,22 @@ describe "vagrant bin" do end end + context "default CLI flags" do + let(:argv) { ["--help"] } + + before do + allow(env).to receive(:ui).and_return(ui) + allow(ARGV).to receive(:dup).and_return(argv) + allow(Kernel).to receive(:at_exit) + allow(Kernel).to receive(:exit) + allow(Vagrant::Environment).to receive(:new).and_call_original + end + + it "should include default CLI flags in command help output" do + expect($stdout).to receive(:puts).with(/--debug/) + end + end + context "when not in installer" do let(:warning) { "INSTALLER WARNING" } diff --git a/test/unit/vagrant/shared_helpers_test.rb b/test/unit/vagrant/shared_helpers_test.rb index 7ff41e6a6..fda3bc073 100644 --- a/test/unit/vagrant/shared_helpers_test.rb +++ b/test/unit/vagrant/shared_helpers_test.rb @@ -8,14 +8,14 @@ describe Vagrant do subject { described_class } - describe "#global_lock" do + describe ".global_lock" do it "yields to the block" do result = subject.global_lock { 42 } expect(result).to eq(42) end end - describe "#in_installer?" do + describe ".in_installer?" do it "is not if env is not set" do with_temp_env("VAGRANT_INSTALLER_ENV" => nil) do expect(subject.in_installer?).to be(false) @@ -29,7 +29,7 @@ describe Vagrant do end end - describe "#installer_embedded_dir" do + describe ".installer_embedded_dir" do it "returns nil if not in an installer" do allow(Vagrant).to receive(:in_installer?).and_return(false) expect(subject.installer_embedded_dir).to be_nil @@ -44,7 +44,7 @@ describe Vagrant do end end - describe "#plugins_enabled?" do + describe ".plugins_enabled?" do it "returns true if the env is not set" do with_temp_env("VAGRANT_NO_PLUGINS" => nil) do expect(subject.plugins_enabled?).to be(true) @@ -58,7 +58,7 @@ describe Vagrant do end end - describe "#server_url" do + describe ".server_url" do it "defaults to the default value" do with_temp_env("VAGRANT_SERVER_URL" => nil) do expect(subject.server_url).to eq( @@ -92,7 +92,7 @@ describe Vagrant do end end - describe "#user_data_path" do + describe ".user_data_path" do around do |example| env = { "USERPROFILE" => nil, @@ -132,7 +132,7 @@ describe Vagrant do end end - describe "#prerelease?" do + describe ".prerelease?" do it "should return true when Vagrant version is development" do stub_const("Vagrant::VERSION", "1.0.0.dev") expect(subject.prerelease?).to be(true) @@ -144,7 +144,7 @@ describe Vagrant do end end - describe "#enable_resolv_replace" do + describe ".enable_resolv_replace" do it "should not attempt to require resolv-replace by default" do expect(subject).not_to receive(:require).with("resolv-replace") subject.enable_resolv_replace @@ -163,7 +163,7 @@ describe Vagrant do end end - describe "#global_logger" do + describe ".global_logger" do after{ subject.global_logger = nil } it "should return a logger when none have been provided" do @@ -176,4 +176,26 @@ describe Vagrant do expect(subject.global_logger).to eq(logger) end end + + describe ".add_default_cli_options" do + it "should raise a type error when no provided with proc" do + expect { subject.add_default_cli_options(true) }. + to raise_error(TypeError) + end + + it "should raise an argument error when proc does not accept argument" do + expect { subject.add_default_cli_options(proc{}) }. + to raise_error(ArgumentError) + end + + it "should accept a proc type argument" do + expect(subject.add_default_cli_options(proc{|o|})).to be_nil + end + end + + describe ".default_cli_options" do + it "should return array of items" do + expect(subject.default_cli_options).to be_a(Array) + end + end end