nickstenning-outback 0.0.1
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/lib/outback/command.rb +33 -0
- data/lib/outback/manager.rb +100 -0
- data/lib/outback/task.rb +61 -0
- data/lib/outback/task_helper.rb +21 -0
- data/lib/outback/yaml.rb +25 -0
- data/lib/outback.rb +12 -0
- data/outback.gemspec +19 -0
- data/spec/outback/manager_spec.rb +125 -0
- data/spec/outback/task_spec.rb +63 -0
- data/spec/outback/yaml_spec.rb +47 -0
- data/spec/spec_helper.rb +4 -0
- metadata +72 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
module Outback
|
2
|
+
|
3
|
+
class Command
|
4
|
+
|
5
|
+
def initialize( script )
|
6
|
+
@manager = Manager.new
|
7
|
+
parse(script)
|
8
|
+
end
|
9
|
+
|
10
|
+
def parse( script )
|
11
|
+
script.each_line do |l|
|
12
|
+
out, back = l[/^([^\^]+)\s*\^\s*(.+)$/]
|
13
|
+
p "o:", out, "b:", back
|
14
|
+
if out and back
|
15
|
+
p out, back
|
16
|
+
t = Task.new("temp")
|
17
|
+
t.rollout { |t| t.sys out }
|
18
|
+
t.rollback { |t| t.sys back }
|
19
|
+
@manager.tasks << t
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def run( command )
|
25
|
+
raise %{Command "#{command}" not understood.} unless [:rollout, :rollback].include? command
|
26
|
+
|
27
|
+
#@manager.tasks.each
|
28
|
+
#@manager.send(command)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
module Outback
|
5
|
+
|
6
|
+
class Manager
|
7
|
+
|
8
|
+
attr_reader :tasks, :status, :errors, :position
|
9
|
+
attr_writer :logger
|
10
|
+
attr_accessor :workdir
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@tasks = []
|
14
|
+
@statuses = []
|
15
|
+
@errors = []
|
16
|
+
@position = 0
|
17
|
+
end
|
18
|
+
|
19
|
+
def rollout
|
20
|
+
@direction = 1
|
21
|
+
run
|
22
|
+
end
|
23
|
+
|
24
|
+
def rollback
|
25
|
+
@direction = -1
|
26
|
+
run
|
27
|
+
end
|
28
|
+
|
29
|
+
def rollout_from( task )
|
30
|
+
@position = @tasks.index(task)
|
31
|
+
rollout
|
32
|
+
end
|
33
|
+
|
34
|
+
def rollback_from( task )
|
35
|
+
@position = @tasks.index(task) - 1
|
36
|
+
rollback
|
37
|
+
end
|
38
|
+
|
39
|
+
def attempt
|
40
|
+
method = {1 => :rollout, -1 => :rollback}[@direction]
|
41
|
+
Dir.chdir(@workdir || Dir.pwd) do
|
42
|
+
@statuses << [method, *current_task.send(method)]
|
43
|
+
end
|
44
|
+
return latest_okay?
|
45
|
+
end
|
46
|
+
|
47
|
+
def latest_okay?
|
48
|
+
status[1] == 0
|
49
|
+
end
|
50
|
+
|
51
|
+
def errors
|
52
|
+
@statuses.select { |status| status[1] != 0 }
|
53
|
+
end
|
54
|
+
|
55
|
+
def status
|
56
|
+
@statuses.last
|
57
|
+
end
|
58
|
+
|
59
|
+
def current_task
|
60
|
+
@tasks[@position]
|
61
|
+
end
|
62
|
+
|
63
|
+
def state
|
64
|
+
{ :position => @position,
|
65
|
+
:direction => @direction,
|
66
|
+
:statuses => @statuses }
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def run
|
72
|
+
if @direction == 1
|
73
|
+
task_list = @tasks[@position..-1]
|
74
|
+
elsif @direction == -1
|
75
|
+
task_list = @tasks[0..@position + 1].reverse
|
76
|
+
end
|
77
|
+
task_list.each do |task|
|
78
|
+
@position = @tasks.index(task)
|
79
|
+
unless attempt
|
80
|
+
fail
|
81
|
+
break
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def fail
|
87
|
+
case status[0]
|
88
|
+
when :rollout
|
89
|
+
rollback_from current_task
|
90
|
+
raise TransactionError, "Could not rollout task #{current_task}, attempting rollback."
|
91
|
+
when :rollback
|
92
|
+
raise TransactionError, "Could not rollback task #{current_task}, aborting."
|
93
|
+
else
|
94
|
+
raise Error, "Unknown direction!"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
data/lib/outback/task.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'open4'
|
5
|
+
|
6
|
+
module Outback
|
7
|
+
|
8
|
+
class Task
|
9
|
+
|
10
|
+
attr_reader :name
|
11
|
+
attr_accessor :stdout, :stderr
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@rollout, @rollback = lambda {}
|
15
|
+
@stdout = StringIO.new
|
16
|
+
@stderr = StringIO.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def rollout( &block )
|
20
|
+
if block_given?
|
21
|
+
@rollout = block
|
22
|
+
else
|
23
|
+
run @rollout
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def rollback( &block )
|
28
|
+
if block_given?
|
29
|
+
@rollback = block
|
30
|
+
else
|
31
|
+
run @rollback
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def run( proc )
|
38
|
+
proc.call(TaskHelper.new(self))
|
39
|
+
[0, stdout.string, stderr.string]
|
40
|
+
rescue SystemCallError => err
|
41
|
+
[1, stdout.string, stderr.string]
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
class ShellTask < Task
|
48
|
+
|
49
|
+
attr_reader :rollout_command, :rollback_command
|
50
|
+
|
51
|
+
def initialize(rollout, rollback)
|
52
|
+
super()
|
53
|
+
@rollout = lambda { |t| t.sys rollout }
|
54
|
+
@rollout_command = rollout
|
55
|
+
@rollback = lambda { |t| t.sys rollback }
|
56
|
+
@rollback_command = rollback
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Outback
|
2
|
+
|
3
|
+
class TaskHelper
|
4
|
+
|
5
|
+
def initialize( task )
|
6
|
+
@task = task
|
7
|
+
end
|
8
|
+
|
9
|
+
def sys( *args )
|
10
|
+
pid, i, o, e = Open4.popen4(*args)
|
11
|
+
o.each_line { |l| @task.stdout.print "[#{pid}] #{l}" }
|
12
|
+
e.each_line { |l| @task.stderr.print "E [#{pid}] #{l}" }
|
13
|
+
end
|
14
|
+
|
15
|
+
def puts( *args )
|
16
|
+
@task.stdout.puts *args
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
data/lib/outback/yaml.rb
ADDED
@@ -0,0 +1,25 @@
|
|
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
|
+
manager.tasks << Outback::ShellTask.new(*task)
|
10
|
+
end
|
11
|
+
return manager
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.load_file( yaml_file )
|
15
|
+
manager = Manager.new
|
16
|
+
tasks = ::YAML.load_file(yaml_file)
|
17
|
+
tasks.each do |task|
|
18
|
+
manager.tasks << Outback::ShellTask.new(*task)
|
19
|
+
end
|
20
|
+
return manager
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
data/lib/outback.rb
ADDED
data/outback.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = %q{outback}
|
3
|
+
s.version = "0.0.1"
|
4
|
+
|
5
|
+
s.specification_version = 2 if s.respond_to? :specification_version=
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Nick Stenning"]
|
9
|
+
s.date = %q{2008-07-14}
|
10
|
+
s.email = ["nick@whiteink.com"]
|
11
|
+
s.files = ["lib/outback/command.rb", "lib/outback/manager.rb", "lib/outback/task.rb", "lib/outback/task_helper.rb", "lib/outback/yaml.rb", "lib/outback.rb", "outback.gemspec", "spec/outback/manager_spec.rb", "spec/outback/task_spec.rb", "spec/outback/yaml_spec.rb", "spec/spec_helper.rb"]
|
12
|
+
s.has_rdoc = true
|
13
|
+
s.homepage = %q{http://github.com/nickstenning/outback}
|
14
|
+
s.require_paths = ["lib"]
|
15
|
+
s.summary = %q{Like rake, but backwards and forwards.}
|
16
|
+
s.description = %{Run pairs of rollout/rollback tasks in a transactional manner.}
|
17
|
+
|
18
|
+
s.add_dependency("open4", [">= 0.9.0"])
|
19
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
describe Outback::Manager do
|
5
|
+
|
6
|
+
before do
|
7
|
+
@obm = Outback::Manager.new
|
8
|
+
@task1 = mock("task1", :name => "Task 1")
|
9
|
+
@task2 = mock("task2", :name => "Task 2")
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "(empty)" do
|
13
|
+
|
14
|
+
it "should have a list of tasks" do
|
15
|
+
@obm.tasks.should be_a_kind_of(Enumerable)
|
16
|
+
@obm.should have(0).tasks
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should have a rollout method" do
|
20
|
+
@obm.should respond_to(:rollout)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should have a rollback method" do
|
24
|
+
@obm.should respond_to(:rollback)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should add tasks to its list with standard array operations" do
|
28
|
+
@obm.should have(0).tasks
|
29
|
+
@obm.tasks << @task1
|
30
|
+
@obm.should have(1).tasks
|
31
|
+
@obm.tasks << @task2
|
32
|
+
@obm.should have(2).tasks
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "(with a few tasks)" do
|
38
|
+
|
39
|
+
before do
|
40
|
+
@obm.tasks << @task1 << @task2
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should call each task's rollout method on rollout (in order)" do
|
44
|
+
@task1.should_receive(:rollout).and_return(0)
|
45
|
+
@task2.should_receive(:rollout).and_return(0)
|
46
|
+
@obm.rollout
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should call each task's rollback method on rollback (in reverse order)" do
|
50
|
+
@task2.should_receive(:rollback).and_return(0)
|
51
|
+
@task1.should_receive(:rollback).and_return(0)
|
52
|
+
@obm.rollback
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should raise an Outback::Error if a rollout fails" do
|
56
|
+
@task1.stub!(:rollback)
|
57
|
+
@task1.should_receive(:rollout).and_return(1)
|
58
|
+
@task2.should_not_receive(:rollout)
|
59
|
+
@task2.should_not_receive(:rollback)
|
60
|
+
lambda { @obm.rollout }.should raise_error(Outback::Error)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should raise an Outback::Error if a rollback fails" do
|
64
|
+
@task2.should_receive(:rollback).and_return(1)
|
65
|
+
@task1.should_not_receive(:rollback)
|
66
|
+
lambda { @obm.rollback }.should raise_error(Outback::Error)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should store the latest task's run direction (rollout, rollback), return code, stdout and stderr in #status" do
|
70
|
+
@task1.should_receive(:rollout).and_return([0, "A message", ""])
|
71
|
+
@task2.should_receive(:rollout).and_return([0, "Another message", ""])
|
72
|
+
@obm.rollout
|
73
|
+
@obm.status.should == [:rollout, 0, "Another message", ""]
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should store the latest task's status even if an earlier task raised an error." do
|
77
|
+
@task1.stub!(:rollback).and_return([0, "Getting rolled back", ""])
|
78
|
+
@task1.should_receive(:rollout).and_return([1, "", "Error message"])
|
79
|
+
@task2.should_not_receive(:rollout)
|
80
|
+
begin
|
81
|
+
@obm.rollout
|
82
|
+
rescue Outback::Error
|
83
|
+
@obm.status.should == [:rollback, 0, "Getting rolled back", ""]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should store any status messages with non-zero return codes in #errors" do
|
88
|
+
@task1.should_receive(:rollout).and_return([0, "All okay", ""])
|
89
|
+
@task2.should_receive(:rollout).and_return([1, "", "Error message"])
|
90
|
+
@task2.should_receive(:rollback).and_return([0, "Getting rolled back", ""])
|
91
|
+
@task1.should_receive(:rollback).and_return([3, "", "Error while rolling back"])
|
92
|
+
begin
|
93
|
+
@obm.rollout
|
94
|
+
rescue Outback::Error
|
95
|
+
@obm.should have(2).errors
|
96
|
+
@obm.errors[0].should == [:rollout, 1, "", "Error message"]
|
97
|
+
@obm.errors[1].should == [:rollback, 3, "", "Error while rolling back"]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should rollback previously rolled-out tasks if a rollout fails" do
|
102
|
+
@task1.should_receive(:rollout).ordered.and_return([1, "", "Error message"])
|
103
|
+
@task2.should_not_receive(:rollout)
|
104
|
+
@task1.should_receive(:rollback).ordered
|
105
|
+
@task2.should_not_receive(:rollback)
|
106
|
+
begin
|
107
|
+
@obm.rollout
|
108
|
+
rescue Outback::Error
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe "(with #workdir set)" do
|
114
|
+
|
115
|
+
before do
|
116
|
+
@obm.tasks << Outback::ShellTask.new('pwd', 'pwd')
|
117
|
+
@obm.workdir = '/tmp'
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should execute all tasks in the workdir" do
|
121
|
+
@obm.rollout
|
122
|
+
@obm.status[2] == "/tmp"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,63 @@
|
|
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 allow its rollout method to be defined with #rollout" do
|
10
|
+
rollout_proc = lambda { |t| t.puts "rollout" }
|
11
|
+
|
12
|
+
lambda do
|
13
|
+
@task.rollout &rollout_proc
|
14
|
+
end.should_not raise_error
|
15
|
+
|
16
|
+
@task.rollout.should == [0, "rollout\n", ""]
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should allow its rollback method to be defined with #rollback" do
|
20
|
+
rollback_proc = lambda { |t| t.puts "rollback" }
|
21
|
+
|
22
|
+
lambda do
|
23
|
+
@task.rollback &rollback_proc
|
24
|
+
end.should_not raise_error
|
25
|
+
|
26
|
+
@task.rollback.should == [0, "rollback\n", ""]
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should have a rollout method" do
|
30
|
+
@task.should respond_to(:rollout)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should have a rollback method" do
|
34
|
+
@task.should respond_to(:rollback)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should return an exit code and the command output when rollout or rollback is run" do
|
38
|
+
returns = @task.rollout
|
39
|
+
returns[0].should be_a_kind_of(Numeric)
|
40
|
+
returns[1].should be_a_kind_of(String)
|
41
|
+
returns[2].should be_a_kind_of(String)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should provide a 'sys' method to rollout and rollback blocks to allow system calls" do
|
45
|
+
@task.rollout do |t|
|
46
|
+
t.sys 'echo', 'system call'
|
47
|
+
end
|
48
|
+
ret = []
|
49
|
+
lambda { ret = @task.rollout }.should_not raise_error
|
50
|
+
ret[0].should == 0
|
51
|
+
ret[1].should match(/\[\d+\] system call\n/)
|
52
|
+
ret[2].should be_empty
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should catch failed system commands and provide an appropriate exit code" do
|
56
|
+
@task.rollout do |t|
|
57
|
+
t.sys "nonexistent"
|
58
|
+
end
|
59
|
+
ret = []
|
60
|
+
lambda { ret = @task.rollout }.should_not raise_error
|
61
|
+
ret[0].should == 1
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,47 @@
|
|
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
|
+
- touch y
|
10
|
+
- rm y
|
11
|
+
-
|
12
|
+
- touch x
|
13
|
+
- 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_command.should == "touch y"
|
39
|
+
manager.tasks[1].rollout_command.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_command.should == "rm y"
|
44
|
+
manager.tasks[1].rollback_command.should == "rm x"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nickstenning-outback
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nick Stenning
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-07-14 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: open4
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.9.0
|
23
|
+
version:
|
24
|
+
description: Run pairs of rollout/rollback tasks in a transactional manner.
|
25
|
+
email:
|
26
|
+
- nick@whiteink.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files: []
|
32
|
+
|
33
|
+
files:
|
34
|
+
- lib/outback/command.rb
|
35
|
+
- lib/outback/manager.rb
|
36
|
+
- lib/outback/task.rb
|
37
|
+
- lib/outback/task_helper.rb
|
38
|
+
- lib/outback/yaml.rb
|
39
|
+
- lib/outback.rb
|
40
|
+
- outback.gemspec
|
41
|
+
- spec/outback/manager_spec.rb
|
42
|
+
- spec/outback/task_spec.rb
|
43
|
+
- spec/outback/yaml_spec.rb
|
44
|
+
- spec/spec_helper.rb
|
45
|
+
has_rdoc: true
|
46
|
+
homepage: http://github.com/nickstenning/outback
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options: []
|
49
|
+
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
version:
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: "0"
|
63
|
+
version:
|
64
|
+
requirements: []
|
65
|
+
|
66
|
+
rubyforge_project:
|
67
|
+
rubygems_version: 1.2.0
|
68
|
+
signing_key:
|
69
|
+
specification_version: 2
|
70
|
+
summary: Like rake, but backwards and forwards.
|
71
|
+
test_files: []
|
72
|
+
|