rv 2.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (9) hide show
  1. data/CHANGELOG +6 -0
  2. data/LICENSE +184 -0
  3. data/Manifest +8 -0
  4. data/README +79 -0
  5. data/Rakefile +11 -0
  6. data/bin/rv +11 -0
  7. data/lib/rv.rb +242 -0
  8. data/lib/rv_harness.rb +42 -0
  9. metadata +61 -0
@@ -0,0 +1,6 @@
1
+
2
+ v2.9. Gem'd; RDoc documentation; automated setup scripts; cluster support.
3
+
4
+ v2. Mongrel static directory handler.
5
+
6
+ v1. First release.
data/LICENSE ADDED
@@ -0,0 +1,184 @@
1
+ Academic Free License (AFL) v. 3.0
2
+
3
+ This Academic Free License (the "License") applies to any original work
4
+ of authorship (the "Original Work") whose owner (the "Licensor") has
5
+ placed the following licensing notice adjacent to the copyright notice
6
+ for the Original Work:
7
+
8
+ Licensed under the Academic Free License version 3.0
9
+
10
+ 1) Grant of Copyright License. Licensor grants You a worldwide,
11
+ royalty-free, non-exclusive, sublicensable license, for the duration of
12
+ the copyright, to do the following:
13
+
14
+ a) to reproduce the Original Work in copies, either alone or as part of
15
+ a collective work;
16
+
17
+ b) to translate, adapt, alter, transform, modify, or arrange the
18
+ Original Work, thereby creating derivative works ("Derivative Works")
19
+ based upon the Original Work;
20
+
21
+ c) to distribute or communicate copies of the Original Work and
22
+ Derivative Works to the public, under any license of your choice that
23
+ does not contradict the terms and conditions, including Licensor's
24
+ reserved rights and remedies, in this Academic Free License;
25
+
26
+ d) to perform the Original Work publicly; and
27
+
28
+ e) to display the Original Work publicly.
29
+
30
+ 2) Grant of Patent License. Licensor grants You a worldwide,
31
+ royalty-free, non-exclusive, sublicensable license, under patent claims
32
+ owned or controlled by the Licensor that are embodied in the Original
33
+ Work as furnished by the Licensor, for the duration of the patents, to
34
+ make, use, sell, offer for sale, have made, and import the Original Work
35
+ and Derivative Works.
36
+
37
+ 3) Grant of Source Code License. The term "Source Code" means the
38
+ preferred form of the Original Work for making modifications to it and
39
+ all available documentation describing how to modify the Original Work.
40
+ Licensor agrees to provide a machine-readable copy of the Source Code of
41
+ the Original Work along with each copy of the Original Work that
42
+ Licensor distributes. Licensor reserves the right to satisfy this
43
+ obligation by placing a machine-readable copy of the Source Code in an
44
+ information repository reasonably calculated to permit inexpensive and
45
+ convenient access by You for as long as Licensor continues to distribute
46
+ the Original Work.
47
+
48
+ 4) Exclusions From License Grant. Neither the names of Licensor, nor the
49
+ names of any contributors to the Original Work, nor any of their
50
+ trademarks or service marks, may be used to endorse or promote products
51
+ derived from this Original Work without express prior permission of the
52
+ Licensor. Except as expressly stated herein, nothing in this License
53
+ grants any license to Licensor's trademarks, copyrights, patents, trade
54
+ secrets or any other intellectual property. No patent license is granted
55
+ to make, use, sell, offer for sale, have made, or import embodiments of
56
+ any patent claims other than the licensed claims defined in Section 2.
57
+ No license is granted to the trademarks of Licensor even if such marks
58
+ are included in the Original Work. Nothing in this License shall be
59
+ interpreted to prohibit Licensor from licensing under terms different
60
+ from this License any Original Work that Licensor otherwise would have a
61
+ right to license.
62
+
63
+ 5) External Deployment. The term "External Deployment" means the use,
64
+ distribution, or communication of the Original Work or Derivative Works
65
+ in any way such that the Original Work or Derivative Works may be used
66
+ by anyone other than You, whether those works are distributed or
67
+ communicated to those persons or made available as an application
68
+ intended for use over a network. As an express condition for the grants
69
+ of license hereunder, You must treat any External Deployment by You of
70
+ the Original Work or a Derivative Work as a distribution under section
71
+ 1(c).
72
+
73
+ 6) Attribution Rights. You must retain, in the Source Code of any
74
+ Derivative Works that You create, all copyright, patent, or trademark
75
+ notices from the Source Code of the Original Work, as well as any
76
+ notices of licensing and any descriptive text identified therein as an
77
+ "Attribution Notice." You must cause the Source Code for any Derivative
78
+ Works that You create to carry a prominent Attribution Notice reasonably
79
+ calculated to inform recipients that You have modified the Original
80
+ Work.
81
+
82
+ 7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants
83
+ that the copyright in and to the Original Work and the patent rights
84
+ granted herein by Licensor are owned by the Licensor or are sublicensed
85
+ to You under the terms of this License with the permission of the
86
+ contributor(s) of those copyrights and patent rights. Except as
87
+ expressly stated in the immediately preceding sentence, the Original
88
+ Work is provided under this License on an "AS IS" BASIS and WITHOUT
89
+ WARRANTY, either express or implied, including, without limitation, the
90
+ warranties of non-infringement, merchantability or fitness for a
91
+ particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL
92
+ WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential
93
+ part of this License. No license to the Original Work is granted by this
94
+ License except under this disclaimer.
95
+
96
+ 8) Limitation of Liability. Under no circumstances and under no legal
97
+ theory, whether in tort (including negligence), contract, or otherwise,
98
+ shall the Licensor be liable to anyone for any indirect, special,
99
+ incidental, or consequential damages of any character arising as a
100
+ result of this License or the use of the Original Work including,
101
+ without limitation, damages for loss of goodwill, work stoppage,
102
+ computer failure or malfunction, or any and all other commercial damages
103
+ or losses. This limitation of liability shall not apply to the extent
104
+ applicable law prohibits such limitation.
105
+
106
+ 9) Acceptance and Termination. If, at any time, You expressly assented
107
+ to this License, that assent indicates your clear and irrevocable
108
+ acceptance of this License and all of its terms and conditions. If You
109
+ distribute or communicate copies of the Original Work or a Derivative
110
+ Work, You must make a reasonable effort under the circumstances to
111
+ obtain the express assent of recipients to the terms of this License.
112
+ This License conditions your rights to undertake the activities listed
113
+ in Section 1, including your right to create Derivative Works based upon
114
+ the Original Work, and doing so without honoring these terms and
115
+ conditions is prohibited by copyright law and international treaty.
116
+ Nothing in this License is intended to affect copyright exceptions and
117
+ limitations (including "fair use" or "fair dealing"). This License shall
118
+ terminate immediately and You may no longer exercise any of the rights
119
+ granted to You by this License upon your failure to honor the conditions
120
+ in Section 1(c).
121
+
122
+ 10) Termination for Patent Action. This License shall terminate
123
+ automatically and You may no longer exercise any of the rights granted
124
+ to You by this License as of the date You commence an action, including
125
+ a cross-claim or counterclaim, against Licensor or any licensee alleging
126
+ that the Original Work infringes a patent. This termination provision
127
+ shall not apply for an action alleging patent infringement by
128
+ combinations of the Original Work with other software or hardware.
129
+
130
+ 11) Jurisdiction, Venue and Governing Law. Any action or suit relating
131
+ to this License may be brought only in the courts of a jurisdiction
132
+ wherein the Licensor resides or in which Licensor conducts its primary
133
+ business, and under the laws of that jurisdiction excluding its
134
+ conflict-of-law provisions. The application of the United Nations
135
+ Convention on Contracts for the International Sale of Goods is expressly
136
+ excluded. Any use of the Original Work outside the scope of this License
137
+ or after its termination shall be subject to the requirements and
138
+ penalties of copyright or patent law in the appropriate jurisdiction.
139
+ This section shall survive the termination of this License.
140
+
141
+ 12) Attorneys' Fees. In any action to enforce the terms of this License
142
+ or seeking damages relating thereto, the prevailing party shall be
143
+ entitled to recover its costs and expenses, including, without
144
+ limitation, reasonable attorneys' fees and costs incurred in connection
145
+ with such action, including any appeal of such action. This section
146
+ shall survive the termination of this License.
147
+
148
+ 13) Miscellaneous. If any provision of this License is held to be
149
+ unenforceable, such provision shall be reformed only to the extent
150
+ necessary to make it enforceable.
151
+
152
+ 14) Definition of "You" in This License. "You" throughout this License,
153
+ whether in upper or lower case, means an individual or a legal entity
154
+ exercising rights under, and complying with all of the terms of, this
155
+ License. For legal entities, "You" includes any entity that controls, is
156
+ controlled by, or is under common control with you. For purposes of this
157
+ definition, "control" means (i) the power, direct or indirect, to cause
158
+ the direction or management of such entity, whether by contract or
159
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
160
+ outstanding shares, or (iii) beneficial ownership of such entity.
161
+
162
+ 15) Right to Use. You may use the Original Work in all ways not
163
+ otherwise restricted or conditioned by this License or by law, and
164
+ Licensor promises not to interfere with or be responsible for such uses
165
+ by You.
166
+
167
+ 16) Modification of This License. This License is Copyright (c) 2005
168
+ Lawrence Rosen. Permission is granted to copy, distribute, or
169
+ communicate this License without modification. Nothing in this License
170
+ permits You to modify this License as applied to the Original Work or to
171
+ Derivative Works. However, You may modify the text of this License and
172
+ copy, distribute or communicate your modified version (the "Modified
173
+ License") and apply it to other original works of authorship subject to
174
+ the following conditions: (i) You may not indicate in any way that your
175
+ Modified License is the "Academic Free License" or "AFL" and you may not
176
+ use those names in the name of your Modified License; (ii) You must
177
+ replace the notice specified in the first paragraph above with the
178
+ notice "Licensed under <insert your license name here>" or with a notice
179
+ of your own that is not confusingly similar to the notice in this
180
+ License; and (iii) You may not claim that your original works are open
181
+ source software unless your Modified License has been approved by Open
182
+ Source Initiative (OSI) and You comply with its license review and
183
+ certification process.
184
+
@@ -0,0 +1,8 @@
1
+ lib/rv_harness.rb
2
+ lib/rv.rb
3
+ bin/rv
4
+ Rakefile
5
+ README
6
+ Manifest
7
+ LICENSE
8
+ CHANGELOG
data/README ADDED
@@ -0,0 +1,79 @@
1
+
2
+ Rv
3
+
4
+ A little <tt>init.d</tt> system for running Camping apps.
5
+
6
+ == License
7
+
8
+ Copyright 2007 Cloudburst, LLC. See the included LICENSE file.
9
+
10
+ == Features
11
+
12
+ * cluster support
13
+ * custom database configuration
14
+ * automated setup tasks
15
+
16
+ Linux is required. Ubuntu is known to work; Gentoo should work; others should work with minor or no changes.
17
+
18
+ == Installation
19
+
20
+ First, run:
21
+
22
+ sudo gem install rv
23
+ sudo rv install
24
+
25
+ Now you have a file <tt>/etc/init.d/rv</tt>. Open it and change the <tt>'user'</tt> keypair in the file if your app user is not <tt>httpd</tt>. There are a few other options you can set; see the Rv class for details.
26
+
27
+ Now, install it as a boot service. On Ubuntu, run:
28
+ sudo /usr/sbin/update-rc.d /etc/init.d/rv defaults
29
+
30
+ On Gentoo, run:
31
+ sudo rc-update add rv default
32
+
33
+ == Application setup
34
+
35
+ Each Camping app should live in its own directory. Traverse to this directory and run:
36
+ sudo rv setup
37
+
38
+ It will now start at boot. You can start it manually (along with your other Rv apps) by running:
39
+ sudo /etc/init.d/rv start
40
+
41
+ Check <tt>/var/log/rv.log</tt> as well as the application log if you're having problems.
42
+
43
+ == Apache configuration
44
+
45
+ If you're using Apache 2.2, here's how to configure it to see your Camping proxy. Add a <tt>VirtualHost</tt> entry in your <tt>httpd.conf</tt> as follows:
46
+
47
+ <VirtualHost *:80>
48
+ ServerName myapp.example.com
49
+
50
+ ProxyRequests Off
51
+ ProxyPass / http://127.0.0.1:4000/
52
+ ProxyPassReverse / http://127.0.0.1:4000/
53
+ ProxyPreserveHost On
54
+
55
+ #Fix for Apache bug 39499
56
+ SetEnv force-proxy-request-1.0 1
57
+ SetEnv proxy-nokeepalive 1
58
+ </VirtualHost>
59
+
60
+ If you configured a cluster, use a <tt>Proxy balancer</tt> instead:
61
+
62
+ <Proxy balancer://myapp_custer>
63
+ BalancerMember http://127.0.0.1:4000
64
+ BalancerMember http://127.0.0.1:4001
65
+ BalancerMember http://127.0.0.1:4002
66
+ # etc.
67
+ </Proxy>
68
+
69
+ and then configure your <tt>ProxyPass</tt> to point to the balancer:
70
+
71
+ ProxyPass / balancer://myapp_custer/
72
+ ProxyPassReverse / balancer://myapp_custer/
73
+
74
+ Do not use the line <tt>ProxyRequests Off</tt>.
75
+
76
+ == Further resources
77
+
78
+ * http://blog.evanweaver.com/pages/code#rv
79
+ * http://rubyforge.org/forum/forum.php?forum_id=13987
@@ -0,0 +1,11 @@
1
+
2
+ require 'rubygems'
3
+ require 'echoe'
4
+
5
+ Echoe.new("rv") do |p|
6
+ p.rubyforge_name = "fauna"
7
+ p.summary = "A little init.d system for running Camping apps."
8
+ p.url = "http://blog.evanweaver.com/pages/code#rv"
9
+ p.docs_host = "blog.evanweaver.com:~/www/snax/public/files/doc/"
10
+ p.extra_deps = ["highline"]
11
+ end
data/bin/rv ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ =begin rdoc
4
+ Executable for running Rv. Accepts <tt>start</tt>, <tt>restart</tt>, <tt>stop</tt>, <tt>status</tt>, <tt>setup</tt> and
5
+ <tt>install</tt> as valid action parameters.
6
+ =end
7
+
8
+ require 'rubygems'
9
+ require 'rv'
10
+
11
+ Rv.new('user' => 'httpd').perform(ARGV[0])
@@ -0,0 +1,242 @@
1
+
2
+ require 'yaml'
3
+ require 'ftools'
4
+ require 'highline/import'
5
+
6
+ # This class implements all the functionality of Rv. You shouldn't need to use this class directly, rather, use the <tt>rv</tt> executable.
7
+ class Rv
8
+
9
+ class << self
10
+
11
+ # Get an Rv parameter from the process environment variables.
12
+ def env(key)
13
+ value = ENV["#{RV}_#{key.upcase}"]
14
+ raise "Rv key #{key} not found" unless value
15
+
16
+ if value == value.to_i.to_s
17
+ value.to_i
18
+ else
19
+ value
20
+ end
21
+ end
22
+
23
+ # Turn an underscored name into a class reference.
24
+ def classify(string)
25
+ eval("::" + string.split("_").map do |word|
26
+ word.capitalize
27
+ end.join)
28
+ end
29
+
30
+ # Get the canonical pid_file name.
31
+ def pid_file(app = nil, port = nil)
32
+ "#{app || env('app')}.#{port || env('port')}.pid"
33
+ end
34
+
35
+ end
36
+
37
+ DEFAULTS = {
38
+ 'user' => 'httpd',
39
+ 'ruby' => '/usr/bin/env ruby',
40
+ 'pidfile' => 'application.pid',
41
+ 'conf_dir' => '/etc/rv',
42
+ 'harness' => 'rv_harness.rb',
43
+ 'log' => '/var/log/rv.log',
44
+ 'null_stream' => "< /dev/null > /dev/null 2>&1",
45
+ 'log_stream' => "< /dev/null >> 'log' 2>&1"
46
+ }
47
+
48
+ VALID_ACTIONS = ['start', 'restart', 'stop', 'status', 'setup', 'install']
49
+
50
+ attr_accessor :options
51
+
52
+ # Create an Rv instance. You can pass an optional hash to override any key in DEFAULTS.
53
+ def initialize(opts = {})
54
+ extra_keys = opts.keys - DEFAULTS.keys
55
+ raise "Invalid options #{extra_keys.join(', ')}" if extra_keys.any?
56
+
57
+ @options = DEFAULTS.merge(opts)
58
+ options['log_stream'].sub!("log", options['log'])
59
+
60
+ # make sure the log exists
61
+ begin
62
+ unless File.exist? options['log']
63
+ File.open(options['log'], "w") {}
64
+ end
65
+ rescue Errno::EACCES
66
+ exit_with "Couldn't write to logfile '#{options['log']}'"
67
+ end
68
+ system "chown #{options['user']} #{options['log']} #{options['null_stream']}"
69
+ system "chgrp #{options['user']} #{options['log']} #{options['null_stream']}"
70
+
71
+ end
72
+
73
+ # Perform any action in VALID_ACTIONS. Defaults to running against all applications. Pass a specific app name as <tt>match</tt> if this is not what you want.
74
+ def perform(action, match = '*')
75
+ exit_with "No action given." unless action
76
+ exit_with "Invalid action '#{action}'." unless VALID_ACTIONS.include? action
77
+
78
+ case action
79
+ when "restart"
80
+ daemon("stop", match)
81
+ daemon("start", match)
82
+ when "install"
83
+ install
84
+ when "setup"
85
+ setup
86
+ else
87
+ daemon(action, match)
88
+ end
89
+
90
+ end
91
+
92
+ # Runs a daemon action. Only called from <tt>perform</tt>.
93
+ def daemon(action, match)
94
+ filenames = Dir["#{options['conf_dir']}/#{match}.yml"]
95
+ exit_with("No applications found for '#{match}' in #{options['conf_dir']}/") if filenames.empty?
96
+
97
+ # Examine matching applications
98
+ filenames.each do |filename|
99
+
100
+ real_config = YAML.load_file(filename)
101
+ puts "Application #{real_config['app']}:"
102
+
103
+ Dir.chdir real_config['dir'] do
104
+
105
+ # cluster loop
106
+ (real_config['cluster_size'] or 1).times do |cluster_index|
107
+ config = real_config.dup
108
+ @port = config['port'] += cluster_index
109
+
110
+ pidfile = Rv.pid_file(config['app'], config['port'])
111
+ pid = File.open(pidfile).readlines.first.chomp rescue nil
112
+ running = pid ? `ps -p #{pid}`.split("\n")[1] : nil
113
+
114
+ case action
115
+ when "status"
116
+ if running
117
+ note "running"
118
+ elsif pid
119
+ note "has died"
120
+ else
121
+ note "not running"
122
+ end
123
+ when "stop"
124
+ if pid and running
125
+ system %[nohup su -c "kill -9 #{pid} #{options['null_stream']}" #{options['user']} #{options['log_stream']}]
126
+ running = nil
127
+ note "stopped"
128
+ elsif pid
129
+ note "not running"
130
+ File.delete pidfile
131
+ else
132
+ note "pid file #{pidfile.inspect} not found. Application was probably not running."
133
+ end
134
+ when "start"
135
+ unless running
136
+ env_variables = config.map {|key, value| "RV_#{key.upcase}=#{value}"}.join(" ")
137
+ system %[nohup su -c "#{env_variables} #{options['ruby']} #{options['harness']} #{options['null_stream']}" #{options['user']} #{options['log_stream']} &]
138
+ sleep(2)
139
+ if File.exist? pidfile
140
+ note "started"
141
+ else
142
+ note "failed to start"
143
+ end
144
+ else
145
+ note "already running"
146
+ end
147
+ end
148
+
149
+ end
150
+ end
151
+ end
152
+ end
153
+
154
+ # Sets up a Camping app for Rv.
155
+ def setup
156
+ this_dir = `pwd`.chomp
157
+ app_name = this_dir.split("/").last
158
+ harness_source = "#{File.dirname(__FILE__)}/rv_harness.rb"
159
+ harness_target = "#{this_dir}/rv_harness.rb"
160
+
161
+ unless File.exist? harness_target
162
+ puts "Installing rv_harness.rb file."
163
+ File.copy harness_source, harness_target
164
+ else
165
+ puts "rv_harness.rb already installed."
166
+ end
167
+
168
+ defaults = {
169
+ 'dir' => this_dir,
170
+ 'app' => app_name,
171
+ 'port' => 4000,
172
+ 'cluster_size' => 1
173
+ }
174
+
175
+ # get the application name
176
+ default_file = current_file = "#{defaults['app']}.rb"
177
+
178
+ begin
179
+ current_file = ask("File of Camping app: ") do |q|
180
+ q.default = default_file
181
+ end
182
+ end while !File.exist?(current_file)
183
+
184
+ defaults['app'] = current_file.split("/").last.gsub(".rb", "")
185
+
186
+ # get the port name
187
+ current_port = ask("Port number to listen on: ") do |q|
188
+ q.default = defaults['port']
189
+ end while current_port.to_i.to_s != current_port
190
+
191
+ defaults['port'] = current_port.to_i
192
+
193
+ # get the cluster size
194
+ current_cluster_size = ask("Listener cluster size (1 recommended): ") do |q|
195
+ q.default = defaults['cluster_size']
196
+ end while current_cluster_size.to_i.to_s != current_cluster_size or current_cluster_size.to_i < 1
197
+
198
+ defaults['cluster_size'] = current_cluster_size.to_i
199
+
200
+ # write the config file
201
+ config_location = "#{options['conf_dir']}/#{defaults['app']}.yml"
202
+ puts "Writing configuration to '#{config_location}'."
203
+
204
+ begin
205
+ unless File.exist? options['conf_dir']
206
+ Dir.mkdir options['conf_dir']
207
+ end
208
+ File.open(config_location, "w") do |file|
209
+ file.write defaults.to_yaml
210
+ end
211
+ rescue Errno::EACCES
212
+ exit_with "Couldn't write to '#{options['conf_dir']}'. Please rerun with 'sudo'."
213
+ end
214
+
215
+ exit_with "All done. Please double-check the database configuration in '#{harness_target}'; then run 'sudo rv start'."
216
+ end
217
+
218
+ # Installs the 'rv' executable into /etc/init.d.
219
+ def install
220
+ bin_source = "#{File.dirname(__FILE__)}/../bin/rv"
221
+ bin_target = "/etc/init.d/rv"
222
+ begin
223
+ File.copy bin_source, bin_target
224
+ rescue Errno::EACCES
225
+ exit_with "Couldn't write to '#{bin_target}'. Please rerun with 'sudo'."
226
+ end
227
+ exit_with "Installed 'rv' executable to '#{bin_target}'."
228
+ end
229
+
230
+ # Exits with a message.
231
+ def exit_with(msg)
232
+ puts msg
233
+ exit
234
+ end
235
+
236
+ # Prints a message along with the current port.
237
+ def note(msg)
238
+ puts " #{msg.capitalize} (#{@port})"
239
+ end
240
+
241
+
242
+ end
@@ -0,0 +1,42 @@
1
+
2
+ # Mongrel harness for Camping apps with Rv.
3
+
4
+ require 'rubygems'
5
+ require 'mongrel'
6
+ require 'mongrel/camping'
7
+ require 'rv'
8
+
9
+ app_name, port = Rv.env('app'), Rv.env('port')
10
+
11
+ # Load the Camping app
12
+ require app_name
13
+ app = Rv.classify(app_name)
14
+
15
+ # Configure your database
16
+ app::Models::Base.establish_connection(
17
+ :adapter => 'mysql',
18
+ :database => "#{app_name}_production",
19
+ :username => 'root'
20
+ )
21
+
22
+ #app::Models::Base.logger = Logger.new("#{app_name}.log")
23
+ app::Models::Base.threaded_connections = false
24
+ app.create
25
+
26
+ Mongrel::Configurator.new :host => '127.0.0.1', :pid_file => Rv.pid_file do
27
+
28
+ listener :port => port do
29
+ # setup routes
30
+ uri '/', :handler => Mongrel::Camping::CampingHandler.new(app)
31
+ uri '/static/', :handler => Mongrel::DirHandler.new("static/")
32
+ uri '/favicon.ico', :handler => Mongrel::Error404Handler.new('')
33
+
34
+ # bootstrap the server
35
+ setup_signals
36
+ run
37
+ write_pid_file
38
+ join
39
+ end
40
+
41
+ end
42
+
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.4
3
+ specification_version: 1
4
+ name: rv
5
+ version: !ruby/object:Gem::Version
6
+ version: "2.9"
7
+ date: 2007-08-06 00:00:00 -04:00
8
+ summary: A little init.d system for running Camping apps.
9
+ require_paths:
10
+ - lib
11
+ email: ""
12
+ homepage: http://blog.evanweaver.com/pages/code#rv
13
+ rubyforge_project: fauna
14
+ description: ""
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - ""
31
+ files:
32
+ - lib/rv_harness.rb
33
+ - lib/rv.rb
34
+ - bin/rv
35
+ - Rakefile
36
+ - README
37
+ - Manifest
38
+ - LICENSE
39
+ - CHANGELOG
40
+ test_files: []
41
+
42
+ rdoc_options: []
43
+
44
+ extra_rdoc_files: []
45
+
46
+ executables:
47
+ - rv
48
+ extensions: []
49
+
50
+ requirements: []
51
+
52
+ dependencies:
53
+ - !ruby/object:Gem::Dependency
54
+ name: highline
55
+ version_requirement:
56
+ version_requirements: !ruby/object:Gem::Version::Requirement
57
+ requirements:
58
+ - - ">"
59
+ - !ruby/object:Gem::Version
60
+ version: 0.0.0
61
+ version: