foreman 0.46.0 → 0.47.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/README.md +6 -0
- data/bin/foreman-runner +3 -7
- data/data/export/bluepill/master.pill.erb +2 -1
- data/data/export/launchd/launchd.plist.erb +22 -0
- data/data/export/upstart/process.conf.erb +1 -1
- data/lib/foreman/cli.rb +3 -2
- data/lib/foreman/engine.rb +2 -1
- data/lib/foreman/export.rb +1 -0
- data/lib/foreman/export/base.rb +15 -0
- data/lib/foreman/export/launchd.rb +27 -0
- data/lib/foreman/process.rb +1 -1
- data/lib/foreman/version.rb +1 -1
- data/man/foreman.1 +1 -1
- data/spec/foreman/cli_spec.rb +3 -3
- data/spec/foreman/engine_spec.rb +7 -0
- data/spec/foreman/export/launchd_spec.rb +24 -0
- data/spec/foreman/export/upstart_spec.rb +6 -0
- data/spec/foreman/process_spec.rb +16 -2
- data/spec/resources/export/bluepill/app-concurrency.pill +2 -0
- data/spec/resources/export/bluepill/app.pill +2 -0
- data/spec/resources/export/launchd/launchd-a.default +22 -0
- data/spec/resources/export/launchd/launchd-b.default +22 -0
- metadata +9 -10
data/README.md
CHANGED
@@ -27,6 +27,12 @@ Manage Procfile-based applications
|
|
27
27
|
* [wiki](http://github.com/ddollar/foreman/wiki)
|
28
28
|
* [changelog](https://github.com/ddollar/foreman/blob/master/Changelog.md)
|
29
29
|
|
30
|
+
## Ports
|
31
|
+
|
32
|
+
* [shoreman](https://github.com/hecticjeff/shoreman) - shell
|
33
|
+
* [honcho](https://github.com/nickstenning/honcho) - python
|
34
|
+
* [norman](https://github.com/josh/norman) - node.js
|
35
|
+
|
30
36
|
## Authors
|
31
37
|
|
32
38
|
#### Created and maintained by
|
data/bin/foreman-runner
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#!/bin/sh
|
2
2
|
#
|
3
|
-
#/ Usage: foreman-runner [-d <dir>] <command>
|
3
|
+
#/ Usage: foreman-runner [-d <dir>] <command> [<args>...]
|
4
4
|
#/
|
5
5
|
#/ Run a command with exec, optionally changing directory first
|
6
6
|
|
@@ -27,10 +27,6 @@ done
|
|
27
27
|
|
28
28
|
shift $((OPTIND-1))
|
29
29
|
|
30
|
-
|
30
|
+
[ -z "$1" ] && usage
|
31
31
|
|
32
|
-
|
33
|
-
usage
|
34
|
-
fi
|
35
|
-
|
36
|
-
exec $1
|
32
|
+
exec "$@"
|
@@ -11,8 +11,9 @@ Bluepill.application("<%= app %>", :foreground => false, :log_file => "/var/log/
|
|
11
11
|
|
12
12
|
process.working_dir = "<%= engine.directory %>"
|
13
13
|
process.daemonize = true
|
14
|
-
process.environment = {"PORT" => "<%= port %>"}
|
14
|
+
process.environment = {"PORT" => "<%= port %>"<% engine.environment.each_pair do |var,env| %> , "<%= var.upcase %>" => "<%= env %>" <% end %>}
|
15
15
|
process.stop_signals = [:quit, 30.seconds, :term, 5.seconds, :kill]
|
16
|
+
process.stop_grace_time = 45.seconds
|
16
17
|
|
17
18
|
process.stdout = process.stderr = "<%= log_root %>/<%= app %>-<%= process.name %>-<%=num%>.log"
|
18
19
|
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
3
|
+
<plist version="1.0">
|
4
|
+
<dict>
|
5
|
+
<key>Label</key>
|
6
|
+
<string><%= "#{app}-#{process.name}-#{num}" %></string>
|
7
|
+
<key>ProgramArguments</key>
|
8
|
+
<array>
|
9
|
+
<string><%= process.command %></string>
|
10
|
+
</array>
|
11
|
+
<key>KeepAlive</key>
|
12
|
+
<true/>
|
13
|
+
<key>RunAtLoad</key>
|
14
|
+
<true/>
|
15
|
+
<key>StandardErrorPath</key>
|
16
|
+
<string><%= log_root %>/<%= app %>-<%= process.name %>-<%=num%>.log</string>
|
17
|
+
<key>UserName</key>
|
18
|
+
<string><%= user %></string>
|
19
|
+
<key>WorkingDirectory</key>
|
20
|
+
<string><%= engine.directory %></string>
|
21
|
+
</dict>
|
22
|
+
</plist>
|
@@ -2,4 +2,4 @@ start on starting <%= app %>-<%= process.name %>
|
|
2
2
|
stop on stopping <%= app %>-<%= process.name %>
|
3
3
|
respawn
|
4
4
|
|
5
|
-
exec su - <%= user %> -c 'cd <%= engine.directory %>; export PORT=<%= port %>;<% engine.environment.each_pair do |var,env| %> export <%= var.upcase %>=<%= env %>; <% end %> <%= process.command %> >> <%= log_root %>/<%=process.name%>-<%=num%>.log 2>&1'
|
5
|
+
exec su - <%= user %> -c 'cd <%= engine.directory %>; export PORT=<%= port %>;<% engine.environment.each_pair do |var,env| %> export <%= var.upcase %>=<%= shell_quote(env) %>; <% end %> <%= process.command %> >> <%= log_root %>/<%=process.name%>-<%=num%>.log 2>&1'
|
data/lib/foreman/cli.rb
CHANGED
@@ -2,6 +2,7 @@ require "foreman"
|
|
2
2
|
require "foreman/helpers"
|
3
3
|
require "foreman/engine"
|
4
4
|
require "foreman/export"
|
5
|
+
require "shellwords"
|
5
6
|
require "thor"
|
6
7
|
require "yaml"
|
7
8
|
|
@@ -59,12 +60,12 @@ class Foreman::CLI < Thor
|
|
59
60
|
puts "valid procfile detected (#{engine.procfile.process_names.join(', ')})"
|
60
61
|
end
|
61
62
|
|
62
|
-
desc "run COMMAND", "Run a command using your application's environment"
|
63
|
+
desc "run COMMAND [ARGS...]", "Run a command using your application's environment"
|
63
64
|
|
64
65
|
def run(*args)
|
65
66
|
engine.apply_environment!
|
66
67
|
begin
|
67
|
-
exec args.
|
68
|
+
exec args.shelljoin
|
68
69
|
rescue Errno::EACCES
|
69
70
|
error "not executable: #{args.first}"
|
70
71
|
rescue Errno::ENOENT
|
data/lib/foreman/engine.rb
CHANGED
@@ -36,6 +36,7 @@ class Foreman::Engine
|
|
36
36
|
|
37
37
|
trap("TERM") { puts "SIGTERM received"; terminate_gracefully }
|
38
38
|
trap("INT") { puts "SIGINT received"; terminate_gracefully }
|
39
|
+
trap("HUP") { puts "SIGHUP received"; terminate_gracefully }
|
39
40
|
|
40
41
|
assign_colors
|
41
42
|
spawn_processes
|
@@ -84,7 +85,7 @@ private ######################################################################
|
|
84
85
|
end
|
85
86
|
|
86
87
|
def base_port
|
87
|
-
options[:port] || 5000
|
88
|
+
options[:port] || environment["PORT"] || ENV["PORT"] || 5000
|
88
89
|
end
|
89
90
|
|
90
91
|
def kill_all(signal="SIGTERM")
|
data/lib/foreman/export.rb
CHANGED
data/lib/foreman/export/base.rb
CHANGED
@@ -48,4 +48,19 @@ private ######################################################################
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
+
# Quote a string to be used on the command line. Backslashes are escapde to \\ and quotes
|
52
|
+
# escaped to \"
|
53
|
+
#
|
54
|
+
# str - string to be quoted
|
55
|
+
#
|
56
|
+
# Examples
|
57
|
+
#
|
58
|
+
# shell_quote("FB|123\"\\1")
|
59
|
+
# # => "\"FB|123\"\\"\\\\1\""
|
60
|
+
#
|
61
|
+
# Returns the the escaped string surrounded by quotes
|
62
|
+
def shell_quote(str)
|
63
|
+
"\"#{str.gsub(/\\/){ '\\\\' }.gsub(/["]/){ "\\\"" }}\""
|
64
|
+
end
|
65
|
+
|
51
66
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "erb"
|
2
|
+
require "foreman/export"
|
3
|
+
|
4
|
+
class Foreman::Export::Launchd < Foreman::Export::Base
|
5
|
+
|
6
|
+
def export
|
7
|
+
error("Must specify a location") unless location
|
8
|
+
|
9
|
+
app = self.app || File.basename(engine.directory)
|
10
|
+
user = self.user || app
|
11
|
+
log_root = self.log || "/var/log/#{app}"
|
12
|
+
template_root = self.template
|
13
|
+
|
14
|
+
FileUtils.mkdir_p(location)
|
15
|
+
|
16
|
+
engine.procfile.entries.each do |process|
|
17
|
+
1.upto(self.concurrency[process.name]) do |num|
|
18
|
+
|
19
|
+
master_template = export_template("launchd", "launchd.plist.erb", template_root)
|
20
|
+
master_config = ERB.new(master_template).result(binding)
|
21
|
+
write_file "#{location}/#{app}-#{process.name}-#{num}.plist", master_config
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
data/lib/foreman/process.rb
CHANGED
data/lib/foreman/version.rb
CHANGED
data/man/foreman.1
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
.\" generated with Ronn/v0.7.3
|
2
2
|
.\" http://github.com/rtomayko/ronn/tree/0.7.3
|
3
3
|
.
|
4
|
-
.TH "FOREMAN" "1" "April 2012" "Foreman 0.
|
4
|
+
.TH "FOREMAN" "1" "April 2012" "Foreman 0.46.0" "Foreman Manual"
|
5
5
|
.
|
6
6
|
.SH "NAME"
|
7
7
|
\fBforeman\fR \- manage Procfile\-based applications
|
data/spec/foreman/cli_spec.rb
CHANGED
@@ -144,7 +144,7 @@ describe "Foreman::CLI", :fakefs do
|
|
144
144
|
before { write_procfile }
|
145
145
|
|
146
146
|
describe "and a command" do
|
147
|
-
let(:command) { ["ls", "-l"] }
|
147
|
+
let(:command) { ["ls", "-l", "foo bar"] }
|
148
148
|
|
149
149
|
before(:each) do
|
150
150
|
stub(subject).exec
|
@@ -160,8 +160,8 @@ describe "Foreman::CLI", :fakefs do
|
|
160
160
|
ENV["FOO"].should be_nil
|
161
161
|
end
|
162
162
|
|
163
|
-
it "should
|
164
|
-
mock(subject).exec(command.
|
163
|
+
it "should exec the argument list as a shell command" do
|
164
|
+
mock(subject).exec(command.shelljoin)
|
165
165
|
subject.run *command
|
166
166
|
end
|
167
167
|
end
|
data/spec/foreman/engine_spec.rb
CHANGED
@@ -100,6 +100,13 @@ describe "Foreman::Engine", :fakefs do
|
|
100
100
|
engine.start
|
101
101
|
end
|
102
102
|
|
103
|
+
it "should set port from .env if specified" do
|
104
|
+
File.open(".env", "w") { |f| f.puts("PORT=8017") }
|
105
|
+
engine = Foreman::Engine.new("Procfile")
|
106
|
+
engine.send(:base_port).should == "8017"
|
107
|
+
engine.start
|
108
|
+
end
|
109
|
+
|
103
110
|
it "should be loaded relative to the Procfile" do
|
104
111
|
FileUtils.mkdir_p "/some/app"
|
105
112
|
File.open("/some/app/.env", "w") { |f| f.puts("FOO=qoo") }
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "foreman/engine"
|
3
|
+
require "foreman/export/launchd"
|
4
|
+
require "tmpdir"
|
5
|
+
|
6
|
+
describe Foreman::Export::Launchd, :fakefs do
|
7
|
+
let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
|
8
|
+
let(:engine) { Foreman::Engine.new(procfile) }
|
9
|
+
let(:options) { Hash.new }
|
10
|
+
let(:launchd) { Foreman::Export::Launchd.new("/tmp/init", engine, options) }
|
11
|
+
|
12
|
+
before(:each) { load_export_templates_into_fakefs("launchd") }
|
13
|
+
before(:each) { stub(launchd).say }
|
14
|
+
|
15
|
+
it "exports to the filesystem" do
|
16
|
+
launchd.export
|
17
|
+
|
18
|
+
normalize_space(File.read("/tmp/init/app-alpha-1.plist")).should == normalize_space(example_export_file("launchd/launchd-a.default"))
|
19
|
+
|
20
|
+
normalize_space(File.read("/tmp/init/app-bravo-1.plist")).should == normalize_space(example_export_file("launchd/launchd-b.default"))
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -33,6 +33,12 @@ describe Foreman::Export::Upstart, :fakefs do
|
|
33
33
|
upstart.export
|
34
34
|
end
|
35
35
|
|
36
|
+
it "quotes and escapes environment variables" do
|
37
|
+
engine.environment['KEY'] = 'd"\|d'
|
38
|
+
upstart.export
|
39
|
+
File.read("/tmp/init/app-alpha-1.conf").should include('KEY="d\"\\\\|d"')
|
40
|
+
end
|
41
|
+
|
36
42
|
context "with concurrency" do
|
37
43
|
let(:options) { Hash[:concurrency => "alpha=2"] }
|
38
44
|
|
@@ -121,11 +121,25 @@ describe Foreman::Process do
|
|
121
121
|
output.should include('777')
|
122
122
|
end
|
123
123
|
|
124
|
-
it 'should handle arguments' do
|
125
|
-
pending
|
124
|
+
it 'should handle multi-word arguments (old test)' do
|
125
|
+
# TODO: This test used to be marked pending; it now passes,
|
126
|
+
# but is very slow. The next test is a fast replacement.
|
126
127
|
run %{ sh -c "trap '' TERM; sleep 10" }
|
127
128
|
subject.should be_alive
|
128
129
|
end
|
130
|
+
|
131
|
+
it 'should handle multi-word arguments' do
|
132
|
+
# We have to be a little clever here since Foreman will always
|
133
|
+
# print a status message that includes the command.
|
134
|
+
run %{ sh -c 'echo abcdef | tr a-c x | tr d-f y' }
|
135
|
+
output.should include('xxxyyy')
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'should not clobber "$x"-subexpressions' do
|
139
|
+
pending 'this conflicts with the variable interpolation hack'
|
140
|
+
run %{ sh -c 'echo \$abcdef | tr \$ %' }
|
141
|
+
output.should include('%abcdef')
|
142
|
+
end
|
129
143
|
end
|
130
144
|
end
|
131
145
|
end
|
@@ -13,6 +13,7 @@ Bluepill.application("app", :foreground => false, :log_file => "/var/log/bluepil
|
|
13
13
|
process.daemonize = true
|
14
14
|
process.environment = {"PORT" => "5000"}
|
15
15
|
process.stop_signals = [:quit, 30.seconds, :term, 5.seconds, :kill]
|
16
|
+
process.stop_grace_time = 45.seconds
|
16
17
|
|
17
18
|
process.stdout = process.stderr = "/var/log/app/app-alpha-1.log"
|
18
19
|
|
@@ -31,6 +32,7 @@ Bluepill.application("app", :foreground => false, :log_file => "/var/log/bluepil
|
|
31
32
|
process.daemonize = true
|
32
33
|
process.environment = {"PORT" => "5001"}
|
33
34
|
process.stop_signals = [:quit, 30.seconds, :term, 5.seconds, :kill]
|
35
|
+
process.stop_grace_time = 45.seconds
|
34
36
|
|
35
37
|
process.stdout = process.stderr = "/var/log/app/app-alpha-2.log"
|
36
38
|
|
@@ -13,6 +13,7 @@ Bluepill.application("app", :foreground => false, :log_file => "/var/log/bluepil
|
|
13
13
|
process.daemonize = true
|
14
14
|
process.environment = {"PORT" => "5000"}
|
15
15
|
process.stop_signals = [:quit, 30.seconds, :term, 5.seconds, :kill]
|
16
|
+
process.stop_grace_time = 45.seconds
|
16
17
|
|
17
18
|
process.stdout = process.stderr = "/var/log/app/app-alpha-1.log"
|
18
19
|
|
@@ -30,6 +31,7 @@ Bluepill.application("app", :foreground => false, :log_file => "/var/log/bluepil
|
|
30
31
|
process.daemonize = true
|
31
32
|
process.environment = {"PORT" => "5100"}
|
32
33
|
process.stop_signals = [:quit, 30.seconds, :term, 5.seconds, :kill]
|
34
|
+
process.stop_grace_time = 45.seconds
|
33
35
|
|
34
36
|
process.stdout = process.stderr = "/var/log/app/app-bravo-1.log"
|
35
37
|
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
3
|
+
<plist version="1.0">
|
4
|
+
<dict>
|
5
|
+
<key>Label</key>
|
6
|
+
<string>app-alpha-1</string>
|
7
|
+
<key>ProgramArguments</key>
|
8
|
+
<array>
|
9
|
+
<string>./alpha</string>
|
10
|
+
</array>
|
11
|
+
<key>KeepAlive</key>
|
12
|
+
<true/>
|
13
|
+
<key>RunAtLoad</key>
|
14
|
+
<true/>
|
15
|
+
<key>StandardErrorPath</key>
|
16
|
+
<string>/var/log/app/app-alpha-1.log</string>
|
17
|
+
<key>UserName</key>
|
18
|
+
<string>app</string>
|
19
|
+
<key>WorkingDirectory</key>
|
20
|
+
<string>/tmp/app</string>
|
21
|
+
</dict>
|
22
|
+
</plist>
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
3
|
+
<plist version="1.0">
|
4
|
+
<dict>
|
5
|
+
<key>Label</key>
|
6
|
+
<string>app-bravo-1</string>
|
7
|
+
<key>ProgramArguments</key>
|
8
|
+
<array>
|
9
|
+
<string>./bravo</string>
|
10
|
+
</array>
|
11
|
+
<key>KeepAlive</key>
|
12
|
+
<true/>
|
13
|
+
<key>RunAtLoad</key>
|
14
|
+
<true/>
|
15
|
+
<key>StandardErrorPath</key>
|
16
|
+
<string>/var/log/app/app-bravo-1.log</string>
|
17
|
+
<key>UserName</key>
|
18
|
+
<string>app</string>
|
19
|
+
<key>WorkingDirectory</key>
|
20
|
+
<string>/tmp/app</string>
|
21
|
+
</dict>
|
22
|
+
</plist>
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foreman
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.47.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-06-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: thor
|
16
|
-
requirement: &
|
16
|
+
requirement: &70170917701380 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,7 +21,7 @@ dependencies:
|
|
21
21
|
version: 0.13.6
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70170917701380
|
25
25
|
description: Process manager for applications with multiple components
|
26
26
|
email: ddollar@gmail.com
|
27
27
|
executables:
|
@@ -38,6 +38,7 @@ files:
|
|
38
38
|
- data/example/ticker
|
39
39
|
- data/example/utf8
|
40
40
|
- data/export/bluepill/master.pill.erb
|
41
|
+
- data/export/launchd/launchd.plist.erb
|
41
42
|
- data/export/runit/log_run.erb
|
42
43
|
- data/export/runit/run.erb
|
43
44
|
- data/export/supervisord/app.conf.erb
|
@@ -51,6 +52,7 @@ files:
|
|
51
52
|
- lib/foreman/export/base.rb
|
52
53
|
- lib/foreman/export/bluepill.rb
|
53
54
|
- lib/foreman/export/inittab.rb
|
55
|
+
- lib/foreman/export/launchd.rb
|
54
56
|
- lib/foreman/export/runit.rb
|
55
57
|
- lib/foreman/export/supervisord.rb
|
56
58
|
- lib/foreman/export/upstart.rb
|
@@ -69,6 +71,7 @@ files:
|
|
69
71
|
- spec/foreman/export/base_spec.rb
|
70
72
|
- spec/foreman/export/bluepill_spec.rb
|
71
73
|
- spec/foreman/export/inittab_spec.rb
|
74
|
+
- spec/foreman/export/launchd_spec.rb
|
72
75
|
- spec/foreman/export/runit_spec.rb
|
73
76
|
- spec/foreman/export/supervisord_spec.rb
|
74
77
|
- spec/foreman/export/upstart_spec.rb
|
@@ -84,6 +87,8 @@ files:
|
|
84
87
|
- spec/resources/export/bluepill/app.pill
|
85
88
|
- spec/resources/export/inittab/inittab.concurrency
|
86
89
|
- spec/resources/export/inittab/inittab.default
|
90
|
+
- spec/resources/export/launchd/launchd-a.default
|
91
|
+
- spec/resources/export/launchd/launchd-b.default
|
87
92
|
- spec/resources/export/runit/app-alpha-1-log-run
|
88
93
|
- spec/resources/export/runit/app-alpha-1-run
|
89
94
|
- spec/resources/export/runit/app-alpha-2-log-run
|
@@ -114,18 +119,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
114
119
|
- - ! '>='
|
115
120
|
- !ruby/object:Gem::Version
|
116
121
|
version: '0'
|
117
|
-
segments:
|
118
|
-
- 0
|
119
|
-
hash: -4034722301368458418
|
120
122
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
123
|
none: false
|
122
124
|
requirements:
|
123
125
|
- - ! '>='
|
124
126
|
- !ruby/object:Gem::Version
|
125
127
|
version: '0'
|
126
|
-
segments:
|
127
|
-
- 0
|
128
|
-
hash: -4034722301368458418
|
129
128
|
requirements: []
|
130
129
|
rubyforge_project:
|
131
130
|
rubygems_version: 1.8.11
|