nickstenning-outback 0.0.3 → 0.0.4
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/README.markdown +3 -0
- data/Rakefile +9 -0
- data/lib/outback.rb +2 -3
- data/lib/outback/manager.rb +53 -63
- data/lib/outback/task.rb +35 -0
- data/lib/outback/task_helper.rb +39 -0
- data/outback.gemspec +2 -2
- data/spec/fixtures/example_manager.rb +61 -0
- data/spec/outback/manager_spec.rb +102 -52
- data/spec/outback/task_helper_spec.rb +46 -0
- data/spec/outback/task_spec.rb +41 -0
- metadata +8 -5
- data/lib/outback/shelltask.rb +0 -53
- data/lib/outback/yaml.rb +0 -22
- data/spec/outback/shelltask_spec.rb +0 -92
- data/spec/outback/yaml_spec.rb +0 -47
data/README.markdown
ADDED
@@ -0,0 +1,3 @@
|
|
1
|
+
# Outback - a transactional shell runner
|
2
|
+
|
3
|
+
Outback is a simple ruby library for running transactional pairs of shell commands ("rollout/rollback") in a known sequence. It's useful for running a set of dependent commands one after another with the ability to stop, find out what's gone wrong, and rollback all the steps so far if something goes awry.
|
data/Rakefile
ADDED
data/lib/outback.rb
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
require 'outback/manager'
|
2
|
-
require 'outback/
|
3
|
-
require 'outback/
|
2
|
+
require 'outback/task_helper'
|
3
|
+
require 'outback/task'
|
4
4
|
|
5
5
|
module Outback
|
6
6
|
|
7
7
|
class Error < RuntimeError; end
|
8
8
|
class TransactionError < Error; end
|
9
|
-
class DuplicateNamedTaskError < Error; end
|
10
9
|
|
11
10
|
end
|
data/lib/outback/manager.rb
CHANGED
@@ -1,104 +1,94 @@
|
|
1
1
|
require 'yaml'
|
2
|
+
require 'observer'
|
2
3
|
|
3
4
|
module Outback
|
4
5
|
|
5
6
|
class Manager
|
6
7
|
|
8
|
+
include Observable
|
9
|
+
|
7
10
|
ROLLOUT = 1
|
8
11
|
ROLLBACK = -1
|
9
12
|
|
10
|
-
attr_reader :tasks
|
11
|
-
attr_accessor :workdir
|
12
|
-
attr_writer :watcher
|
13
|
+
attr_reader :tasks
|
14
|
+
attr_accessor :direction, :position, :workdir, :cache
|
13
15
|
|
14
16
|
def initialize
|
15
17
|
@tasks = []
|
16
|
-
@
|
18
|
+
@cache = {}
|
17
19
|
@position = 0
|
20
|
+
@direction = 1
|
18
21
|
end
|
19
22
|
|
20
23
|
def add_tasks( *tasks )
|
21
|
-
|
22
|
-
task.workdir = @workdir unless task.workdir
|
23
|
-
|
24
|
-
if task.name
|
25
|
-
if @names.has_key?(task.name)
|
26
|
-
raise DuplicateNamedTaskError, "Cannot add a named task more than once!"
|
27
|
-
else
|
28
|
-
@names[task.name] = @tasks.length
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
@tasks << task
|
33
|
-
end
|
24
|
+
@tasks += tasks
|
34
25
|
end
|
35
26
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
27
|
+
def add_task( task=nil, &block )
|
28
|
+
if block_given?
|
29
|
+
task = Outback::Task.new(&block)
|
30
|
+
end
|
31
|
+
add_tasks( task ) if task
|
40
32
|
end
|
41
33
|
|
42
34
|
def rollout!
|
43
35
|
@direction = ROLLOUT
|
44
|
-
|
36
|
+
run_all
|
45
37
|
end
|
46
38
|
|
47
39
|
def rollback!
|
48
40
|
@direction = ROLLBACK
|
49
|
-
|
41
|
+
run_all
|
50
42
|
end
|
51
43
|
|
52
|
-
def
|
53
|
-
|
54
|
-
|
44
|
+
def run_all
|
45
|
+
cache.delete(:errors)
|
46
|
+
|
47
|
+
tasks_to_run.each do |task|
|
48
|
+
temp = cache.dup
|
49
|
+
begin
|
50
|
+
run task, @direction
|
51
|
+
rescue => e
|
52
|
+
self.cache = temp
|
53
|
+
cache[:errors] ||= []
|
54
|
+
cache[:errors] << e
|
55
|
+
break false
|
56
|
+
end
|
57
|
+
@position += @direction
|
58
|
+
changed
|
59
|
+
notify_observers(state, cache)
|
60
|
+
end
|
55
61
|
end
|
56
62
|
|
57
|
-
def
|
58
|
-
|
59
|
-
|
63
|
+
def tasks_to_run
|
64
|
+
if @direction == ROLLOUT
|
65
|
+
@tasks[@position..-1]
|
66
|
+
elsif @direction == ROLLBACK
|
67
|
+
@tasks[0...@position].reverse
|
68
|
+
end
|
60
69
|
end
|
61
70
|
|
62
|
-
def
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
return ret
|
71
|
+
def state
|
72
|
+
{ :position => @position,
|
73
|
+
:direction => @direction
|
74
|
+
}
|
67
75
|
end
|
68
76
|
|
69
|
-
def
|
70
|
-
@
|
77
|
+
def restore_state( state )
|
78
|
+
@position = state[:position] || @position
|
79
|
+
@direction = state[:direction] || @direction
|
80
|
+
self
|
71
81
|
end
|
82
|
+
|
83
|
+
def run( task, direction=1 )
|
84
|
+
method = { ROLLOUT => :rollout!, ROLLBACK => :rollback! }[direction]
|
72
85
|
|
73
|
-
|
74
|
-
|
75
|
-
def run
|
76
|
-
if @direction == ROLLOUT
|
77
|
-
task_list = @tasks[@position..-1]
|
78
|
-
elsif @direction == ROLLBACK
|
79
|
-
task_list = @tasks[0..@position + 1].reverse
|
80
|
-
end
|
81
|
-
task_list.each do |task|
|
82
|
-
@position = @tasks.index(task)
|
83
|
-
unless attempt current_task
|
84
|
-
fail
|
85
|
-
break
|
86
|
-
end
|
87
|
-
end
|
86
|
+
task.send(method, task_helper)
|
88
87
|
end
|
89
88
|
|
90
|
-
def
|
91
|
-
|
92
|
-
when ROLLOUT
|
93
|
-
#rollback_from current_task
|
94
|
-
raise Error, "Could not rollout task #{current_task}, attempting rollback."
|
95
|
-
when ROLLBACK
|
96
|
-
raise TransactionError, "Could not rollback task #{current_task}, aborting."
|
97
|
-
else
|
98
|
-
raise Error, "Unknown direction!"
|
99
|
-
end
|
89
|
+
def task_helper
|
90
|
+
@task_helper ||= TaskHelper.new(self)
|
100
91
|
end
|
101
|
-
|
102
92
|
end
|
103
93
|
|
104
|
-
end
|
94
|
+
end
|
data/lib/outback/task.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
module Outback
|
2
|
+
class Task
|
3
|
+
def initialize
|
4
|
+
@rollback = proc {}
|
5
|
+
@rollout = proc {}
|
6
|
+
if block_given?
|
7
|
+
yield self
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def rollout( &block )
|
12
|
+
if block_given?
|
13
|
+
@rollout = block
|
14
|
+
else
|
15
|
+
@rollout
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def rollback( &block )
|
20
|
+
if block_given?
|
21
|
+
@rollback = block
|
22
|
+
else
|
23
|
+
@rollback
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def rollout!( task_helper = nil )
|
28
|
+
@rollout.call(task_helper)
|
29
|
+
end
|
30
|
+
|
31
|
+
def rollback!( task_helper = nil )
|
32
|
+
@rollback.call(task_helper)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'open4'
|
3
|
+
|
4
|
+
module Outback
|
5
|
+
class TaskHelper
|
6
|
+
def initialize( manager=nil )
|
7
|
+
@manager = manager
|
8
|
+
end
|
9
|
+
|
10
|
+
def cache
|
11
|
+
if @manager and cache = @manager.cache
|
12
|
+
cache
|
13
|
+
else
|
14
|
+
{}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def workdir
|
19
|
+
if @manager and workdir = @manager.workdir
|
20
|
+
workdir
|
21
|
+
else
|
22
|
+
Dir.getwd
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def sys( command )
|
27
|
+
result = {}
|
28
|
+
Dir.chdir(workdir) do
|
29
|
+
status = Open4.popen4(*command) do |pid, i, o, e|
|
30
|
+
result[:stdout] = o.read
|
31
|
+
result[:stderr] = e.read
|
32
|
+
end
|
33
|
+
result[:exit_status] = status.exitstatus
|
34
|
+
end
|
35
|
+
return result
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
data/outback.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = %q{outback}
|
3
|
-
s.version = "0.0.
|
3
|
+
s.version = "0.0.4"
|
4
4
|
|
5
5
|
s.specification_version = 2 if s.respond_to? :specification_version=
|
6
6
|
|
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.authors = ["Nick Stenning"]
|
9
9
|
s.date = %q{2008-07-14}
|
10
10
|
s.email = ["nick@whiteink.com"]
|
11
|
-
s.files = ["lib/outback/manager.rb", "lib/outback/
|
11
|
+
s.files = ["lib/outback/manager.rb", "lib/outback/task.rb", "lib/outback/task_helper.rb", "lib/outback.rb", "outback.gemspec", "Rakefile", "README.markdown", "spec/fixtures/example_manager.rb", "spec/outback/manager_spec.rb", "spec/outback/task_helper_spec.rb", "spec/outback/task_spec.rb", "spec/spec_helper.rb"]
|
12
12
|
s.has_rdoc = true
|
13
13
|
s.homepage = %q{http://github.com/nickstenning/outback}
|
14
14
|
s.require_paths = ["lib"]
|
@@ -0,0 +1,61 @@
|
|
1
|
+
$: << File.expand_path(File.dirname(__FILE__) + '/../../lib')
|
2
|
+
require 'outback'
|
3
|
+
|
4
|
+
include Outback
|
5
|
+
|
6
|
+
if $0 == __FILE__
|
7
|
+
|
8
|
+
@man = Manager.new
|
9
|
+
|
10
|
+
@man.add_task do |t|
|
11
|
+
t.rollout do |m|
|
12
|
+
m.cache[:result] = 1
|
13
|
+
end
|
14
|
+
t.rollback do |m|
|
15
|
+
m.cache.delete(:result)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
@man.add_task do |t|
|
20
|
+
t.rollout do |m|
|
21
|
+
m.cache[:result] += 2
|
22
|
+
end
|
23
|
+
t.rollback do |m|
|
24
|
+
m.cache[:result] -= 2
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
@man.add_task do |t|
|
29
|
+
t.rollout do |m|
|
30
|
+
m.cache[:number_three] = m.cache[:result]
|
31
|
+
end
|
32
|
+
t.rollback do |m|
|
33
|
+
m.cache.delete(:number_three)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
@man.add_task do |t|
|
38
|
+
t.rollout do |m|
|
39
|
+
m.cache[:b0rk] = "hello"
|
40
|
+
end
|
41
|
+
t.rollback do |m|
|
42
|
+
m.cache.delete(:b0rk)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
@man.add_task do |t|
|
47
|
+
t.rollout do |m|
|
48
|
+
m.cache[:syscall] = m.sys("pwd")[:stdout].strip
|
49
|
+
end
|
50
|
+
t.rollback do |m|
|
51
|
+
m.cache.delete(:syscall)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
@man.rollout!
|
56
|
+
y @man.cache
|
57
|
+
@man.rollback!
|
58
|
+
y @man.cache
|
59
|
+
|
60
|
+
|
61
|
+
end
|
@@ -5,9 +5,9 @@ describe Outback::Manager do
|
|
5
5
|
|
6
6
|
before do
|
7
7
|
@obm = Outback::Manager.new
|
8
|
-
@task1 = mock(
|
9
|
-
@task2 = mock(
|
10
|
-
@task3 = mock(
|
8
|
+
@task1 = mock(:task1, :null_object => true)
|
9
|
+
@task2 = mock(:task2, :null_object => true)
|
10
|
+
@task3 = mock(:task3, :null_object => true)
|
11
11
|
end
|
12
12
|
|
13
13
|
it "should have a list of tasks" do
|
@@ -22,6 +22,12 @@ describe Outback::Manager do
|
|
22
22
|
@obm.should have(2).tasks
|
23
23
|
end
|
24
24
|
|
25
|
+
it "should add a new Outback::Task and add it if #add_task is called with a block" do
|
26
|
+
@obm.add_task do
|
27
|
+
end
|
28
|
+
@obm.should have(1).tasks
|
29
|
+
end
|
30
|
+
|
25
31
|
it "should add multiple tasks to its list, in order, with #add_tasks" do
|
26
32
|
@obm.add_tasks(@task1, @task2, @task3)
|
27
33
|
@obm.should have(3).tasks
|
@@ -30,20 +36,20 @@ describe Outback::Manager do
|
|
30
36
|
@obm.tasks[2].should == @task3
|
31
37
|
end
|
32
38
|
|
33
|
-
it "should
|
34
|
-
|
35
|
-
|
36
|
-
lambda { @obm.add_tasks(@task1, @task3, @task3) }.should raise_error(Outback::DuplicateNamedTaskError)
|
39
|
+
it "should give a hash representing its state on #state" do
|
40
|
+
@obm.state[:position].should == 0
|
41
|
+
@obm.state[:direction].should == 1
|
37
42
|
end
|
38
43
|
|
39
|
-
it "should
|
40
|
-
|
44
|
+
it "should restore its state when passed in a state hash on #restore_state" do
|
45
|
+
@obm.restore_state({:position => 3, :direction => -1})
|
46
|
+
@obm.position.should == 3
|
47
|
+
@obm.direction.should == -1
|
41
48
|
end
|
42
49
|
|
43
|
-
it "should
|
44
|
-
@obm.
|
45
|
-
@obm.
|
46
|
-
@obm.find_task('task3').should == @task3
|
50
|
+
it "should update its cache with #cache=" do
|
51
|
+
@obm.cache = {:foo => "bar"}
|
52
|
+
@obm.cache[:foo].should == "bar"
|
47
53
|
end
|
48
54
|
|
49
55
|
describe "(with a few tasks)" do
|
@@ -52,67 +58,111 @@ describe Outback::Manager do
|
|
52
58
|
@obm.add_tasks(@task1, @task2)
|
53
59
|
end
|
54
60
|
|
55
|
-
it "should
|
56
|
-
@
|
57
|
-
@task2.should_receive(:rollout!).and_return(true)
|
58
|
-
@obm.rollout!
|
61
|
+
it "should, by default, be rolling out" do
|
62
|
+
@obm.direction.should == Outback::Manager::ROLLOUT
|
59
63
|
end
|
60
64
|
|
61
|
-
it "should
|
62
|
-
@
|
63
|
-
@task2.should_receive(:rollout!).and_return(true)
|
64
|
-
@obm.rollout!
|
65
|
+
it "should start at the first task" do
|
66
|
+
@obm.position.should == 0
|
65
67
|
end
|
66
68
|
|
67
|
-
it "should
|
68
|
-
@
|
69
|
-
@
|
70
|
-
@
|
71
|
-
@
|
72
|
-
|
69
|
+
it "should report the tasks it will run in any given state with #tasks_to_run" do
|
70
|
+
@obm.add_task(@task3)
|
71
|
+
@obm.tasks_to_run.should == [@task1, @task2, @task3]
|
72
|
+
@obm.direction = -1
|
73
|
+
@obm.tasks_to_run.should be_empty
|
74
|
+
@obm.position = 3
|
75
|
+
@obm.tasks_to_run.should == [@task3, @task2, @task1]
|
76
|
+
@obm.position = 2
|
77
|
+
@obm.tasks_to_run.should == [@task2, @task1]
|
78
|
+
@obm.direction = 1
|
79
|
+
@obm.tasks_to_run.should == [@task3]
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should call each task's #rollout! method, in order, on #rollout!" do
|
83
|
+
@task1.should_receive(:rollout!)
|
84
|
+
@task2.should_receive(:rollout!)
|
85
|
+
@obm.rollout!.should == [@task1, @task2]
|
73
86
|
end
|
74
87
|
|
75
|
-
it "should
|
76
|
-
@task2.should_receive(:rollback!).and_return(false)
|
88
|
+
it "should not roll back any tasks if it isn't already rolled out" do
|
77
89
|
@task1.should_not_receive(:rollback!)
|
78
|
-
|
90
|
+
@task2.should_not_receive(:rollback!)
|
91
|
+
@obm.rollback!.should be_empty
|
79
92
|
end
|
80
93
|
|
81
|
-
|
82
|
-
|
83
|
-
|
94
|
+
it "should halt the rollout if any task's #rollout! method throws an error, and put the error in the cache" do
|
95
|
+
@error_task = mock(:error_task, :null_object => true)
|
96
|
+
@error_task.should_receive(:rollout!).and_raise("Just some runtime error.")
|
97
|
+
@obm.add_tasks(@error_task, @task2)
|
98
|
+
@obm.rollout!.should_not be_true
|
99
|
+
@obm.cache.should have(1).error
|
100
|
+
@obm.tasks_to_run.should == [@error_task, @task2]
|
101
|
+
end
|
84
102
|
|
85
|
-
before do
|
86
|
-
@
|
87
|
-
@
|
88
|
-
@
|
89
|
-
@obm.
|
90
|
-
@obm.
|
103
|
+
it "should clear the cache errors before every rollout or rollback" do
|
104
|
+
@obm.cache[:errors] = "I'm an error."
|
105
|
+
@obm.rollout!
|
106
|
+
@obm.cache[:errors].should be_nil
|
107
|
+
@obm.cache[:errors] = "I'm an error."
|
108
|
+
@obm.rollback!
|
109
|
+
@obm.cache[:errors].should be_nil
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
it "should run each task in a transactional manner, so changes to the cache that are followed by an error are reversed" do
|
114
|
+
@error_task = Outback::Task.new do |t|
|
115
|
+
t.rollout do |m|
|
116
|
+
m.cache[:result] = "Foo"
|
117
|
+
raise "Some cockup!"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
@obm.add_tasks(@error_task, @task2)
|
122
|
+
@obm.rollout!.should_not be_true
|
123
|
+
@obm.cache[:result].should be_nil
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should call each task's #rollback! method, in reverse order, on #rollback!, provided it's already rolled out" do
|
127
|
+
@obm.position = 2
|
128
|
+
@task2.should_receive(:rollback!)
|
129
|
+
@task1.should_receive(:rollback!)
|
130
|
+
@obm.rollback!.should == [@task2, @task1]
|
91
131
|
end
|
92
132
|
|
93
|
-
it "should
|
94
|
-
@
|
95
|
-
@
|
133
|
+
it "should not roll out any tasks if it isn't already rolled back" do
|
134
|
+
@obm.position = 2
|
135
|
+
@task1.should_not_receive(:rollout!)
|
136
|
+
@task2.should_not_receive(:rollout!)
|
137
|
+
@obm.rollout!.should be_empty
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should pass an instance of TaskHelper into tasks' #rollout! and #rollback! methods" do
|
141
|
+
th = @obm.task_helper
|
142
|
+
@task1.should_receive(:rollout!).with(th)
|
143
|
+
@obm.rollout!
|
96
144
|
end
|
97
145
|
|
98
146
|
end
|
99
147
|
|
100
|
-
describe "(with
|
148
|
+
describe "(with observers)" do
|
101
149
|
|
102
150
|
before do
|
103
|
-
@task1 = Outback::ShellTask.new("pwd", "")
|
104
|
-
@task2 = Outback::ShellTask.new("echo 'hello'", "")
|
105
|
-
require 'tempfile'
|
106
|
-
@obm.workdir = Dir.tmpdir
|
107
151
|
@obm.add_tasks(@task1, @task2)
|
108
|
-
|
109
|
-
@
|
152
|
+
|
153
|
+
@watcher = mock(:watcher)
|
154
|
+
@watcher.stub!(:update)
|
155
|
+
|
156
|
+
@obm.add_observer(@watcher)
|
110
157
|
end
|
111
158
|
|
112
|
-
it "should call the watcher's #
|
113
|
-
@watcher.should_receive(:
|
114
|
-
@watcher.should_receive(:
|
159
|
+
it "should call the watcher's #update method after each rollout or rollback with a state hash and the results cache as parameters." do
|
160
|
+
@watcher.should_receive(:update).ordered.with({:position => 1, :direction => 1}, {})
|
161
|
+
@watcher.should_receive(:update).ordered.with({:position => 2, :direction => 1}, {})
|
162
|
+
@watcher.should_receive(:update).ordered.with({:position => 1, :direction => -1}, {})
|
163
|
+
@watcher.should_receive(:update).ordered.with({:position => 0, :direction => -1}, {})
|
115
164
|
@obm.rollout!
|
165
|
+
@obm.rollback!
|
116
166
|
end
|
117
167
|
|
118
168
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Outback::TaskHelper do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@th = Outback::TaskHelper.new(@manager)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should give an empty hash on #cache" do
|
10
|
+
@th.cache.should be_a_kind_of(Hash)
|
11
|
+
@th.cache.should be_empty
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should give the current working directory on #workdir" do
|
15
|
+
@th.workdir.should == Dir.getwd
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should provide a #sys method which makes a system call, returning a hash with stdout, stderr and exit_status" do
|
19
|
+
result = @th.sys("pwd")
|
20
|
+
result[:stdout].should == Dir.getwd + "\n"
|
21
|
+
result[:stderr].should == ""
|
22
|
+
result[:exit_status].should == 0
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "(with a manager set)" do
|
26
|
+
before do
|
27
|
+
@cache = {}
|
28
|
+
@manager = mock(:manager, :cache => @cache, :workdir => '/myworkdir')
|
29
|
+
@th = Outback::TaskHelper.new(@manager)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should give the manager's cache on #cache" do
|
33
|
+
@th.cache.should == @cache
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should give the manager's workdir on #workdir" do
|
37
|
+
@th.workdir.should == '/myworkdir'
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should execute calls to sys in the workdir" do
|
41
|
+
@manager.should_receive(:workdir).and_return("/")
|
42
|
+
lambda { @result = @th.sys("pwd") }.should_not raise_error
|
43
|
+
@result[:stdout].should == "/\n"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Outback::Task do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@task = Outback::Task.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should take an optional block on its constructor, passing itself in as the block parameter" do
|
10
|
+
lambda { @task = Outback::Task.new }.should_not raise_error
|
11
|
+
temp = nil
|
12
|
+
@task = Outback::Task.new do |t|
|
13
|
+
temp = t
|
14
|
+
end
|
15
|
+
temp.should == @task
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should have blank rollout and rollback procs by default" do
|
19
|
+
@task.rollout.call.should be_nil
|
20
|
+
@task.rollback.call.should be_nil
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should define rollout and rollback tasks by calling #rollback and #rollout with a block" do
|
24
|
+
@task.rollout { 1 + 2 }
|
25
|
+
@task.rollout.call.should == 3
|
26
|
+
@task.rollback { 4 + 2 }
|
27
|
+
@task.rollback.call.should == 6
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "(with a rollout and rollback task defined)" do
|
31
|
+
before do
|
32
|
+
@task.rollout { 1 + 2 }
|
33
|
+
@task.rollback { 4 + 2 }
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should run the rollback/rollout procs when called with #rollout!/#rollback!, returning the return value of the proc" do
|
37
|
+
@task.rollout!.should == 3
|
38
|
+
@task.rollback!.should == 6
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nickstenning-outback
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Stenning
|
@@ -32,13 +32,16 @@ extra_rdoc_files: []
|
|
32
32
|
|
33
33
|
files:
|
34
34
|
- lib/outback/manager.rb
|
35
|
-
- lib/outback/
|
36
|
-
- lib/outback/
|
35
|
+
- lib/outback/task.rb
|
36
|
+
- lib/outback/task_helper.rb
|
37
37
|
- lib/outback.rb
|
38
38
|
- outback.gemspec
|
39
|
+
- Rakefile
|
40
|
+
- README.markdown
|
41
|
+
- spec/fixtures/example_manager.rb
|
39
42
|
- spec/outback/manager_spec.rb
|
40
|
-
- spec/outback/
|
41
|
-
- spec/outback/
|
43
|
+
- spec/outback/task_helper_spec.rb
|
44
|
+
- spec/outback/task_spec.rb
|
42
45
|
- spec/spec_helper.rb
|
43
46
|
has_rdoc: true
|
44
47
|
homepage: http://github.com/nickstenning/outback
|
data/lib/outback/shelltask.rb
DELETED
@@ -1,53 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'open4'
|
3
|
-
|
4
|
-
module Outback
|
5
|
-
|
6
|
-
class ShellTask
|
7
|
-
|
8
|
-
attr_accessor :rollout, :rollback, :workdir, :name
|
9
|
-
attr_reader :result, :errors, :exit_code
|
10
|
-
|
11
|
-
def initialize(out, back)
|
12
|
-
@rollout, @rollback = out, back
|
13
|
-
@rolled_out = false
|
14
|
-
end
|
15
|
-
|
16
|
-
def rollout!
|
17
|
-
run @rollout
|
18
|
-
@rolled_out = true
|
19
|
-
return @exit_code == 0
|
20
|
-
end
|
21
|
-
|
22
|
-
def rollback!
|
23
|
-
run @rollback
|
24
|
-
@rolled_out = false
|
25
|
-
return @exit_code == 0
|
26
|
-
end
|
27
|
-
|
28
|
-
def rolled_out?
|
29
|
-
@rolled_out
|
30
|
-
end
|
31
|
-
|
32
|
-
def reset_strings
|
33
|
-
@result, @errors = "", ""
|
34
|
-
end
|
35
|
-
|
36
|
-
def run( command )
|
37
|
-
reset_strings
|
38
|
-
Dir.chdir(@workdir || Dir.getwd) do
|
39
|
-
@status = Open4.popen4(*command) do |pid, i, o, e|
|
40
|
-
@result = o.read
|
41
|
-
@errors = e.read
|
42
|
-
end
|
43
|
-
@exit_code = @status.exitstatus
|
44
|
-
end
|
45
|
-
# Catch nonexistent commands at this point and return a sensible error
|
46
|
-
rescue Errno::ENOENT => e
|
47
|
-
@exit_code = 127
|
48
|
-
@errors = e.message
|
49
|
-
end
|
50
|
-
|
51
|
-
end
|
52
|
-
|
53
|
-
end
|
data/lib/outback/yaml.rb
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
module Outback
|
2
|
-
|
3
|
-
module YAML
|
4
|
-
|
5
|
-
def self.load( yaml_string )
|
6
|
-
manager = Manager.new
|
7
|
-
tasks = ::YAML.load(yaml_string)
|
8
|
-
tasks.each do |task|
|
9
|
-
task = [task['out'], task['back']]
|
10
|
-
manager.tasks << Outback::ShellTask.new(*task)
|
11
|
-
end
|
12
|
-
return manager
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.load_file( yaml_file )
|
16
|
-
yaml = File.read( yaml_file )
|
17
|
-
load( yaml )
|
18
|
-
end
|
19
|
-
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
@@ -1,92 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
-
|
3
|
-
describe Outback::ShellTask do
|
4
|
-
|
5
|
-
before do
|
6
|
-
@task = Outback::ShellTask.new("out", "back")
|
7
|
-
end
|
8
|
-
|
9
|
-
it "should have an attr_accessor for @name" do
|
10
|
-
@task.name.should be_nil
|
11
|
-
@task.name = "Henry"
|
12
|
-
@task.name.should == "Henry"
|
13
|
-
end
|
14
|
-
|
15
|
-
it "should use the first parameter to the rollout command" do
|
16
|
-
@task.rollout.should == "out"
|
17
|
-
end
|
18
|
-
|
19
|
-
it "should use the second parameter as the rollback command" do
|
20
|
-
@task.rollback.should == "back"
|
21
|
-
end
|
22
|
-
|
23
|
-
it "should allow its rollout command to be changed with #rollout=" do
|
24
|
-
@task.rollout = "foo"
|
25
|
-
@task.rollout.should == "foo"
|
26
|
-
end
|
27
|
-
|
28
|
-
it "should allow its rollback command to be changed with #rollback=" do
|
29
|
-
@task.rollout = "bar"
|
30
|
-
@task.rollout.should == "bar"
|
31
|
-
end
|
32
|
-
|
33
|
-
it "should not be rolled out by default" do
|
34
|
-
@task.should_not be_rolled_out
|
35
|
-
end
|
36
|
-
|
37
|
-
it "should rollout when called with #rollout!" do
|
38
|
-
@task.rollout!
|
39
|
-
@task.should be_rolled_out
|
40
|
-
end
|
41
|
-
|
42
|
-
it "should run its commands in the current working directory if #workdir hasn't been set" do
|
43
|
-
@task = Outback::ShellTask.new("pwd", "")
|
44
|
-
@task.rollout!
|
45
|
-
@task.result.chomp.should == Dir.getwd
|
46
|
-
end
|
47
|
-
|
48
|
-
it "should run its commands in the workdir, if set with #workdir=" do
|
49
|
-
@task = Outback::ShellTask.new("pwd", "")
|
50
|
-
@task.workdir = "/private/tmp" ## FIXME for *nix systems
|
51
|
-
@task.rollout!
|
52
|
-
@task.result.chomp.should == @task.workdir
|
53
|
-
end
|
54
|
-
|
55
|
-
it "should return true on successful #rollout! or #rollback!" do
|
56
|
-
@task = Outback::ShellTask.new("echo", "echo")
|
57
|
-
@task.rollout!.should be_true
|
58
|
-
@task.rollback!.should be_true
|
59
|
-
end
|
60
|
-
|
61
|
-
it "should return false on unsuccessful #rollout! or #rollback!" do
|
62
|
-
@task = Outback::ShellTask.new("I-am-a-command-most-unlikely-to-exist", "I-am-a-command-most-unlikely-to-exist")
|
63
|
-
@task.rollout!.should be_false
|
64
|
-
@task.rollback!.should be_false
|
65
|
-
end
|
66
|
-
|
67
|
-
describe "(when rolled out)" do
|
68
|
-
|
69
|
-
before do
|
70
|
-
@task = Outback::ShellTask.new('pwd', 'pwd')
|
71
|
-
@task.rollout!
|
72
|
-
end
|
73
|
-
|
74
|
-
it "should be rolled out" do
|
75
|
-
@task.should be_rolled_out
|
76
|
-
end
|
77
|
-
|
78
|
-
it "should have an integer exit code" do
|
79
|
-
@task.exit_code.should be_a_kind_of(Fixnum)
|
80
|
-
end
|
81
|
-
|
82
|
-
it "should have a string result" do
|
83
|
-
@task.result.should be_a_kind_of(String)
|
84
|
-
end
|
85
|
-
|
86
|
-
it "should have a string for errors (stderr)" do
|
87
|
-
@task.errors.should be_a_kind_of(String)
|
88
|
-
end
|
89
|
-
|
90
|
-
end
|
91
|
-
|
92
|
-
end
|
data/spec/outback/yaml_spec.rb
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
-
require 'yaml'
|
3
|
-
|
4
|
-
describe Outback::YAML do
|
5
|
-
|
6
|
-
before do
|
7
|
-
@yaml =<<-EOM.gsub(/^\s{4}/, '')
|
8
|
-
-
|
9
|
-
out: touch y
|
10
|
-
back: rm y
|
11
|
-
-
|
12
|
-
out: touch x
|
13
|
-
back: rm x
|
14
|
-
EOM
|
15
|
-
@file = '/tmp/outback_yaml_spec_tmp'
|
16
|
-
File.open(@file, 'w') { |f| f.puts @yaml }
|
17
|
-
end
|
18
|
-
|
19
|
-
after do
|
20
|
-
File.delete(@file)
|
21
|
-
end
|
22
|
-
|
23
|
-
describe do
|
24
|
-
it "should return an Outback::Manager object" do
|
25
|
-
Outback::YAML.load(@yaml).should be_a_kind_of(Outback::Manager)
|
26
|
-
Outback::YAML.load_file(@file).should be_a_kind_of(Outback::Manager)
|
27
|
-
end
|
28
|
-
it "should return an Outback::Manager object with as many tasks as the YAML passed into it" do
|
29
|
-
Outback::YAML.load(@yaml).should have(2).tasks
|
30
|
-
Outback::YAML.load_file(@file).should have(2).tasks
|
31
|
-
end
|
32
|
-
it "should add instances of Outback::ShellTask to the Outback::Manager's task array" do
|
33
|
-
manager = Outback::YAML.load(@yaml)
|
34
|
-
manager.tasks.first.should be_a_kind_of(Outback::ShellTask)
|
35
|
-
end
|
36
|
-
it "should set the rollout_command to the first element of the YAML array" do
|
37
|
-
manager = Outback::YAML.load(@yaml)
|
38
|
-
manager.tasks[0].rollout.should == "touch y"
|
39
|
-
manager.tasks[1].rollout.should == "touch x"
|
40
|
-
end
|
41
|
-
it "should set the rollback_command to the second element of the YAML array" do
|
42
|
-
manager = Outback::YAML.load(@yaml)
|
43
|
-
manager.tasks[0].rollback.should == "rm y"
|
44
|
-
manager.tasks[1].rollback.should == "rm x"
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|