lib/kitchen/command.rb in test-kitchen-1.6.0 vs lib/kitchen/command.rb in test-kitchen-1.7.0

- old
+ new

@@ -1,185 +1,185 @@ -# -*- encoding: utf-8 -*- -# -# Author:: Fletcher Nichol (<fnichol@nichol.ca>) -# -# Copyright (C) 2013, Fletcher Nichol -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# 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" - -module Kitchen - - module Command - - # Base class for CLI commands. - # - # @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, -> { "No help provided" }) - @config = options.fetch(:config, nil) - @loader = options.fetch(:loader, nil) - @shell = options.fetch(:shell) - end - - private - - # @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 - - # @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 - - # 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. " \ - "Please try again or consult http://rubular.com/ (#{e.message})" - end - result = Array(result) - - if result.empty? - die "No instances for regex `#{regexp}', try running `kitchen list'" - 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" ? 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 } - concurrency.times { queue << nil } - - threads = [] - concurrency.times do - threads << Thread.new do - while instance = queue.pop - instance.public_send(action, *args) - instance.cleanup! - end - end - end - threads.map(&:join) - end - end - end -end +# -*- encoding: utf-8 -*- +# +# Author:: Fletcher Nichol (<fnichol@nichol.ca>) +# +# Copyright (C) 2013, Fletcher Nichol +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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" + +module Kitchen + + module Command + + # Base class for CLI commands. + # + # @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, -> { "No help provided" }) + @config = options.fetch(:config, nil) + @loader = options.fetch(:loader, nil) + @shell = options.fetch(:shell) + end + + private + + # @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 + + # @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 + + # 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. " \ + "Please try again or consult http://rubular.com/ (#{e.message})" + end + result = Array(result) + + if result.empty? + die "No instances for regex `#{regexp}', try running `kitchen list'" + 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" ? 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 } + concurrency.times { queue << nil } + + threads = [] + concurrency.times do + threads << Thread.new do + while instance = queue.pop + instance.public_send(action, *args) + instance.cleanup! + end + end + end + threads.map(&:join) + end + end + end +end