lib/kitchen/command.rb in test-kitchen-1.2.1 vs lib/kitchen/command.rb in test-kitchen-1.3.0

- old
+ new

@@ -14,11 +14,11 @@ # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -require 'thread' +require "thread" module Kitchen module Command @@ -27,47 +27,98 @@ # @author Fletcher Nichol <fnichol@nichol.ca> class Base include Logging + # Contstructs a new Command object. + # + # @param cmd_args [Array] remainder of the arguments from processed ARGV + # @param cmd_options [Hash] hash of Thor options + # @param options [Hash] configuration options + # @option options [String] :action action to take, usually corresponding + # to the subcommand name (default: `nil`) + # @option options [proc] :help a callable that displays help for the + # command + # @option options [Config] :config a Config object (default: `nil`) + # @option options [Loader] :loader a Loader object (default: `nil`) + # @option options [String] :shell a Thor shell object def initialize(cmd_args, cmd_options, options = {}) @args = cmd_args @options = cmd_options @action = options.fetch(:action, nil) - @help = options.fetch(:help, lambda { "No help provided" }) + @help = options.fetch(:help, -> { "No help provided" }) @config = options.fetch(:config, nil) @loader = options.fetch(:loader, nil) @shell = options.fetch(:shell) end - protected + private - attr_reader :args, :options, :help, :config, :shell, :action + # @return [Array] remainder of the arguments from processed ARGV + # @api private + attr_reader :args + # @return [Hash] hash of Thor options + # @api private + attr_reader :options + + # @return [proc] a callable that displays help for the command + # @api private + attr_reader :help + + # @return [Config] a Config object + # @api private + attr_reader :config + + # @return [Thor::Shell] a Thor shell object + # @api private + attr_reader :shell + + # @return [String] the action to perform + # @api private + attr_reader :action + + # Emit an error message, display contextual help and then exit with a + # non-zero exit code. + # + # **Note** This method calls exit and will not return. + # + # @param msg [String] error message + # @api private def die(msg) error "\n#{msg}\n\n" help.call exit 1 end - def get_all_instances + # @return [Array<Instance>] an array of instances + # @raise [SystemExit] if no instances are returned + # @api private + def all_instances result = @config.instances if result.empty? die "No instances defined" else result end end - def get_filtered_instances(regexp) + # Return an array on instances whos name matches the regular expression. + # + # @param regexp [Regexp] a regular expression matching on instance names + # @return [Array<Instance>] an array of instances + # @raise [SystemExit] if no instances are returned or the regular + # expression is invalid + # @api private + def filtered_instances(regexp) result = begin @config.instances.get(regexp) || @config.instances.get_all(/#{regexp}/) rescue RegexpError => e - die "Invalid Ruby regular expression, " + - "you may need to single quote the argument. " + + die "Invalid Ruby regular expression, " \ + "you may need to single quote the argument. " \ "Please try again or consult http://rubular.com/ (#{e.message})" end result = Array(result) if result.empty? @@ -75,43 +126,59 @@ else result end end + # @return [Logger] the common logger + # @api private def logger Kitchen.logger end + # Return an array on instances whos name matches the regular expression, + # the full instance name, or the `"all"` literal. + # + # @param arg [String] an instance name, a regular expression, the literal + # `"all"`, or `nil` + # @return [Array<Instance>] an array of instances + # @api private def parse_subcommand(arg = nil) - arg == "all" ? get_all_instances : get_filtered_instances(arg) + arg == "all" ? all_instances : filtered_instances(arg) end end # Common module to execute a Kitchen action such as create, converge, etc. # # @author Fletcher Nichol <fnichol@nichol.ca> module RunAction + # Run an instance action (create, converge, setup, verify, destroy) on + # a collection of instances. The instance actions will take place in a + # seperate thread of execution which may or may not be running + # concurrently. + # + # @param action [String] action to perform + # @param instances [Array<Instance>] an array of instances def run_action(action, instances, *args) concurrency = 1 if options[:concurrency] concurrency = options[:concurrency] || instances.size concurrency = instances.size if concurrency > instances.size end queue = Queue.new - instances.each {|i| queue << i } + instances.each { |i| queue << i } concurrency.times { queue << nil } threads = [] concurrency.times do threads << Thread.new do while instance = queue.pop instance.public_send(action, *args) end end end - threads.map { |i| i.join } + threads.map(&:join) end end end end