jamie 0.1.0.alpha21 → 0.1.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.travis.yml +8 -0
- data/Rakefile +32 -24
- data/jamie.gemspec +1 -0
- data/lib/jamie.rb +132 -18
- data/lib/jamie/cli.rb +29 -8
- data/lib/jamie/version.rb +1 -1
- data/spec/jamie_spec.rb +6 -0
- metadata +18 -2
    
        data/.travis.yml
    CHANGED
    
    
    
        data/Rakefile
    CHANGED
    
    | @@ -1,24 +1,38 @@ | |
| 1 1 | 
             
            require 'bundler/gem_tasks'
         | 
| 2 | 
            -
            require 'cane/rake_task'
         | 
| 3 2 | 
             
            require 'rake/testtask'
         | 
| 4 | 
            -
             | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
               | 
| 9 | 
            -
                Jamie::RakeTasks#define
         | 
| 10 | 
            -
                Jamie::ThorTasks#define
         | 
| 11 | 
            -
                Jamie::CLI#pry_prompts
         | 
| 12 | 
            -
              )
         | 
| 13 | 
            -
              cane.style_exclude = %w(
         | 
| 14 | 
            -
                lib/vendor/hash_recursive_merge.rb
         | 
| 15 | 
            -
              )
         | 
| 16 | 
            -
              cane.doc_exclude = %w(
         | 
| 17 | 
            -
                lib/vendor/hash_recursive_merge.rb
         | 
| 18 | 
            -
              )
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            Rake::TestTask.new do |t|
         | 
| 5 | 
            +
              t.libs.push "lib"
         | 
| 6 | 
            +
              t.test_files = FileList['spec/**/*_spec.rb']
         | 
| 7 | 
            +
              t.verbose = true
         | 
| 19 8 | 
             
            end
         | 
| 20 9 |  | 
| 21 | 
            -
             | 
| 10 | 
            +
            task :default => [ :test ]
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            unless RUBY_ENGINE == 'jruby'
         | 
| 13 | 
            +
              require 'cane/rake_task'
         | 
| 14 | 
            +
              require 'tailor/rake_task'
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              desc "Run cane to check quality metrics"
         | 
| 17 | 
            +
              Cane::RakeTask.new do |cane|
         | 
| 18 | 
            +
                cane.abc_exclude = %w(
         | 
| 19 | 
            +
                  Jamie::RakeTasks#define
         | 
| 20 | 
            +
                  Jamie::ThorTasks#define
         | 
| 21 | 
            +
                  Jamie::CLI#pry_prompts
         | 
| 22 | 
            +
                  Jamie::Instance#synchronize_or_call
         | 
| 23 | 
            +
                )
         | 
| 24 | 
            +
                cane.style_exclude = %w(
         | 
| 25 | 
            +
                  lib/vendor/hash_recursive_merge.rb
         | 
| 26 | 
            +
                )
         | 
| 27 | 
            +
                cane.doc_exclude = %w(
         | 
| 28 | 
            +
                  lib/vendor/hash_recursive_merge.rb
         | 
| 29 | 
            +
                )
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
              Tailor::RakeTask.new
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              Rake::Task[:default].enhance [ :cane, :tailor ]
         | 
| 35 | 
            +
            end
         | 
| 22 36 |  | 
| 23 37 | 
             
            desc "Display LOC stats"
         | 
| 24 38 | 
             
            task :stats do
         | 
| @@ -28,10 +42,4 @@ task :stats do | |
| 28 42 | 
             
              sh "countloc -r spec"
         | 
| 29 43 | 
             
            end
         | 
| 30 44 |  | 
| 31 | 
            -
            Rake:: | 
| 32 | 
            -
              t.libs.push "lib"
         | 
| 33 | 
            -
              t.test_files = FileList['spec/**/*_spec.rb']
         | 
| 34 | 
            -
              t.verbose = true
         | 
| 35 | 
            -
            end
         | 
| 36 | 
            -
             | 
| 37 | 
            -
            task :default => [ :test, :cane, :tailor, :stats ]
         | 
| 45 | 
            +
            Rake::Task[:default].enhance [ :stats ]
         | 
    
        data/jamie.gemspec
    CHANGED
    
    
    
        data/lib/jamie.rb
    CHANGED
    
    | @@ -18,6 +18,7 @@ | |
| 18 18 |  | 
| 19 19 | 
             
            require 'base64'
         | 
| 20 20 | 
             
            require 'benchmark'
         | 
| 21 | 
            +
            require 'celluloid'
         | 
| 21 22 | 
             
            require 'delegate'
         | 
| 22 23 | 
             
            require 'digest'
         | 
| 23 24 | 
             
            require 'erb'
         | 
| @@ -29,6 +30,7 @@ require 'net/https' | |
| 29 30 | 
             
            require 'net/scp'
         | 
| 30 31 | 
             
            require 'net/ssh'
         | 
| 31 32 | 
             
            require 'pathname'
         | 
| 33 | 
            +
            require 'thread'
         | 
| 32 34 | 
             
            require 'socket'
         | 
| 33 35 | 
             
            require 'stringio'
         | 
| 34 36 | 
             
            require 'vendor/hash_recursive_merge'
         | 
| @@ -41,6 +43,8 @@ module Jamie | |
| 41 43 | 
             
              class << self
         | 
| 42 44 |  | 
| 43 45 | 
             
                attr_accessor :logger
         | 
| 46 | 
            +
                attr_accessor :crashes
         | 
| 47 | 
            +
                attr_accessor :mutex
         | 
| 44 48 |  | 
| 45 49 | 
             
                # Returns the root path of the Jamie gem source code.
         | 
| 46 50 | 
             
                #
         | 
| @@ -49,10 +53,15 @@ module Jamie | |
| 49 53 | 
             
                  @source_root ||= Pathname.new(File.expand_path('../../', __FILE__))
         | 
| 50 54 | 
             
                end
         | 
| 51 55 |  | 
| 56 | 
            +
                def crashes?
         | 
| 57 | 
            +
                  ! crashes.empty?
         | 
| 58 | 
            +
                end
         | 
| 59 | 
            +
             | 
| 52 60 | 
             
                def default_logger
         | 
| 53 61 | 
             
                  env_log = ENV['JAMIE_LOG'] && ENV['JAMIE_LOG'].downcase.to_sym
         | 
| 62 | 
            +
                  env_log = Util.to_logger_level(env_log) unless env_log.nil?
         | 
| 54 63 |  | 
| 55 | 
            -
                  Logger.new(: | 
| 64 | 
            +
                  Logger.new(:stdout => STDOUT, :level => env_log)
         | 
| 56 65 | 
             
                end
         | 
| 57 66 | 
             
              end
         | 
| 58 67 |  | 
| @@ -101,9 +110,7 @@ module Jamie | |
| 101 110 | 
             
                # @return [Array<Instance>] all instances, resulting from all platform and
         | 
| 102 111 | 
             
                #   suite combinations
         | 
| 103 112 | 
             
                def instances
         | 
| 104 | 
            -
                   | 
| 105 | 
            -
                    platforms.map { |platform| new_instance(suite, platform) }
         | 
| 106 | 
            -
                  }.flatten)
         | 
| 113 | 
            +
                  instances_array(load_instances)
         | 
| 107 114 | 
             
                end
         | 
| 108 115 |  | 
| 109 116 | 
             
                # @return [String] path to the Jamie YAML file
         | 
| @@ -162,6 +169,24 @@ module Jamie | |
| 162 169 |  | 
| 163 170 | 
             
                private
         | 
| 164 171 |  | 
| 172 | 
            +
                def load_instances
         | 
| 173 | 
            +
                  return @instance_count if @instance_count && @instance_count > 0
         | 
| 174 | 
            +
             | 
| 175 | 
            +
                  results = []
         | 
| 176 | 
            +
                  suites.product(platforms).each_with_index do |arr, index|
         | 
| 177 | 
            +
                    results << new_instance(arr[0], arr[1], index)
         | 
| 178 | 
            +
                  end
         | 
| 179 | 
            +
                  @instance_count = results.size
         | 
| 180 | 
            +
                end
         | 
| 181 | 
            +
             | 
| 182 | 
            +
                def instances_array(instance_count)
         | 
| 183 | 
            +
                  results = []
         | 
| 184 | 
            +
                  instance_count.times do |index|
         | 
| 185 | 
            +
                    results << Celluloid::Actor["instance_#{index}".to_sym]
         | 
| 186 | 
            +
                  end
         | 
| 187 | 
            +
                  Collection.new(results)
         | 
| 188 | 
            +
                end
         | 
| 189 | 
            +
             | 
| 165 190 | 
             
                def new_suite(hash)
         | 
| 166 191 | 
             
                  path_hash = {
         | 
| 167 192 | 
             
                    :data_bags_path => calculate_path("data_bags", hash[:name]),
         | 
| @@ -182,19 +207,24 @@ module Jamie | |
| 182 207 | 
             
                  Driver.for_plugin(hash[:driver_plugin], hash[:driver_config])
         | 
| 183 208 | 
             
                end
         | 
| 184 209 |  | 
| 185 | 
            -
                def new_instance(suite, platform)
         | 
| 186 | 
            -
                  log_root = File.expand_path(File.join(jamie_root, ".jamie", "logs"))
         | 
| 210 | 
            +
                def new_instance(suite, platform, index)
         | 
| 187 211 | 
             
                  platform_hash = platform_driver_hash(platform.name)
         | 
| 188 212 | 
             
                  driver = new_driver(merge_driver_hash(platform_hash))
         | 
| 189 213 | 
             
                  FileUtils.mkdir_p(log_root)
         | 
| 190 214 |  | 
| 191 | 
            -
                  Instance. | 
| 215 | 
            +
                  supervisor = Instance.supervise_as(
         | 
| 216 | 
            +
                    "instance_#{index}".to_sym,
         | 
| 192 217 | 
             
                    :suite    => suite,
         | 
| 193 218 | 
             
                    :platform => platform,
         | 
| 194 219 | 
             
                    :driver   => driver,
         | 
| 195 220 | 
             
                    :jr       => Jr.new(suite.name),
         | 
| 196 | 
            -
                    :logger   => new_instance_logger( | 
| 221 | 
            +
                    :logger   => new_instance_logger(index)
         | 
| 197 222 | 
             
                  )
         | 
| 223 | 
            +
                  supervisor.actors.first
         | 
| 224 | 
            +
                end
         | 
| 225 | 
            +
             | 
| 226 | 
            +
                def log_root
         | 
| 227 | 
            +
                  File.expand_path(File.join(jamie_root, ".jamie", "logs"))
         | 
| 198 228 | 
             
                end
         | 
| 199 229 |  | 
| 200 230 | 
             
                def platform_driver_hash(platform_name)
         | 
| @@ -203,13 +233,14 @@ module Jamie | |
| 203 233 | 
             
                  h.select { |key, value| [ :driver_plugin, :driver_config ].include?(key) }
         | 
| 204 234 | 
             
                end
         | 
| 205 235 |  | 
| 206 | 
            -
                def new_instance_logger( | 
| 236 | 
            +
                def new_instance_logger(index)
         | 
| 207 237 | 
             
                  level = Util.to_logger_level(self.log_level)
         | 
| 238 | 
            +
                  color = Color::COLORS[index % Color::COLORS.size].to_sym
         | 
| 208 239 |  | 
| 209 240 | 
             
                  lambda do |name|
         | 
| 210 241 | 
             
                    logfile = File.join(log_root, "#{name}.log")
         | 
| 211 242 |  | 
| 212 | 
            -
                    Logger.new(:stdout => STDOUT, :logdev => logfile,
         | 
| 243 | 
            +
                    Logger.new(:stdout => STDOUT, :color => color, :logdev => logfile,
         | 
| 213 244 | 
             
                      :level => level, :progname => name)
         | 
| 214 245 | 
             
                  end
         | 
| 215 246 | 
             
                end
         | 
| @@ -276,6 +307,31 @@ module Jamie | |
| 276 307 | 
             
              # Default log level verbosity
         | 
| 277 308 | 
             
              DEFAULT_LOG_LEVEL = :info
         | 
| 278 309 |  | 
| 310 | 
            +
              module Color
         | 
| 311 | 
            +
                ANSI = {
         | 
| 312 | 
            +
                  :reset => 0, :black => 30, :red => 31, :green => 32, :yellow => 33,
         | 
| 313 | 
            +
                  :blue => 34, :magenta => 35, :cyan => 36, :white => 37,
         | 
| 314 | 
            +
                  :bright_black => 30, :bright_red => 31, :bright_green => 32,
         | 
| 315 | 
            +
                  :bright_yellow => 33, :bright_blue => 34, :bright_magenta => 35,
         | 
| 316 | 
            +
                  :bright_cyan => 36, :bright_white => 37
         | 
| 317 | 
            +
                }.freeze
         | 
| 318 | 
            +
             | 
| 319 | 
            +
                COLORS = %w(
         | 
| 320 | 
            +
                  cyan yellow green magenta red blue bright_cyan bright_yellow
         | 
| 321 | 
            +
                  bright_green bright_magenta bright_red, bright_blue
         | 
| 322 | 
            +
                ).freeze
         | 
| 323 | 
            +
             | 
| 324 | 
            +
                def self.escape(name)
         | 
| 325 | 
            +
                  return "" if name.nil?
         | 
| 326 | 
            +
                  return "" unless ansi = ANSI[name]
         | 
| 327 | 
            +
                  "\e[#{ansi}m"
         | 
| 328 | 
            +
                end
         | 
| 329 | 
            +
             | 
| 330 | 
            +
                def self.colorize(str, name)
         | 
| 331 | 
            +
                  "#{escape(name)}#{str}#{escape(:reset)}"
         | 
| 332 | 
            +
                end
         | 
| 333 | 
            +
              end
         | 
| 334 | 
            +
             | 
| 279 335 | 
             
              # Logging implementation for Jamie. By default the console/stdout output will
         | 
| 280 336 | 
             
              # be displayed differently than the file log output. Therefor, this class
         | 
| 281 337 | 
             
              # wraps multiple loggers that conform to the stdlib `Logger` class behavior.
         | 
| @@ -286,10 +342,12 @@ module Jamie | |
| 286 342 | 
             
                include ::Logger::Severity
         | 
| 287 343 |  | 
| 288 344 | 
             
                def initialize(options = {})
         | 
| 345 | 
            +
                  color = options[:color] || :bright_white
         | 
| 346 | 
            +
             | 
| 289 347 | 
             
                  @loggers = []
         | 
| 290 348 | 
             
                  @loggers << logdev_logger(options[:logdev]) if options[:logdev]
         | 
| 291 | 
            -
                  @loggers << stdout_logger(options[:stdout]) if options[:stdout]
         | 
| 292 | 
            -
                  @loggers << stdout_logger(STDOUT) if @loggers.empty?
         | 
| 349 | 
            +
                  @loggers << stdout_logger(options[:stdout], color) if options[:stdout]
         | 
| 350 | 
            +
                  @loggers << stdout_logger(STDOUT, color) if @loggers.empty?
         | 
| 293 351 |  | 
| 294 352 | 
             
                  self.progname = options[:progname] || "Jamie"
         | 
| 295 353 | 
             
                  self.level = options[:level] || default_log_level
         | 
| @@ -318,10 +376,10 @@ module Jamie | |
| 318 376 | 
             
                  Util.to_logger_level(Jamie::DEFAULT_LOG_LEVEL)
         | 
| 319 377 | 
             
                end
         | 
| 320 378 |  | 
| 321 | 
            -
                def stdout_logger(stdout)
         | 
| 379 | 
            +
                def stdout_logger(stdout, color)
         | 
| 322 380 | 
             
                  logger = StdoutLogger.new(stdout)
         | 
| 323 381 | 
             
                  logger.formatter = proc do |severity, datetime, progname, msg|
         | 
| 324 | 
            -
                    "#{msg}\n"
         | 
| 382 | 
            +
                    Color.colorize("#{msg}\n", color)
         | 
| 325 383 | 
             
                  end
         | 
| 326 384 | 
             
                  logger
         | 
| 327 385 | 
             
                end
         | 
| @@ -500,8 +558,13 @@ module Jamie | |
| 500 558 | 
             
              # @author Fletcher Nichol <fnichol@nichol.ca>
         | 
| 501 559 | 
             
              class Instance
         | 
| 502 560 |  | 
| 561 | 
            +
                include Celluloid
         | 
| 503 562 | 
             
                include Logging
         | 
| 504 563 |  | 
| 564 | 
            +
                class << self
         | 
| 565 | 
            +
                  attr_accessor :mutexes
         | 
| 566 | 
            +
                end
         | 
| 567 | 
            +
             | 
| 505 568 | 
             
                # @return [Suite] the test suite configuration
         | 
| 506 569 | 
             
                attr_reader :suite
         | 
| 507 570 |  | 
| @@ -538,6 +601,7 @@ module Jamie | |
| 538 601 | 
             
                  @logger = logger.is_a?(Proc) ? logger.call(name) : logger
         | 
| 539 602 |  | 
| 540 603 | 
             
                  @driver.instance = self
         | 
| 604 | 
            +
                  setup_driver_mutex
         | 
| 541 605 | 
             
                end
         | 
| 542 606 |  | 
| 543 607 | 
             
                # @return [String] name of this instance
         | 
| @@ -643,7 +707,7 @@ module Jamie | |
| 643 707 | 
             
                    destroy if destroy_mode == :passing
         | 
| 644 708 | 
             
                  end
         | 
| 645 709 | 
             
                  info "Finished testing #{to_str} (#{elapsed.real} seconds)."
         | 
| 646 | 
            -
                   | 
| 710 | 
            +
                  Actor.current
         | 
| 647 711 | 
             
                ensure
         | 
| 648 712 | 
             
                  destroy if destroy_mode == :always
         | 
| 649 713 | 
             
                end
         | 
| @@ -670,6 +734,15 @@ module Jamie | |
| 670 734 | 
             
                  end
         | 
| 671 735 | 
             
                end
         | 
| 672 736 |  | 
| 737 | 
            +
                def setup_driver_mutex
         | 
| 738 | 
            +
                  if driver.class.serial_actions
         | 
| 739 | 
            +
                    Jamie.mutex.synchronize do
         | 
| 740 | 
            +
                      self.class.mutexes ||= Hash.new
         | 
| 741 | 
            +
                      self.class.mutexes[driver.class] = Mutex.new
         | 
| 742 | 
            +
                    end
         | 
| 743 | 
            +
                  end
         | 
| 744 | 
            +
                end
         | 
| 745 | 
            +
             | 
| 673 746 | 
             
                def transition_to(desired)
         | 
| 674 747 | 
             
                  result = nil
         | 
| 675 748 | 
             
                  FSM.actions(last_action, desired).each do |transition|
         | 
| @@ -704,13 +777,13 @@ module Jamie | |
| 704 777 | 
             
                  info("Finished #{output_verb.downcase} #{to_str}" +
         | 
| 705 778 | 
             
                       " (#{elapsed.real} seconds).")
         | 
| 706 779 | 
             
                  yield if block_given?
         | 
| 707 | 
            -
                   | 
| 780 | 
            +
                  Actor.current
         | 
| 708 781 | 
             
                end
         | 
| 709 782 |  | 
| 710 | 
            -
                def action(what)
         | 
| 783 | 
            +
                def action(what, &block)
         | 
| 711 784 | 
             
                  state = load_state
         | 
| 712 785 | 
             
                  elapsed = Benchmark.measure do
         | 
| 713 | 
            -
                     | 
| 786 | 
            +
                    synchronize_or_call(what, state, &block)
         | 
| 714 787 | 
             
                  end
         | 
| 715 788 | 
             
                  state[:last_action] = what.to_s
         | 
| 716 789 | 
             
                  elapsed
         | 
| @@ -718,6 +791,18 @@ module Jamie | |
| 718 791 | 
             
                  dump_state(state)
         | 
| 719 792 | 
             
                end
         | 
| 720 793 |  | 
| 794 | 
            +
                def synchronize_or_call(what, state, &block)
         | 
| 795 | 
            +
                  if Array(driver.class.serial_actions).include?(what)
         | 
| 796 | 
            +
                    debug("#{to_str} is synchronizing on #{driver.class}##{what}")
         | 
| 797 | 
            +
                    self.class.mutexes[driver.class].synchronize do
         | 
| 798 | 
            +
                      debug("#{to_str} is messaging #{driver.class}##{what}")
         | 
| 799 | 
            +
                      block.call(state)
         | 
| 800 | 
            +
                    end
         | 
| 801 | 
            +
                  else
         | 
| 802 | 
            +
                    block.call(state)
         | 
| 803 | 
            +
                  end
         | 
| 804 | 
            +
                end
         | 
| 805 | 
            +
             | 
| 721 806 | 
             
                def load_state
         | 
| 722 807 | 
             
                  if File.exists?(statefile)
         | 
| 723 808 | 
             
                    Util.symbolized_hash(YAML.load_file(statefile))
         | 
| @@ -1037,6 +1122,10 @@ module Jamie | |
| 1037 1122 |  | 
| 1038 1123 | 
             
                  attr_writer :instance
         | 
| 1039 1124 |  | 
| 1125 | 
            +
                  class << self
         | 
| 1126 | 
            +
                    attr_reader :serial_actions
         | 
| 1127 | 
            +
                  end
         | 
| 1128 | 
            +
             | 
| 1040 1129 | 
             
                  def initialize(config = {})
         | 
| 1041 1130 | 
             
                    @config = config
         | 
| 1042 1131 | 
             
                    self.class.defaults.each do |attr, value|
         | 
| @@ -1096,6 +1185,9 @@ module Jamie | |
| 1096 1185 |  | 
| 1097 1186 | 
             
                  attr_reader :config, :instance
         | 
| 1098 1187 |  | 
| 1188 | 
            +
                  ACTION_METHODS = %w{create converge setup verify destroy}.
         | 
| 1189 | 
            +
                    map(&:to_sym).freeze
         | 
| 1190 | 
            +
             | 
| 1099 1191 | 
             
                  def logger
         | 
| 1100 1192 | 
             
                    instance.logger
         | 
| 1101 1193 | 
             
                  end
         | 
| @@ -1122,6 +1214,17 @@ module Jamie | |
| 1122 1214 | 
             
                  def self.default_config(attr, value)
         | 
| 1123 1215 | 
             
                    defaults[attr] = value
         | 
| 1124 1216 | 
             
                  end
         | 
| 1217 | 
            +
             | 
| 1218 | 
            +
                  def self.no_parallel_for(*methods)
         | 
| 1219 | 
            +
                    Array(methods).each do |meth|
         | 
| 1220 | 
            +
                      if ! ACTION_METHODS.include?(meth)
         | 
| 1221 | 
            +
                        raise ArgumentError, "##{meth} is not a whitelisted method."
         | 
| 1222 | 
            +
                      end
         | 
| 1223 | 
            +
                    end
         | 
| 1224 | 
            +
             | 
| 1225 | 
            +
                    @serial_actions ||= []
         | 
| 1226 | 
            +
                    @serial_actions += methods
         | 
| 1227 | 
            +
                  end
         | 
| 1125 1228 | 
             
                end
         | 
| 1126 1229 |  | 
| 1127 1230 | 
             
                # Base class for a driver that uses SSH to communication with an instance.
         | 
| @@ -1435,4 +1538,15 @@ module Jamie | |
| 1435 1538 | 
             
              end
         | 
| 1436 1539 | 
             
            end
         | 
| 1437 1540 |  | 
| 1541 | 
            +
            # Initialize the base logger and use that for Celluloid's logger
         | 
| 1438 1542 | 
             
            Jamie.logger = Jamie.default_logger
         | 
| 1543 | 
            +
            Celluloid.logger = Jamie.logger
         | 
| 1544 | 
            +
             | 
| 1545 | 
            +
            # Setup a collection of instance crash exceptions for error reporting
         | 
| 1546 | 
            +
            Jamie.crashes = []
         | 
| 1547 | 
            +
            Celluloid.exception_handler do |exception|
         | 
| 1548 | 
            +
              Jamie.logger.debug("An instance crashed because of #{exception.inspect}")
         | 
| 1549 | 
            +
              Jamie.crashes << exception
         | 
| 1550 | 
            +
            end
         | 
| 1551 | 
            +
             | 
| 1552 | 
            +
            Jamie.mutex = Mutex.new
         | 
    
        data/lib/jamie/cli.rb
    CHANGED
    
    | @@ -35,6 +35,7 @@ module Jamie | |
| 35 35 | 
             
                # Constructs a new instance.
         | 
| 36 36 | 
             
                def initialize(*args)
         | 
| 37 37 | 
             
                  super
         | 
| 38 | 
            +
                  $stdout.sync = true
         | 
| 38 39 | 
             
                  @config = Jamie::Config.new(ENV['JAMIE_YAML'])
         | 
| 39 40 | 
             
                end
         | 
| 40 41 |  | 
| @@ -46,9 +47,11 @@ module Jamie | |
| 46 47 |  | 
| 47 48 | 
             
                [:create, :converge, :setup, :verify, :destroy].each do |action|
         | 
| 48 49 | 
             
                  desc(
         | 
| 49 | 
            -
                    "#{action} [(all|<REGEX>)]",
         | 
| 50 | 
            +
                    "#{action} [(all|<REGEX>)] [opts]",
         | 
| 50 51 | 
             
                    "#{action.capitalize} one or more instances"
         | 
| 51 52 | 
             
                  )
         | 
| 53 | 
            +
                  method_option :parallel, :aliases => "-p", :type => :boolean,
         | 
| 54 | 
            +
                    :desc => "Perform action against all matching instances in parallel"
         | 
| 52 55 | 
             
                  define_method(action) { |*args| exec_action(action) }
         | 
| 53 56 | 
             
                end
         | 
| 54 57 |  | 
| @@ -63,17 +66,26 @@ module Jamie | |
| 63 66 | 
             
                  * always: instances will always be destroyed afterwards.\n
         | 
| 64 67 | 
             
                  * never: instances will never be destroyed afterwards.
         | 
| 65 68 | 
             
                DESC
         | 
| 69 | 
            +
                method_option :parallel, :aliases => "-p", :type => :boolean,
         | 
| 70 | 
            +
                  :desc => "Perform action against all matching instances in parallel"
         | 
| 66 71 | 
             
                method_option :destroy, :aliases => "-d", :default => "passing",
         | 
| 67 72 | 
             
                  :desc => "Destroy strategy to use after testing (passing, always, never)."
         | 
| 68 73 | 
             
                def test(*args)
         | 
| 74 | 
            +
                  if ! %w{passing always never}.include?(options[:destroy])
         | 
| 75 | 
            +
                    raise ArgumentError, "Destroy mode must be passing, always, or never."
         | 
| 76 | 
            +
                  end
         | 
| 77 | 
            +
             | 
| 69 78 | 
             
                  banner "Starting Jamie"
         | 
| 70 79 | 
             
                  elapsed = Benchmark.measure do
         | 
| 71 | 
            -
                    destroy_mode = options[:destroy]
         | 
| 72 | 
            -
                     | 
| 73 | 
            -
             | 
| 80 | 
            +
                    destroy_mode = options[:destroy].to_sym
         | 
| 81 | 
            +
                    @task = :test
         | 
| 82 | 
            +
                    results = parse_subcommand(args.first)
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                    if options[:parallel]
         | 
| 85 | 
            +
                      run_parallel(results, destroy_mode)
         | 
| 86 | 
            +
                    else
         | 
| 87 | 
            +
                      run_serial(results, destroy_mode)
         | 
| 74 88 | 
             
                    end
         | 
| 75 | 
            -
                    result = parse_subcommand(args.first)
         | 
| 76 | 
            -
                    Array(result).each { |instance| instance.test(destroy_mode.to_sym) }
         | 
| 77 89 | 
             
                  end
         | 
| 78 90 | 
             
                  banner "Jamie is finished. (#{elapsed.real} seconds)"
         | 
| 79 91 | 
             
                end
         | 
| @@ -132,12 +144,21 @@ module Jamie | |
| 132 144 | 
             
                  banner "Starting Jamie"
         | 
| 133 145 | 
             
                  elapsed = Benchmark.measure do
         | 
| 134 146 | 
             
                    @task = action
         | 
| 135 | 
            -
                     | 
| 136 | 
            -
                     | 
| 147 | 
            +
                    results = parse_subcommand(args.first)
         | 
| 148 | 
            +
                    options[:parallel] ? run_parallel(results) : run_serial(results)
         | 
| 137 149 | 
             
                  end
         | 
| 138 150 | 
             
                  banner "Jamie is finished. (#{elapsed.real} seconds)"
         | 
| 139 151 | 
             
                end
         | 
| 140 152 |  | 
| 153 | 
            +
                def run_serial(instances, *args)
         | 
| 154 | 
            +
                  Array(instances).map { |i| i.public_send(task, *args) }
         | 
| 155 | 
            +
                end
         | 
| 156 | 
            +
             | 
| 157 | 
            +
                def run_parallel(instances, *args)
         | 
| 158 | 
            +
                  futures = Array(instances).map { |i| i.future.public_send(task) }
         | 
| 159 | 
            +
                  futures.map { |i| i.value }
         | 
| 160 | 
            +
                end
         | 
| 161 | 
            +
             | 
| 141 162 | 
             
                def parse_subcommand(arg = nil)
         | 
| 142 163 | 
             
                  arg == "all" ? get_all_instances : get_filtered_instances(arg)
         | 
| 143 164 | 
             
                end
         | 
    
        data/lib/jamie/version.rb
    CHANGED
    
    
    
        data/spec/jamie_spec.rb
    CHANGED
    
    | @@ -28,8 +28,10 @@ end | |
| 28 28 | 
             
            SimpleCov.start 'gem'
         | 
| 29 29 |  | 
| 30 30 | 
             
            require 'fakefs/spec_helpers'
         | 
| 31 | 
            +
            require 'logger'
         | 
| 31 32 | 
             
            require 'minitest/autorun'
         | 
| 32 33 | 
             
            require 'ostruct'
         | 
| 34 | 
            +
            require 'stringio'
         | 
| 33 35 |  | 
| 34 36 | 
             
            require 'jamie'
         | 
| 35 37 | 
             
            require 'jamie/driver/dummy'
         | 
| @@ -391,6 +393,10 @@ describe Jamie::Instance do | |
| 391 393 |  | 
| 392 394 | 
             
              let(:instance) { Jamie::Instance.new(opts) }
         | 
| 393 395 |  | 
| 396 | 
            +
              before do
         | 
| 397 | 
            +
                Celluloid.logger = Logger.new(StringIO.new)
         | 
| 398 | 
            +
              end
         | 
| 399 | 
            +
             | 
| 394 400 | 
             
              it "raises an ArgumentError if suite is missing" do
         | 
| 395 401 | 
             
                opts.delete(:suite)
         | 
| 396 402 | 
             
                proc { Jamie::Instance.new(opts) }.must_raise ArgumentError
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: jamie
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.1.0. | 
| 4 | 
            +
              version: 0.1.0.beta1
         | 
| 5 5 | 
             
              prerelease: 6
         | 
| 6 6 | 
             
            platform: ruby
         | 
| 7 7 | 
             
            authors:
         | 
| @@ -9,8 +9,24 @@ authors: | |
| 9 9 | 
             
            autorequire: 
         | 
| 10 10 | 
             
            bindir: bin
         | 
| 11 11 | 
             
            cert_chain: []
         | 
| 12 | 
            -
            date: 2013-01- | 
| 12 | 
            +
            date: 2013-01-12 00:00:00.000000000 Z
         | 
| 13 13 | 
             
            dependencies:
         | 
| 14 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 15 | 
            +
              name: celluloid
         | 
| 16 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 17 | 
            +
                none: false
         | 
| 18 | 
            +
                requirements:
         | 
| 19 | 
            +
                - - ! '>='
         | 
| 20 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 21 | 
            +
                    version: '0'
         | 
| 22 | 
            +
              type: :runtime
         | 
| 23 | 
            +
              prerelease: false
         | 
| 24 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 25 | 
            +
                none: false
         | 
| 26 | 
            +
                requirements:
         | 
| 27 | 
            +
                - - ! '>='
         | 
| 28 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 29 | 
            +
                    version: '0'
         | 
| 14 30 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 15 31 | 
             
              name: thor
         | 
| 16 32 | 
             
              requirement: !ruby/object:Gem::Requirement
         |