bosh_common 0.4.0 → 0.5.0

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/Rakefile CHANGED
@@ -19,14 +19,14 @@ require "ci_task"
19
19
 
20
20
  gem_helper = Bundler::GemHelper.new(Dir.pwd)
21
21
 
22
- desc "Build Blobstore Client gem into the pkg directory"
22
+ desc "Build BOSH Common gem into the pkg directory"
23
23
  task "build" do
24
24
  gem_helper.build_gem
25
25
  end
26
26
 
27
- desc "Build and install Blobstore Client into system gems"
27
+ desc "Build and install BOSH Common into system gems"
28
28
  task "install" do
29
- sh("bundle install --local --without test development")
29
+ Rake::Task["bundler:install"].invoke
30
30
  gem_helper.install_gem
31
31
  end
32
32
 
@@ -36,7 +36,6 @@ if defined?(RSpec)
36
36
  namespace :spec do
37
37
  desc "Run Unit Tests"
38
38
  rspec_task = RSpec::Core::RakeTask.new(:unit) do |t|
39
- t.gemfile = "Gemfile"
40
39
  t.pattern = "spec/unit/**/*_spec.rb"
41
40
  t.rspec_opts = %w(--format progress --colour)
42
41
  end
@@ -46,6 +45,6 @@ if defined?(RSpec)
46
45
  end
47
46
  end
48
47
 
49
- desc "Install dependencies and run tests"
50
- task :spec => %w(bundler:install:test spec:unit)
51
- end
48
+ desc "Run tests"
49
+ task :spec => %w(spec:unit)
50
+ end
@@ -0,0 +1,47 @@
1
+ # Copyright (c) 2012 VMware, Inc.
2
+
3
+ module Bosh
4
+
5
+ # Module for common methods used throughout the BOSH code.
6
+ module Common
7
+
8
+ # Converts all keys of a [Hash] to symbols. Performs deep conversion.
9
+ #
10
+ # @param [Hash] hash to convert
11
+ # @return [Hash] a copy of the original hash
12
+ def symbolize_keys(hash)
13
+ hash.inject({}) do |h, (key, value)|
14
+ h[key.to_sym] = value.is_a?(Hash) ? symbolize_keys(value) : value
15
+ h
16
+ end
17
+ end
18
+
19
+ module_function :symbolize_keys
20
+
21
+ # @overload which(program, path)
22
+ # Looks for program in the executables search path (PATH).
23
+ # The file must be executable to be found.
24
+ # @param [String] program
25
+ # @param [String] path search path
26
+ # @return [String] full path of the executable,
27
+ # or nil if not found
28
+ # @overload which(programs, path)
29
+ # Looks for one of the programs in the executables search path (PATH).
30
+ # The file must be executable to be found.
31
+ # @param [Array] programs
32
+ # @param [String] path search path
33
+ # @return [String] full path of the executable,
34
+ # or nil if not found
35
+ def which(programs, path=ENV["PATH"])
36
+ path.split(File::PATH_SEPARATOR).each do |dir|
37
+ Array(programs).each do |bin|
38
+ exe = File.join(dir, bin)
39
+ return exe if File.executable?(exe)
40
+ end
41
+ end
42
+ nil
43
+ end
44
+
45
+ module_function :which
46
+ end
47
+ end
@@ -0,0 +1,19 @@
1
+ # Copyright (c) 2012 VMware, Inc.
2
+
3
+ module Bosh::Exec
4
+ # Raised when there was an error executing the command
5
+ class Error < StandardError
6
+ def initialize(status, command)
7
+ @status = status
8
+ @command = command
9
+ end
10
+
11
+ def message
12
+ if @status
13
+ "command '#{@command}' failed with exit code #{@status}"
14
+ else
15
+ "command not found: #{@command}"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,35 @@
1
+ # Copyright (c) 2012 VMware, Inc.
2
+
3
+ module Bosh::Exec
4
+ class Result
5
+ # command that generated the result
6
+ # @return [String]
7
+ attr_reader :command
8
+ # output from the executed command
9
+ # @return [String]
10
+ attr_reader :output
11
+ # exit status of the command
12
+ # @return [Integer]
13
+ attr_reader :exit_status
14
+
15
+ def initialize(command, output, exit_status, not_found=false)
16
+ @command = command
17
+ @output = output
18
+ @exit_status = exit_status
19
+ @not_found = not_found
20
+ end
21
+
22
+ def success?
23
+ @exit_status == 0
24
+ end
25
+
26
+ def failed?
27
+ @exit_status != 0 || @not_found
28
+ end
29
+
30
+ # true if the command was not found
31
+ def not_found?
32
+ @not_found
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,87 @@
1
+ # Copyright (c) 2012 VMware, Inc.
2
+
3
+ require "common/exec/result"
4
+ require "common/exec/error"
5
+
6
+ module Bosh
7
+
8
+ # Module to execute shell commands using different ways to invoke processes.
9
+ module Exec
10
+
11
+ # Execute commands in a way that forces you to deal with failures and
12
+ # helps you to simplify testing. The module can be included which will
13
+ # add sh both as an instance and a class method.
14
+ #
15
+ # A sample way to mock the execution of "ls /":
16
+ # it "should be possible to mock the result of a command execution" do
17
+ # cmd = "ls /"
18
+ # result = Bosh::Exec::Result.new(cmd, "bin etc var", "", 0)
19
+ # Bosh::Exec.should_receive(:sh).with(cmd).and_return(result)
20
+ # result = Bosh::Exec.sh(cmd)
21
+ # result.success?.should be_true
22
+ # end
23
+ #
24
+ # @note As commands are executed using %x{...} you need to append 2>&1 to
25
+ # redirect stderr or it will be output to the stderr of the process
26
+ # invoking the sh method
27
+ # @param [String] command shell command to execute
28
+ # @param [Hash] options
29
+ # @option options [Symbol] :on_error if set to :return failing commands
30
+ # return [Bosh::Exec::Result] instead of raising [Bosh::Exec::Error]
31
+ # @option options [Symbol] :yield if set to :on_false it will execute
32
+ # the block when the command fails, else it will execute the block
33
+ # only when the command succeeds. Implies :on_error = :return
34
+ # @yield [Bosh::Exec::Result] command result
35
+ # @return [Bosh::Exec::Result] command result
36
+ # @raise [Bosh::Exec::Error] raised when the command isn't found or
37
+ # the command exits with a non zero status
38
+ # @example by default execute block only when command succeeds and raise
39
+ # error on failure
40
+ # sh("command") do |result|
41
+ # ...
42
+ # end
43
+ # @example don't raise error if the command fails
44
+ # result = sh("command", :on_error => :return)
45
+ # @example execute block only when command fails (which implies
46
+ # :on_error => :return)
47
+ # sh("command", :yield => :on_false) do |result|
48
+ # ...
49
+ # end
50
+ def sh(command, options={})
51
+ opts = options.dup
52
+ # can only yield if we don't raise errors
53
+ opts[:on_error] = :return if opts[:yield] == :on_false
54
+
55
+ output = %x{#{command}}
56
+ result = Result.new(command, output, $?.exitstatus)
57
+
58
+ if result.failed?
59
+ unless opts[:on_error] == :return
60
+ raise Error.new(result.exit_status, command)
61
+ end
62
+ yield result if block_given? && opts[:yield] == :on_false
63
+
64
+ else
65
+ yield result if block_given?
66
+ end
67
+
68
+ result
69
+ rescue Errno::ENOENT => e
70
+ msg = "command not found: #{command}"
71
+
72
+ raise Error.new(nil, command) unless opts[:on_error] == :return
73
+
74
+ result = Result.new(command, msg, -1, true)
75
+
76
+ yield result if block_given? && opts[:yield] == :on_false
77
+ result
78
+ end
79
+
80
+ # Helper method to add sh as a class method when it is included
81
+ def self.included(base)
82
+ base.extend(Bosh::Exec)
83
+ end
84
+
85
+ module_function :sh
86
+ end
87
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Bosh
4
4
  module Common
5
- VERSION = "0.4.0"
5
+ VERSION = "0.5.0"
6
6
  end
7
7
  end
data/spec/assets/foo1 ADDED
File without changes
data/spec/assets/foo2 ADDED
File without changes
data/spec/spec_helper.rb CHANGED
@@ -1,7 +1,13 @@
1
- require 'rspec/core'
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
2
 
3
- $:.unshift(File.expand_path("../../lib", __FILE__))
3
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
4
4
 
5
- RSpec.configure do |c|
6
- c.color_enabled = true
5
+ require "rubygems"
6
+ require "bundler"
7
+ Bundler.setup(:default, :test)
8
+
9
+ require "rspec"
10
+
11
+ def asset(file)
12
+ File.expand_path(File.join(File.dirname(__FILE__), "assets", file))
7
13
  end
@@ -0,0 +1,59 @@
1
+ # Copyright (c) 2012 VMware, Inc.
2
+
3
+ require "spec_helper"
4
+
5
+ require "common/common"
6
+
7
+ describe Bosh::Common do
8
+
9
+ describe "#symbolize_keys" do
10
+ ORIGINAL = {
11
+ "foo1" => "bar",
12
+ :foo2 => "bar",
13
+ "foo3" => {
14
+ "foo4" => "bar"
15
+ }
16
+ }.freeze
17
+
18
+ EXPECTED = {
19
+ :foo1 => "bar",
20
+ :foo2 => "bar",
21
+ :foo3 => {
22
+ :foo4 => "bar"
23
+ }
24
+ }.freeze
25
+
26
+ it "should not modify the original hash" do
27
+ duplicate = ORIGINAL.dup
28
+ Bosh::Common.symbolize_keys(ORIGINAL)
29
+ ORIGINAL.should == duplicate
30
+ end
31
+
32
+ it "should return a new hash with all keys as symbols" do
33
+ Bosh::Common.symbolize_keys(ORIGINAL).should == EXPECTED
34
+ end
35
+ end
36
+
37
+ describe "#which" do
38
+ let(:path) {
39
+ path = ENV["PATH"]
40
+ path += ":#{File.expand_path('../../assets', __FILE__)}"
41
+ }
42
+
43
+ it "should return the path when it finds the executable" do
44
+ Bosh::Common.which("foo1", path).should_not be_nil
45
+ end
46
+
47
+ it "should return the path when it finds an executable" do
48
+ Bosh::Common.which(%w[foo2 foo1], path).should match(%r{/foo1$})
49
+ end
50
+
51
+ it "should return nil when it isn't executable" do
52
+ Bosh::Common.which("foo2", path).should be_nil
53
+ end
54
+
55
+ it "should return nil when it doesn't find an executable" do
56
+ Bosh::Common.which("foo1").should be_nil
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,111 @@
1
+ # Copyright (c) 2012 VMware, Inc.
2
+
3
+ require "spec_helper"
4
+ require "common/exec"
5
+
6
+ describe Bosh::Exec do
7
+ let(:opts) { {} }
8
+
9
+ describe "existing command" do
10
+
11
+ describe "executes successfully" do
12
+ it "should not fail" do
13
+ Bosh::Exec.sh("ls /", opts).failed?.should be_false
14
+ end
15
+
16
+ it "should execute block" do
17
+ block = false
18
+ Bosh::Exec.sh("ls /", opts) do
19
+ block = true
20
+ end
21
+ block.should be_true
22
+ end
23
+ end
24
+
25
+ describe "fails to execute" do
26
+ it "should raise error by default" do
27
+ lambda {
28
+ Bosh::Exec.sh("ls /asdasd 2>&1", opts)
29
+ }.should raise_error Bosh::Exec::Error
30
+ end
31
+
32
+ it "should yield block on false" do
33
+ opts[:yield] = :on_false
34
+ block = false
35
+ Bosh::Exec.sh("ls /asdasd 2>&1", opts) do
36
+ block = true
37
+ end
38
+ block.should be_true
39
+ end
40
+
41
+ it "should return result" do
42
+ opts[:on_error] = :return
43
+ Bosh::Exec.sh("ls /asdasd 2>&1", opts).failed?.should be_true
44
+ end
45
+ end
46
+
47
+ end
48
+
49
+ describe "missing command" do
50
+ it "should raise error by default" do
51
+ lambda {
52
+ Bosh::Exec.sh("/asdasd 2>&1", opts)
53
+ }.should raise_error Bosh::Exec::Error
54
+ end
55
+
56
+ it "should not raise error when requested" do
57
+ opts[:on_error] = :return
58
+ lambda {
59
+ Bosh::Exec.sh("/asdasd 2>&1", opts)
60
+ }.should_not raise_error Bosh::Exec::Error
61
+ end
62
+
63
+ it "should execute block when requested" do
64
+ opts[:yield] = :on_false
65
+ lambda {
66
+ Bosh::Exec.sh("/asdasd 2>&1", opts) do
67
+ raise "foo"
68
+ end
69
+ }.should raise_error "foo"
70
+ end
71
+
72
+ end
73
+
74
+ describe "mock" do
75
+ it "should be possible fake result" do
76
+ cmd = "ls /"
77
+ result = Bosh::Exec::Result.new(cmd, "output", 0)
78
+ Bosh::Exec.should_receive(:sh).with(cmd).and_return(result)
79
+ result = Bosh::Exec.sh(cmd)
80
+ result.success?.should be_true
81
+ end
82
+ end
83
+
84
+ describe "module" do
85
+ it "should be possible to invoke as a module" do
86
+ Bosh::Exec.sh("ls /").success?.should be_true
87
+ end
88
+ end
89
+
90
+ describe "include" do
91
+ class IncludeTest
92
+ include Bosh::Exec
93
+ def run
94
+ sh("ls /")
95
+ end
96
+
97
+ def self.run
98
+ sh("ls /")
99
+ end
100
+ end
101
+
102
+ it "should add instance method" do
103
+ inc = IncludeTest.new
104
+ inc.run.success?.should be_true
105
+ end
106
+
107
+ it "should add class method" do
108
+ IncludeTest.run.success?.should be_true
109
+ end
110
+ end
111
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bosh_common
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,33 +9,28 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-02-22 00:00:00.000000000Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
15
- name: rspec
16
- requirement: &2156296060 !ruby/object:Gem::Requirement
17
- none: false
18
- requirements:
19
- - - ! '>='
20
- - !ruby/object:Gem::Version
21
- version: '0'
22
- type: :development
23
- prerelease: false
24
- version_requirements: *2156296060
25
- description: Bosh common
12
+ date: 2012-07-27 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: BOSH common
26
15
  email: support@vmware.com
27
16
  executables: []
28
17
  extensions: []
29
18
  extra_rdoc_files: []
30
19
  files:
31
- - README
32
- - Rakefile
20
+ - lib/common/common.rb
21
+ - lib/common/exec.rb
22
+ - lib/common/exec/error.rb
23
+ - lib/common/exec/result.rb
33
24
  - lib/common/thread_formatter.rb
34
25
  - lib/common/thread_pool.rb
35
26
  - lib/common/version.rb
36
- - spec/Rakefile
37
- - spec/lib/cloud/spec.rb
27
+ - README
28
+ - Rakefile
29
+ - spec/assets/foo1
30
+ - spec/assets/foo2
38
31
  - spec/spec_helper.rb
32
+ - spec/unit/common_spec.rb
33
+ - spec/unit/exec_spec.rb
39
34
  - spec/unit/thread_pool_spec.rb
40
35
  homepage: http://www.vmware.com
41
36
  licenses: []
@@ -51,7 +46,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
51
46
  version: '0'
52
47
  segments:
53
48
  - 0
54
- hash: -472840810854006979
49
+ hash: 852108980354805257
55
50
  required_rubygems_version: !ruby/object:Gem::Requirement
56
51
  none: false
57
52
  requirements:
@@ -60,15 +55,18 @@ required_rubygems_version: !ruby/object:Gem::Requirement
60
55
  version: '0'
61
56
  segments:
62
57
  - 0
63
- hash: -472840810854006979
58
+ hash: 852108980354805257
64
59
  requirements: []
65
60
  rubyforge_project:
66
- rubygems_version: 1.8.10
61
+ rubygems_version: 1.8.24
67
62
  signing_key:
68
63
  specification_version: 3
69
- summary: Bosh common
64
+ summary: BOSH common
70
65
  test_files:
71
- - spec/Rakefile
72
- - spec/lib/cloud/spec.rb
66
+ - spec/assets/foo1
67
+ - spec/assets/foo2
73
68
  - spec/spec_helper.rb
69
+ - spec/unit/common_spec.rb
70
+ - spec/unit/exec_spec.rb
74
71
  - spec/unit/thread_pool_spec.rb
72
+ has_rdoc:
data/spec/Rakefile DELETED
@@ -1,87 +0,0 @@
1
- require "tempfile"
2
- require "rake"
3
-
4
- APP_DIR = File.expand_path(File.join("..", ".."), __FILE__)
5
- ENV["BUNDLE_GEMFILE"] ||= File.join(APP_DIR, "Gemfile")
6
- require "rubygems"
7
- require "bundler"
8
- Bundler.setup(:default, :test)
9
-
10
- require "rspec/core/rake_task"
11
- require "ci/reporter/rake/rspec"
12
-
13
- desc "Run all examples"
14
- RSpec::Core::RakeTask.new(:spec) do |t|
15
- t.pattern = "**/*_spec.rb"
16
- t.rspec_opts = %w[--color]
17
- end
18
-
19
- task :default => [:spec]
20
-
21
- coverage_dir = File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_coverage"))
22
- reports_dir = File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_reports"))
23
- dump_file = File.join(Dir.tmpdir, "bosh-common.rcov")
24
-
25
- ENV["CI_REPORTS"] = reports_dir
26
-
27
- namespace "spec" do
28
- gemfile = "../Gemfile"
29
- spec_opts = ["--format", "documentation", "--colour"]
30
-
31
- if RUBY_VERSION < "1.9"
32
- desc "Run specs for ci"
33
- task "ci" => [ "ci:setup:rspec", "spec:rcov", "convert_rcov_to_clover" ]
34
-
35
- desc "Run spec with coverage"
36
- RSpec::Core::RakeTask.new("rcov") do |t|
37
- FileUtils.rm_rf(dump_file)
38
- t.gemfile = gemfile
39
- t.pattern = "**/*_spec.rb"
40
- t.rspec_opts = ["--format", "progress", "--colour"]
41
- t.rcov = true
42
- t.rcov_opts = %W{--aggregate #{dump_file} --exclude osx\/objc,gems\/,spec\/,unit\/,features\/ -o "#{coverage_dir}"}
43
- end
44
-
45
- task "convert_rcov_to_clover" do |t|
46
- ignore_pattern = "spec,[.]bundle,[/]gems[/]"
47
- clover_output = File.join(coverage_dir, "clover.xml")
48
-
49
- sh("bundle exec rcov_analyzer #{dump_file} #{ignore_pattern} > #{clover_output}")
50
- FileUtils.rm_rf(dump_file)
51
- end
52
-
53
- else
54
- desc "Run specs for ci"
55
- task "ci" => [ "ci:setup:rspec", "spec:rcov" ]
56
-
57
- desc "Run spec with coverage"
58
- task :rcov => :cleanup_coverage do
59
- require "simplecov"
60
- require "simplecov-rcov"
61
- require "simplecov-clover"
62
-
63
- class SimpleCov::Formatter::CombinedFormatter
64
- def format(result)
65
- SimpleCov::Formatter::CloverFormatter.new.format(result)
66
- SimpleCov::Formatter::RcovFormatter.new.format(result)
67
- end
68
- end
69
-
70
- SimpleCov.formatter = SimpleCov::Formatter::CombinedFormatter
71
- SimpleCov.root('..')
72
- SimpleCov.coverage_dir('cov')
73
- SimpleCov.start do
74
- require "rspec/core"
75
- add_filter "/spec/"
76
- spec_dir = File.expand_path("..", __FILE__)
77
- RSpec::Core::Runner.disable_autorun!
78
- RSpec::Core::Runner.run([spec_dir], STDERR, STDOUT)
79
- end
80
- end
81
- end
82
-
83
- task "cleanup_coverage" do
84
- rm_rf "cov"
85
- end
86
-
87
- end
@@ -1,8 +0,0 @@
1
- module Bosh
2
- module Clouds
3
- class Spec
4
- def initialize(options)
5
- end
6
- end
7
- end
8
- end