jamie 0.1.0.beta3 → 0.1.0.beta4

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -10,5 +10,4 @@ end
10
10
 
11
11
  group :test do
12
12
  gem 'rake', '~> 0.9'
13
- gem 'pry'
14
13
  end
data/Rakefile CHANGED
@@ -7,7 +7,7 @@ Rake::TestTask.new do |t|
7
7
  t.verbose = true
8
8
  end
9
9
 
10
- task :default => [ :test ]
10
+ task :default => [:test]
11
11
 
12
12
  unless RUBY_ENGINE == 'jruby'
13
13
  require 'cane/rake_task'
@@ -29,9 +29,17 @@ unless RUBY_ENGINE == 'jruby'
29
29
  )
30
30
  end
31
31
 
32
- Tailor::RakeTask.new
32
+ Tailor::RakeTask.new do |task|
33
+ task.file_set('bin/*', 'binaries')
34
+ task.file_set('lib/**/*.rb', 'code') do |style|
35
+ # TODO: Tailor is confused thinking `module Jamie` is a class. Until
36
+ # the classes are split in seperate files, let's punt on this
37
+ style.max_code_lines_in_class 1550, level: :warn
38
+ end
39
+ task.file_set('spec/**/*.rb', 'tests')
40
+ end
33
41
 
34
- Rake::Task[:default].enhance [ :cane, :tailor ]
42
+ Rake::Task[:default].enhance [:cane, :tailor]
35
43
  end
36
44
 
37
45
  desc "Display LOC stats"
@@ -42,4 +50,4 @@ task :stats do
42
50
  sh "countloc -r spec"
43
51
  end
44
52
 
45
- Rake::Task[:default].enhance [ :stats ]
53
+ Rake::Task[:default].enhance [:stats]
@@ -22,6 +22,7 @@ Gem::Specification.new do |gem|
22
22
 
23
23
  gem.add_dependency 'celluloid'
24
24
  gem.add_dependency 'thor'
25
+ gem.add_dependency 'pry'
25
26
  gem.add_dependency 'net-ssh'
26
27
  gem.add_dependency 'net-scp'
27
28
  gem.add_dependency 'mixlib-shellout'
@@ -164,7 +164,7 @@ module Jamie
164
164
  def log_level
165
165
  @log_level ||= begin
166
166
  ENV['JAMIE_LOG'] && ENV['JAMIE_LOG'].downcase.to_sym ||
167
- Jamie::DEFAULT_LOG_LEVEL
167
+ Jamie::DEFAULT_LOG_LEVEL
168
168
  end
169
169
  end
170
170
 
@@ -286,7 +286,7 @@ module Jamie
286
286
  def platform_driver_hash(platform_name)
287
287
  h = yaml[:platforms].find { |p| p[:name] == platform_name } || Hash.new
288
288
 
289
- h.select { |key, value| [ :driver_plugin, :driver_config ].include?(key) }
289
+ h.select { |key, value| [:driver_plugin, :driver_config].include?(key) }
290
290
  end
291
291
 
292
292
  def new_instance_logger(index)
@@ -355,7 +355,7 @@ module Jamie
355
355
 
356
356
  def common_driver_hash
357
357
  yaml.select do |key, value|
358
- [ :driver_plugin, :driver_config ].include?(key)
358
+ [:driver_plugin, :driver_config].include?(key)
359
359
  end
360
360
  end
361
361
  end
@@ -374,7 +374,7 @@ module Jamie
374
374
 
375
375
  COLORS = %w(
376
376
  cyan yellow green magenta red blue bright_cyan bright_yellow
377
- bright_green bright_magenta bright_red, bright_blue
377
+ bright_green bright_magenta bright_red bright_blue
378
378
  ).freeze
379
379
 
380
380
  def self.escape(name)
@@ -563,7 +563,7 @@ module Jamie
563
563
  private
564
564
 
565
565
  def validate_options(opts)
566
- [ :name, :run_list ].each do |k|
566
+ [:name, :run_list].each do |k|
567
567
  raise ClientError, "Suite#new requires option :#{k}" if opts[k].nil?
568
568
  end
569
569
  end
@@ -604,7 +604,7 @@ module Jamie
604
604
  private
605
605
 
606
606
  def validate_options(opts)
607
- [ :name ].each do |k|
607
+ [:name].each do |k|
608
608
  raise ClientError, "Platform#new requires option :#{k}" if opts[k].nil?
609
609
  end
610
610
  end
@@ -792,7 +792,7 @@ module Jamie
792
792
  private
793
793
 
794
794
  def validate_options(opts)
795
- [ :suite, :platform, :driver, :jr, :logger ].each do |k|
795
+ [:suite, :platform, :driver, :jr, :logger].each do |k|
796
796
  raise ClientError, "Instance#new requires option :#{k}" if opts[k].nil?
797
797
  end
798
798
  end
@@ -838,7 +838,7 @@ module Jamie
838
838
  banner "#{output_verb} #{to_str}"
839
839
  elapsed = action(verb) { |state| driver.public_send(verb, state) }
840
840
  info("Finished #{output_verb.downcase} #{to_str}" +
841
- " #{Util.duration(elapsed.real)}.")
841
+ " #{Util.duration(elapsed.real)}.")
842
842
  yield if block_given?
843
843
  Actor.current
844
844
  end
@@ -927,7 +927,7 @@ module Jamie
927
927
 
928
928
  private
929
929
 
930
- TRANSITIONS = [ :destroy, :create, :converge, :setup, :verify ]
930
+ TRANSITIONS = [:destroy, :create, :converge, :setup, :verify]
931
931
 
932
932
  def self.index(transition)
933
933
  if transition.nil?
@@ -953,7 +953,7 @@ module Jamie
953
953
  # @param [Hash] opts optional configuration
954
954
  # @option opts [TrueClass, FalseClass] :use_sudo whether or not to invoke
955
955
  # sudo before commands requiring root access (default: `true`)
956
- def initialize(suite_name, opts = {:use_sudo => true})
956
+ def initialize(suite_name, opts = { :use_sudo => true })
957
957
  validate_options(suite_name)
958
958
 
959
959
  @suite_name = suite_name
@@ -972,7 +972,7 @@ module Jamie
972
972
  @setup_cmd ||= if local_suite_files.empty?
973
973
  nil
974
974
  else
975
- <<-INSTALL_CMD.gsub(/ {10}/, '')
975
+ <<-INSTALL_CMD.gsub(/^ {10}/, '')
976
976
  #{sudo}#{ruby_bin} -e "$(cat <<"EOF"
977
977
  #{install_script}
978
978
  EOF
@@ -994,7 +994,7 @@ module Jamie
994
994
  @sync_cmd ||= if local_suite_files.empty?
995
995
  nil
996
996
  else
997
- <<-INSTALL_CMD.gsub(/ {10}/, '')
997
+ <<-INSTALL_CMD.gsub(/^ {10}/, '')
998
998
  #{sudo}#{jr_bin} cleanup-suites
999
999
  #{local_suite_files.map { |f| stream_file(f, remote_file(f)) }.join}
1000
1000
  INSTALL_CMD
@@ -1053,7 +1053,7 @@ module Jamie
1053
1053
  def stream_file(local_path, remote_path)
1054
1054
  local_file = IO.read(local_path)
1055
1055
  md5 = Digest::MD5.hexdigest(local_file)
1056
- perms = sprintf("%o", File.stat(local_path).mode)[3,3]
1056
+ perms = sprintf("%o", File.stat(local_path).mode)[3, 3]
1057
1057
  jr_stream_file = "#{jr_bin} stream-file #{remote_path} #{md5} #{perms}"
1058
1058
 
1059
1059
  <<-STREAMFILE.gsub(/^ {8}/, '')
@@ -1115,7 +1115,7 @@ module Jamie
1115
1115
 
1116
1116
  def self.symbolized_hash(obj)
1117
1117
  if obj.is_a?(Hash)
1118
- obj.inject({}) { |h, (k,v)| h[k.to_sym] = symbolized_hash(v) ; h }
1118
+ obj.inject({}) { |h, (k, v)| h[k.to_sym] = symbolized_hash(v) ; h }
1119
1119
  elsif obj.is_a?(Array)
1120
1120
  obj.inject([]) { |a, v| a << symbolized_hash(v) ; a }
1121
1121
  else
@@ -1126,7 +1126,7 @@ module Jamie
1126
1126
  def self.duration(total)
1127
1127
  minutes = (total / 60).to_i
1128
1128
  seconds = (total - (minutes * 60))
1129
- "(%dm%.2fs)" % [ minutes, seconds ]
1129
+ "(%dm%.2fs)" % [minutes, seconds]
1130
1130
  end
1131
1131
  end
1132
1132
 
@@ -1316,7 +1316,7 @@ module Jamie
1316
1316
  end
1317
1317
  end
1318
1318
  end
1319
- @validations << [ attr, block ]
1319
+ @validations << [attr, block]
1320
1320
  end
1321
1321
 
1322
1322
  def self.no_parallel_for(*methods)
@@ -1391,7 +1391,7 @@ module Jamie
1391
1391
  opts[:password] = config[:password] if config[:password]
1392
1392
  opts[:keys] = Array(config[:ssh_key]) if config[:ssh_key]
1393
1393
 
1394
- [ state[:hostname], config[:username], opts ]
1394
+ [state[:hostname], config[:username], opts]
1395
1395
  end
1396
1396
 
1397
1397
  def chef_home
@@ -1475,7 +1475,7 @@ module Jamie
1475
1475
  socket = TCPSocket.new(hostname, config[:port])
1476
1476
  IO.select([socket], nil, nil, 5)
1477
1477
  rescue SocketError, Errno::ECONNREFUSED,
1478
- Errno::EHOSTUNREACH, Errno::ENETUNREACH, IOError
1478
+ Errno::EHOSTUNREACH, Errno::ENETUNREACH, IOError
1479
1479
  sleep 2
1480
1480
  false
1481
1481
  rescue Errno::EPERM, Errno::ETIMEDOUT
@@ -1546,8 +1546,9 @@ module Jamie
1546
1546
  end
1547
1547
 
1548
1548
  def upload_path(scp, path, dir = File.basename(path))
1549
- scp.upload!(path, "#{chef_home}/#{dir}", :recursive => true
1550
- ) do |ch, name, sent, total|
1549
+ dest = "#{chef_home}/#{dir}"
1550
+
1551
+ scp.upload!(path, dest, :recursive => true) do |ch, name, sent, total|
1551
1552
  if sent == total
1552
1553
  info("Uploaded #{name.sub(%r{^#{path}/}, '')} (#{total} bytes)")
1553
1554
  end
@@ -1593,7 +1594,8 @@ module Jamie
1593
1594
  fatal("#{name} must be installed, add it to your Gemfile.")
1594
1595
  raise UserError, "#{bin} command not found"
1595
1596
  end
1596
- run_command "#{bin} install --path #{tmpdir}"
1597
+
1598
+ Jamie.mutex.synchronize { run_command "#{bin} install --path #{tmpdir}" }
1597
1599
  end
1598
1600
 
1599
1601
  def cp_cookbooks(tmpdir)
@@ -1628,7 +1630,7 @@ module Jamie
1628
1630
  # attributes or nil values if they could not be determined
1629
1631
  def self.extract(metadata_file)
1630
1632
  mc = new(File.expand_path(metadata_file))
1631
- [ mc[:name], mc[:version] ]
1633
+ [mc[:name], mc[:version]]
1632
1634
  end
1633
1635
 
1634
1636
  # Creates a new instances and loads in the contents of the metdata.rb
@@ -47,10 +47,10 @@ module Jamie
47
47
  def list(*args)
48
48
  result = parse_subcommand(args.first)
49
49
  if options[:bare]
50
- say Array(result).map{ |i| i.name }.join("\n")
50
+ say Array(result).map { |i| i.name }.join("\n")
51
51
  else
52
52
  table = [
53
- [ set_color("Instance", :green), set_color("Last Action", :green) ]
53
+ [set_color("Instance", :green), set_color("Last Action", :green)]
54
54
  ]
55
55
  table += Array(result).map { |i| display_instance(i) }
56
56
  print_table(table)
@@ -107,7 +107,7 @@ module Jamie
107
107
  results = get_filtered_instances(regexp)
108
108
  if results.size > 1
109
109
  die task, "Argument `#{regexp}' returned multiple results:\n" +
110
- results.map{ |i| " * #{i.name}" }.join("\n")
110
+ results.map { |i| " * #{i.name}" }.join("\n")
111
111
  end
112
112
  instance = results.pop
113
113
 
@@ -210,7 +210,7 @@ module Jamie
210
210
  when nil then set_color("<Not Created>", :red)
211
211
  else set_color("<Unknown>", :white)
212
212
  end
213
- [ set_color(instance.name, :white), action ]
213
+ [set_color(instance.name, :white), action]
214
214
  end
215
215
 
216
216
  def die(task, msg)
@@ -220,18 +220,19 @@ module Jamie
220
220
  end
221
221
 
222
222
  def pry_prompts
223
- [ proc { |target_self, nest_level, pry|
224
- [ "[#{pry.input_array.size}] ",
223
+ [
224
+ proc { |target_self, nest_level, pry|
225
+ ["[#{pry.input_array.size}] ",
225
226
  "jc(#{Pry.view_clip(target_self.class)})",
226
227
  "#{":#{nest_level}" unless nest_level.zero?}> "
227
228
  ].join
228
229
  },
229
230
  proc { |target_self, nest_level, pry|
230
- [ "[#{pry.input_array.size}] ",
231
+ ["[#{pry.input_array.size}] ",
231
232
  "jc(#{Pry.view_clip(target_self.class)})",
232
233
  "#{":#{nest_level}" unless nest_level.zero?}* "
233
234
  ].join
234
- }
235
+ },
235
236
  ]
236
237
  end
237
238
  end
@@ -265,7 +266,7 @@ module Jamie
265
266
  puts ">>>>> Jamie gem not loaded, omitting tasks" unless ENV['CI']
266
267
  end
267
268
  THOR
268
- empty_directory "test/integration/standard" if init_test_dir?
269
+ empty_directory "test/integration/default" if init_test_dir?
269
270
  append_to_gitignore(".jamie/")
270
271
  append_to_gitignore(".jamie.local.yml")
271
272
  add_plugins
@@ -277,7 +278,7 @@ module Jamie
277
278
  url_base = "https://opscode-vm.s3.amazonaws.com/vagrant/boxes"
278
279
  platforms = [
279
280
  { :n => 'ubuntu', :vers => %w(12.04 10.04), :rl => "recipe[apt]" },
280
- { :n => 'centos', :vers => %w(6.3 5.8), :rl => "recipe[yum::epel]" }
281
+ { :n => 'centos', :vers => %w(6.3 5.8), :rl => "recipe[yum::epel]" },
281
282
  ]
282
283
  platforms = platforms.map do |p|
283
284
  p[:vers].map do |v|
@@ -296,15 +297,14 @@ module Jamie
296
297
  nil
297
298
  end
298
299
  run_list = cookbook_name ? "recipe[#{cookbook_name}]" : nil
299
- attributes = cookbook_name ? { cookbook_name => nil } : nil
300
300
 
301
301
  { 'driver_plugin' => 'vagrant',
302
302
  'platforms' => platforms,
303
303
  'suites' => [
304
- { 'name' => 'standard',
304
+ { 'name' => 'default',
305
305
  'run_list' => Array(run_list),
306
- 'attributes' => attributes
307
- }
306
+ 'attributes' => Hash.new
307
+ },
308
308
  ]
309
309
  }.to_yaml
310
310
  end
@@ -345,7 +345,7 @@ module Jamie
345
345
 
346
346
  def list_plugins
347
347
  specs = fetch_gem_specs.map { |t| t.first }.map { |t| t[0, 2] }.
348
- sort { |x,y| x[0] <=> y[0] }
348
+ sort { |x, y| x[0] <=> y[0] }
349
349
  specs = specs[0, 49].push(["...", "..."]) if specs.size > 49
350
350
  specs = specs.unshift(["Gem Name", "Latest Stable Release"])
351
351
  print_table(specs, :indent => 4)
@@ -55,14 +55,22 @@ module Jamie
55
55
  private
56
56
 
57
57
  def report(action, state)
58
- info("[Dummy] Action ##{action} called on " +
59
- "instance=#{instance} with state=#{state}")
58
+ what = action.capitalize
59
+ info("[Dummy] #{what} on instance=#{instance} with state=#{state}")
60
+ sleep_if_set
61
+ random_failure_if_set
62
+ debug("[Dummy] #{what} completed (#{config[:sleep]}s).")
63
+ end
64
+
65
+ def sleep_if_set
60
66
  sleep(config[:sleep].to_f) if config[:sleep].to_f > 0.0
67
+ end
68
+
69
+ def random_failure_if_set
61
70
  if config[:random_failure] && [true, false].sample
62
71
  debug("[Dummy] Random failure for action ##{action}.")
63
72
  raise ActionFailed, "Action ##{action} failed for #{instance.to_str}."
64
73
  end
65
- debug("[Dummy] Action ##{action} completed (#{config[:sleep]}s).")
66
74
  end
67
75
  end
68
76
  end
@@ -55,7 +55,7 @@ module Jamie
55
55
 
56
56
  self.class.desc "all", "Run all test instances"
57
57
  self.class.send(:define_method, :all) do
58
- config.instances.each { |i| invoke i.name.gsub(/-/, '_') }
58
+ config.instances.each { |i| invoke i.name.gsub(/-/, '_') }
59
59
  end
60
60
  end
61
61
  end
@@ -18,5 +18,5 @@
18
18
 
19
19
  module Jamie
20
20
 
21
- VERSION = "0.1.0.beta3"
21
+ VERSION = "0.1.0.beta4"
22
22
  end
@@ -0,0 +1,77 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
4
+ #
5
+ # Copyright (C) 2012, Fletcher Nichol
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+
19
+ require_relative '../../spec_helper'
20
+
21
+ describe Jamie::Config::Collection do
22
+
23
+ let(:collection) do
24
+ Jamie::Config::Collection.new([
25
+ obj('one'), obj('two', 'a'), obj('two', 'b'), obj('three')
26
+ ])
27
+ end
28
+
29
+ it "transparently wraps an Array" do
30
+ collection.must_be_instance_of Array
31
+ end
32
+
33
+ describe "#get" do
34
+
35
+ it "returns a single object by its name" do
36
+ collection.get('three').must_equal obj('three')
37
+ end
38
+
39
+ it "returns the first occurance of an object by its name" do
40
+ collection.get('two').must_equal obj('two', 'a')
41
+ end
42
+
43
+ it "returns nil if an object cannot be found by its name" do
44
+ collection.get('nope').must_be_nil
45
+ end
46
+ end
47
+
48
+ describe "#get_all" do
49
+
50
+ it "returns a Collection of objects whose name matches the regex" do
51
+ result = collection.get_all(/(one|three)/)
52
+ result.size.must_equal 2
53
+ result[0].must_equal obj('one')
54
+ result[1].must_equal obj('three')
55
+ result.get_all(/one/).size.must_equal 1
56
+ end
57
+
58
+ it "returns an empty Collection if on matches are found" do
59
+ result = collection.get_all(/noppa/)
60
+ result.must_equal []
61
+ result.get("nahuh").must_be_nil
62
+ end
63
+ end
64
+
65
+ describe "#as_name" do
66
+
67
+ it "returns an Array of names as strings" do
68
+ collection.as_names.must_equal %w{one two two three}
69
+ end
70
+ end
71
+
72
+ private
73
+
74
+ def obj(name, extra = nil)
75
+ OpenStruct.new(:name => name, :extra => extra)
76
+ end
77
+ end