bosh_common 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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