JasonKing-pulp 0.0.2
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 +38 -0
- data/bin/pulp +13 -0
- data/lib/passenger/config.rb +426 -0
- metadata +65 -0
data/README.markdown
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
pulp
|
2
|
+
====
|
3
|
+
|
4
|
+
This is a simple helper for [passenger](http://modrails.com/) in development. It does two things:
|
5
|
+
|
6
|
+
1. Simplifies the setup of new passenger virtual hosts by adding the necessary
|
7
|
+
records to your apache config as well as to your hosts file.
|
8
|
+
2. Checks your apache config to make sure that you have the right settings, and
|
9
|
+
right order of settings (like that your passenger vhosts are **after** your
|
10
|
+
`NameVirtualHost` directive).
|
11
|
+
|
12
|
+
It works magically, by querying apache itself to find the location of your conf
|
13
|
+
files. It **isn't** magical enough to work on Windows.
|
14
|
+
|
15
|
+
Installation
|
16
|
+
------------
|
17
|
+
|
18
|
+
To perform a system wide installation:
|
19
|
+
|
20
|
+
gem source -a http://gems.github.com
|
21
|
+
gem install JasonKing-pulp
|
22
|
+
|
23
|
+
Usage
|
24
|
+
-----
|
25
|
+
|
26
|
+
Typically you'll setup a new rails app with the `rails` executable, and then
|
27
|
+
call `pulp` afterwards, like this:
|
28
|
+
|
29
|
+
> rails foobar
|
30
|
+
> sudo pulp foobar
|
31
|
+
|
32
|
+
Done. You will now be able to visit http://foobar.dev/ and see your new rails
|
33
|
+
site running.
|
34
|
+
|
35
|
+
Contributors
|
36
|
+
------------
|
37
|
+
|
38
|
+
* Jason King (JasonKing)
|
data/bin/pulp
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require File.join( File.dirname(__FILE__), '..', 'lib', 'passenger', 'config')
|
3
|
+
|
4
|
+
if %w(--version -v).include? ARGV.first
|
5
|
+
puts "#{File.basename(__FILE__)} #{Passenger::Config::VERSION}"
|
6
|
+
exit(0)
|
7
|
+
end
|
8
|
+
|
9
|
+
c = Passenger::Config.new( :root => ARGV[0] )
|
10
|
+
c.update_hosts
|
11
|
+
c.update_apache
|
12
|
+
|
13
|
+
c.consolidate
|
@@ -0,0 +1,426 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'etc'
|
3
|
+
require 'find'
|
4
|
+
require 'grep'
|
5
|
+
|
6
|
+
module Passenger
|
7
|
+
class Config
|
8
|
+
VERSION = '0.8.1'
|
9
|
+
attr_reader :domain
|
10
|
+
attr_reader :ip
|
11
|
+
attr_reader :hosts
|
12
|
+
|
13
|
+
@@marker_string = "#----- #{File.basename($0, '.rb')} marker line -- DO NOT DELETE -----#"
|
14
|
+
|
15
|
+
@@httpd_cmd = 'httpd'
|
16
|
+
@@apachectl = 'apachectl'
|
17
|
+
|
18
|
+
@@user_re = /^\s*User\s+(\S+)/i
|
19
|
+
@@group_re = /^\s*Group\s+(\S+)/i
|
20
|
+
|
21
|
+
def initialize(p)
|
22
|
+
self.root = p[:root]
|
23
|
+
@domain = (p[:domain] || '.dev').sub(/^\.*/,'.')
|
24
|
+
@hosts = p[:hosts] || '/etc/hosts'
|
25
|
+
@ip = p[:ip] || '127.0.0.1'
|
26
|
+
|
27
|
+
@check_for_user = lambda {|l|
|
28
|
+
if m = l.match(@@user_re)
|
29
|
+
@user = m[1]
|
30
|
+
end
|
31
|
+
}
|
32
|
+
@check_for_group = lambda {|l|
|
33
|
+
if m = l.match(@@user_re)
|
34
|
+
@group = m[1]
|
35
|
+
end
|
36
|
+
}
|
37
|
+
|
38
|
+
read_conf
|
39
|
+
check_root_perms
|
40
|
+
|
41
|
+
setup_vhost
|
42
|
+
end
|
43
|
+
|
44
|
+
def consolidate
|
45
|
+
_hosts = list_hosts
|
46
|
+
_vhosts = list_vhosts
|
47
|
+
|
48
|
+
_hosts.each_index do |i|
|
49
|
+
case _hosts[i] <=> _vhosts[i]
|
50
|
+
when 0
|
51
|
+
next
|
52
|
+
when 1
|
53
|
+
puts "Missing from #{hosts}: #{_vhosts[i]}"
|
54
|
+
_hosts.insert(i, _vhosts[i])
|
55
|
+
when -1
|
56
|
+
puts "Missing from #{passenger_conf}: #{_hosts[i]}"
|
57
|
+
_vhosts.insert(i, _hosts[i])
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def update_hosts
|
63
|
+
_had_domain_line = false
|
64
|
+
File.open(hosts, 'r+') do |f|
|
65
|
+
f.flock File::LOCK_EX
|
66
|
+
_buffer = []
|
67
|
+
f.each do |l|
|
68
|
+
if l.match(domain_re) # add it to the same line that the other #{domain} entries are on
|
69
|
+
_had_domain_line = true
|
70
|
+
unless l.match(host_re) # already exists - don't re-add
|
71
|
+
l = "#{l.chomp} #{host}\n"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
_buffer << l
|
75
|
+
end
|
76
|
+
|
77
|
+
unless _had_domain_line # if there was no #{domain} line then just add it to the end
|
78
|
+
_buffer << "#{ip} #{host}\n"
|
79
|
+
end
|
80
|
+
f.seek 0
|
81
|
+
f.truncate 0
|
82
|
+
f << _buffer
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def update_apache
|
87
|
+
File.open(passenger_conf, 'r+') do |f|
|
88
|
+
f.flock File::LOCK_EX
|
89
|
+
catch(:out) do
|
90
|
+
f.each("\n\n") do |ir|
|
91
|
+
if ir == @vhost_entry
|
92
|
+
f.seek 0, IO::SEEK_END
|
93
|
+
throw :out
|
94
|
+
end
|
95
|
+
end
|
96
|
+
f.puts @vhost_entry
|
97
|
+
end
|
98
|
+
end
|
99
|
+
system("#{@@apachectl} restart")
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
def list_hosts
|
104
|
+
_hosts = []
|
105
|
+
File.open(hosts).each do |l|
|
106
|
+
if l.match(domain_re)
|
107
|
+
_hosts += l.scan(/\S+#{Regexp.quote(domain)}(?!\S)/)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
_hosts.sort.uniq
|
111
|
+
end
|
112
|
+
|
113
|
+
def list_vhosts
|
114
|
+
_h = []
|
115
|
+
File.open(passenger_conf).each do |l|
|
116
|
+
if m = l.match( %r{^\s*ServerName\s+(\S+#{Regexp.quote(domain)})(?!\S)})
|
117
|
+
_h << m[1]
|
118
|
+
end
|
119
|
+
end
|
120
|
+
_h.sort.uniq
|
121
|
+
end
|
122
|
+
|
123
|
+
def setup_vhost
|
124
|
+
@vhost_entry =<<-__EOI
|
125
|
+
<VirtualHost #{vhost}>
|
126
|
+
DocumentRoot #{root}
|
127
|
+
ServerName #{host}
|
128
|
+
<Location />
|
129
|
+
Order allow,deny
|
130
|
+
Allow from all
|
131
|
+
</Location>
|
132
|
+
</VirtualHost>
|
133
|
+
|
134
|
+
__EOI
|
135
|
+
end
|
136
|
+
|
137
|
+
def root=(_d)
|
138
|
+
@root = File.expand_path(_d || '.')
|
139
|
+
end
|
140
|
+
|
141
|
+
def root
|
142
|
+
File.join(@root, 'public')
|
143
|
+
end
|
144
|
+
|
145
|
+
def app
|
146
|
+
@app ||= File.basename(@root)
|
147
|
+
end
|
148
|
+
|
149
|
+
def host
|
150
|
+
@host ||= app + domain
|
151
|
+
end
|
152
|
+
|
153
|
+
def localhost_re
|
154
|
+
@localhost_re ||= %r{^\s*#{Regexp.quote(ip)}\s.*}
|
155
|
+
end
|
156
|
+
|
157
|
+
def domain_re
|
158
|
+
@domain_re ||= %r{#{localhost_re}\b#{Regexp.quote(domain)}(?!\S)}
|
159
|
+
end
|
160
|
+
|
161
|
+
def host_re
|
162
|
+
@host_re ||= %r{#{localhost_re}\s#{Regexp.quote(host)}(?!\S)}
|
163
|
+
end
|
164
|
+
|
165
|
+
def conf
|
166
|
+
@conf ||= from_server('SERVER_CONFIG_FILE')
|
167
|
+
end
|
168
|
+
|
169
|
+
def dir
|
170
|
+
@dir ||= File.dirname(self.conf)
|
171
|
+
end
|
172
|
+
|
173
|
+
def server_root
|
174
|
+
@server_root ||= File.open(conf).grep(/^\s*ServerRoot\s+['"]?([^'"\s]+)['"]?/i).first[:match][1] || from_server('HTTPD_ROOT')
|
175
|
+
end
|
176
|
+
|
177
|
+
def dir_handle
|
178
|
+
@dir_handle ||= Dir.open(dir)
|
179
|
+
end
|
180
|
+
|
181
|
+
def user
|
182
|
+
@user ||= get_user
|
183
|
+
end
|
184
|
+
|
185
|
+
def group
|
186
|
+
@group ||= get_group
|
187
|
+
end
|
188
|
+
|
189
|
+
def get_user
|
190
|
+
File.open(conf).each do |line|
|
191
|
+
return @user if @check_for_user.call(line)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def check_root_perms
|
196
|
+
system("sudo -u #{user} ls #{root} 1>/dev/null 2>&1") or raise %Q{Your Apache user "#{user}" can't read your document root "#{root}"}
|
197
|
+
end
|
198
|
+
|
199
|
+
def get_group
|
200
|
+
File.open(conf).each do |line|
|
201
|
+
return @group if @check_for_group.call(line)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def retrieve_passenger_conf
|
206
|
+
File.open(conf) do |f|
|
207
|
+
f.each do |line|
|
208
|
+
@check_for_user.call(line)
|
209
|
+
@check_for_group.call(line)
|
210
|
+
if line.chomp == @@marker_string
|
211
|
+
until line.match(/^\s*[^#]/)
|
212
|
+
line = f.gets
|
213
|
+
unless m = line.match(/^\s*Include\s+(\S+)/)
|
214
|
+
raise "Non-include following marker: #{@@marker_string} in #{conf}"
|
215
|
+
end
|
216
|
+
return m[1]
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
return nil
|
222
|
+
end
|
223
|
+
|
224
|
+
def passenger_conf
|
225
|
+
return @passenger_conf if @passenger_conf || @passenger_conf = retrieve_passenger_conf
|
226
|
+
|
227
|
+
# the logic for where we're going to add our vhosts is a little complex
|
228
|
+
#
|
229
|
+
# 1. We use the RailsEnv file as long as it comes after the
|
230
|
+
# NameVirtualHost entry
|
231
|
+
# 2. Otherwise we're going to create our own file, include it from the
|
232
|
+
# main conf, and use that
|
233
|
+
|
234
|
+
if @conf_files[:renv][:order] > @conf_files[:vhost][:order]
|
235
|
+
if @conf_files[:renv][:file] != conf
|
236
|
+
return @passenger_conf = @conf_files[:renv][:file]
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
@passenger_conf = make_new_file
|
241
|
+
end
|
242
|
+
|
243
|
+
def read_conf
|
244
|
+
@conf_files = {}
|
245
|
+
# Strings that we're looking for:
|
246
|
+
#
|
247
|
+
# NameVirtualHost *:80
|
248
|
+
# LoadModule passenger_module /opt/local/lib/ruby/gems/1.8/gems/passenger-2.0.6/ext/apache2/mod_passenger.so
|
249
|
+
# PassengerRoot /opt/local/lib/ruby/gems/1.8/gems/passenger-2.0.6
|
250
|
+
# PassengerRuby /opt/local/bin/ruby
|
251
|
+
#
|
252
|
+
@_conf_strings = {
|
253
|
+
:vhost => /^\s*NameVirtualHost\s+(\S+)/i,
|
254
|
+
:load => %r{^\s*LoadModule\s+passenger_module\s+((/\S+)/lib/ruby/gems/\S+/passenger-[\d.]+)/ext/apache2/mod_passenger.so}i,
|
255
|
+
:root => %r{^\s*PassengerRoot\s+(['"]?)(/\S+/lib/ruby/gems/\S+/passenger-[\d.]+)\1}i,
|
256
|
+
:ruby => %r{^\s*PassengerRuby\s+(['"]?)(/\S+)/bin/ruby\1}i,
|
257
|
+
:renv => %r{^\s*RailsEnv\s+(['"]?)(\S+)\1}i
|
258
|
+
}
|
259
|
+
|
260
|
+
# change into the server root so that any relative paths in the conf files work
|
261
|
+
Dir.chdir(server_root) do |p|
|
262
|
+
|
263
|
+
# start at the conf and drill down through all includes looking for our
|
264
|
+
# strings and recording where they are - we're just going to barf if we
|
265
|
+
# find the strings in more than one location - let the user sort that
|
266
|
+
# out
|
267
|
+
drill_down(conf)
|
268
|
+
end
|
269
|
+
ensure_conf
|
270
|
+
end
|
271
|
+
|
272
|
+
def ensure_dir(d)
|
273
|
+
_umask = File.umask(022)
|
274
|
+
_dir = File.mkdirs(File.join(dir, d))
|
275
|
+
File.umask(_umask)
|
276
|
+
_dir
|
277
|
+
end
|
278
|
+
|
279
|
+
def make_new_file
|
280
|
+
_dir = ensure_dir('extra')
|
281
|
+
|
282
|
+
# we're going to make sure that we get a filename that doesn't exist
|
283
|
+
%w{passenger.conf mod_rails.conf httpd-passenger.conf httpd-mod_rails.conf j20qmcjidhe93knd.conf}.each do |fn|
|
284
|
+
_f = File.join(_dir,fn)
|
285
|
+
if !File.exist?(_f)
|
286
|
+
FileUtils.touch _f
|
287
|
+
File.open(conf, 'a') do |f|
|
288
|
+
f.puts @@marker_string
|
289
|
+
f.puts "Include #{_f}"
|
290
|
+
end
|
291
|
+
return _f
|
292
|
+
end
|
293
|
+
end
|
294
|
+
raise "Couldn't find a unique filename in #{_dir}."
|
295
|
+
end
|
296
|
+
|
297
|
+
def ensure_conf
|
298
|
+
_need_re_read = false
|
299
|
+
unless @conf_files[:root]
|
300
|
+
add_to_conf( "PassengerRoot #{@conf_files[:load][:match][1]}", :load, :root )
|
301
|
+
_need_re_read = true
|
302
|
+
end
|
303
|
+
|
304
|
+
unless @conf_files[:ruby]
|
305
|
+
add_to_conf( "PassengerRuby #{@conf_files[:load][:match][2]}/bin/ruby", :root, :ruby )
|
306
|
+
_need_re_read = true
|
307
|
+
end
|
308
|
+
|
309
|
+
unless @conf_files[:renv]
|
310
|
+
add_to_conf( "RailsEnv #{ENV['RAILS_ENV'] || 'development'}\n", :ruby, :renv )
|
311
|
+
_need_re_read = true
|
312
|
+
end
|
313
|
+
|
314
|
+
unless @conf_files[:vhost]
|
315
|
+
add_to_conf( "NameVirtualHost *:80\n", :renv, :vhost )
|
316
|
+
_need_re_read = true
|
317
|
+
end
|
318
|
+
|
319
|
+
if _need_re_read
|
320
|
+
read_conf
|
321
|
+
end
|
322
|
+
check_conf
|
323
|
+
end
|
324
|
+
|
325
|
+
def add_to_conf( str, from, to)
|
326
|
+
p = @conf_files[from]
|
327
|
+
File.open( p[:file], 'r+' ) do |f|
|
328
|
+
f.flock File::LOCK_EX
|
329
|
+
_buffer = []
|
330
|
+
f.each do |l|
|
331
|
+
_buffer << l
|
332
|
+
if $. == p[:lineno]
|
333
|
+
@conf_files[to] = { :file => p[:file], :lineno => $. + 1 + str.count("\n") }
|
334
|
+
_buffer << str + "\n"
|
335
|
+
end
|
336
|
+
end
|
337
|
+
f.truncate 0
|
338
|
+
f.seek 0
|
339
|
+
f << _buffer
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
def check_conf
|
344
|
+
# we can add everything except the LoadModule line
|
345
|
+
unless @conf_files[:load]
|
346
|
+
raise "LoadModule line missing, maybe you forgot to run: passenger-install-apache2-module"
|
347
|
+
end
|
348
|
+
|
349
|
+
_load_order = @conf_files[:load][:order]
|
350
|
+
[ :root, :ruby, :renv ].each do |s|
|
351
|
+
next unless @conf_files[s]
|
352
|
+
if _load_order > @conf_files[s][:order]
|
353
|
+
raise "Passenger module loaded too late: #{@conf_files[:load][:file]},#{@conf_files[:load][:lineno]} needs to happen before #{@conf_files[s][:file]},#{@conf_files[s][:lineno]}"
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
_load_passenger_location = @conf_files[:load][:match][1]
|
358
|
+
if @conf_files[:root]
|
359
|
+
unless _load_passenger_location == _root_passenger_location = @conf_files[:root][:match][2]
|
360
|
+
raise "Passenger module location #{_load_passenger_location} and PassengerRoot setting #{_root_passenger_location} should be the same."
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
_load_passenger_prefix = @conf_files[:load][:match][2]
|
365
|
+
if @conf_files[:ruby]
|
366
|
+
unless _load_passenger_prefix == _ruby_passenger_prefix = @conf_files[:ruby][:match][2]
|
367
|
+
raise "Passenger module prefix #{_load_passenger_prefix} and PassengerRuby prefix #{_ruby_passenger_prefix} should be the same."
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
def vhost
|
373
|
+
@vhost ||= @conf_files[:vhost][:match][1]
|
374
|
+
end
|
375
|
+
|
376
|
+
def drill_down(_c)
|
377
|
+
@_order ||= 0
|
378
|
+
_c = File.expand_path(_c)
|
379
|
+
File.open(_c).each_line do |line|
|
380
|
+
@_conf_strings.each do |k,v|
|
381
|
+
if m = line.match(v)
|
382
|
+
_exists = @conf_files[k]
|
383
|
+
raise "#{k} was already found in #{_exists[:file]},#{_exists[:lineno]} for #{_c},#{$.}" if _exists
|
384
|
+
@conf_files[k] = { :file => _c, :lineno => $., :match => m, :order => @_order += 1 }
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
if m = line.match(/^\s*Include\s+(['"]?)(\S+)\1/i)
|
389
|
+
# apache includes are commonly file globs
|
390
|
+
Dir.glob(m[2]).each do |f|
|
391
|
+
drill_down(f)
|
392
|
+
end
|
393
|
+
end
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
|
398
|
+
def recursive_tracking(_c)
|
399
|
+
_c.each do |c|
|
400
|
+
_filename = c[:file]
|
401
|
+
_new = dir_handle.grep(/^\s*Include.*#{Regexp.escape(_filename)}/i)
|
402
|
+
unless _new.size > 0
|
403
|
+
# do some other things
|
404
|
+
end
|
405
|
+
|
406
|
+
if _new.find{|c| c[:file] == conf}
|
407
|
+
return true
|
408
|
+
end
|
409
|
+
|
410
|
+
ret = recursive_tracking(_new)
|
411
|
+
if ret
|
412
|
+
@includes << c
|
413
|
+
else
|
414
|
+
@includes.pop
|
415
|
+
end
|
416
|
+
return ret
|
417
|
+
end
|
418
|
+
return false
|
419
|
+
end
|
420
|
+
|
421
|
+
def from_server(s)
|
422
|
+
@httpd_string ||= `#{@@httpd_cmd} -V`
|
423
|
+
@httpd_string.match(/#{s}="([^"]+)"/i)[1]
|
424
|
+
end
|
425
|
+
end
|
426
|
+
end
|
metadata
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: JasonKing-pulp
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jason King
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-03-12 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: JasonKing-grep
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.2
|
24
|
+
version:
|
25
|
+
description:
|
26
|
+
email: jk@handle.it
|
27
|
+
executables:
|
28
|
+
- pulp
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files: []
|
32
|
+
|
33
|
+
files:
|
34
|
+
- README.markdown
|
35
|
+
- lib/passenger/config.rb
|
36
|
+
- bin/pulp
|
37
|
+
has_rdoc: true
|
38
|
+
homepage: http://github.com/JasonKing/pulp
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options:
|
41
|
+
- --inline-source
|
42
|
+
- --charset=UTF-8
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: "0"
|
50
|
+
version:
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: "0"
|
56
|
+
version:
|
57
|
+
requirements: []
|
58
|
+
|
59
|
+
rubyforge_project:
|
60
|
+
rubygems_version: 1.2.0
|
61
|
+
signing_key:
|
62
|
+
specification_version: 2
|
63
|
+
summary: pulp - Passenger Helper - for simple setup of Ruby Apps using Passenger
|
64
|
+
test_files: []
|
65
|
+
|